For awhile in Scala, I was really fighting the idea of giving up IoC/dependency injection. When Spring came around I was in J2EE hell. Dealing with EJB deployment descriptors and porting things from one bad app server to the next, realizing that write once/run anywhere was a total lie when it came to the J2EE spec. Spring was just what the doctor ordered, say good by to complicated deployment descriptors, JNDI, all that nonsense. Of course over time Spring turn into XML hell, which was the replaced by annotations. I’ve used some other IoC frameworks as well, and sorta got used to doing things that way.
The fact Scala has built in singletons via Object, pretty quickly convinced me I didn’t need IoC anymore. It was sorta like duh, yeah, that makes total sense we should just have stuff like that built in. The next really common Java’ism I had to rethink was context. Java loves context. You have the servlet context, thread local context, context for this, context for that, there is a context is just about every api you encounter. You need these little things to hold onto state while you do something. Basically, you want to push some little bit of data somewhere and pull it out way down in your stack, and if you had to pass that around to every method call you make you’d have to touch like 40,000 api’s 1/2 of which you can’t control, and so it goes. But we’ve all encountered how fragile these little guys are. They have some magic name that gets stuck in a constant someone, which is one point of failure when the name changes. Then if on the consumer side, if that guy didn’t get put there, you are just screwed, and you just sorta hope whoever or whatever was supposed to put in there did so.
One way to avoid all this context nonsense in Scala is with implicit parameters. An implicit parameter is an optional parameter you can define on a method. You can either implicitly call a function with a value for it, or if you don’t provide the value, the compiler will look for a value in the scope somewhere.
You mark a parameter as being implicit in your function definition like so:
So now you can call this in the normal way, like this:
or if these parameters can be set as implicit somewhere in the scope, and they magically get applied, like this:
In a web app, this sort of stuff is great for the user, request, role, customer, or whatever normal state things you have that you need often, but don’t necessarily want to have to pass all around.
Ok so now the real voodoo. You can in fact magically insert functions into existing classes. Ruby has something like this called monkey patching, C# has something called extensions, the other dynamic languages have something similar as well. The problem with the dynamic languages is that one framework could monkey patch something in with one name and another framework uses the same name, and then you have a whole problem. In our happy statically typed world of Scala, the compiler will catch these problems for you and bitch.
Ok so how does this work. I’ll give a little example where I tried it out. In a typical web app, you have some domain classes modeling your database layer. Then you start through those into your view and you realize there are some things you need that might be based on the domain but need some dynamic generation or whatever. In my example, I have a meeting for a web conferencing tool. Most of the meeting info is in the database, but then I have to dynamically create a join url in the view, because there are user parameters, and checksums, and what have you. In Java, you might have to create another class that decorates your domain object. Or you might build up some maps and pass them down. But what if I could just add a joinUrl() method to my meeting object, so when I’m iterating over a list in the view I can just spit that out, without any more bother.
Here’s how that might work:
The first thing you do is define your class that models the method you want to add. The create an Object which defines the implicit method, giving it a name and tying it to your class that has the implementation. Then where you want to use this, you simply bring in the Conversions object in the import and it will magically be available in a Play template, or any other Scala code where you might want to use it:
You can read about how monkey patching causes problems in dynamic languages. Readability, collisions, etc, etc. You can see in Scala, because things are strongly typed, and you have to actually import the implicit method conversion to have it work, that the complier helps you avoid some of those pitfalls. Its still probably a valid argument that these types of tools should be used sparingly, but you can see how powerful they are and how they can make other code much more readable and clean.