- 🛈 Background
- 🗲 Why I'm excited
- ✍ Current status
Traditionally, there has been no standard way to canonicalize slot values. For instance, you might declare a slot as having type string, but prefer to let the user specify any string designator. In this situation, there are various suboptimal approaches you could take:
Give up and let the user specify a string designator and store that value directly, coercing it to a string when reading the slot's value. This is semantically nauseating and inefficient, and could compromise correctness and the debugging experience.
Give up and force the user to specify the canonicalized value (a string). This is maximally convenient for the implementor, but fairly inconvenient for the user.
Let the user specify a string designator, and correctly canonicalize it to a string internally before storing it in the slot. This is maximally convenient for the user, but fairly inconvenient for the implementor, especially as there is no idiomatic way to do this. It took me 10+ years to find the best way to do this without infrastructure, and it's still fairly inconvenient for the implementor. This could be made easier with a macro, but it's still semantically suboptimal. It would basically be a design pattern, and as Alan Kay said,
Design patterns are for when you run out of language. It can also be a great burden to properly document the specific canonicalization strategy you chose, especially as canonicalization is incredibly often desirable.
The complete lack of built-in support for slot value canonicalization (or even of a standard idiom for it) might be seen as one of the biggest unacknowledged blind spots in the Common Lisp language. (Although most programming languages probably share that limitation.)
My upcoming initargs canonicalization library implements the platonically ideal solution using the MOP. You can just pass
:canonicalize #'string as a slot option and the corresponding initarg will be canonicalized! There is also a
:canonicalize class option (similar to
:default-initargs) to canonicalize initargs not necessarily associated with slots.
This is a very intuitive and broadly useful killer app for the MOP!
Along the way, I solved several extensibility and usability problems regarding the MOP. There is one last supporting library I have yet to finish:
a truly extensible version of
defclassthat can accurately control the expansion according to the metaclass and automatically detect the suitable metaclass by analyzing the
I'm almost 100% done with the design and implementation.
At some point, I had 10 upcoming libraries and thought I would finish and release them all at once to take advantage of the dependency graph between them to demonstrate use-cases, but this didn't work out at all, mostly because it was way too stressful and depressing, so I am now finishing them and releasing them one at a time, quite successfully.
definitions-systems 1.0 is a bit too minimalist.
Creating a new definitions-system should be a bit easier.
Some obvious extensions are left as an exercise to the user.
The user needs to write too much boilerplate.
definitions-systems 1.0 is already my most important library, and
definitions-systems 2.0 will be my most important library update ever!
definitions-systems 2.0 adds support for
defsys:owner, externalizable definitions (through generation of recursive
defsys:locate forms by walking owners up to a root system),
defsys:unbind-definition (a subprotocol of
defsys:unbind that implements the actual removal if said definition does exist and makes it easy to notify the system and/or definition about it),
defsys:check-definition (which allows to validate a definition before it's actually added to a system),
defsys:simple-expansion-mixin (a very simple yet very powerful default),
defsys:count, automatic tracking of primary and alias bindings for definitions,
defsys:base-definition-class-mixin for easy determination of the class to use for definitions.
I'm almost completely done, this is blocked on initargs canonicalization.
I also need to write unit tests for the new features.
Documentation of the new features is almost completely done.
format is a disgrace, a black mark on Common Lisp. Packing a complex control language into a string is deeply insane when we could and should just use s-expressions.
format is the single worst-designed feature in Common Lisp, even worse than loop.
format is not extensible, despite the very constrained
~/~/ escape hatch.
It is simply mind-boggling that
format is still used and largely embraced by the community in 2020.
lispy-format 1.0 properly translates the essence of
format into a proper s-expressions form. A guaranteed smash hit!
I know exactly what the final product will look like. There are 2 levels: individual functions which can be used standalone or in concert, and a macro for concisely and efficiently combining multiple output operations in one go.
lispy-format 1.0 will be far more readable than
format, and it will be completely modular and extensible. And of course, it properly uses the package system, so you can easily write your own extended version of the standard built-in operators if you like, or design your own features which will seamlessly integrate with built-in features and third-party features.
One of several advantages of lispy-format 1.0 is that a command's arguments are specified with the command instead of all commands being specified ahead of time and then all arguments, making it hard to correlate commands with their arguments.
lispy-format 1.0 will be very easy to learn, regardless of the user's level of proficiency with
format. That said,
format experts will find many familiar similarities compared to
format, making transition easy. Tools should eventually be provided to help migration.
I've already achieved significant progress on a private branch.
This is blocked on definitions-systems 2.0.
(I made the Epic FORMAT table years ago as a precursor to this work.)
This library will implement a revolutionary new paradigm for iteration and mapping. It is extremely simple, intuitive, modular, flexible, powerful and optimizable, and easily scales from trivial use-cases to very complex, so you can just use it always. It will basically obsolete every iteration and mapping construct you know of, and then some.
This is a spiritual successor to my various Loopless projects that I worked on for years and deleted relatively recently, and other related work such as multiple-value mapping. I completely stopped using
loop eons ago and now make heavy use of
mapcar and friends, but this is not enough and after several iterations of failed attempts at LOOP replacement, I finally came up with a truly revolutionary paradigm shift in computer science (or at least, a very big evolutionary leap). This is actually just a different arrangement of already existing concepts such as iterators, but designed and integrated in a much more flexible and powerful way without sacrificing performance (and in fact, improving it).
I already know what the project will be called, but I'm keeping it a secret until a first release.
I already know exactly what the high-level syntax and semantics will be. I could trivially tell you what it is, but I want to keep all the glory for myself on this one. ;P (It took me quite a bit of really hard work to reach that point, and if I immediately revealed the fruits of my labor then someone could implement a crude version and reap all the glory before I have perfected the entirety of the design at all layers of abstraction.) The high-level syntax and semantics is actually just an embarrassingly simple variation on one of the standard Common Lisp constructs.
As for the mid-level and low-level semantics, I have some good ideas about it, but much work yet remains to be done. I recently became an expert in an area of the MOP that I believe will be absolutely crucial to the mid-level and low-level semantics.
I have already spent several months designing this on graph paper. I am now ready to try actually implementing this (once I'm done with the above work items).