Page 4 of 6

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 12:48 am
by tayssir
Paul wrote:
tayssir wrote:

Code: Select all

CL-USER> (defvar *foo*
           '((:a . 1)
             (:b . 2)))

;; “I just sensed a glitch in the Matrix.”
...
It's undefined to destructively modify "literals" like quoted lists.
Judging by the prompt in front, your "literal" was defined at the REPL, so it's perfectly well defined, but in any case, how would that be "an inconsistency"?
The spec contradicts this claim, and Kent Pitman (hyperspec author extraordinare) cites fairly nasty consequences — even at the REPL.

This common misconception is instructive: we see inconsistencies in CL's spec even where there are none. (In this case, special-casing of the REPL.) This is not unlike the situation that many of us have probably been in (I hope I'm not the only one), where we're wrestling with some difficult-to-install library, and come to blame the library even in particular moments when we happen to be at fault.

Note that Kent was replying to a lisp implementor (Roger Corman) who just goofed up on this point. (So there's no shame in that.) Elsewhere in the thread, you'll find another implementor (Duane Rettig of Franz) share his own war-stories of discovering that Franz software had similar bugs due to modifying literals, which he claimed nearly led to more years of hard-to-reproduce bugs.

The reader must generate a new list when it reads the form in, and QUOTE just returns the identical list that is its argument, therefore it returns the fresh list constructed by the reader; there's no way to tell the difference between that list and one constructed with LIST, therefore there's no way mutating it can have any different effect than if you had used LIST. So either all list mutations are undefined, or this one isn't (or Lisp is magical).
As Kent cited, simple optimizations can defeat that, REPL or no. Implementations like MCL can decide to share quoted literals throughout the program, put them in read-only spaces, etc.

And if Kent and the spec are wrong, the resulting inconsistency would only provide more lurid evidence of CL's inconsistency.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 1:07 am
by skypher
tayssir wrote:This common misconception is instructive: we see inconsistencies in CL's spec even where there are none. (In this case, special-casing of the REPL.) This is not unlike the situation that many of us have probably been in (I hope I'm not the only one), where we're wrestling with some difficult-to-install library, and come to blame the library even in particular moments when we happen to be at fault.

[...] goofed up [...] war-stories [...] bugs due to modifying literals, which he claimed nearly led to more years of hard-to-reproduce bugs.

[...]

And if Kent and the spec are wrong, the resulting inconsistency would only provide more lurid evidence of CL's inconsistency.
Sorry, but I think this is all impractical nitpicking (I meant to put in some harsher phrase here but reconsidered).

I've been programming in C, C++, Java, PHP and Perl for years before starting with Common Lisp.
Now in all the years I spent with CL I have found it to provide an extreme productivity boost, shortening the path between thought and tangible product considerably. Hardly have I ever found literals to impede this, and they certainly never caused visible bugs in libraries or the implementations I've been using.

I suspect this is because most sane Lisp programmers follow some simple rules, like:

* don't use destructive functions unless you need to; if you do, be careful and double-check.
* don't use literal lists until you're absolutely sure what you're doing.

Note that the first thing is imperative even if dealing with non-literal lists. Once you get destructive you're much more liable to mess up. This is not a CL problem.
As Kent cited, simple optimizations can defeat that, REPL or no. Implementations like MCL can decide to share quoted literals throughout the program, put them in read-only spaces, etc.
That's right.


This discussion now went the way a lot of discussions on comp.lang.lisp go: some CL newbie is asking innocent questions that are answered well. Then some more or less disgruntled guy comes along, picks one minor issue in CL and leads the whole topic astray, making people discuss obscure corners of the spec. This makes me incredibly sad because it makes the thread pretty much worthless for the OP from the point on, and I hope the Lispforum community will not continue to follow this path.

Please, please at least start your own topic instead of hijacking more productive threads if you want to argue about stuff like this.

Leslie

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 1:24 am
by Paul
tayssir wrote:The spec contradicts this claim,
It really doesn't.
tayssir wrote:and Kent Pitman (hyperspec author extraordinare) cites fairly nasty consequences — even at the REPL.
Haha. Kent's wrong on this one! Calling compile doesn't make any difference—compile can't change the identity of its data.
tayssir wrote:As Kent cited, simple optimizations can defeat that, REPL or no. Implementations like MCL can decide to share quoted literals throughout the program, put them in read-only spaces, etc.
It can't, because it can't identify them. Any implementation can coalesce externalized data (in the implementation binary and/or FASL files), but it can't change the identity of any data in core.
tayssir wrote:And if Kent and the spec are wrong, the resulting inconsistency would only provide more lurid evidence of CL's inconsistency.
Inconsistency with what? It's perfectly consistent with the definitions of all the functions, special operators, and macros in use. It would inconsistent only if it behaved differently for read-time values than run-time values.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 3:58 am
by tayssir
Sorry, but I think this is all impractical nitpicking (I meant to put in some harsher phrase here but reconsidered).
Good thing you spare us the pejoratives, as you may otherwise be moderated, and I'd rather you not be. This alternative passive-aggressive path (telling me about the flames you wish to roast me with, without actually daring to say them) is fine by me. ;)

Sometimes I prefer to make concrete references to code and the hyperspec, as these are the meat & potatoes things which real lisp programmers must employ. This is a necessary counterweight to the necessarily more vague philosophical discussions, since anyone can say anything if not confronted by the hyperspec, lisp output and reality.

This discussion now went the way a lot of discussions on comp.lang.lisp go: some CL newbie is asking innocent questions that are answered well.
Excuse me? The original poster enthusiastically talks about rewriting lisp, because "It seems cruel to me that the amazing power of Lisp is hidden away in a cryptic language riddled with idiosyncrasies and inconsistencies." This so-called 'innocent newbie' can perceive beauty through wild cryptic idiosyncracy.

That post sounded cool, and the author happens to be part of my intended audience. You're not.

Then some more or less disgruntled guy comes along, picks one minor issue in CL and leads the whole topic astray, making people discuss obscure corners of the spec.
You must be aware, this is a curious claim. Did I just make you publicly go offtopic and post personally uncivil claims which have nothing to do with technical issues? I apologize for having that power over you.

But I'm really quite gruntled! On this very topic, I advocated my two fave languages (CL and one of its direct descendants).

Yes, you know, admittedly I get a bit sick when I see the whole groupthink which sometimes occurs on lisp hangouts (especially when phrases like "get used to it" creep into the discussion). This is admittedly an emotional motivation on my part, and if it really bothers you, I'll try to tone it down.

That said, the flipside of advocacy is honesty. If you don't "police your own" (in a nice way) when they make factual errors, or you paint an absurdly rosy picture of your tools, I consider that less than honest and a disservice to interested newcomers.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 9:01 am
by gugamilare
If the discussion wasn't off-topic, it is going to that direction now. Please, gentlemen, calm down.

I agree with Paul when he says this is not an "inconsistency", it does not fit the definition of the word itself. At most it is a small defect of the language (like any language has) which causes a few headaches when you find it, but not more than, for instance, the headache you get when you still don't know that floating-points are only the approximate value you give in decimal because it is converted to binary, and that may lead to some mathematical mistakes (for instance, when you handle money). You may even end up losing a few pennies ;)

I disagree with tayssir when he implies that "getting used to" is a bad thing. There are always things you need to get used to, in any language, because that is what we trade for efficiency. For instance, if you don't need to get used to modifying constant data in Clojure it is because it will make a fresh copy of everything it needs to modify, and that will certainly create more trash and require more memory. I'm not criticising Clojure for this behaviour, since this particular behaviour will make programs safer. I'm just saying it is a matter of choice.

Finally I agree with tayssir that this behaviour is not a very good thing. Even if there is no problem using quoted lists in defvars, there still is a problem to bind quoted lists in local variables and modifying it, so his point is still valid. But he is making of this more of an issue than it really is, this is really no big deal, because every mature programmer knows about that and that is easily avoidable.

Anyway, that should be my last post about this, I think I don't have any constructive point yet to be made.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 11:52 am
by Unne
Clojure does "clean up" some things that are inconsistent or arcane in CL in my opinion. Clojure has only one implementation (so far) and so there are very few holes where things "vary by implementation", which makes sharing code a whole lot easier. I think some of the naming conventions are better; you don't have to remember if it's SOMETHINGP or SOME-THING-P, it's always "something?". Unifying mapping and iteration and access functions for lists/vectors/hashmaps/sets under one common interface simplifies a lot of things. Built-in syntax for {:hash 'maps}, #(sets), [vectors], #(anonymous functions), and #"regexes" brings me no end of glee. Case-sensitivity of symbol names is a boon. There are few mutable data structures in Clojure, so you don't have to worry about destructive vs. non-destructive functions. Paring away some unneeded parens in various places was a good thing. Being able to drop some of the historic vocabulary (CAR, CDR, LAMBDA) and some of the lengthy yet cryptic function names (DESTRUCTURING-BIND, ENOUGH-NAMESTRING) in favor of shorter and simpler names was a good thing. All just my opinion of course.

However Clojure has stumbling blocks of its own. It has the same "everything dumped into one package" for its built-in functions arrangement that CL has (with very few exceptions, like clojure.set and clojure.xml). Some names are abbreviated but it's not obvious what the abbreviation means. What does "comp" do? Complement? Compose? Compare? (It's "compose".) There's repeat vs. replicate vs. repeatedly, pr vs. prn vs. print vs. println, cons vs. conj, and so on. You have (map f coll) but (nth coll n), (conj coll x) but (cons x coll).

Or for an example vaguely reminiscent of CL's funky behavior with literal lists: a literal hash-map in Clojure is made an array-map by default if the length is short, for performance reasons. But this leads to odd behavior if you have duplicate keys.

Code: Select all

user> (def x {:foo 'bar :foo 'huh?})
#'user/x
user> x
{:foo bar, :foo huh?}
user> (count x)
2
user> (:foo x)
bar
I've seen people complain that given a function that you know must exist, tracking down its name can be difficult in Clojure. There's find-doc in Clojure and APROPOS in CL but it's still a guessing game sometimes. Another quirk common to CL and Clojure is remembering whether something is a macro or a function, and whether it needs its arguments quoted or not. This used to trip me up a lot at first.

But no language is free from these kinds of inconsistencies. I clearly remember having these same problems and complaints when learning Python and Ruby and Java. And Perl, which is pretty much nothing but inconsistencies. All of these problems go away to some degree with time and practice and the unpleasant grunt-work of reading APIs and memorizing things.

I used to make fun of Java because you can't really write good Java code without an IDE to support you; it's too verbose to type without typos and remembering the name of everything is painful. But it's almost true for Lisps too that you really need a good editor to write Lisp code effectively. First and foremost to keep your parens balanced for you a la paredit, and secondly to let you quickly access documentation. You don't really need to remember the order of arguments of a function when Emacs is going to remind you of that function's signature every time you start to type it.

If you rewrote CL to clean it up, you could get a long way to making it look like something present-day programmers are more familiar and comfortable with, but it still wouldn't be perfect and it would still require a bunch of fumbling and memorization at first just like any other language.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 1:42 pm
by Paul Donnelly
Unne wrote:I think some of the naming conventions are better; you don't have to remember if it's SOMETHINGP or SOME-THING-P, it's always "something?".
So you just have to remember to use a question mark to denote statements of fact. :? And have to disambiguate it when speaking, unless you consider spoken Lisp to be a tonal language.

Sorry, that naming convention just drives me batty. IMO, marking predicates with a “p” makes a heck of a lot more sense.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 1:50 pm
by skypher
gugamilare wrote:[...] Anyway, that should be my last post about this, I think I don't have any constructive point yet to be made.
Well, at least you did a better job than me in explaining the point I originally intended to convey.

So thanks, and sorry everyone if my own post weighed in too much ad hominem, this wasn't intentional.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 3:11 pm
by Unne
Paul Donnelly wrote:So you just have to remember to use a question mark to denote statements of fact. :? And have to disambiguate it when speaking, unless you consider spoken Lisp to be a tonal language.

Sorry, that naming convention just drives me batty. IMO, marking predicates with a “p” makes a heck of a lot more sense.
I don't really see them as statements of fact, I see them as questions. "Is this a hash table?" is the question, and the answer is true or false. But I don't know, which is better, "hash hyphen table hyphen pee" or "hash hyphen table question mark"? They're both pretty terrible to say aloud. You could say "hash table predicate" and everyone would just know there's a question mark on the end, probably. Schemers have been using ? for a long time, they must have some conventions. Tonal languages are fun though. Japanese Lispers would be happy. :D

I don't think programming languages are really meant to be spoken aloud. Especially Lisp. How do you communicate parentheses? I could envision a rudimentary form of sign language.

Re: Experience of Learning Lisp

Posted: Mon Jul 20, 2009 3:57 pm
by findinglisp
Paul Donnelly wrote:
Unne wrote:I think some of the naming conventions are better; you don't have to remember if it's SOMETHINGP or SOME-THING-P, it's always "something?".
So you just have to remember to use a question mark to denote statements of fact. :? And have to disambiguate it when speaking, unless you consider spoken Lisp to be a tonal language.

Sorry, that naming convention just drives me batty. IMO, marking predicates with a “p” makes a heck of a lot more sense.
I haven't said much and don't care much on the general conversation, but I have to disagree with you on this one. When I first saw that convention in Scheme, it made instant sense to me. The "-p" convention only makes sense once you figure out that it stands for "predicate," and you happen to know what a predicate is, which many programmers won't.

Ditto with using a prefix "n" for non-consing mutable routines. It took me a couple months of working with CL before I found a reference that described that. I still think Scheme's "!" notation makes more sense.

That said, this is all just personal preference. Either way we're talking about arbitrary character sequences. The just happen to tickle each of our brains in a slightly different way.