
Modern, functional Common Lisp: myths and best practices - Ambrevar
https://ambrevar.xyz/modern-common-lisp/index.html
======
atgreen
Common Lisp is also a pleasure to use for k8s-hosted services. Just deploy
your Lisp-based service to k8s, forward the sly/slime port to your local
system, and continue to work on it interactively with emacs and sly/slime.
It's really the most interactive development approach for k8s-hosted services.
See [https://github.com/container-lisp/s2i-lisp](https://github.com/container-
lisp/s2i-lisp)

~~~
lvh
How do you do the forwarding? (That’s an interesting question to me by itself,
but I ask because it seems like that feature is just as good outside of k8s
too :))

~~~
simiones
With k8s, you just create a service of type NodePort and it assigns a free
external port for that service, which is mapped back to a specific port in the
Lisp container.

~~~
ohithereyou
What sort of encryption and authentication can I expect if I do that? Can
anybody who guesses the port dump code into my running Lisp instance?

~~~
e12e
This is entirely to hard to find the answer to in the kubernetes/kubectl
documentation. Apparently the forward is done via socat over tls:

[https://stackoverflow.com/questions/50645059/is-kubectl-
port...](https://stackoverflow.com/questions/50645059/is-kubectl-port-forward-
encrypted)

And socat is mentioned in:

[https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/po...](https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/portforward/portforward.go)

I didn't actually manage to find out what or how socat is called - but I'm
also on mobile, so it's a little convoluted to browse source code.

Anyone know where the call to socat happens, after kubectl port-forward?

------
mark_l_watson
Thanks for writing that up. Common Lisp as a language and ecosystem is so huge
that we all have our own view of what CL is and how to use it to build
applications. I have been actively using CL since around 1982 for prototyping
and also building applications and tools but I feel like I use a small part of
what is available, mostly because I prefer to use what I am used to. I should
should probably spend a little less time building things with CL and a little
more time studying it.

EDIT: off topic, sorry, but I have been actively evaluating CL (using an
embedded web server that starts a browser) vs. Swift (using mostly SwiftUI)
for a new product I want to write. I find myself using Swift like I would CL:
using Playgrounds to prototype low level code and utilities, then XCode for
developing the UI. To be honest, Swift and SwiftUI is a better fit technology-
wise for what I want to do, but I am so much happier when working in CL.

~~~
thrwer234231
> Common Lisp as a language and ecosystem is so huge

This is not true IMO, when compared with the languages of today. Even if you
include the numerous little details of MOP, the CL spec is nowhere near as
confusing as say something like C++ 17.

~~~
mark_l_watson
You are correct, of course. Java, Python, C++, etc. also have huge ecosystems.

------
pfdietz
I've been doing some functional style programming in Common Lisp, and I was
wondering what exactly should be considered functional programming.

In particular, is object identity with EQ consistent with functional
programming? Constructors do not act like functions if EQ is the equality. Or
should that be more "immutable programming"?

Common Lisp, because it has EQ and object identity, cannot perform some
optimizations that a truly functional language's implementation could. In
particular, it cannot combine equivalent function calls, and cannot merge
equivalent data (hash consing or the equivalent.)

~~~
Ambrevar
Immutability is something I'm still exploring in Common Lisp. Any pointer,
anyone?

~~~
pfdietz
It's a matter of not modifying things once constructed. CL has hooks to help
do that, although a user can always get around them.

A package I've been involved with lately is fset, which is available through
quicklisp, or at

[https://github.com/slburson/fset](https://github.com/slburson/fset)

It has some interesting features, including "functional setf expansion". This
would turn something like

(setf (fcar x) y)

into something equivalent to

(setf x (cons y (fcdr x)))

(where "fcar" and "fcdr" are the same as "car" and "cdr", except when they are
in a setf-able place form.)

(fcar and fcdr are not in fset; I used those names just for exposition here.)

It could work with nested accessors, but only if it bottoms out in a variable.

~~~
thsealienbstrds
Are you aware of any memory-leak issues with fset? I once used it in a game
where I updated an fset sequence in real-time. I let it run for a while, after
coming back I noticed my computer was completely frozen (out of RAM).

~~~
TurboHaskal
It's inspired by Clojure after all. The language of choice for users that
don't care about performance.

~~~
mikelevins
It probably isn't. The initial public release of Clojure was in the fall of
2007. Scott Burson has been working on FSet since at least 2004. He himself
says it's inspired by Refine.

~~~
TurboHaskal
I stand corrected. I still maintain my point about (idiomatic) Clojure being
terribly slow though.

~~~
Scarbutt
And terribly beautiful ;)

Just personal preference and enjoy programming in it. Programmers give too
much importance to programming languages.

Clojure can be made to run very fast (it compiles to the same bytecode as Java
after all) for the hot paths at the cost at writing less idiomatic Clojure.

------
mumblemumble
Assuming that the subtext here is wanting to address potential reasons for
Lisp's chronic underpopularity, I think that all conversations like this miss
the mark. Lisp was never failing to attract many users because people hadn't
experienced sufficient evangelism about all its advanced features. It fails to
attract many people because it's not a fun language to get started in.

A year or so back I picked up a copy of Land of Lisp and burned through it for
pleasure reading. And I was struck by how _gross_ Lisp looks in that beginner-
oriented treatment. Just this huge slog of car and cdr and let/letrec/let* and
the 37 flavors of equals and the function namespace. . . and, all the while,
you're being told that persevering in mastering this confusing minefield of
subtleties will somehow enable you to write bug-free software. I doubt it's
actually fun for most people, and the grandiose claims should beggar belief
for everyone. I suppose I should count myself fortunate that I got to learn
Lisp in college, where there was little attempt to make it fun, and plenty of
graded assignments to keep me motivated.

Racket and Clojure are right to clean up some of the language's evolutionary
history. That's a start. But even then, the treatment in beginner's guides
isn't all _that_ enticing. I've also skimmed through Realm of Racket and
Clojure for the Brave and True, and, while both of them work hard at being
entertaining (and were fun to just sit and read), they don't really succeed at
dispelling the sensation that what you're mostly doing is wrangling with the
language itself.

Compare with some of the more popular Python guides. They tend to be much more
dryly written, but the actual flow of the guide tends to get you pretty
quickly to

    
    
        from pypi import have_fun
        have_fun()

~~~
abrax3141
First off, Lisp is chronically POPULAR not unpopular. (It is critically
unpopular.) Secondly, Lisp is the most fun you can have programming, yeah from
the start. You apparently had either a very poor teacher, or taught yourself
Lisp ... same thing.

~~~
kick
The above post didn't say unpopular, they said 'underpopular'. While that's a
bit of a neologism, it just implies that it's less popular than it should be.

Also: _" Lisp is the most fun you can have programming, yeah from the start,"_
while subjective, is by most accounts, wrong. Especially when referring to
Common Lisp; there could hardly be a more convoluted Lisp than Common Lisp.

~~~
lispm
I learned much of my initial Lisp programming decades ago with Macintosh
Common Lisp. I found it to be incredible fun to work with a tight interactive
environment on my Mac.

~~~
mikelevins
So did I--or, rather, I started with Coral Common Lisp, which is what it was
called before Apple bought Coral Software.

I found it hugely fun--so much so that it took over my brain. I've been
primarily a Lisp programmer ever since.

Coral Common Lisp offered an extremely easy way in to Lisp programming that
was also tons of fun to work with, and an industrial-strength development
environment for the full panoply of Mac applications. At AAAI in Detroit in
1989 I mentioned to someone that I was working in Coral Common Lisp and a
passer by quipped, "Oh, the good Lisp."

It ran just fine on a 1 MB Mac Plus. You could start it up with a double-
click. It launched with a Listener window and a blank Lisp source file (unless
you launched it by double-clicking an existing Lisp file with some code in
it.) You could save an image, copy the image file to a different machine,
launch it, and you would see the same windows in the same state.

Creating a fully-functional Mac window looked like:

    
    
        (make-instance 'window)
    

You could populate the window with working widgets with similarly simple
interactions. If you built something you wanted to keep using, you could turn
it into a Mac application by doing

    
    
        (save-application "Foobar")
    

If you preferred constructing UI by dragging together widgets by direct
manipulation, you could do that, too. Once your UI was assembled, you could
tell the Lisp to save the Lisp source code needed to reconstruct it.

The built-in editor, Fred, was a species of Emacs, with the Lisp-oriented
features that you would expect, but you'd never have to know that if you
didn't want to, because it was also a fully-featured Tesler-style modeless
editor at the same time.

The stepper, inspector, apropos, and other development niceties all had Mac
graphic interfaces that made them easy to discover and tinker with. They were
all written in Lisp, so you could use the Lisp reflection tools to crack them
open and poke around inside to see how they worked.

Coral Common Lisp made it easy to get started using Lisp to build apps--about
as easy at it can possibly be. At the same time, though, it imposed no
arbitrary limits on what you could do with it. When I first met Dave Vronay he
was working on the GUI for SK8, and gushed about how easy it was to write
window-definition resources (WDEFs) in assembly language using CCL's LAP
subsystem. He was an experienced arcade-game hacker, well versed in assembler,
but Coral Common Lisp was his first fully-interactive assembler, able to
define and integrate new assembly-language code while the program under
development was running.

The CCL of today, Clozure Common Lisp, is still a great Lisp, but it isn't as
easy or as inviting for newbies. It doesn't have the same graphical
environment or the tight integration with the underlying system.

In part that's because when the Clozure Common Lisp project was created (under
the name "OpenMCL"), its creators had the rights to the compiler and the Lisp
runtime, but not to the Macintosh graphical environment. In part it's because
modern macOS is quite a bit more complex than Macintosh System 9 and its
predecessors, and development systems have a lot of additional hoops to jump
through nowadays to do the kinds of things that MCL was able to do.

If a modern MCL existed, I expect a lot more people would find Lisp a lot
easier and more fun to get started with. I think it's perfectly possible to
create such a Lisp, but it would be a heck of a lot of work.

~~~
lispm
I used MacScheme earlier, which also was a huge amount of fun - even though I
did not have the extension to access the Mac Toolbox (Toolsmith, IIRC).

MCL was a whole new world then. First with Object Lisp and later with CLOS. I
used MCL before it was owned by Apple - at one time it was called MACL (from a
market agreement with Franz, IIRC). But later LispWorks was another step up,
because it was a __big __grown up full extended Common Lisp with everything
from the commercial UNIX workstation Lisps (like Allegro CL, Lucid CL,
LispWorks): it suddenly ran on small and simple to use Apple or Windows
laptops, plus it had a Cocoa port.

But, as you describe, the simplicity and integration of MCL into the early
MacOS was a lot of fun and there was a lot of tinkering by users. Some friends
were still using MCL years after it was obsolete...

~~~
mikelevins
I started with the full version of MacScheme about the same time that I
started with CCL. I loved them both, and at first I liked MacScheme better
because Scheme was a smaller, simpler language, and easier to learn. CCL won
me over in the end because it was just so much easier to get things done.

Later on, John Ulrich, who owned Lightship Software, the publisher of
MacScheme, came to work at Apple and became a friend and colleague. I
continued to use MacScheme off and on for years.

I’ve happily paid for Lispworks licenses many times now, but even Lispworks
isn’t a good solution for everything I want to use Lisp for. A modern version
of CCL’s graphical environment would still be a nicer place for newbies to
start. You could even use Lispworks to build a product like that, if the
license didn’t prevent it. (Lispworks doesn’t allow their product to be used
to make Lisp development systems, which is understandable. They’re a small
company who don’t want to put themselves out of business by enabling a
customer to give their Crown Jewels away.)

~~~
lispm
yes, building a product to include development tools (compiler, ...) of
LispWorks or Allegro CL would be expensive and not really attractive. I think
Franz, Inc. has such a licensing agreement for Allegro CL, but their licensing
model is different anyway.

In former times there was a market for add-one GUI or IDE tools. Lucid CL made
money from licensing their Lisp to other companies, which then resold those
with tools added on (like the SUN Common Lisp IDE). The Action! GUI designer
was available for MCL. CLIM was an add-on product. The big Expert System
development environments were available as add-on products to Lisp systems.

For a commercial customer something like LispWorks or Allegro CL might still
be worth it - they are technically very stable platforms.

~~~
mikelevins
I tried to work out a way to reimplement my old programmable WYSIWIG word-
processor, Alpaca, using Lispworks, but we've been unable to reach an
agreement that works for me and for Lispworks. They don't want me to make
something that someone could use to compete with their product, and I don't
want to make a crippled version of Alpaca.

I wrote the original Alpaca in CCL, using its Cocoa interface. I used it to
write a book, and a Japanese company approached me about licensing it for a
product, but I fell ill before I could do anything more with it. By the time I
recovered enough to look at it again, it had bitrotted. The macOS interfaces
had changed out from under it.

I imagine I could fix it up and get it going again, but I'd really like to
make a version of Alpaca that works on Linux and Windows as well as macOS. The
obstacle is that I need a rich-text engine that can do a good job with page
layout, and I don't know whether there's a suitable one, or which Lisp (that
isn't Lispworks) would be best to use with it. Qt maybe? Perhaps with ECL? I
guess I'd rather use CCL or SBCL. Anybody know of a text-and-page-layout
engine or collection of libraries that will work well on macOS, Linux, and
Windows with CCL or SBCL?

------
tombert
I really need to learn CL one of these days; I know Clojure reasonably well,
and enough Lisp-Flavour-Erlang, Chicken Scheme, and Racket to be dangerous,
but for some reason I seem to have completely avoided CL.

Based on the blog posts I've read, it seems like CL occupies the kind of space
I want to be in: sort of the halfway point between theoretical and
engineering. Is that a fair conclusion to draw?

~~~
reikonomusha
It’s a practical language that sometimes chooses less elegant ways to do
things in favor of a complete, robust engineering experience. For instance,
the fact defined functions sit in a different namespace than values creates
mostly aesthetic ugliness where named functions and named values have
different treatments.

    
    
        (defun f (x) (* x x))
        (setq g (compose f f))
        (g 5)
    

This is wrong in Common Lisp on many levels: f must be referred to as #'f, and
g cannot be called as such, you must use funcall: (funcall g 5)

These might go against the sensibilities one might have had in learning a Lisp
in the first place. But in practice, these don’t stop you from writing solid,
readable code.

It won’t feel as “clean” or “academic” as Scheme, but you’ll feel it easier to
build large and efficient programs without pulling your hair out.

~~~
dreamcompiler
If I were doing the above a lot, I'd write compose as a macro (or better yet a
compiler macro). In that case, the only thing above that needs to be changed
is the setq, which would have to be written as

    
    
      (setf (fdefinition g) (compose f f))
    

Still different from Scheme, but some of the differences can be papered over
with macros.

------
vindarel
On tools: note that the popular Atom editor has a great extension for
interactive CL development, SLIMA, which has all the important features from
Slime.

We can also use CL in Jupyter notebooks, see those good examples:
[https://gist.github.com/WetHat/a49e6f2140b401a190d45d31e052a...](https://gist.github.com/WetHat/a49e6f2140b401a190d45d31e052af8f)

And Vim, Lem, cl-repl, Eclipse (not so interactive)…
[https://lispcookbook.github.io/cl-cookbook/editor-
support.ht...](https://lispcookbook.github.io/cl-cookbook/editor-support.html)

------
tsm
I learned Common Lisp in high school over a decade ago and have been passively
looking for a CL job that doesn't require relocation since. This has been hard
(though I did land a few Clojure gigs). Is anyone aware of active Lisp shops?

------
chalst
Amusing set of quotes about CL by famous lispers:

[http://xahlee.info/comp/Common_Lisp_quotations.html](http://xahlee.info/comp/Common_Lisp_quotations.html)

~~~
Ambrevar
A fun read with some good points, although many of them are a bit dated :p

------
fmakunbound
Common Lisp is still the most fun language to use for me. Sadly lacking in all
the currently fashionable languages is interactivity.

------
0xcde4c3db
> The myth: Common Lisp scripts and binaries are hard to distribute; binaries
> are too big.

As far as I can tell, it's more like you have to pick one or the other.
Distribution is easy if you don't mind distributing a 50 MB image (which is,
of course, trivial for some applications and catastrophic for others). Most of
the suggestions on reducing application size are essentially accounting
sleight-of-hand that doesn't actually reduce the overall footprint (I'm
reminded of the compressor that can "compress" any file by one byte... by
moving the byte to the file name).

------
lincpa
Lisp(Clojure) best practices: The Pure Function Pipeline Data Flow with
Warehouse/Workshop Model

[https://github.com/linpengcheng/PurefunctionPipelineDataflow](https://github.com/linpengcheng/PurefunctionPipelineDataflow)

------
tom-thistime
This doesn't scratch my itch at all. I love Lisp but boring old Python has the
libraries I need.

EDIT: Based on a comment and downvote I suppose I didn't make my point clear
above. _I am saying that myths are not the only thing holding Lisp back._ (I
may be wrong. I _hope_ I'm wrong. Big thank-you to people who are linking ways
to get libraries in Lisp, especially Python libraries.)

I care 10x as much about libraries as about all these red herrings (EDIT: or
myths, as you like) combined: " * Common Lisp does not have compile-time type
checking. * Common Lisp is for imperative, object-oriented programming. *
Common Lisp is too specialized, it’s not for general-purpose development. *
Common Lisp applications are hard to deploy. "

~~~
Jach
I'm always curious when this comes up: which libraries in particular do you
have in mind? If you love Lisp and they're really absent, a short list would
at least provide a data point for something that would be desirable and
ambitious newcomers could cut their teeth on.

Anyway I don't think the library ecosystem is so dire... Lots of good
libraries are distributed through quicklisp. It's pretty straightforward to
wrap a C library. (You can even do C++ easily if you switch CL implementations
to Clasp...) If you need Java libraries, you can switch CL implementations
again and use ABCL. (But of course all your CL code and CL libraries still
work.) Lastly, for Python there's [https://github.com/pinterface/burgled-
batteries](https://github.com/pinterface/burgled-batteries) (and
[https://github.com/snmsts/burgled-
batteries3](https://github.com/snmsts/burgled-batteries3) for py3) that even
in an incomplete state might suit your particular library needs.

Perhaps this capability isn't very compelling since Python can also access C
without trouble (and Java via Jython, .NET via IronPython)? Well I guess all I
have left to ask is whether you've considered there might be libraries (or
features) in Lisp that would be needed that don't have equivalents in Python?
What do you do then? One possible library for admittedly niche applications
that came to mind was a hierarchical task planner ([https://github.com/shop-
planner/shop3](https://github.com/shop-planner/shop3)) but I forgot someone
did indeed make a Python library
([https://github.com/oubiwann/pyhop](https://github.com/oubiwann/pyhop)) based
on an older version (SHOP1) of the background work, so depending on if you
need the v3 features it might suffice.

~~~
tom-thistime
Thanks for the links! I'll check them out. I like the "higher level" of Python
libraries better than C or even Java, because I tend to write what most people
would call prototype code. Small user base, small applications, and the really
harsh constraint is development time from concept through validation.

No-doubt-unnecessary boilerplate: I understand that people have language wars,
and it's possible you may have identified me as belonging to one side or
another, but I'll pass. That whole state of affairs is just unfortunate.

------
pjmlp
Very nice overview, I failed to see references to LispWorks and Allegro,
though.

~~~
Ambrevar
I've never used them myself, so in all honesty I have nothing to say about
them! :p

That said, I support free software and I believe a proprietary compiler is not
a good idea :(

~~~
TurboHaskal
Ideology aside, most proprietary compilers (mostly for Forth, Pascal and Lisp)
I have used are of _excellent_ quality.

A lot also provide you the source code once you pay. AllegroCL is one of them
I think.

------
patrec
I hate the "lists of myths" (that aren't) genre.

> Common Lisp does not have compile-time type checking.

Nothing in the standard mentions compile time checking requirements and there
is no useful de-facto standard that you (or tooling!) could seriously build
upon either. I'd be suprised if python did not have better "compile-time type
checking" for all practical purposes. Yes, SBCL gives much better type
warnings at compile time than python, but for python you have mypy and it's A
Thing, and still a joke compared to a proper type system like Ocaml's.

> Common Lisp is too specialized, it’s not for general-purpose development.

Common Lisp has no eco-system to speak of for machine learning, web
development, command-line utilities, games programming, mobile development,
GUI programming, embedded development or pretty much anything real general
purpose languages do. If you have something for which Common Lisp is a good
fit, you can still be commercially successful using it because not everything
requires a super rich eco-system and for some problems what Common Lisp has is
in fact highly competitive. But if you want to use common lisp effectively you
definitely need to pre-select the problems you want to work on accordingly to
an extent that's not true of python, C, C++, Rust, javascript, Go, Java, and
half a dozen other languages.

> Common Lisp applications are hard to deploy.

No server or desktop or web-browser comes with common lisp pre-installed.
Building common lisp is a pain, because packaging/ASDF is terrible and you
don't easily get a nice and small statically linked executable out either.
Compared to exactly what language is common lisp not hard to deploy?

~~~
vindarel
web development: kind of agree, but that didn't prevent me and two other
colleagues to build a commercial website last year, for 1,5 month. It receives
tens of thousands of visits a month and has a small admin panel for a three
persons team. Job done, rent paid

CLI utils: it's simple to use cl-readline. There are a couple libraries for
ncurses. The Lem editor is a good example.

mobile: nope. For the adventurous, see
[https://gitlab.com/eql/EQL5-Android](https://gitlab.com/eql/EQL5-Android) and
its REPL.

GUI: [https://github.com/CodyReichert/awesome-
cl#gui](https://github.com/CodyReichert/awesome-cl#gui) Qt4, Gtk3, IUP, Tk,
Nuklear have good bindings. Qt5 is possible with gobject-introspection (for
the adventurous). Proprietary: CAPI. Electron: Ceramic. Java GUI interop with
ABCL?

ML: [https://github.com/CodyReichert/awesome-cl#machine-
learning](https://github.com/CodyReichert/awesome-cl#machine-learning) MGL's
author won the Higgs Boson Machine Learning Challenge, but yeah.

for the rest: IDK [https://lisp-lang.org/success/](https://lisp-
lang.org/success/)

~~~
patrec
CLI utils: you're missing the point. Of course you can write some simple
terminal apps with common lisp, but can you name a single one that anyone who
is not a lisp fanatic uses? If not, ever wonder why?

GUI: would you develop a commercial app (to pay your rent) in any of these
apart from CAPI?

ML: You are joking, right?

~~~
vindarel
I can name one :) pgloader [https://tapoueh.org/blog/2014/05/why-is-pgloader-
so-much-fas...](https://tapoueh.org/blog/2014/05/why-is-pgloader-so-much-
faster/)

I'd use Electron with Ceramic, not the GUI bindings. Or maybe Nuklear. But I
would build personal projects with them.

ML: yeah, yeah. Just to show there have been work on it, that (of course) the
platform is capable.

~~~
patrec
Yup, pgloader was also the one example I could think off; I was wondering if
you'd name it :) Amusingly I have not been able to get the non-docker version
to work due to some bogus openssl problem.

Anyway, I completely agree that Common Lisp is capable, my point also isn't
that it's impossible to do things like GUIs, or write something cool and
successful with it – just that the eco-system is not general-purpose language
quality. If you want to make something that's successful commercially or as a
well-adopted open-source project you have to be much more careful what
problems you tackle than with a genuinely general purpose language.

Blog posts that claim otherwise really rub me the wrong way; I think it's
possible to present CL in a favorable light without distorting reality and no
one is gonna thank you later for joining the rank of people who missed out
career-wise for making non-viable technology choices.

~~~
vindarel
> not general-purpose language quality.

= not top-notch in all areas? Yeah, there's room for improvement. Buuut, given
CL's features and stability, I will very much consider it for a commercial
project in the future instead of, say, Python. I'd reject Python, for sure,
for GUIs or web dev (except a small website maybe where admins would use the
Django admin). Now I must find another language, and it's difficult. Many
things drive me back to CL, including its state of libraries, actually pretty
good compared to other languages, newer or older. No kidding.

> If you want to make something that's successful commercially or as a well-
> adopted open-source project

maybe. Reading you, it seems one should avoid using CL altogether. But there's
a lot of room for a successful use of CL before falling into these categories:
one-off scripts, quick GUIs at work, personal tools? Commercial websites (with
adequate requirements), like I did? yes, it's possible to use CL for that.
Yes, it is possible to do web development for a job with CL (what kind of
sites? We have to ask the few redditors that do it). My point is that CL is
general-purpose enough so that it could be more used in the wild (because it
is used in the wild).

Anyways. Just trying to be positive :)

~~~
patrec
> Buuut, given CL's features and stability, I will very much consider it for a
> commercial project in the future instead of, say, Python[...]My point is
> that CL is general-purpose enough so that it could be more used in the wild

Yeah, I'm not arguing against that at all. I just hate articles which
encourage people towards doomed efforts rather than building out existing
areas of strengths or address things that are real obstacles towards using
them. I'd like CL to be around for at least long enough till all it's
important ideas have made it into other programming languages ;)

For example, one core strength of CL is that it's the about the only really
interactive/malleable/live language that can generate pretty performant code,
and for sbcl you can hook deeply into the machine code generation as well.
Luajit is nicer in some ways (e.g. much smaller footprint in every possible
way) but CL has a much more sophisticated interactive development experience
(restarts, powerful debugging, pretty-printing etc. etc.). So tooling for
automation of binary rewriting, refactoring and hardening like GrammarTech
seems to be working on (see
[https://github.com/GrammaTech?utf8=&q=&type=&language=common...](https://github.com/GrammaTech?utf8=&q=&type=&language=common+lisp))
seems like a much more promising area to work on with common lisp to me than
e.g. generic web development.

------
chalst
I don't consider a language supportive of functional programming unless it
supports tail-call optimisation, which is performed by some but not all
implementations of Common Lisp.

The article recommends SBCL, which does support TCO.

An old (2011) survey of TCO support is at [https://0branch.com/notes/tco-
cl.html](https://0branch.com/notes/tco-cl.html)

~~~
pdexter
That sounds more like an implementation detail, in most cases. By this metric
Haskell wouldn't be a functional language.

~~~
nybble41
It's a _very important_ implementation detail. Explicit loops tend to imply
mutation, which is contrary to idiomatic functional programming. Recursive
calls don't require mutation but _do_ require TCO to achieve equivalent space
complexity. Constant-factor optimizations are one thing but failing to perform
TCO turns constant-space algorithms into linear-space algorithms (or linear
ones into quadratic, etc.). It's less a matter of "optimizing" the calls and
more a matter of not wasting limited stack space on data which is clearly not
required to execute the remainder of the program. One might as well label the
practice of freeing stack frames when a function returns "Function Return
Optimization" (FRO) and consider it a mere "implementation detail". After all,
wouldn't it be much simpler to grab new memory every time the program needs
some storage space and never bother with cleaning it up? It would certainly
make debugging easier with all those old variables retained for the life of
the program and not constantly overwritten by new data. However, programs
written for a language without guaranteed "FRO" would look very different from
normal programs, much as programs designed to compensate for the lack of
guaranteed TCO look very different from idiomatic functional programs.

Haskell uses a different (data-centric, non-strict) evaluation model where
recursive _definitions_ don't result in recursive _calls_ , so traditional TCO
isn't as relevant. Recursion is used very heavily in Haskell—which has no
first-class looping constructs—but the resulting programs generally do not
require large stacks. It's not unusual to be able to run even large Haskell
programs with a 1 KiB maximum stack size (+RTS -K1k). Space leaks are
possible, of course, but they take place in the heap.

~~~
lispm
Common Lisp was designed without requiring TCO because:

* various platforms don't support TCO. It was designed such that it can be implemented by a simple non-TCO interpreter, transpiled to a non-TCO C compiler, compiled to a non-TCO Lisp Machine CPU, or to a non-TCO virtual machine (like the JVM). Many languages don't support TCO on the JVM and may only implement explicit tail recursion or have a compiler detecting tail recursion - which is far from supporting TCO. Thus a portable conforming Common Lisp program will run in ABCL (a full Common Lisp implementation on top of the JVM) - because it will not depend on TCO to not blow up the stack, or similar.

* another reason was that Lisp has a bunch of features with don't work that well with TCO. For example Lisp always supported various dynamic scoping constructs and made extensive use of those - something which Scheme in its core does not, but provides via libraries or language extensions. Using dynamic scoping constructs makes TCO more difficult, may require a different language design, etc.

~~~
nybble41
I agree with you on the first point. There are good technical reasons why TCO
can't be implemented on some platforms. However, that just punts the issue one
level down the stack: These platforms should have built in support for
guaranteed TCO.

As for language features like dynamic scoping, I would say that a function
call which needs to be followed by some cleanup activity is not in tail
position, so TCO would not apply. The cleanup code could be in tail position,
however, if implemented as a function call. In Common Lisp most forms of
dynamic scoping or unwinding are explicit anyway, so this shouldn't come as a
surprise as it might in languages like C++ and Rust where destructors are
called implicitly when objects go out of scope.

~~~
lispm
They are often explicit, but they are widely used and often generated behind
the scenes by macros or declarations.

~~~
nybble41
Macros would need to specify whether any expressions will be evaluated in tail
position. However, expressions in macros don't _look_ like they should be
subject to TCO, so the default assumption should be that they aren't unless
declared otherwise. Do you have any examples of cases that would be likely to
cause confusion—in particular where a function call appears to occur in tail
position in the code but can't be TCO'd because of a macro?

~~~
lispm
For example I see sometimes macros which generate code with compilation
quality (speed, ...) declarations for all or parts of their code. Depending on
the combination of qualities TCO might be enabled or disabled in code
sections.

~~~
nybble41
If TCO is guaranteed at the language level, as in Scheme, then it will always
be enabled regardless of compilation settings. Debug builds are no more
tolerant of stack space leaks than release builds. The fact that TCO isn't
guaranteed is the problem here.

~~~
lispm
> If TCO is guaranteed at the language level, as in Scheme, then it will
> always be enabled regardless of compilation settings

[https://www.gnu.org/software/kawa/Compatibility.html](https://www.gnu.org/software/kawa/Compatibility.html)

~~~
nybble41
Your point? The page you linked to specifically says that Kawa only implements
a subset of modern Scheme—by which I mean R5RS or later. Early versions of the
Scheme language standard didn't require TCO, but all the recent ones do. This
doesn't affect the core point that if TCO is guaranteed by the language
standard, as in _modern_ Scheme, then it cannot be selectively disabled
because doing so would break perfectly compliant code.

