Every programming language has idioms–patterns used so frequently that they are almost considered part of the language itself. (See these C idioms for examples.) Common Lisp, with almost unlimited possibilities for syntax, depends more heavily on idioms to remain comprehensible. Some examples are defsomething
or define-something
for definitions, something-p
for predicate tests, and make-something
for constructors.
Marco Antoniotti created a clever macro package called DEFINER that codifies the most common of these, definitions, into a single macro with consistent syntax for any object that is being defined. With DEFINER, all definitions can be made with a single macro: def
, which is followed by a symbol specifying what is being defined. So defun
becomes def function
, defvar
becomes def var
, and define-condition
becomes def condition
.
Of course, this is Lisp, so def
can be turned on itself to produce new definition forms with def definer
. New def
forms can then be created that follow the same syntactic pattern of:
(def type-of-thing name properties...)
As Marco writes, DEFINER “makes it possible to homogeneize a natural programming practice followed by several CL programmers.”
I say, why not extend this practice to other idioms? Here’s a list of other Common Lisp idioms I think could be well-served by the same sort of homogeneization:
- with
- Use
with thing
to delimit the scope of certain things–local variables, special variables, functions, open files, etc. Thenlet
becomeswith lexicals
,labels
becomeswith functions
, andwith-open-file
becomeswith file
. - make
- A generic constructor for any anonymous (unnamed) object. This could ensure that all object constructors follow a predictable pattern after
make instance
, and turnslambda
into the infinitely more readablemake function
. Also begs the question of why one can’t create anonymous classes. - is
- A generic predicate, borrowed from the FiveAM testing framework. Should alway return a boolean true/false value. Gives us the more readable
is even
instead ofevenp
. - equal
- Replace Lisp’s scattering of equality predicates–
eq
,eql
,equal
,equalp
,=
,string=
, etc.–with forms likeequal object
,equal contents
,equal number
, andequal string
. One could alternately useis equal
, although that looks odd in English grammar. - as
- A generic type converter. Makes it more obvious, for example, when
string
is being used as a type specifier and when as a coercion function. Also makes it very easy to define new converters between types, assuming these are implemented as generic functions. - get
- Generic accessor. Replaces both primitives like
car
as well as object-related functions likeslot-value
. - set
- Replacement for
setf
. Everyget
form should have a correspondingset
. Primitives likerplacd
becomeset cdr
.
And of course, to top it off we would want def with
, def maker
, def is
, def equality
, and def as
. And while we’re at it, def idiom
!
The point of all this is to make code more readable. One can reduce the 978 Common Lisp symbols to pairs of symbols, the first naming the general category of operation and the second specifying the exact operation within that category.
When examining unfamiliar code that uses these idiomatic macros, a programmer can look at the categorical names to get a rough idea of what is happening even without knowing about the specific functions being used. This can make Common Lisp more manageable without sacrificing any of its expressiveness.
I’m new to Lisp, well kinda anyway, and I couldn’t agree with you more. The lack of generality in certain areas of Common Lisp is the only thing that has bothered me, might just be me not being used to Common Lisp. I hope that someone will make this possible, or maybe I will be able to do it when I know Common Lisp a little better. Awsome post!