Thursday, December 19, 2019

DreamLisp - A Lisp dialect in Objective-C

DreamLisp is a Lisp dialect with modules, lazy collections and is a Lisp-2 with an unhygienic macro system. DreamLisp interpreter is implemented in Objective-C and as such can run on macOS and iOS. It is tail recursive, uses ARC instead of garbage collection, has asynchronous communication using notifications taking advantage of the underlying Objective-C runtime and Foundation library. In the experimental version objc-rt-1 branch, we can define classes and create objects at runtime from the REPL. At present, the language runs in interpreted mode.

The language takes inspiration from MAL which itself is heavily influenced by Clojure, LFE and Erlang. DreamLisp has unhygienic macros, is single-threaded for the most part has a bunch of built-in modules core, network, test. Core module contains the native functions implemented in Objective-C and exposed to DreamLisp. The network module has functions to make simple REST based HTTP requests. The test module contains macros and functions to write unit tests which resembles Clojure tests.

The main goal of the project was to have a working Lisp that can use all the Objective-C runtime capabilities and thereby develop software that runs on Apple devices using Lisp. In that front, we need a Lisp language, REPL and there is nothing better than having the language itself be written in Objective-C directly. This helps to use Objective-C internal functions without having to resort to FFIs. The language part is ready, i.e, the specification and the implementation. Even though it's Lisp, it's not Common Lisp or any other Lisp. It's a dialect of its own. Next is the Objective-C interop, which is partial. These built-in functions follow ideas from CLOS. Currently, we can dynamically create classes, add methods, create objects of the classes, invoke methods for a certain set use cases. We can also create objects of the built-in classes and invoke methods on it. It's not robust yet and interop between native Objective-C types and DLisp types are not fully functional, also the Lisp case to camel, Pascal casing and vice-versa. Once we have these, then we can use the same code to run through a transpiler written in DLisp, generate Objective-C or Swift code, then use xcodebuild to generate native code with no eval and the code will be just like handwritten code.

Currently, the language is fully interpreted and as such works for simple use cases, but with full-fledged app development, having a language that runs natively either using LLVM or at least JIT would provide a better development experience. In that regards, I find malc interesting, which is MAL to LLVM or targetting MMIX bytecode. MMIX is a RISC architecture by Donald Knuth and is really cool.