-
Notifications
You must be signed in to change notification settings - Fork 114
FAQ
Yes, just call rootScope.toString()
and print it.
No, Toothpick only allows to inject classes and interfaces. This is a design decision that allows Toothpick to use IdentityHashMap
and get better performances.
Probably not. Toothpick has been designed to remain simple. Simple to code, simple to maintain, simple to use. And we largely favor this over any feature. But, hey, it's an OSS project, take it where you want..
Since the inception of the JSR 330 by Crazy Bob, many DI libraries were created. We start the history of Toothpick were we saw it started from our point of view : on Android.
Mike Burton has created RoboGuice in August 2009. At that time, the early days of Android, it was just great to enjoy Dependency Injection on Android. Though, the library had several problems that became more and more important as Android development was getting more and more mature:
- Guice is slow, at least it didn't match any more the expected performance of Android apps.
- Guice 4 uses guava which contains tens of thousands of methods that contribute to multidex issues and heavy apks
- Guice uses reflection and reflection is especially slow on Android. Mostly because there is no JIT of reflection code as opposed to PC JVMs.
- Guice stack traces are horrible to debug.
- RoboGuice's scope was large, and made the library more difficult to maintain. It was doing DI, view injection, events, etc. And not all features were as great as others (especially events).
Jesse Wilson has created Dagger 1 in June 2012. Dagger bore radical change to DI : Guice and all other DI framework where doing a lot of things at runtime, Dagger does most of DI at compile time. In Dagger, reflection is fully replaced by annotation processing (an old idea of crazy bob).
Dagger 1 is a great progress conceptually for DI. But it also comes with a price tag:
- dagger syntax is a bit bloated with annotations, it's definitely harder than Guice to use
- take care of the injection tree at compile time requires a lot of efforts from developers
- dagger syntax requires quite some boiler plate, we tend to forget it but it's not intuitive to write something like
@Provides @Singleton Heater provideHeater() {
return new ElectricHeater();
}
Developers do all the work even the simplest dependency creation.
Dagger 2 pushes Dagger 1 approach even further. It is a joint effort of many developers to make DI even faster, and to generate code that is either to trace. Dagger 2 also makes the notion of scope much sharper than Dagger 1. But Dagger 2 also comes with a price to pay:
- DI graph is completely static and there is no support for using it for testing, which is one of the main motivation behind DI.
- Dagger 2 requires as much boiler plate
- Dagger 2 introduces the notion of component which is new from a JSR 330 perspective
- Dagger 2 forces to use constructor injection for dependencies, methods injection is more or less supported, a few things are strange like the middle-man component pass over trick.
On our side, we have been maintaining RoboGuice, trying to make it faster, understand exactly what was making it slow. We loved the simplicity and clarity of Guice, and wanted to keep it. And we made great progress:
- RG 3 uses annotation processing and performed 35 % faster than RG 2
- RG 4 uses even more optimisations and performed again 35% faster than RG 3
We have also investigated other techniques like byte code weaving, AST manipulations, etc. to make Guice faster. Though annotation processing helped, it has proved to be hard to change Guice, and we could only fork it, none of our PRs were accepted to make Guice faster. We perfectly understand this, Guice has its niche in DI where advanced features are required, and Dagger is there for the full speed use case.
So, we ended up creating Toothpick. And we like it a lot and are happy to publish it as an Open Source project:
- Toothpick is fast, not as fast as Dagger 1 & 2 because it's runtime based, but much faster than Guice / RoboGuice.
- Toothpick doesn't use reflection at all
- Toothpick aims to be as simple as Guice, it's syntax is a charm, it has few rules.
- Toothpick exposes scopes clearly, which makes it very powerful at a conceptual level. It is very well suited to work with context aware frameworks like web frameworks or android,
- Toothpick scopes make it easier to use advanced programming techniques like MVP on Android, or a set of shared objects in scopes that span over multiple activities,
- Toothpick is thread safe and locks as little and as lately as possible,
- Toothpick offers android support via Smoothie,
- Toothpick offers advanced testing support via toothpick-testing
- Toothpick stack traces are clear and simple. Generated code is simple too.
//testing with Toothpick
@Mock private Computer mockComputer;
@Mock private Computer2 mockComputer2;
//do not use test subject from easymock, it by passes toothpick injection
private SimpleEntryPoint simpleEntryPointUnderTest = new SimpleEntryPoint();
@Test
public void testMultiply() throws Exception {
//GIVEN
expect(mockComputer.compute()).andReturn(4);
expect(mockComputer2.compute()).andReturn(4);
replay(mockComputer, mockComputer2);
toothPickRule.inject(simpleEntryPointUnderTest);
//WHEN
int result = simpleEntryPointUnderTest.multiply();
//THEN
assertThat(result, is(48));
verify(mockComputer);
}
Toothpick & smoothie are puns in different ways:
- it is sharper than a dagger, and yes, we also find the name funny :)
- Toothpick is definitely less square than dagger 2, see its simpler rules and concepts
- it is made of wood, trees are made of wood
- Toothpick exposes 2 dags (scope trees and injection graph), it is a dag square
- Smoothie is the best of Guice, RoboGuice and Blender (the annotation processor of RoboGuice).