Hacker News new | past | comments | ask | show | jobs | submit login
Lisp is Not an Acceptable Lisp (2006) (steve-yegge.blogspot.com)
67 points by krmboya on Dec 7, 2013 | hide | past | favorite | 47 comments



Steve Yegge regarding Clojure (2012):

" For a few years I had been really excited to start learning Clojure, and my initial experiences with it were quite positive. However, I eventually learned that the Clojure community is extremely conservative. That is is pretty unusual for a Lisp dialect. Lisp is widely regarded as one of the most liberal language families in existence. And Clojure has the superficial appearance of being a laissez-faire kind of language. It is quite expressive, including a -- ahem -- liberal dose of new syntax. And it eschews static type annotations and strong type modeling in favor of a small set of highly regular, composable data types and operations -- not unlike, say, Scheme or Python. But the resemblance to a liberal language ends there. Clojure's community came pre-populated with highly conservative programmers from the pure-functional world: basically Haskell/ML types (lots of puns today!) who happen to recognize the benefits of Lisp's tree syntax. So under its expressive covers, everything about Clojure is strongly conservative, with a core overriding bias towards protecting programmers from mistakes."

https://plus.google.com/110981030061712822816/posts/KaSKeg4v...

He defines conservative:

"I hope you'll agree that this definition is minimally controversial. After all, the adjective "conservative" is more or less synonymous with caution and risk aversion. Financial conservatism is frequently (and intuitively) associated with age and with wealth. "

My own feeling is that he misunderstands functional programming. I could say "functional programming offers safety from side-effects" and then he might say "Yes, that is what I mean by conservative" but who wants to have their code undermined by uncontrolled side effects? By his definition, "conservative" applies to every programmer; which makes me think his definition is useless.


The motivation of Clojure, to me, is making concurrency safe and easy. So far, the best way to reduce "risk" in concurrent systems is to constrain side effects, and not share mutable state between units of concurrency.

If you're choosing to reduce the number of side effects, then a functional language is clearly the best suited for the job. The creators of Erlang knew this. The creators of Haskell discovered(?) this.

In my opinion, the fact that Clojure is a lisp is completely irrelevant, personally I prefer ML-family syntax, but the consistent standard library of Clojure makes it too powerful to ignore.

The focus on concurrent programming is also indicated by its relaxed stance of side effects. It is not a pure language, it only sets the constraint that you cant have side effects that leak state into other units of concurrency. If your mutations don't create a risk of data loss, then you are welcome to use them.


I think the combination of expressiveness, flexibility, and safety that Yegge describes is exactly what clojure is aiming for, so he's actually giving it a huge unintentional complement. He simply doesn't like the goals of the language.


> And it eschews static type annotations and strong type modeling

I don't know that this is true. core.typed is really solid.

> Clojure's community came pre-populated with highly conservative programmers from the pure-functional world"

What does he have against Haskell? ;) Haskell is ahead of its time. I agree with Ikrubner here, that his definition of conservative is quite desirable. Additionally, people with experience in Ruby/Javascript/CL/Python make up the majority of the community.


I posted that article to HN, but it didn't get any votes. I know very little about Clojure, but I think the conservative/liberal dichotomy he describes is very real. Liberalism and conservativism in software are closely related to liberalism and conservativism in politics. The description of conservativism in that quote is not terribly insightful, because he's obviously going out of his way not to offend anybody, so he made it excessively simple and superficial. To get a good handle on how conservativism manifests itself in software, ideally you'd need a subtle appreciation of how it manifests itself in politics; less in terms of dry theory and more in terms of the character traits and basic orientation toward life that precede adopting conservative views. Yegge speculates that someone could be a liberal in software and a conservative in politics or vice versa, but I kind of doubt this. If it does occur, it's probably in borderline cases, or in cases where somebody may be truly a conservative deep down, say, but is not engaged enough in politics to have realized it yet, or they side with the left politically as a result of specific issues rather than temperament (e.g. the person is a racial minority).

You could say that conservatives, both in software and politics, tend to be sticklers for rules and structure. That may be enough to shed some light on the difference as a practical matter. But I think that doesn't really get to the essence. Liberals can also be for rules and structure. What differs is the nature of the rules and who they apply to. I think it's closer to the truth to say that conservatives generally distrust people. In politics this general distrust manifests as, e.g. opposition to social welfare programs, because of the belief that people will invariably take advantage and abuse them. In software, the distrust manifests as, e.g. opposing programming languages and language constructs that are too laid-back and give the programmer too much freedom. The belief is that programmers, in general, can't be trusted to make good choices, and will invariably write bad code if they're allowed to.


I agree with Yegge on this: I think the true strength and weakness of Clojure is its FP safety, which is probably great for many specific applications but comes across to me as needlessly ceremonious and conservative for typical applications.

I personally prefer something multi-paradigm like CL where I can happily use, for example, variable assignment (setf) and write "liberal" code.


Side effects are useful. We use them all the time: IO, graphics, sockets, signals, etc. We even use mutable data because in certain cases it's more efficient. So I think I agree with Yegge there wrt, "conservative."


Not sure if it was your intention to imply so, but neither Clojure nor Haskell* eschew side effects. However Haskell provides tools to manage side effects. I'm not sure about Clojure since I haven't dove into that pool yet.

* I mention Haskell since there is a lot of FUD going around about Haskellers not using side effects.


Nobody said that side effects aren't useful, as Rich Hickey would be the first to remind you. Clojure has full support for side effects and mutable data structures if you need it for efficiency. The point is that in Clojure, there are easy and idiomatic ways to control complexity by minimizing side effects and use of mutability.


When I first read Guy Steele's 2nd edition of Common LISP, the Language in the early 90s I remember thinking "This is a huge language, how could anyone implement this reliably?"

A recent pass through that book, and the language actually seems small. Not trivial, but definitely doable by a smallish group of people in a reasonable amount of time. Implementing a browser DOM plus JavaScript, or a C++ compiler, seems a lot more daunting.


I wonder to what extent this is still true with Clojure picking up steam. It doesn't have the old-Lisp roots sticking out, but replaces them with protruding Java bits[0]. Plus I seem to recall Steve wanted Clojure to "say yes more" (can't find the link now), but don't know if he still feels that strongly.

[0] I have only done a little bit of Clojure programming, but I remember being mildly frustrated by having to deal with unfamiliar Java-isms that were showing, not having done Java at that time. This was around a year ago.


For me (and lots of other people, too) Clojure is a fantastically acceptable flavor of LISP.


Of course, but Clojure didn't exist in 2006. I wonder what Steve Yegge would say today.


He wrote the foreword to The Joy of Clojure:

"... It’s an astoundingly high-quality language, sure—in fact, I’m beginning to think it’s the best I’ve ever seen..."

Not sure what he thinks now.


Here is what he said then re Arc: "My prediction: someone will get tired of waiting, and they'll Torvalds Arc into obsolescence before it's ever released. (If you don't get the reference, it's what Linux did to GNU Hurd)."


There was a whole "yes language" kerfuffle a while back. Quite frankly, I'm glad Clojure doesn't fit in to Yegge's world view.


Racket has become a pleasant and acceptable, modern, batteries included Lisp as well.

Now our cup runneth over. Common Lisp is the same as it was while Clojure and Racket offer ways to a lispy future.


>Common Lisp is the same

But the great thing about Lisps is that they can't get stuck in the past.

For example, if, say, Python didn't have decorators and you wanted to add them in, you'd have to present the idea in a PEP, get approval from Guido, write some code, et cetera. In Common Lisp, you just write some reader macros and that's it[1]. If Python stopped being maintained, it would lag behind other languages, but the fact that the Common Lisp spec hasn't been updated since 1996 doesn't make it any less modern.

A more relevant example: Lisp doesn't have hash table literals, which every "modern" language these days has, but those can also be added, trivially in less than fifty lines[2] of CL code, and suddenly Common Lisp is modern again.

[1]: https://github.com/arielnetworks/cl-annot

[2]: http://frank.kank.net/essays/hash.html


In programming languages, having 3 proper solutions to a problem is worse than having a single proper default solution - simply due to the overhead of first having to choose, and then the unneeded difficulty when reading other people's code who chose a different lib for the same thing.

For things such as hash table literals, you're not supposed to simply have some way of doing it - you're supposed to have a good and commonly used way of how most everyone else would be doing it and representing them in his/her code. Having a bunch of nonobvious, nonstandartized ways alone hurts readability, maintenance and reusability - and thinking that it is okay is a sign of being stuck in the past.

Being able to add it trivially yourself is an order of magnitude worse - because results in everybody rolling out his own. If you want to make an usable ecosystem (not just 'language core') then you have to make sure that for all/most commonly needed things, the default 'batteries included' or 'batteries taken from first google result' work well, not that it's simply possible to get them somehow.


You know, people say that Common Lisp "is the same as it was" but I dunno. Even if the spec is the same a lot of new libraries are coming out that're changing the playing field, like LiL (Lisp interface Library) or STMX (Software Transactional Memory).

I still do think that we need some new Lisps to do new stuff which can then be cherry picked and so on by new Lisps though.


How the implementation compares to SBCL?


Yes, but its not the features per se that make Clojure and Racket different from CL; any feature in these languages can be tacked on top of CL fairly easily by a half-decent hacker.

What makes these languages different is their vibrant communities. I do hope they get faster implementations out sometime :) (and allow people the freedom they've been used to in the CL world).


>Once you've got a canonical AST defined, syntax should, in theory, be like CSS chrome

This is an awesome idea. Are there any projects working on this concept? I guess multiple languages targeting the same bytecode is as-close-as-practical at the moment.


AIUI, this was the original genesis of Lisp - the S-expressions were supposed to be an internal abstract representation, and programmers would write "M-expressions" in a language a bit like Fortran. But everyone involved in Lisp realised you could just write S-expressions directly, and never got round to defining the M-expression syntax.

More recently, the GNU scheme project, Guile, had people working on pluggable syntax translators that would allow you to write Guile programs in TCL or JavaScript syntax, but AFAIK that project never produced anything completely usable.



Isn't this pretty much what Dylan is (or was supposed to be)? I may be wrong though, but I remember it being described as a LISP minus the (visible) S-Exp... Or maybe just the parenthesis.


Sigh. This blog post again.

At least it's been posted with the "2006" date in the title, but some of the problems:

1. The title is catchy and provocative, but it should really read "Common Lisp is Not An Acceptable Lisp". "Lisp" by itself is a family of languages, not a single language. Most of the blog post is dedicated to attributes of Common Lisp specifically. The title always struck me as a bit disingenuous and link-baitey, especially since his very first point is about how there are multiple different Lisps.

2. Which implementation of Common Lisp are you talking about? There are several, and when you talk Haskell "kicking its ass all over the performance map" because of the type system, it's helpful to know whether you're talking about CLISP (an interpreter by default), or SBCL (a Lisp compiler, and one that is highly focused on speed.)

3. CLOS looks weird to people who are used to "object oriented" languages like Java, sure, but it's much more true to the nature of object-oriented programming as a whole. I'll refrain from pulling out the old Alan Kay quotation in which he (the father of the term "object oriented") identifies Lisp and Smalltalk as the only two OO languages that he's aware of, but CLOS is much more true to the spirit of OO programming than any other system I've worked with (except perhaps Smalltalk)[0].

4. "There is no acceptable Lisp". In 2013, this is utter nonsense. I'll give Yegge the benefit of the doubt when it comes to 2006, but even still, it's rather frustrating to read 3000 words (yes, I counted) about the shortcomings of Common Lisp, and then suddenly the author jumps to the conclusion that all Lisp dialects are equally bad, with no supporting evidence.

I have my fair share of frustrations with Common Lisp. The spec shows its age in many ways, and I really wish it had a number of features that I like about modern Lisp-like languages like Racket[1] - dialect scoping, hygenic macros, optional typing, etc.

But I cringe when I see links to this post in 2013. For a blog post that's so long, it's surprisingly spare on evidence that supports the argument presented in title or the conclusion, even if it gets a number of things right along the way.

[0] As pointed out below (thanks, cwzwarich), Kay's quotation mentions Lisp (not CLOS by name), so it's a jump for me to assume that it implies his support of CLOS specifically. That said, if you implemented OO-programming (as Kay defined it, not as Gosling defined it) in Lisp in the most straightforward way possible, you'd end up writing something that resembled CLOS.

[1] I say "Lisp-like" to pre-emptively deflect any debate over whether or not Racket is a "true" LISP (it certainly isn't a true Scheme, because it is not fully compliant with any single Scheme standard; it uses a hybrid of R5RS and R6RS)

EDIT: Okay, here's the Kay quotation: "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I’m not aware of them. " (http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...)


> "OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I’m not aware of them. "

Excellent quote. He correctly omits types from his description, yet OOP is typically taught (especially in school) as a system of types. We're being dishonest when we say "object oriented" when we really mean "class oriented".


It's not just in schools. It's more a consequence of the fact that the vast majority of mainstream languages use the Nygaard model class-oriented incarnation of OOP, rather than Kay's model of messaging.


> I'll refrain from pulling out the old Alan Kay quotation in which he (the father of the term "object oriented") identifies Lisp and Smalltalk as the only two OO languages that he's aware of.

I think he was referring to Lisp in general in that quotation, not CLOS, although I remember glowing praise from him regarding The Art of the Metaobject Protocol.


This is how i remembered it too. I thought he said something along the lines of lisp and smalltalk are the only two languages i am aware you can do OOP in. I tried to find this and couldn't.

And OOP here means these two things from Kay: (i)'In computer terms, Smalltalk is a recursion on the notion of computer itself. Instead of dividing "computer stuff" into things each less strong than the whole--like data structures, procedures, and functions which are the usual paraphernalia of programming languages--each Smalltalk object is a recursion on the entire possibilities of the computer.'

(ii) "Four techniques used together--persistent state, polymorphism, instantiation, and methods-as-goals for the object--account for much of the power."

i, ii are from http://www.smalltalk.org/smalltalk/TheEarlyHistoryOfSmalltal...


> each Smalltalk object is a recursion on the entire possibilities of the computer.

So it's like a lambda expression. Except that:

1. OOP was invented 35 years later.

2. OOP is not based on the mathematical concept of the function, which is (arguably) the most successful idea ever dreamed up by (not as arguably) some of the smartest human beings ever to live.

3. Objects are lies. An object that calls itself a COW is not a cow; a function that calls itself SEND-COWS-TO-MONTANA really does send the cows to Montana.

Ergo OOP=dumb. What am I missing?


I'm curious why "an object that calls itself a COW is not a cow" yet "a function that calls itself SEND-COWS-TO-MONTANA really does"? Both are merely abstractions over ideas, no? One over the idea of a thing, one over the idea of doing something.


I think the idea is that domain logic is encapsulated in functions, while the objects themselves only contain metadata. So if you have an class of objects named 'COW', then the objects themselves will contain information about cows. If you simply delete the object, the cow will still exist.

However, if you run a function called, "slaughter_cow", then that should actually do something, maybe it will mark that cow for slaughter. Running functions should have real-world effects, directly manipulating data objects won't. (except maybe to cause confusion)


But this really just falls into the "no true Scottsman" fallacy, doesn't it? I mean, running a function called "slaughter_cow" that will only "mark that cow for slaughter" it is misnamed in some sense. Same for any function. Unless what you are doing is fully abstract in the first place, than any abstraction over it will in many senses be a lie.


The worker who got the message on the screen slaughters the cow, how can you not consider the worker and his process part of the code as well?


>3. Objects are lies. An object that calls itself a COW is not a cow; a function that calls itself SEND-COWS-TO-MONTANA really does send the cows to Montana.

Err, no it doesn't. Both are manipulating symbols (names), not actual cows.

That's how we can have games like Sim City that don't cost trillions of dollars to play.


I think I found the source of the original quote here:

http://www.purl.org/stefan_ram/pub/doc_kay_oop_en


Yep, this is at least what I thought the commenter was referring to. Thanks!


Common Lisp do have optional typing though, and hygienic macros is a controversial subject. Dialect scoping is cool though


> hygienic macros is a controversial subject

The amount of work which Racket people put into hygienic macros in the recent years gave effects. If by "controversial" you mean "less expressive" or "less composable" then those controversies should disappear already.

For example: http://www.schemeworkshop.org/2011/papers/Barzilay2011.pdf http://blog.racket-lang.org/2011/04/writing-syntax-case-macr...

Related: http://www.ccs.neu.edu/racket/pubs/

On a side note, it's impressive that language implementors write such a large amount of papers for almost all new language features. Compare it to the usual one-line point in changelog. This makes Racket foundations incredibly solid and learning it in depth easy and satisfying.


The same Yegge implemented JavaScript in Emacs Lisp...


    Just have to say it: Clojure *is* an Acceptable Lisp


It's funny how 'older' articles submitted to HN get a second (third?) wind. Why? Why? Why? Is this a slow day?


Yeah bro it is. I'm bored, browsing HN, seeing articles I've already disliked.

The article seems to blame the programming language for the issues cause by the social involvement of the community.. and laziness to research and find a good environment to develop with.. come the fuck on. If you're a programmer, you're a problem solver. Don't bitch about solving one..

Funny how this ^ is still... 7 years later.


I really don't like this authors way of writing. His only valid success criteria seems to boil down to something similar in meaning of "An acceptable lisp is a lisp that every single programmer uses it".

1. "Killing adoption"? For what goal? People have different thought process, each dialect will be more natural for a certain subset of people. Offering dialects and diversity in choice is a good thing. I have only limited experience, last semester when i graduated i took a SICP course and now i have read through On Lisp because i thought macros sounded powerful, so i am going to be programming a hobby project in Common lisp. But that doest mean i want Scheme to disappear from the world.

2. Libraries.

3. I haven't used CLOS much so i can't really say anything. But making complaints that things are "bolted on" Common Lisp because of the macro system seems to me that he has missed the point of what people like with Common Lisp and its macro system.

4. Can't one use Scheme if one wants portable hygienic macros? I can agree somewhat with the macro situation and my own research seems to point this to the historical decision to pass on fexprs to gain efficient compilers. The plus side is that macros can expand macros means is generally works. And i don't get this "band-aid" notion. From what i understand macros are argument to use lisp and should be utilized.

NewLisp offers fexprs and is focus on interpreted, which means that at any time you have access to a functions definition to use for self-modifying code and eval is blazingly fast compared to other lisps that support compilation. I want to start experiment with true ai that can modify its behaviour in newLisp soon. This is also an argument on point 1 of the diversity of lisps. ( yet i guess you could in common lisp use a macro that always saved the interpreted function definition in some global has that you could operate on in a macro dsl )

On a closing note i would like to add that it isn't really important to attracts people to lisp. Infact from an ethical standpoint trying to sway people which tools they "need to use" is questionable. And in a similar spirit of the HN article "People don't like creativity" i am not convinced that everyone actually would prefer lisp even if we lived in a world where lisp were as popular as C# and Java together.

Every programmer will hear about lisp at some point and if they are interested in it they will probably explore it.


Haha, I remember reading this back in the day. While I came from a primarily C background, I have to say that Clojure truly is not only an acceptable lisp, but a refreshingly "modern" language -- in the same sense that Algol was a modern language for AI researchers. It packages cutting edge features, like STM, without necessarily complicating certain abstractions.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: