Anyways, in OO, separating interface from implementation is a key thing in managing complexity. Therefore we use interfaces, packages, private members etc. You know all this, right. Also, you might know that none of the above facilities exist in Haskell. But, let's start with an example now. And let's pretend we are in a desperate need of a new logging framework. In Java, we could start with
And POW, we have separated interface from implementation and are ready to start writing the EJBLogger class.
But, in Haskell? We've got
types(which are just synonyms for other types)
dataswhich are like immutable structs to simplify
typeclasseswhich are somewhat similar to OO interfaces. You can declare an
datato give it this interface.
Typeclasses may seem like the obvious solution for Logger, for instance, but they are not as practical as you'd think at first. That's what I discovered when trying to model Rx for Haskell, as I already told you about in my previous post.
I found out that the less sexy
The Haskell version isn't so different:
Except for, of course, that it's type-safe and has a real interface for Logger. It also appears a bit shorter, because of Haskell's more compact formatting conventions and its support for partially applied functions (currying).
In the above example, the closure, or the hidden part of the "object" actually consists of the statically defined method
log. In the next example, there's also a constructor parameter involved:
With this logger, you can specify the logging threshold in the constructor. See:
Dead simple. Now bash me for trying to bring my OO thinking to the functional wonderland. Then bash me some more, because the rest of this posting contains more questions than answers. Then tell me how I deploy this kind of a logging framework in Haskell. I mean, how do I pragmatically obtain the Logger in all of my IO code. With Java I'm used to
Which implies that the logging framework is statically configured and is practically using global varibles, which is a sin, but maybe acceptable in the logging example. Now how do I do similar stuff in Haskell? Should I resort to global variables there too? I would feel a bit sad passing around a Logger to every possible service that might need it.
In some other cases I might use a Dependency Injection framework to get implementations of certain services.
Like, if I've got an Application that's using a Web Service in the Internet for getting stock quotes and then displaying them to the user as stunning 3D graphs. When running in a test setup, I'd like to use a different URL for the Web Service. I'd also like to be able to configure the app so that I can run it locally on my machine, so that the stock quotes would actually be generated randomly instead of using a Web Service at all. Like
Now putting together the application would involve creating a bunch of services and stuff and the passing them around to, like, the GUI layer or so. I could create the services differently depending on whether we are running in production, test, or local setup. Now is this just the Enterprise Java Architect mindset or do we need something like Dependency Injection in a larger scale application? Will we end up in a mess without something like it? In Java we did, because we had to manually pass tons of arguments to put the shit together. Using DI, the art of binding interfaces to implementations is separated from actual object creation. Using DI magic, I don't need to pass stuff down the chain of constructors.
Any experiences with Enterprise Haskell anyone? :)