Clojure solves the inversion-of-control problem

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

Interesting:

The emphasis on concurrency via shared, immutable data promotes standard, dynamic methods for libraries and functions to interact. Since a user can trust that data is immutable and reliable, there is no need for things like defensive copying as is standard practice (or should be) in multi-threaded object systems like java. It’s simply not easy or expedient to go out of your way to destroy someone else’s data. This trust in data integrity coupled with the syntactic abstraction afforded via macros and higher-order functions means you can write concise code that composes in intuitive ways, without the need to hook yourself into someone else’s sandbox (eg Spring or Rails).

The most troublesome thing about such frameworks is the use of polymorphism and inversion of control as a sledgehammer to get around the inherent problems of OO. Namely, OO couples state-change to objects (binds the effects of time to a specific bucket of memory), and functions to classes. Clojure, on the other hand, feels like nothing you write is actually ‘doing’ anything at all. Functions generally simply transform data, and occasionally you might fire off a side-effect or perform some coordinated state change. You can trust that there is usually a simple relationship of inputs to outputs. When you want polymorphism, you can get it in spades, but you’ll end up sprinkling it in occasionally instead of being bound to a particular style throughout the construction of your application.

When was the last time you tried to switch some Spring beans or Rails controllers over to another framework, or use two such frameworks in one application? This is problematic primarily due to inversion of control binding all your code to the framework’s assumptions. In clojure, you compose functions yourself, making more choices along the way, but the benefits of doing so coupled with the ease of dealing in data overshadows the need to trust in someone else’s choices. Code becomes actually reusable, and it usually even reads more like a tree-expansion than a graph traversal. The language features themselves are mostly orthogonal, and are similarly composable.

Source