Kent Pitman
nhplace.com · Personal blog · on HN since 2007
Kent Pitman, a Common Lisp standards contributor, writes papers and essays on Lisp design, condition handling, and language history.
What HN saysHN commenters call him a good read on equality in dynamic languages, condition handling, and the Lisp-1 versus Lisp-2 tradeoffs.
70HN people shared it
48linked it in comments
29stories submitted
693story points
3 months agolast shared
2007people per year2026
Most-shared posts
- 1Technical Issues of Separation in Lisp Function Cells and Value Cells (1988)15 people · 103 points · first shared 2009 · 47 comments on HN
- 2Condition Handling in the Lisp Language Family (2001)14 people · 56 points · first shared 2008 · 14 comments on HN
- 3Kent Pitman on Equal Rights -- and Wrongs -- in Lisp (1993)13 people · 33 points · first shared 2009 · 6 comments on HN
- 4More than just words: Lambda, the ultimate political party (1995)9 people · 22 points · first shared 2011 · discussion on HN
- 5The paper that killed FEXPRs (1980)9 people · 13 points · first shared 2011 · discussion on HN
- 6Common Lisp: The Untold Story8 people · 332 points · first shared 2012 · 30 comments on HN
- 7Lisp as a Vehicle for Rapid Prototyping (1997)3 people · 91 points · first shared 2011 · 22 comments on HN
- 8Unwind-protect vs. Continuations (2003)3 people · 39 points · first shared 2015 · 13 comments on HN
- 9What's in a Name? Uses and Abuses of Lispy Terminology2 people · 3 points · first shared 2010 · discussion on HN
- 10Acm2 people · first shared 2007
- 11Fortran to Lisp2 people · first shared 2011
- 12Kent Pitman's X3J13 Page1 people · 1 points · first shared 2017 · discussion on HN
- 13X3j13 sd 051 people · first shared 2023
- 14Exceptional Situations 19901 people · first shared 2018
- 15Papers1 people · first shared 2023
What HN people wrote when they linked it
rurban · 2020-06-11
Common Lisp already supports fsym, a function with the same name as a non-callable symbol. Hence its called a Lisp-2, in opposite to older and simplier lisps (like Scheme) with only one namespace. Lisp 1.5 started with that. https://en.wikipedia.org/wiki/Common_Lisp#The_function_namespace
http://www.nhplace.com/kent/Papers/Technical-Issues.html
The - is significant. Most people hearing lisp-2 would refer to the namespace seperation, not the 1.5 followup version.
deckard1 · 2015-10-18
Kent Pitman has always been a good read, for the problems of equality in dynamic languages. The typical Ruby or JS programmer stumbles through the day just "getting by", where it comes to comparing objects.
http://www.nhplace.com/kent/PS/EQUAL.html
agentultra · 2015-08-05
> It's not really at the core of the Lisp essence
This isn't the first time this has been pointed out to me. Someone had pointed me to Kent Pitmans'[0] paper on Common Lisp's condition handling system. It is quite a good read.
As I wasn't even born when Multics and PL/1 were released and was never old enough when they were around to have used them I do lack that context.
To me, having started using CL around 2008, it is an essential "feature" of the Lisp experience. One that no other language I'm aware of implements and few, if any, operating systems implement today.
Unix signals perhaps could emulate it?
So... my apologies if my ignorance characterizes Lisp incorrectly but I still wish this style of error handling was more common. It is just so damn useful.
[0] http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html
cbd1984 · 2015-06-18
In Haskell, the facetious answer is simple:
No instance for (Eq (a0 -> a0)) arising from a use of `=='
That is, functions aren't comparable (for equality, anyway), so the type system won't allow you to compare them.
The better answer is either "Look at their type signatures" or "See if they evaluate to the same values when given the same input"; the first is trivial, the second won't, in general, terminate, so you need a more nuanced conception of "equality" to apply in this instance. This is non-trivial to come up with.
Kent Pitman has an interesting essay on this problem from a Common Lisp perspective: "The Best of Intentions: EQUAL Rights—and Wrongs—in Lisp"
http://www.nhplace.com/kent/PS/EQUAL.html
bmf · 2013-09-09
Richard Gabriel did a great write-up of the trade-offs during the ANSI Common Lisp standardization process:
http://www.nhplace.com/kent/Papers/Technical-Issues.html
What I took away from it was that macros get more tricky to write when you have possible variable capture for functions, which we humans seem to be a little more blind to than for values.
Item 18 contains the compatibility concerns for existing code, which the guys writing the standard seemed to think critical to keep the various vendors on board.
TheMiller · 2013-01-10
I realize this is quite off the main topic, but I thought it was interesting and worth passing on.
If you really think that "four different kinds of equality" in Common Lisp is a wart, then I recommend that you read "The Best of Intentions" (http://www.nhplace.com/kent/PS/EQUAL.html) by Kent Pitman. The article explains why that situation is quite intentional, and why it is very rational, and why it is in fact ill-advised to expect a single meaning for "equal" ... or, in fact, other "obvious" concepts like "copy" ... to be sufficient.
That article was one of the many over the years that helped me refine the way I think about programming and programming languages.
nostrademons · 2011-01-26
See Lambda: The Ultimate Political Party:
http://www.nhplace.com/kent/PS/Lambda.html
Languages are more than just syntax and semantics. There's also a whole culture that grows up around the language, a set of "best practices" and common idioms. And the one that's grown up around Java seems to value abstraction and design patterns and convoluted, overgeneralized solutions.
This doesn't apply to all Java code, of course. You can write lean Java just like you'd write lean C or lean Python. But a non-trivial amount of the Java jobs out there expect you to layer frameworks on top of frameworks and jump through an amazing number of hoops just to get something done.
gcv · 2008-07-01
Exceptions in mainstream languages have a fatal flaw: they unconditionally unwind the stack when thrown. This sacrifices flexibility and makes it unnecessarily difficult to save state or take action at the point of the throw. Of all languages I've ever seen, only Common Lisp really does this right by separating out the concept of signaling a condition and of handling it.
I don't want to get into the details here, but Kent Pitman wrote a great paper on the subject: http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html
EdwardCoffin · 2023-04-12
Very much in the same spirit is Kent Pitman reflecting on the value of the charter for the X3J13 standardization committee [1]:
5.3 Charter: Susan Ennis (1986)
Sitting in a room for a good part of a meeting coming up with words to write as part of our mission did not seem like a good use of time to me at that moment. But I went along with it because there seemed no stopping it. In retrospect, I consider this a major administrative contribution and I credit the committee chair, Susan Ennis, for getting us to do it.
What I found later was that there were many times during work on the standard where people disagreed about what the right way to proceed was. In many of those cases, we might have been hopelessly deadlocked, each wanting to pursue a different agenda, but I was able instead to point to the charter and say, “No, we agreed that this is how we’d resolve things like this.”
...
The time spent writing the charter later paid for itself many times over and it’s an exercise I recommend to any committee engaged in any large endeavor over a period of time.
Edit: I just noticed that the very next section, 5.4 Cleanup: Larry Masinter, discusses this very point about forms
[1] http://www.nhplace.com/kent/Papers/cl-untold-story.html
mananaysiempre · 2022-04-28
> I don't really know what "conditions+restarts" is but a few articles landed me into LISP which I find totally unreadable. So, can you point me to some "conditions+restarts" code that I can understand/appreciate easily?
You’ll have to read Lisp, I’m afraid; the best description I know is in the book Practical Common Lisp[1].
(Come on, Lisp syntax is quirky, but it’s not unreadable, and unlike APL or Forth or even Haskell it doesn’t require you to memorize a bunch of semi-meaningless punctuation before you can understand what is going on—it’s pretty wordy usually. I’m not saying you must bring yourself to love writing (f x y) instead of f(x, y), only that adjusting from one to the other should not be particularly hard.)
I mean, I have done a toy Forth implementation, but that is hardly more readable with no experience with the language.
One system that is almost conditions and restarts is 32-bit(!) Win32 SEH, but it is not particularly well-documented and the language bindings usually try rather hard to hide that (though, if you think about it, On Error Resume Next from classic VB is unimplementable on top of bare try/catch).
...
OK, you nerd-sniped me :) Here’s a toy (no subtyping! no introspection! no condition firewall[2]! no tracebacks! no support for native errors! etc.) condition system in Lua (sorry, nested functions in Python are painful):
-- save as cond.lua
local M =
{}
local error, unpack = error, unpack or table.unpack
local running =…
lispm · 2019-03-20
That might be more like what was called an FEXPR mechanism in some early Lisps or some niche Lisps, or even in languages like R.
https://en.wikipedia.org/wiki/Fexpr
When an FEXPR is called, it gets unevaluated args and can then at runtime decide what to do.
Macros OTOH are a different mechanism, where expressions get rewritten at macro expansion time, which can be for example at compile time. The macro then gets called with arbitrary expressions it encloses (those don't need to be valid code by themselves) and computes new source.
Thus macros are code generators from expressions. In a compiled implementation, macro expansion is done with compilation interleaved: each form gets expanded, even repeatedly until it no longer expands into a macro, and then the resulting non-macro form gets compiled.
Thus in a way a macro does not delay execution, it does the opposite: it actually shifts computation to compile time -> the computation of code from expressions and the computation of arbitrary side effects in the compile-time environment.
In an interpreter version of Lisp, the macro gets also expanded at runtime - but in its own macroexpansion during evaluation. There eval will call the macroexpander repeatedly until it gets a non-macro form.
Now, what can you do with arbitrary complex code generators at compile time? https://stackoverflow.com/a/2563308/69545
Actually Paul Graham wrote a classical Lisp book explaining a bunch of things around macros. Available here for…
Jach · 2018-11-11
The 'failing' of checked exceptions comes from essentially being forced to couple the type signatures of your methods' successful results with their error results. A more explicit way to do this is with Optional/Either types, and now you don't need the checked exceptions feature nor need to get people to remember to check for a global errno or some other data convention like an empty string / null. There's a lot of boilerplate though, just like with checked exceptions.
I prefer a more decoupled/late-binding approach to error handling; so far Common Lisp does it the best I've seen.[0] The key insight CL people had was that often in the face of an error, you need help from somewhere away from your local context to figure out how to resolve it, but then for many cases, you want to return back to where the error has occurred and take the resolution path with your local context. In other languages that automatically unwind the stack to the exception handler, it's too late.
[0] http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html
mschaef · 2016-10-25
It's hard (if not impossible) to pick a single attribute of 'Lisp' that's shared by all the languages that are part of the Lisp family of languages. There are Lisps without macros, there are Lisps without the simple syntax, there are Lisps without dynamic typing, or lexical scope, or any of a dozen other features that are present in at least on Lisp.... so I think reducing Lisp to a handful of features and calling that 'basically it' is a good way to miss the point. (Not to belabor the obvious
One of my favorite points about Lisp was made by Kent Pitman back in 1995: http://www.nhplace.com/kent/PS/Lambda.html
In it, he describes through a though experiment what it means for a language to be defined by its community and how that impacts its development and use. It isn't as much about the specific features as it is the approach that led the language to get to have those features in the first place.
Just to illustrate, the simple syntax is a good example. It's not immediately obvious why simple syntax is a good thing... in fact, given the fact people prefer infix and a big part of the backlash against Lisp is due to the syntax, you might argue that it'd be better for Lisp to drop the syntax entirely. (As was tried in Dylan and Logo) That, you'd lose a lot that's not necessarily obvious. There's a real value in having a concrete syntax for your language's core data types and then defining the language in terms of those data types. The simple syntax isn't the point as much as…
stray · 2016-04-11
Actually, Common Lisp has a very nice (optional) type system.
It is not uncommon to declare types once everything is working to speed things up -- so with Lisp, you get the best of both worlds.
What sets Lisp's condition system apart is that it separates signaling a condition, handling it, and restarts. In other words, the decision about which handler to choose for an exception is usually made in much higher-level code, where it belongs.
And when no suitable handler is found you get dropped into the debugger. While in the debugger you can create the handler you need, and then call it.
And all this without unwinding the stack at all.
So while in another language I'll have to restart a long running process over and over again until the code covers all the unexpected cases -- in Lisp I can just start off assuming the happy path and refine as I go along, without ever having to start over because of an error.
I almost always feel that people talk about the wrong things regarding Lisp. A huge deal is made over macros, but nobody ever mentions the reader which is what makes macros possible. And when people do talk about macros they almost never mention reader macros.
And sometimes people do make a completely justified big deal out of the MOP (meta-object protocol) -- but frankly, I think generic functions and multiple dispatch are far more important. Or the fact that Lisp offers multiple-inheritance done right (multiple inheritance gets a bad rap because most other…
PuercoPop · 2014-08-21
Great concrete examples, a couple of things to add about them:
Handler, conditions and restarts are much more expressive than in other languages, you can signal a condition (the analogue of throw) with restarts attached to it which only if you desire to handle it in another part of the program where(/if) you decide to handle the conditions(the analogue to try). It is analogue to throwing an error with catch statements attached and when you write the try statemet the catch statements attach to the throw statement are made available to said catch. Kent Pitman explains it much more eloquently than me[1].
Also to add how well thought out CLOS dynamic redifining of classes is, when one redifines the change is garaunteed to happen between redefinition and the next time you access said class, as to give leeway to the implementation to decide the best strategy to do so (for example if redifining a class with 10K+ instances if you do it all at once the system may become unresponsive). Also if the redefinition isn't just adding or removing slots you can provide a function to handle the updating of slots for the redefinition.[2]
[1]: http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html
[2]: http://www.lispworks.com/documentation/HyperSpec/Body/f_upda_1.htm
chalst · 2013-12-06
Kent Pitman's idea of "languages as political parties" [1] seems to me to offer the best perspective on the surprising reliability of C. The core community shaping C over the years has been:
1. Unix-centric, so the community has a coherent view on the preferred sort of semantics offered to users of code;
2. Applies Kernighan--Ritchie--Pike coding style that gives a clear "code smell" [2] for C code; and
3. Is the natural home of "Worse is Better", which favours source-code simplicity over specification simplicity.
For example, the "C party" favours procedures "succeeding" with non-zero exit codes on failure where other language parties have language constructs to represent failure. This can be better from the point of view of source-code simplicity, both in code and compiler, than exceptions, and worse in terms of semantics. The LK coding style, among many other C coding styles, prefers the use of goto (or sometimes setjmp/longjmp) to handle exit status [3], which is frowned upon in nearly all non-C programming language communities; the restriction of goto/longjmp to handling errors in this way avoids the problems Dijkstra pointed out [4,5], and correct usage of goto/longjmp in properly checking exit status has good code smell if generally accepted coding conventions for the use of goto to handle failure are followed.
There's a nice fragment of code illustrating the idea on SO [6].
[1]: Pitman 1994, Lambda: The ultimate political party,…
edw · 2011-04-14
"A brilliant and insightful analysis."
I asked one of my CL hacker friends about the L1/L2 question, and he waved has hands a lot and said that Richard Gabriel said that L2s were better. I read the essay that he alluded to (but didn't actually read, apparently) and it read as a compelling argument FOR L1s until the end:
[Quoting from the paper, available at http://www.nhplace.com/kent/Papers/Technical-Issues.html]
The bulk of arguments that focus on clean semantics and notational simplicity tend to favor uniting the function and value namespaces. In spite of this, there are those who hold strongly to a belief that a two-namespace system affords useful expressive power that they are unwilling to do without. In the end, practical considerations favor the status quo for Common Lisp. There is a large number of improvements beyond a single namespace that could be made to Common Lisp that would clean it up and simplify it. We feel that the time for such radical changes to Common Lisp passed…
[End quote]
So I have a CL expert, writing for the standard committee, arguing that all things considered, L2s suck, but we're stuck with keeping CL an L2.
So that, in addition to my own experience with CL, Scheme, and other languages, is the basis of my informed opinion.
akkartik · 2011-03-15
I think bottom-up programming is great, but I have a bone to pick with that On Lisp quote.
"So yes, reading a bottom-up program requires one to understand all the new operators defined by the author. But this will nearly always be less work than having to understand all the code that would have been required without them."
Here's the problem: it's hard to build good abstractions. Every abstraction has a cost and an overhead in learning it, getting used to it, managing the cognitive overhead. The binary black-and-white phrasing of this argument utterly sidesteps any mention of the tradeoffs involved. Most abstractions we encounter in real-world code fail to take into account the cost of using an abstraction. You built it, you're used to it, you can't empathize with others who need to learn it.
Here's my stab at articulating the tradeoffs: http://news.ycombinator.com/item?id=2329613
Common Lisp is a great language, but it's littered with crappy abstractions: too many kinds of equality http://www.nhplace.com/kent/PS/EQUAL.html, an inability to override or extend coerce, redundant control abstractions like keyword args to reverse traversal order (http://dreamsongs.com/Files/PatternsOfSoftware.pdf, pages 28-30), the list goes on and on.
slowmovintarget · 2025-03-07
"No true Scotsman..."
Lisp-1 and Lisp-2 are the only interesting distinctions. Everything else boils down to "does it use S-expressions?" The "OMG! it doesn't have ~cons~!" is a silly argument, but that's because it's an opinion (just like this).
https://www.nhplace.com/kent/Papers/Technical-Issues.html
troad · 2024-06-17
Certainly, but the original quote was "It is quite hard to even tell a noun from a verb" (emph. added), and this is correct, you can't tell whether an identifier refers to a function or variable in Scheme by sight alone. This seems desirable if one wants first-class functions, and is very much an intentional choice for Scheme, but it can admittedly be more difficult to build up a mental model of new code if you have no idea what's a variable and what's a function (esp. amidst an already-difficult-to-grok sea of parentheses).
Notably, this isn't intrinsic to Lisps - Common Lisp uses a different syntax and namespace for function names and variables. My understanding is that Scheme et al's decision to merge the namespaces/syntax was not without controversy in the Lisp community (the Lisp-1 v Lisp-2 debate).[0]
[0] http://www.nhplace.com/kent/Papers/Technical-Issues.html
antonvs · 2023-03-26
FEXPRs haven’t been relevant in mainstream Lisp since the 1980s. See Kent Pitman’s 1980 article describing the problems with them: https://www.nhplace.com/kent/Papers/Special-Forms.htmL
The languages you mention probably use them mainly because they’re easy to implement in the language implementation, which has nothing to do with what the community values, except in a post-hoc sense when the community tries to justify to itself why it’s using such an inherently intractable feature.
Jtsummers · 2022-01-15
Pitman's "Special Forms in Lisp" is available online at: https://www.nhplace.com/kent/Papers/Special-Forms.html
If you want to see the full text of what's being rebutted in this essay.
kragen · 2021-08-04
It doesn't, no, but yes, that was my thought: write a version of with-open-file implemented in terms of dynamic-wind that raises a runtime error if you try to reenter. Better hope people are using call/cc for exception handling and not threading though...
Pitman's comments on this are in http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuations-origi… Sitaram's response is at http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.79.3107, and Pitman's final response is at http://www.nhplace.com/kent/PFAQ/unwind-protect-vs-continuations-updat…
DonaldFisk · 2020-12-06
There's a discussion of the relative merits of Lisp 1 vs Lisp 2 (or higher) in Technical Issues of Separation in Function Cells and Value Cells by Richard Gabriel (http://www.nhplace.com/kent/Papers/Technical-Issues.html).
pmoriarty · 2020-10-29
I'm not sure if it'll make things clearer for you, but there's some background of fexprs in Kent Pitman's "Special Forms in Lisp" paper here:
http://www.nhplace.com/kent/Papers/Special-Forms.html
phoe-krk · 2020-07-15
Trivia: Kent M. Pitman (also known as kmp) is the father of the condition system as it exists nowadays. The code in the book is based on Portable Condition System - a library that I have created, and Portable Condition System itself is in turn based on the original implementation of the condition system available at http://www.nhplace.com/kent/CL/Revision-18.lisp
After a wee bit of massaging that code to compile it on modern Lisp implemenations (the above code is CLtL1, which is an old version of Common Lisp from 1984), it still works!
DalekBaldwin · 2018-08-28
And for more on the history and philosophy behind it: http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html
vzcx · 2018-03-14
The CL condition system separates the signaling of a condition (of which errors are a subtype), the handling of a condition, and the definition of recovery strategies (restarts).
Instead of unwinding the stack when a condition is signaled, handler code is invoked in the dynamic context of the signal and thus has much more information available to decide how to recover.
If a decision on how to recover can't be made programmatically, the system kicks out to the user where they are presented with the choices you have given them.
See: http://www.nhplace.com/kent/Papers/Condition-Handling-2001.html for more.
sillysaurus3 · 2017-09-10
Related:
Special Forms in Lisp: Fexprs vs. Macros (1980)
http://www.nhplace.com/kent/Papers/Special-Forms.html
hga · 2015-08-05
PL/1 had such an influence. Multics had its own version of it as its system language, which had "on-conditions", which per http://www.multicians.org/pl1-raf.html made optimization difficult. Bernie Greenberg was a major Multics "kernel" hacker, and wrote Multics Emacs in MACLISP and PL/1 before joining Symbolics. Per vague memory and Wikipedia (https://en.wikipedia.org/wiki/Bernard_Greenberg):
Greenberg was involved in the design of the "New Error System" at Symbolics, which in turn influenced the condition system adopted by ANSI Common Lisp.
And per the referenced citation (http://www.nhplace.com/kent/CL/Revision-18.txt):
Many aspects of the NES were inspired by the (PL/1) condition system used by the Honeywell Multics operating system.