It's not just the compilers. Clojure is nice in its way, but it lacks some essentials of Lisp programming. For a while now I've been wishing for a Clojure implementation that is a proper Lisp--one that restores what Clojure has lost. One that has, as I wrote elsewhere, Lisp's flesh and bones.
I'd also like it to conform well enough to the JVM implementation that I could use my full-blown Lispy Clojure for development, and still deploy with confidence on the JVM Clojure.
Obviously, someone's going to want to know what I think is missing from Clojure, so following is a partial list. These are things I've been accustomed to relying on for decades now, and that I always miss keenly when working with Clojure.
Instant startup with my environment already customized to my specifications.
Comprehensive reflection with full UI support. Support for inspecting absolutely everything in the runtime, with the ability to interactively edit everything you inspect.
The ability to reproduce my whole development environment and its entire dynamic runtime state on a different account or machine simply by copying over a file.
A real Lisp repl that can inspect and redefine everything in memory, save and restore the complete dynamic state of the running system, and deliver a finished executable from an expression typed at the repl. In short, anything you can do with the Lisp, you should be able to do from within the Lisp, by evaluating an s-expression at the repl.
Proper Lisp-style error-handling. The ability to catch any error or exception in an interactive breakloop, walk up and down the call stack, inspect and modify variables, types, and functions, and resume execution with the changed definitions just as if the pending function had been called with them in place originally.
People rightly complain about Clojure's atrocious error messages. They've gotten better, but they're still very far from what I expect in a Lisp error-handling system. I want the real thing: when something unexpected happens you get a proper Lisp-style interactive breakloop from which you can see and modify everything on the call stack and, indeed, everything in the running system, and you can tell the runtime where to resume execution from, either interactively or under program control.
A runtime designed with the understanding that you're going to be writing your application by changing it while it runs. Lisp and Smalltalk have had these features forever. Apple's Dylan and SK8 had them. It's disappointing that Clojure doesn't.
Common Lisp, for example, defines a standard protocol that enables you to redefine classes with the confidence that the Lisp will automatically update any existing instances to conform to the new definition. When Lisp can't figure out how to make things consistent, it doesn't quit or spew a dead stack trace; it starts a breakloop that captures the pending call stack. As I mentioned before, you can use the breakloop to inspect everything on the stack, make whatever changes are needed, and then resume computation with the changes in place.
I wish it were as easy to subsume foreign type systems into Clojure as it is in Common Lisp. Clojure's Java interop is good, but it's special. You have the nice Java interop, but you don't have a standard API for building your own equally-nice interops. Compare with Clozure Common Lisp's Cocoa interop. It's also good, but more importantly, it's built on common APIs (CLOS and the MOP) that you can use to make your own interop subsystems that are just as good.
To me, these are table stakes for a Lisp. I've already had them for decades. Working in Clojure means I have to give them up, and the whole time I'm missing them. A Lisp that doesn't know how to do them is only part of a toolbox. Whole drawers of essential tools are missing. I mean, sure, you can build apps with them. And you can build a house with stone knives and bearskins, but if you've used a proper toolbox before, you'll be missing it the whole time.
If there were a Clojure implementation with these features, then I wouldn't miss Common Lisp so much the whole time I'm working in Clojure. I probably wouldn't spend as much time looking forward to when I can get back to using a real Lisp. I'd get more done faster and with greater joy in my work.
I'm sort of hoping Cloture will turn out to be a step in the right direction.
I'd also like it to conform well enough to the JVM implementation that I could use my full-blown Lispy Clojure for development, and still deploy with confidence on the JVM Clojure.
Obviously, someone's going to want to know what I think is missing from Clojure, so following is a partial list. These are things I've been accustomed to relying on for decades now, and that I always miss keenly when working with Clojure.
Instant startup with my environment already customized to my specifications.
Comprehensive reflection with full UI support. Support for inspecting absolutely everything in the runtime, with the ability to interactively edit everything you inspect.
The ability to reproduce my whole development environment and its entire dynamic runtime state on a different account or machine simply by copying over a file.
A real Lisp repl that can inspect and redefine everything in memory, save and restore the complete dynamic state of the running system, and deliver a finished executable from an expression typed at the repl. In short, anything you can do with the Lisp, you should be able to do from within the Lisp, by evaluating an s-expression at the repl.
Proper Lisp-style error-handling. The ability to catch any error or exception in an interactive breakloop, walk up and down the call stack, inspect and modify variables, types, and functions, and resume execution with the changed definitions just as if the pending function had been called with them in place originally.
People rightly complain about Clojure's atrocious error messages. They've gotten better, but they're still very far from what I expect in a Lisp error-handling system. I want the real thing: when something unexpected happens you get a proper Lisp-style interactive breakloop from which you can see and modify everything on the call stack and, indeed, everything in the running system, and you can tell the runtime where to resume execution from, either interactively or under program control.
A runtime designed with the understanding that you're going to be writing your application by changing it while it runs. Lisp and Smalltalk have had these features forever. Apple's Dylan and SK8 had them. It's disappointing that Clojure doesn't.
Common Lisp, for example, defines a standard protocol that enables you to redefine classes with the confidence that the Lisp will automatically update any existing instances to conform to the new definition. When Lisp can't figure out how to make things consistent, it doesn't quit or spew a dead stack trace; it starts a breakloop that captures the pending call stack. As I mentioned before, you can use the breakloop to inspect everything on the stack, make whatever changes are needed, and then resume computation with the changes in place.
I wish it were as easy to subsume foreign type systems into Clojure as it is in Common Lisp. Clojure's Java interop is good, but it's special. You have the nice Java interop, but you don't have a standard API for building your own equally-nice interops. Compare with Clozure Common Lisp's Cocoa interop. It's also good, but more importantly, it's built on common APIs (CLOS and the MOP) that you can use to make your own interop subsystems that are just as good.
To me, these are table stakes for a Lisp. I've already had them for decades. Working in Clojure means I have to give them up, and the whole time I'm missing them. A Lisp that doesn't know how to do them is only part of a toolbox. Whole drawers of essential tools are missing. I mean, sure, you can build apps with them. And you can build a house with stone knives and bearskins, but if you've used a proper toolbox before, you'll be missing it the whole time.
If there were a Clojure implementation with these features, then I wouldn't miss Common Lisp so much the whole time I'm working in Clojure. I probably wouldn't spend as much time looking forward to when I can get back to using a real Lisp. I'd get more done faster and with greater joy in my work.
I'm sort of hoping Cloture will turn out to be a step in the right direction.