
\documentclass[12pt]{article}
\usepackage[T2A,OT1]{fontenc}
\usepackage[default]{cantarell}
\usepackage[a4paper, top=20mm, bottom=20mm, left=20mm, right=20mm]{geometry}
\usepackage[utf8]{inputenc}
\usepackage[russian, english]{babel}
\usepackage{tabu}
\usepackage{hyperref}
\usepackage{parskip}
\usepackage{graphicx}
\usepackage{tabularx}
\usepackage[normalem]{ulem}
\usepackage{float}
\floatstyle{boxed}
\restylefloat{figure}
\usepackage{setspace}
\onehalfspacing
\author{Artyom Bologov \href{mailto:my-generics@aartaka.me}{(email)}}
\date{\today}
\title{How I Write Generics}
\makeatletter
\def\endenv{\expandafter\end\expandafter{\@currenvir}}
\makeatother
\begin{document}
\maketitle


\includegraphics[width=\textwidth,height=\textheight,keepaspectratio]{./assets/my-generics.png}

Generic functions are beautiful as an idea.
But they are also somewhat ugly as a syntax.

My (ab)use of generics led to a certain programming style.
This style, I conjecture, ends up in more readable and correct functions.
Although it’s up to you whether to believe me.

This post will be structured around what generics are.
This overview will explain intuition behind my style of writing generics.
With examples and reasoning, of course.
In the end, I’ll share a small macro that nicely abstracts away some of my conventions.

Don’t expect some eye-opening experience,
it’s mostly about formatting and ordering of generic options.
Still, helps in setting up style guides.

\section*{Structure of Generics} \label{structure}

Generics are

\begin{itemize}\item functions
\item with multiple methods,
\item type dispatch,
\item and metadata (like documentation and method combinations.)
\end{itemize}

Let’s go through these one by one.

\section*{Generics Are Ugly Functions} \label{functions}

That’s the reason a lot of people prefer
\verb|defmethod| over \verb|defgeneric|: Generics are ugly.
They require a lot of keywords and don’t even look like functions.
Even though they are ones.

So my style aims to bring generics as close to regular functions as possible.
Which means putting documentation and declarations first, and methods last
(taken from
\href{https://github.com/aartaka/cl-blc}{CL-BLC}):

\begin{figure}[h!]\begin{verbatim}
(defgeneric compile (expr \&optional stack)
  (:documentation "Compile Lispy EXPR into binary lambdas...")
  (:method ((expr list) \&optional stack)
   #|...|#))
\end{verbatim}\caption{Making generics look a bit more like functions}\end{figure}

Why not just use \verb|defmethod|?
Because defining a generic via \verb|defmethod| doesn’t attach source location info.
So \verb|xref| / \verb|edit-definition| / \verb|swank:find-source-location| on generics often gets confused by this.
Define your generics with \verb|defgeneric|.
And enjoy the increased transparency it brings!

A note on arglists: it’s useful listing all the keyword/optional arguments in the generic definition.
Instead of splitting these into separate methods.
This way, even the dumbest tooling (and most inattentive reader) knows what keywords/optionals to expect.
Yes, SLIME/SLY infers the arglist somehow.
But there’s no such a thing as too much caring for the user.


\subsection*{Generics Have Methods} \label{methods}

That’s the main feature of generics: they have methods.
Generics dispatch over argument types to call most relevant method(s).

While most methods are born equal, some have a generic-related role.
Like termination / dispatch / default ones.
These usually represent the empty state or some stub for the actual implementation to replace.

One can put all the methods as \verb|:method| options in generic.
One can also define them all as separate \verb|defmethod|-s.
The former keeps things together in one place.
The latter gives methods more metadata and pins them to certain source locations.

My preference is to define termination/default methods in generics.
And other methods on their own.
This way, one can immediately see the default behavior of the generic.
And only after that can they get to the actual implementation / extension with \verb|defmethod|-s.

Here’s a bit of (old and somewhat orthogonal to the style I’m suggesting, but nonetheless exemplary in default method case)
code from
\href{https://nyxt.atlas.engineer/article/njson.org}{NJSON}:

\begin{figure}[h!]\begin{verbatim}
(defgeneric decode-from-stream (stream)
  (:method (stream)
    (declare (ignore stream))
    (signal 'decode-from-stream-not-implemented))
  (:documentation "Decode JSON from STREAM..."))
\end{verbatim}\caption{Putting only the termination/base case method in generics}\end{figure}

I also tend to write all the other methods
in terms of transforming data to a proper format and calling next/default method on it.
This way, most of the actual logic is concentrated in one method.
While other methods provide nice wrappers and validators for it.


\subsection*{Generics Dispatch Over Types} \label{type-dispatch}

This is somewhat tautologic with methods, but hear me out:
Generics dispatch over almost all built-in and user-defined types.
Including the \verb|eql| types.
And this type-exact nature makes them extremely composable.
One can encode a lot in argument lists.

It’s easy enough to re-implement
\verb|documentation|-like control args with \verb|eql| specializers:

\begin{figure}[h!]\begin{verbatim}
(defmethod coerce ((term list) (type (eql 'list)) \&optional inner-type final-type)
  #|...|#)
(defmethod coerce ((term list) (type (eql t)) \&optional inner-type final-type)
  #|...|#)
\end{verbatim}\caption{Using type dispatch (including eql types) with generic specializers}\end{figure}

One can also dispatch over type hierarchies, like \verb|list|/\verb|cons|/\verb|null|.
This way, typed edge cases are all covered without extra branching in the actual methods.

So yes, I abuse this power of specializers for common good.
And you should too!

\paragraph{But method dispatch is expensive!} \begin{quote}
No.
One can use something like \verb|(declare (optimize speed))| in generic declaration.
This should get one 90% there.
And the rest is up to implementation magic
(which is pretty good even by default, at least on SBCL) to figure out.
Don’t over-optimize, focus on designing a clear contract in your generics!
\end{quote}


\subsection*{Meta(data): combinations and classes} \label{meta-data}

Finally, a bit of cryptic stuff: method combinations and generic classes.
You’ll be surprized with how mendable the whole system is.
For example, here’s a simple method combination
\href{https://github.com/aartaka/trivial-inspect}{Trivial Inspect}
uses to reorder and index returned properties:

\begin{figure}[h!]\begin{verbatim}
(defun reverse-append-index (\&rest lists)
  (let ((fields (remove-duplicates (reduce #'append (nreverse lists))
                                   :key #'first
                                   :from-end t)))
    (mapcar #'cons (field-indices fields)
            fields)))

(define-method-combination reverse-append-index
  :identity-with-one-argument t)

(defgeneric fields (object \&key \&allow-other-keys)
  (:method-combination reverse-append-index)
  (:documentation "Return a list of OBJECT fields to inspect..."))
\end{verbatim}\caption{Simple method combination to reorder the results of method calls}\end{figure}

The logic is:

\begin{itemize}\item Get the list of properties returned by other methods.
\item Reverse the list so that most specific methods come last (and thus the default-ish/universal properties come at the top)
\item And then index it with nice and meaningful numbers.
\end{itemize}

I might’ve used an
\verb|:around| method to sort things.
\href{https://funcall.blogspot.com/2024/04/you-may-not-need-that-around-method.html?m=1}{But you may not need that around method}.
And I prefer to not touch auxiliary methods.
Downstream user might want to use \verb|:around| to override generic behavior.
So custom method combination it is!

Generic function and method classes are even more obscure.
I didn’t encounter a use-case for them yet
(except for \verb|command| class in Nyxt.)
But once there’s such a case, only these classes can save the situation, so better be prepared!

I tend to put this meta-data (pun intended) before or after the docstring, so that it resembles regular functions.
Functions allow declarations after docstring, after all.
But you can see (in the code listing above) that I’m somewhat inconsistent in that.
Still, put metadata/docs at the top and implementation at the bottom—will be clearer this way!


\section*{A New Syntax, Maybe?} \label{syntax}

But hey, it’s much harder to write out generics the way I’m suggesting, even if it’s actually useful!
Luckily, we have macros in CL.
One can define a macro to shorten generics and typical use patterns like mine.
\href{https://github.com/atlas-engineer/nclasses?tab=readme-ov-file#define-generic}{define-generic from Nclasses} does that
(Do check out Nclasses version, it clocks at 100 lines of useful macro code.
I’ve gone to great length to make it work nicely!)
Or use this simplistic macro from my
\href{https://github.com/aartaka/graven-image}{Graven Image} project:

\begin{figure}[h!]\begin{verbatim}
(defmacro define-generic (name (\&rest method-args) \&body (documentation . body))
  (check-type documentation string "Documentation string")
  `(let ((generic (defgeneric ,name (,@(mapcar #'first (mapcar #'uiop:ensure-list method-args)))
                    (:method (,@method-args)
                      ,@body)
                    (:documentation ,documentation))))
     (setf (documentation (fdefinition ',name) t) ,documentation)
     (ignore-errors
       (setf (documentation ',name 'function) ,documentation))
     generic))
\end{verbatim}\caption{define-generic, an opinionated (and simplistic) generic-writing macro inspired by Nclasses}\end{figure}

Used as

\begin{figure}[h!]\begin{verbatim}
(define-generic (setf function-lambda-expression*) ((value list) function \&optional force)
  "Setter for `function-lambda-expression*'."
  (declare (ignorable force))
  (let ((name (if (symbolp function)
                  function
                  (function-name* function))))
    (function-lambda-expression* (compile name value))))
\end{verbatim}\caption{Example of define-generic use}\end{figure}

Lots of niceties there:

\begin{itemize}\item Mandatory docstring.
\item Method lambda list with type specializers in place of generic arglist to not repeat myself.
\item Default method as the only method in body.
\item No need for \verb|:documentation| or \verb|:method| keywords—they are implied.
\end{itemize}

Which all compounds to a good and readable generic definition.
It also looks almost like \verb|defmethod| without sacrificing any benefits of generics.
It’s not some generic-writing Swiss knife, but it gets one 90% there.
Leaving the complex cases to Nclasses or whatever else one prefers.

\section*{Wrapping Up: Write Generics Like I Do} \label{wrapping-up}

Just kidding!
I’m not forcing you to any type of style.
You might even ignore generics altogether.
But, hopefully, this post has shown you some useful techniques of working with generics.
Here’s a full reference for how I suggest writing generics.

\begin{figure}[h!]\begin{verbatim}
(defgeneric generic-name (arg1 arg2 \&optional opt)
  (:documentation "Generic function docs
See https://nyxt.atlas.engineer/article/lisp-documentation-patterns.org for additional context")
  (:generic-function-class meta-data-meta-class)
  (:method-class meta-data-method-class)
  (:method-combination meta-combination)
  (declare (optimize (speed 3)))
  (:method ((arg1 list) (arg2 (eql 't)) \&optional (opt 8))
    "Simple default/termination method."
    t))
(defmethod generic-name ((arg1 cons) (arg2 null) \&optional opt)
  "Implementation method documentation.
Not strictly necessary, but nice for extra implementation details."
  #|...|#)
\end{verbatim}\caption{Reference for my style of generic writing}\end{figure}

But this full form is unlikely to ever get useful, because you usually don’t need that much meta.
Here’s a more realistic reference:

\begin{figure}[h!]\begin{verbatim}
(defgeneric generic-name (arg1 arg2 \&optional opt)
  (:documentation "Generic function docs
See https://nyxt.atlas.engineer/article/lisp-documentation-patterns.org")
  (:method ((arg1 list) (arg2 (eql 't)) \&optional (opt 8))
    "Simple default/termination method."
    t))
(defmethod generic-name ((arg1 4) arg2 \&optional opt)
  "A less simple method."
  (generic-name (list arg1) t opt))
\end{verbatim}\caption{A simplified reference for my style of generic writing}\end{figure}

I hope that I also motivated you to try more of generics in your next project.
\href{lisp-design-patterns#protocols}{And maybe even use them as an architectural device!}
Thanks for following me up until here!


\par\noindent\rule{\textwidth}{0.4pt}
\href{https://creativecommons.org/licenses/by/4.0}{CC-BY 4.0} 2022-2026 by Artyom Bologov (aartaka,)
\href{https://codeberg.org/aartaka/pages/commit/a91befa}{with one commit remixing Claude-generated code}.
Any and all opinions listed here are my own and not representative of my employers; future, past and present.
\end{document}
