Why Clojure?
Why did I write yet another programming language? Basically because I wanted:
- A Lisp
- for Functional Programming
- symbiotic with an established Platform
- designed for Concurrency
and couldn't find one. Here's an outline of some of the motivating ideas behind Clojure.
Lisp is a good thing
- Often emulated/pillaged, still not duplicated
- Lambda calculus yields an extremely small core
- Almost no syntax
- Core advantage still code-as-data and syntactic abstraction
- What about the standard Lisps (Common Lisp and Scheme)?
- Slow/no innovation post standardization
- Core data structures mutable, not extensible
- No concurrency in specs
- Good implementations already exist for JVM (ABCL, Kawa, SISC et al)
- Standard Lisps are their own platforms
- Clojure is a Lisp not constrained by backwards compatibility
- Extends the code-as-data paradigm to maps and vectors
- Defaults to immutability
- Core data structures are extensible abstractions
- Embraces a platform (JVM)
Functional programming is a good thing
- Immutable data + first-class functions
- Could always be done in Lisp, by discipline/convention
- But if a data structure can be mutated, dangerous to presume it won't be
- In traditional Lisp, only the list data structure is structurally recursive
- Pure functional languages tend to strongly static types
- Not for everyone, or every task
- Clojure is a functional language with a dynamic emphasis
- All data structures immutable & persistent, supporting recursion
- Heterogeneous collections, return types
- Dynamic polymorphism
Languages and Platforms
- VMs, not OSes, are the platforms of the future, providing:
- Type system
- Dynamic enforcement and safety
- Libraries
- Abstract away OSes
- Huge set of facilities
- Built-in and 3rd-party
- Memory and other resource management
- GC is platform, not language, facility
- Bytecode + JIT compilation
- Abstracts away hardware
- Type system
- Language as platform vs. language + platform
- Old way - each language defines its own runtime
- GC, bytecode, type system, libraries etc
- New way (JVM, .Net)
- Common runtime independent of language
- Old way - each language defines its own runtime
- Language built for platform vs language ported-to platform
- Many new languages still take 'Language as platform' approach
- When ported, have platform-on-platform issues
- Memory management, type-system, threading issues
- Library duplication
- If original language based on C, some extension libraries written in C don't come over
- Platforms are dictated by clients
- 'Must run on JVM' or .Net vs 'must run on Unix' or Windows
- JVM has established track record and trust level
- Now also open source
- Interop with other code required
- C linkage insufficient these days
- Java/JVM is language + platform
- Not the original story, but other languages for JVM always existed, now embraced by Sun
- Java can be tedious, insufficiently expressive
- Lack of first-class functions, no type inference, etc
- Ability to call/consume Java is critical
- Clojure is the language, JVM the platform
Object Orientation is overrated
- Born of simulation, now used for everything, even when inappropriate
- Encouraged by Java/C# in all situations, due to their lack of (idiomatic) support for anything else
- Mutable stateful objects are the new spaghetti code
- Hard to understand, test, reason about
- Concurrency disaster
- Inheritance is not the only way to do polymorphism
- "It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures." - Alan J. Perlis
- Clojure models its data structures as immutable objects represented by interfaces, and otherwise does not offer its own class system.
- Many functions defined on just 3 primary data structures (seq, map, vector).
- Extend Java in Java, consume Java from Clojure.
Polymorphism is a good thing
- Switch statements, structural matching etc yield brittle systems
- Polymorphism yields extensible, flexible systems
- Clojure multimethods decouple polymorphism from OO and types
- Supports multiple taxonomies
- Dispatches via static, dynamic or external properties, metadata, etc
Concurrency and the multi-core future
- Immutability makes much of the problem go away
- Share freely between threads
- But changing state a reality for simulations and for in-program proxies to the outside world
- Locking is too hard to get right over and over again
- Clojure's software transactional memory does the hard part
In short, I think Clojure occupies a unique niche as a functional Lisp for the JVM with strong concurrency support. Check out some of the features.