A Rubyist's Impressions of Common Lisp

It has been nearly 6 months since I dove into Common Lisp. I have been studying and/or using Common Lisp almost every day, working on Ambienome and related code. So, I wanted to take some time to document my observations, feelings, and impressions of Common Lisp at this time. Be advised that this is a fairly long post, even though I have trimmed out a lot of details and examples to keep it from growing even longer. (Apparently I have a lot of impressions!)

I have approached CL from nearly 8 years of programming in Ruby. I mention this because my experience with Ruby has certainly colored my impressions of CL, and many of my observations are about how CL compares to Ruby.

Different Yet Similar

Overall, I'd rate Ruby and CL as being about equal, on my personal, subjective scale of programming language goodness. They differ in many ways, both good and bad, but it feels to me like the differences balance out. So, the two languages are different, but neither one is clearly superior.

On a conceptual level, the two languages are actually fairly similar. They are certainly more similar to each other than either one is to a language like C, for example. They both have an interactive prompt, automatic memory management and garbage collection, first-class functions, anonymous functions and closures, arrays and hash tables, mutable strings, arbitrarily large integers, namespaces (modules in Ruby, packages in CL), and class-based OOP systems that don't force you into an OOP style. There are probably many other smaller similarities that I could think of if I took the time. (A dedicated Lisper would point out that many of these concepts originated in some Lisp dialect or another.)

Naturally, the details of many of these things are different. For example, CL's packages work very differently than Ruby's modules, despite fulfilling the same basic purpose. But in general, the concepts in each language are similar enough that knowing one language will make it significantly easier to learn the other.

Strengths (In Brief)

There are several aspects of Ruby that I feel are especially strong relative to Common Lisp. Stated briefly, they are:

Of course, Common Lisp has several areas where I feel it has the advantage:

I describe these in more detail near the end of this post.

Weaknesses

I'd like to be able to make a list of the areas each language is weak, but I'm too close to Ruby because of my years of use, yet also distant from it because I haven't used it actively for perhaps a year. Both of those situations affect my perspective and make it hard to see Ruby's real flaws.

Of course, Ruby has some weird bits of syntax (like {|args| ... } code blocks) and other quirks, but no more so than most languages, including CL. Ruby's performance is traditionally a bit weak, but that varies across implementations, and is improving in leaps and bounds. The community is generally pretty great, although I find the “brogrammer” trend in some parts of the community to be distasteful and regressive.

My relationship to Common Lisp is a different situation. My eyes are still fresh and I'm actively using it, so I can see and describe Common Lisp's shortcomings pretty clearly. But, I want to emphasize that just because I can still see the flaws in Common Lisp, that doesn't mean there are no flaws in Ruby. I'm sure someone else could point out just as many problems in Ruby as I can in Common Lisp.

So, with that caveat, I'll describe what I consider to be Common Lisp's problem areas.

Minor Problem: Batteries Not Included

Ruby, Python, and other “batteries included” languages come with all kinds of nifty features (e.g. networking, regular expressions, XML/JSON/etc. support) right out of the box. A programmer coming to CL from one of those languages might expect CL to be the same way, but it's not. Why?

The main reason is that CL has a formal ANSI standard, designed in the 1980s and early 1990s as a way to consolidate several different Lisp dialects. It took 10 years, countless man hours, and hundreds of thousands of dollars in direct expenses to finish the standard. Every detail was weighed and debated to make sure it was acceptable to the many people and groups with a vested interest in the process, such as the vendors who sold implementations of the old dialects.

So basically, only features that were acceptable to everybody were put in the standard. Things that they disagreed about, or that would put too much burden on the implementors, or that didn't even exist back then, are not in the standard. Adding a new feature to the standard now would probably take many more years of debate and nitpicking, and would only succeed if practically everybody agreed that it was such a great feature that it is worth the effort. In other words, it would take a miracle and a half.

That is a very different scenario than you have with Ruby/Python/etc., where someone can submit a new feature to the most popular implementation, a core dev likes the features and commits it, and it's released in the next version.

So, why is this not a huge deal in Common Lisp?

Well, most features can be written as libraries that you can install when you need them. CL is so flexible that even major changes to the language syntax can be installed as libraries! And with the advent of Quicklisp, installing libraries in CL is just as easy as installing gems in Ruby, or eggs in Python.

As for the features that can't be written as libraries, individual CL implementations can provide them as extensions. For example, the implementation I use comes with a bunch of goodies that aren't in the ANSI standard, such as threading, networking, code coverage and profiling tools, and a foreign function interface (FFI) for wrapping C libraries (such as OpenGL, as I'm using for Ambienome). If a feature is popular and many implementations provide it, someone will usually create a wrapper library that smooths out the differences between implementations, so that programmers can use the feature without being tied to one particular implementation.

(That's an idealized scenario, of course. It doesn't always work out so smoothly. Some implementations don't add new features very often, if ever. Sometimes an implementation adds a feature in a way that isn't compatible with other implementations, making it difficult or impossible to create a portable wrapper library. In such cases, if a programmer really needs the feature, they might target a specific implementation, rather than trying to keep their code portable. If they really need their code to be portable too, they can write code that acts differently for each implementation.)

That process of adding a feature to an implementation, letting other implementations copy it, and writing a wrapper library on top, is far from perfect. But, it's faster, less onerous, and more flexible than trying to update the ANSI standard, and the results are usually satisfactory.

So, once you realize the implications of Common Lisp being formally standardized, and find out that there's an easy way to install libraries, it's not such a big deal that Common Lisp does not come with “batteries included”.

But, it's still a minor problem that affects new Lispers coming from other languages. It might be possible to alleviate the problem through expectations management. If new Lispers understood from the start that many features are not part of the standard, but nevertheless are readily available as libraries, they wouldn't be so surprised and disappointed.

I'm not sure who would be most effective at this sort of expectations management, though. Implementations? Book authors? Teachers? Bloggers? Wiki editors? IRC and newsgroup participants? I suspect all of the above are already doing it to some degree, yet many newcomers are still surprised. This is one area where having an “official website” for Common Lisp might make things easier.

Moderate Problem: Historical Baggage

Common Lisp has a lot of historical baggage: things that are done a certain way just because that's how they were done in the past, even if they don't make much sense nowadays. Perhaps that's only natural for a programming language with such a long history. CL itself is nearly 20 years old (or 30, if you count from the first edition of Common Lisp the Language), and it inherited baggage from several older Lisp dialects, going all the way back to the original Lisp over 60 years ago.

That's not to say that other languages don't have some historical baggage of their own. For example, Ruby and many other languages inherit the bizarre old syntax of putting a 0 (zero) in front of a number to interpret it as octal form. (E.g. 10 means ten, yet 010 means eight. Surprise!) CL seems to have an especially large amount of baggage, though, and many Common Lispers seem to cling to that baggage rather tightly.

Historical baggage manifests itself in CL in many ways. One way is as individual quirks, like the setq operator. Setq was, I hear, originally invented as shorthand, so you could write (setq x 3) instead of (set (quote x) 3). But that was before the read macros were available; these days you can type (set 'x 3), which also means (set (quote x) 3) and is not any more characters than using setq. (Although, setq works a bit differently in CL than in earlier Lisps, so (setq x 3) isn't quite the same as either (set (quote x) 3) or (set 'x 3) anymore.) Furthermore, CL has the setf operator, which can do everything setq can do and more, so there's not really any reason to retain setq. It's just historical baggage, kept around because that's what they used in the old days. (Setq is still quite widely used today, usually with the rationale that it expresses the programmer's intentions more clearly because it can do fewer things than setf.)

Historical baggage also manifests as old idioms that affect many parts of the language. Take for example the idiom of adding “p” to the names of predicate functions, functions that check something and return true or false (actually t or nil, another bit of historical baggage). For example, (evenp x) returns true if the value of x is an even number. It could have been (even? x), which I would argue is significantly clearer. But, Lispers used “p” in the old days, so (most, but not all) predicate functions in the CL standard use “p”, and therefore most Common Lispers still use “p” when they write their own predicate functions today.

Historical baggage also manifests itself as strange inconsistencies and curiosities in the underlying architecture. For example, Common Lisp has types, which it inherited from older Lisp dialects. It also has classes, which were added fairly late in the ANSI standardization process. Types and classes are very similar in many ways, but just different enough that they can't be unified without breaking tons of old code. As a result, CL has both systems existing simultaneously, where each class has a corresponding type, but not all types have a corresponding class. Some features use types (like function and variable type declarations), while other features use classes (like generic function dispatching). I suppose the standards committee made the right choice given the circumstances back then, to avoid breaking all that old code. But, it is nevertheless historical baggage that all Common Lispers still carry nearly 20 years later.

Finally, historical baggage manifests itself as concepts and features that were useful many decades ago, but are pretty much obsolete today (and in some cases were already obsolete when the standard was written). For example, every symbol in Common Lisp has “properties”, a list of data that the symbol carries around in its guts. But nowadays, it would often be just as efficient to store that data in hash tables with the symbol as the key, and doing so would entirely avoid the possibility of two unrelated pieces of code coincidentally using the same property names. But, Lisp has had symbol properties since the very beginning, so Common Lisp has symbol properties too, along with the half-dozen functions used to manipulate them. (Symbol properties don't seem to be used much anymore.)

These kinds of historical baggage aren't a serious problem, because for the most part you can ignore the obsolete features, and either cover up or learn to live with the weird idioms and inconsistencies. But it is a moderate problem, because this historical baggage adds to the mental burden of every Common Lisp programmer in the world. (There are many, many other examples of historical baggage that I have omitted for the sake of brevity.)

It's especially burdensome for new Lispers. Year after year, new Lispers have to go through a kind of rite of passage, learning the obscure idioms of years gone by, separating the useful features from the cruft, and trying to remember function names that seem arbitrary and inconsistent. Many of them give up and leave for other languages because of needless obstacles (this being just one of many they face). Some of them could have contributed a lot to the community over time, if only “the wall” hadn't been built so high.

Serious Problem: The Community Atmosphere

That brings me to the most serious problem Common Lisp has: the community's atmosphere, its prevailing moods and attitudes. This is such an important topic that it deserves its own post, but I'll summarize the problem here.

I'll admit that I started learning CL with the knowledge that many people (usually people who tried to join the community but were repelled) consider the community to be antagonistic, especially towards newcomers. So, I may be exhibiting some confirmation bias: seeing what I expected to see, and tending to ignore evidence to the contrary. But with issues like this, the widespread perception of a problem can be just as damaging as the reality of the problem itself.

I suspect that most people who use Common Lisp, as with any language, are probably decent folk who just want to write nifty code without a lot of fuss or drama. But these people are not very visible or active in community discussion venues (e.g. the comp.lang.lisp newsgroup or #lisp IRC channel). They're off somewhere else, writing their nifty code in peace.

Alas, many of the people who are highly visible and active can best be characterized as “toxic”. These are people who, because of the nature of their personalities and attitudes, have a consistently negative emotional effect on the people they interact with. Without necessarily intending to do so, they have created a constant miasma of disrespect, nitpicking, defensiveness, discouragement, and intolerance. This toxic atmosphere permeates the entire culture, gradually driving less toxic people into seclusion or to other languages, or souring their moods such that they become toxic as well. This leaves an even higher concentration of toxicity, affecting even more people, on and on.

Is it possible to reverse this trend? I don't know. It may be too late. If it can be reversed, I suspect the way to do it is for the quiet, decent folk to put on emotional hazmat suits and start being more active in the community. Participate in discussions, help new Lispers, and discourage toxic behavior by privately and tactfully informing people about the effect they have. Reducing the toxicity of the community atmosphere would be a major culture shift, but with a sustained effort it might be possible to create a more healthy and positive atmosphere.

I can't help but compare this to the Ruby community's notion of MINSWAN (Matz Is Nice So We Are Nice), and wish there were more positive role models in the CL community to set a good example. Most of the people who are revered in the CL community are quite intelligent and knowledgeable about CL and computer science, but are also very toxic. The motto for this community would be something along the lines of NaWTSWAT: Naggum Was Toxic So We Are Toxic. The community discussion venues have become an echo chamber, perpetuating and reinforcing the notion that it is okay to be derogatory and inflammatory, as long as you are intelligent or know a lot about CL. The people who disagree with this attitude tend to give up in disgust and either leave or stop talking, so you won't hear many dissenting opinions about that from the people who remain.

This may seem like a gloomy assessment, but the situation is not all bad. There are some awesome people making cool things with Common Lisp, and many people who will try to help as best they can when you have a problem. It's just a shame that the predominant attitude is so negative.

It's Not All Bad!

I have spent many more words so far describing the weaknesses and problems of Common Lisp, than describing its strengths and interesting features. But despite its quirks and baggage and toxic people, Common Lisp is an incredibly flexible and powerful tool for creating software. Ruby may offer a more polished baseline experience, but you can't take it as far as you can take CL.

The ANSI Common Lisp standard may stand still, but Common Lisp does not. It is constantly growing and evolving on top of the stable (albeit lumpy and uneven) foundation provided by the standard. For example, ASDF (which is a bit like Rake or Make) was created in 2001, and revolutionized the way CL libraries are defined and loaded. ASDF laid the groundwork for Quicklisp (CL's analog to RubyGems), created in 2010, to revolutionize the way CL libraries are downloaded and installed. That in turn lays the groundwork for further development and progress.

Flexibility (Macros and Read Macros)

One reason CL can keep evolving without needing to change the standard, is the flexibility provided by features like macros and read macros. In addition to the usual small utility macros, I've created macros for Ambienome to implement a limited form of prototypal inheritance, and extensible object properties. They are somewhat longer than the average macro, but fairly mundane; they merely expand into a few formulaic functions with the details filled in. There are much more complex and interesting things you can do with macros, like the famous (or infamous) loop macro, which implements a specialized mini-language within CL, dedicated to making it easy to write fairly sophisticated code loops. Even the Common Lisp Object System (CLOS), which provides CL's class-based OOP system, is largely implemented via some very complex macros. CLOS and loop are both defined in the standard, but they probably could have been implemented as separate libraries. (I'm guessing that having those things standardized enables implementations to optimize their performance. Or maybe they were just considered fundamental to the language.)

Read macros take flexibility and extensibility even further. They let you write code in CL that reprograms the way CL parses the text of your source code, potentially altering the language in radical ways. One fairly common and not-so-radical use for read macros is adding syntax sugar. For example, the CL standard doesn't have a literal syntax for reading or printing hash tables, but thanks to read macros you can add Ruby's hash table syntax to CL in 40 lines of code (or less if you don't need the hashrockets and commas). Similarly, you can add literal syntax for regular expressions, even though regular expressions are provided by libraries like CL-PPCRE instead of being defined in the standard. I don't know of any other language where you can think of some syntax that would make the language more expressive or powerful, then add it with just a couple of afternoon hacking sessions.

Generic Functions

Next to CL's flexibility from macros and read macros, the thing I find most interesting in CL is the generic functions system. Classes in CL don't (usually) have methods in the same sense that classes in Ruby do. Instead, CL has generic functions, and each method implements the behavior as it relates to instances of a certain class (or combination of classes). It's quite different from Ruby or any other object-oriented language I've used, but very flexible and powerful. I'd like to write more about the CLOS object model and how it compares to Ruby's, but this post is already rather long.

Conditions and Restarts

Another interesting feature of CL is its condition system. Conditions are analogous to Ruby's exceptions, but much more flexible and powerful. (That seems to be a recurring theme.) Besides raising errors and warnings, you can use conditions to send any kind of signal up the call chain, with the lower-level code possibly providing some “restarts”, ways to proceed. Depending on how you set up the restarts, your higher-level code might interrupt the lower-level code like in Ruby, or ignore the signal and resume the lower-level code where it left off, or modify something and then resume, or pretty much anything else you can imagine. I haven't had much opportunity to use conditions in a substantial way yet, but I'm sure they will prove useful as my code matures.

Integrated Development Environments

CL also has some nice IDEs. I use Emacs with SLIME, which is a big step up from my Ruby workflow. It offers the usual IDE amenities like tab-completion, parameter hints, jumping to function definitions, and looking up documentation (which is stored in each function/macro/etc., not derived from scanning comments like RDoc and YARD do). It also lets you inspect and modify the guts of most objects, which is pretty handy for debugging. And apparently even SLIME pales in comparison to the fancy IDEs provided by some commercial CL implementations.

Optimization Hints

Finally, CL has a system for declaring optimization hints to tweak the way the implementation compiles or interprets your code. (These are hints, so the implementation decides what to actually do. Some implementations might just ignore your hints.) Besides optimizing for computational speed, you can optimize for space (compiled code size, and runtime memory use), safety (run-time error checks), compilation speed, and/or ease of debugging. You can also optionally declare the argument and/or return types for functions, which can help the implementation generate even more efficient code. And finally, you can declare that a function can be compiled inline into other code that calls it, which can reduce or eliminate the overhead from function dispatch (this works well for short utility functions). I have read that with the right optimization hints, some implementations can compile number-crunching functions into code that is nearly as performant as C code. I'm pretty relaxed about performance (I used Ruby for over 7 years, after all!), but it's nice to have extra tools available for dealing with bottlenecks.

Final Thoughts

So, those are my impressions of Common Lisp after 6 months of focused study and use. There are a lot of good things about CL, but also some really bad. It's a pretty amazing language, but has some warts and flaws. The community is mostly decent people, but anyone who tries to participate in discussion ends up choking in the toxic atmosphere. The warts and flaws can be covered up or worked around pretty easily, but creating a more healthy community atmosphere seems nearly impossible. But I hope it can happen somehow, because it's a shame to see the language being held back like this.


Comments


I see more and more people coming over from Ruby to Common Lisp. What was your reason?

I am happy that you get a generally good impression about the language and what surrounds it. I especially liked that you rate the library situation as positive; in the past, it was most often rated as negative.

It is true that comp.lang.lisp and #lisp sometimes is full of bitter people. Often you get genuine help, sometimes in a way you don't like. Sadly, the bitterest people often belong to the most knowledgeable ones (and the ones with the most time, it appears). There are some counterexamples, though.

I hope that you will stay with us and contribute in a way or another. Because the lisp community is relatively small, a small amount of positive people can try to drone out the few bitter people.

So, let's start droning :)



Regarding the community thing, I do wonder why people still deal with comp.lang.lisp when they consider it to be a hostile environment in the first place. I have seen none of the ascribed c.l.l attitude in places like LispForum or StackOverflow.

Whether the complaints one hears about it are true or not (which I can't give a judgment on), it might be better to let c.l.l fall into oblivion than to try to fix it. Given that newbies go there expecting hostility, which doesn't really help with regard to the atmosphere, it's unlikely for things to change in the foreseeable future.


Hi,

Just wanted to comment on some of the historical baggage. Some of the things you identify as such definitely are, but some aren't.

SETQ and SET are both baggage. RPLACA and RPLACD are baggage. SORT being destructive by default is baggage. NTH having different argument order from ELT and AREF is baggage. Etc. There's a plenty of it, no kidding.

However, the -P convention isn't baggage. It's a convention. It's even a fairly nice one, because it makes those names pronounceable. How do you say EVEN? Still, there are codebases which use the -? convention instead -- it's a matter of taste. (I would actually point to the N-prefix for non-consing-but-not-necessarily-destructive as being worse, since it's used way less consistently. REVERSE and NREVERSE -- fine. But REMOVE vs DELETE? Etc...)

Having both classes and types isn't baggage. Types allow expressing things classes cannot: being able to say (declare (type (integer 0 100) percentage) is valuable -- but that CANNOT be a class. Similarly, you cannot specialize methods on arbitrary types because you cannot sort them into a precedence order, so both are there for a reason. That said, yes, classes were a late addition to the system, and there are rough edges in places.

The community stuff... Every time I check out cll, it's a cesspit. #lisp I'm fond of, but it can be derailed fairly easily, and some of the folks there are a bit combative.

Here are some hot tips: Planet Lisp, the lisp-pro mailing list, implementation specific mailing lists and IRC channels, and library specific mailing lists. A lot of those mailing lists are very low volume, so you can follow a crapload of them without much trouble. Some might have real volume, but most are pretty quiet these days. (There's also lispforum, but I've never spent any real time there, so I don't know.)

Anyways, good article. I came to CL by way of Ruby originally, and remember it fondly. There are things I miss from Ruby/Smalltalk style languages, but they arise from "message passing for everything", and you can pry generic functions from my cold, dead fingers... Can't have everything all the time.

Extra props for waiting six months before writing this. We've seen way too many "My View of CL" posts over the years written by someone who has barely gotten their toes wet. :)



I wonder if there could be a short vocalization for “?”, such as the way “!” is called “bang”

I'd nominate "Eh?" -- "Zero, eh? Digit-char, eh?". Canadians should love it.


The printer's name for '?' is 'hook'. Not as memorable as 'bang', but equally short.


I've been working on SIP parsing lately, and so I've had a lot of exposure to character names of many types. In the process, I reviewed the Intercal names of characters that I had originally been exposed to many years ago. The funny thing is, many or most of those names are rather...inspiring.

Under Incercal, "!" is called "wow", and "?" is called "what" (although I also like A.H.'s "eh"). For some reason unbeknownst to me, I've taken a dislike to calling "!" a "bang", and "exclamation" is a bit long...I might just adopt "wow".

I would have to admit that I don't like all of Intercal's names, though, but they are nonetheless thought-provoking. I particularly like "wax" for "(" and "wane" for ")"; this inspired me to refer to "" as "rex" (for their roles in XML)...and I'm still in the thought-process of renaming other characters.

Of course, this is somewhat academic, because in Java (which is what my work uses), you have to be Formal with your names, and when I tinker with this at home in Common Lisp, I have found that all the names have already been taken care of with the syntax.


Regarding the toxic atmosphere: I'd have to agree that there a bit of toxicity in the community, but that toxicity is concentrated in places like c.l.l. In other places it is at low levels or non-existent. I suspect that this is largely due to the fact that people need to wade through troll posts in order to find anything legitimate. Where ever you have people cutting their teeth on the futility of countering trolls, you will probably expect this kind of atmosphere. I'd also agree that there is a majority of Lisp users that do not conduct themselves like this but have remained quiet.

There is Lisp Forum, which is still sort of active (though I don't go there anymore, no RSS feeds). It is very much a nice community of people that post questions which are sometimes interesting. The biggest problem there, IIRC, was people posting boring questions that seemed very much like homework and the rare occasions where they get a bit upset when rather than getting a solution they get guidance. I would say that on the whole there are more interesting posts on c.l.l, but with c.l.l. you get trolls and with LispForum you get people so new that they don't even match parentheses in their code.

Since you are programming a game, I'm sure you are aware there is a loosely knit circle of people interested in Lisp game development. Perhaps a step in combating toxicity is to start on the small scale and lead by example. Make the LGD community a place with the right atmosphere.


This is a good overview, and I'm impressed with some of the things you saw here, which some people take a lot longer to discover.

One note, on SETF: yes, it obviously is more powerful, but this is also part of the appeal of a Lisp. If I'm writing or porting a Lisp compiler, there's only 25 special forms, of which SETQ is one, and it's a pretty simple one. SETF is much more complex (and even extensible!), but being a macro, I can just take an existing implementation and drop it in.

Now, maybe they went and screwed it up by making Common Lisp so big that nobody would ever actually want to write a compiler for it. :-) But there is definitely a feeling when reading through the documentation that it was designed at least in part for guiding compiler writers. With Ruby, there is very much One Ruby, and it doesn't matter if there's a small core, or a logical way to implement features, because if you want to write your own compiler, you're completely on your own. In the 1980's, a language was a spec; in the 2010's, a language is a free and open-source reference implementation.

There are actually a lot of subtleties involved in whether a feature is defined as a special form or a macro. It looks arbitrary at first, but actually turns out to be quite significant in some cases.

One note, on being nice:

"the Ruby community's notion of MINSWAN (Matz Is Nice So We Are Nice)"

I've been programming in Lisp and Ruby for years (Lisp a few more...), and I've actually never seen this. Perhaps it exists in other cities, or in Japan. A large portion of the Ruby programmers I've met in person are very aggressive, much more so than users of any other language I've met. The only place I've ever been physically assaulted was at a Ruby meetup.

But as Dan Weinreb says, the alleged nastiness of Lisp communities is a common enough refrain so we should assume it's real, and try to figure out exactly what is going on. (Naggum died 3 years ago so he's not still posting.) Please feel free to raise issues with the relevant moderators, for example.



I'd have to agree that I've found the Ruby culture to be somewhat off-putting myself. In my exposures to the Ruby culture, I have the impression that their conferences tend to be mysogenic (and in ways that are particularly offensive to a religious person like myself), and Ruby blogposts tend to be filled with vulgarity. And while I wanted to get through "Why's Poignant Guide to Ruby" (I like weird, off the wall things), the guide was a bit *too* weird for me (although I still have great admiration for it).

Having said that, this culture hasn't been the primary reason why I haven't gotten into Ruby. I'm pretty good at ignoring culture when I have to. I think the biggest reason I haven't gotten into Ruby is because I've spent so many years in Python, and I don't see what I could learn from Ruby, that's going to be all that different from Python...and I have also concluded that I would learn everything that Ruby can offer me, but Python can't, by learning Common Lisp.

I would also add that the Python community has had a bit of a reputation for being "cold", particularly compared to the Perl community...so it probably can't be held up as the best standard, either...


When my three-year old son met my new cat, he grabbed its tail and rubbed her fur the wrong way. The cat batted at him, and used pseudo-bites, and other "non-loving, unwelcoming" signals, and my son quickly learned to give the cat plenty of space -- he respects the cat now.

Similarly, many programmers float into the common lisp community expecting warm welcome, while at the same time, expecting to be free to say whatever they want. It is those people who are going to meet some "toxicity".

Reviewing some of the cases where Naggum and others were "toxic", I have come to realize there was often some reason for it. What's at stake is "the internet community" which takes work to defend. In my opinion, boundaries should be clear.



What's at stake is “the internet community” which takes work to defend

Are you serious? There is nothing at "stake" here. It's just the mind of "CL" programmers players tricks on them.

John Croisant wrote a pretty detailed response as to "why" this is bad, but I'll just say that the CL community needs to get its act together and maybe learn a bit from the Python community. A long time back I tried starting with a new language and asking help from the CL community of how it compares to other languages I know of (Java, C, C++). I was labelled a troll and in not so many words asked to GTFO. I'll be honest and admit that a few replies were logical/mature but most "regulars" were more interested in flaming and showing off their chops rather than helping someone.

I was a little heartbroken and turned to Python community. The replies were friendly, they even went as far asking me the areas (text processing, internet applications, games etc.) I was interested in. Fast forward a few years and here I am doing hobby Python programming, teaching kids and helping out other beginner Python programmers on message boards.

But I guess CL programmers really don't mind losing a rookie or two; after all, it's much more important to protect what's at "stake" and make sure that you "respect the cat".

Peace.


Thanks for the thoughtful post. I come from a database background and went through some of the same puzzles (trying to figure out the proper time and place for setq v. setf, the convention for p or -p and why not ?, etc.).

Coming into CLL, I had also heard about the toxic atmosphere, but I never personally experienced it pointed at me. I certainly saw it pointed at three groups (a) trolls (b) students who wanted their homework solved, not pointers that still required them to think and (c) people who wanted to change the language because their way made more sense. If you didn't fit into one of those three groups, you tended to actually get thoughtful answers.

I might suggest that there is sometimes a difference between over-the-top cll fans and over-the-top [insert language here] fans. Language fans will often claim that their language is the "best" for xyz reasons. Cll fans sometimes claim that cll has changed their way of thinking in a way that other languages cannot. This can be perceived as "I am better than you" instead of "my language is better than yours". Now the implicit conversation has moved from the equivalent of arguing about favorite sports teams (impersonal) to claims of individual superiority (personal) and that shift of framing would contribute to a toxicity feeling.


You shouldn't derive the "toxic" view of CL community from c.l.l. These days there are more trolls and bots there, than normal people. It's not a Common Lisp place at all, I would say. You should come to some Lisp meeting to see the real people, who are in the community. I think, you'll be very pleasantly surprised. Or look at Stack Overflow tag common-lisp and see, if answers there are any different from other languages :)

IMHO, what's really "toxic" about CL is its perception by many outsiders. So few people have ever programmed in Lisp, but everyone has some opinion about it, which often includes such notions as "weird", "impractical" or "outdated".


I'm new to CL, coming from Ruby I stumbled upon your post. I think you made some good points about the many choices facing lisp beginners. Have you found a good source for documentation similar to ruby-doc or the rails api? I am currently reading Practical Common Lisp and have not found a good central location that is easily searchable for documentation.



Thanks John. Unusual to see an evenhanded language comparison.

I love Lisp, and I'm willing to put up with Common Lisp's quirks, and even perversely enjoy them at times. I want to highlight one piece of historical baggage that is really foolish, but that's so old and ingrained that it can never be changed in CL:

It's the fact that the same entity is (a) a list, (b) a symbols, and (c) false. Nil is the empty list as a regular Lisp symbol. (You can even give it a property list!) And it's the only false value; any other thing is true. Nil's multifaceted nature is convenient at times, but it's also something that you have to be careful about.

Example: The fact that () prints out as NIL can be a p.i.t.a. if you're trying to format a list for use by some other program. You can't just treat parentheses one way, and symbols or strings or numbers another way. You have to have special tests for NIL, and in some cases worry that you might some day embed the string "NIL" into something else and treat the middle of a symbol name or other string as the empty list. Or false. Depending. It's not that hard to work around these issues, but they do have to be handled.

(It's also somewhat counterintuitive, coming from some languages, that the number zero counts as true. It's OK, but I feel it's important to comment code in which a zero might be treated as a boolean to prevent anyone not deep into Lisp from being confused.)

(Scheme fixes the problems with nil, and more generally rationalizes away many of CL's quirks. That's not a plug for Scheme over CL. Scheme/CL tradeoffs are well known.)


Comments are closed.

Previous post: Physics Engine and Object Selection Next post: Ambienome Brain Dump