mourning sanity

Thursday, September 25, 2008

Lisp syntax is great!

lots of people complain about Lisp syntax -- they find it too weird and verbose, they call LISP "Lots of Irritating  Silly Parentheses"; and sometimes they even pop up with proposals to "fix Lisp" on comp.lang.lisp -- "Lisp is sort of cool, but this syntax... let me show you my great ideas."

on the other hand, most lispers (and I among them) actually love s-expression syntax.

who is right here? are syntax preferences a subjective thing, or one can decide which is better quite in an (more-or-less) objective way? or, perhaps, that's just a matter of taste and custom?

i've got a good example today.. i'm using Parenscript -- cool Common Lisp library that automatically generates JavaScript from Lisp-like syntax -- and i've wrote a function that caches document.getElementById results (that makes sence for dumb browsers like IE):

   (defun my-element-by-id (cache id)
     (return (or (slot-value cache id)
                 (setf (slot-value cache id)
                       (document.get-element-by-id id)))))

this is a common Lisp idiom to use (or place (setf place value)) construct for a things like caches, and sometimes people even make a macro for it, i.e. (get-or-init place value). but after writing this i had some concerns -- while that works fine in Lisp, will Parenscript compiler be able to handle such trick? after all, Parenscript is quite simple, and it might not know such complicated stuff. so i've checked how this compiles to JavaScript:

function myElementById(cache, id) {
    return cache[id] || cache[id] = document.getElementById(id);
};

well.. it did not look plainly wrong to me, but it looked more than suspictious, so i've decided to check this in browser. and indeed, Firefox said SyntaxError: invalid assignment left-hand side. it turned out that || operator's priority is higher than priority of =, so it was interpreted like (cache[id] || cache[id]) = document.getElementById(id), which is obviously wrong. adding parentheses in correct way:

function myElementById(cache, id) {
    return cache[id] || (cache[id] = document.getElementById(id));
};

fixed the issue.

so this gives us clue about syntax characteristics -- with Lisp-style uniform prefix syntax you're always sure that compiler understands you correctly, while with C-style syntax you're not so certain. so you can easily see why Lispers actually love s-expressions -- such syntax gives them a feeling of confidence, it is sort of a joy when you write the thing and you know it is correct. and vice-versa: if you're not confident, you're feeling somewhat distracted, even if you've wrote it right!

one might ask -- can't you just learn JavaScript and be confident?

theoretically you can, but it's not so easy. first of all, why bother at all? how can you say that JavaScript syntax is superior if it requires you to memorize arcane precedence rules? those rules are definitely not a simple thing, if even Parenscript compiler authors got them wrong; and so i'd say chances you'll mess something in some complex case are pretty high. as i've noted above, it's just possibility of an error what bugs you, not errors themselves. so even if you get most cases right, it doesn't really help... also, knowledge of operator precedence table alone is not enough -- when you're programming, you need to understand syntax on subconciousness level to do it quickly and effectively. not that it's impossible -- somehow i felt that something is wrong with that JS expression, but it's hard to reliably know these precedence rules.

another reason, there are different languages with different syntax quirks. for example, in PHP expression $cache[$id] || $cache[$id] = 5 -- i guess (PHP has no formal specification, so one can only guess anyway) = operator has higher priority than ||. (but operator || has other semantics -- it coerces value to boolean, so it won't work as expected). this precedence rule is pretty weird if you consider such snippet:

$a = '';
$b = $a or 'b';
echo $b;
echo htmlentities($a or 'b');

you might think that expression $a or 'b' is same thing in both cases, and it should yield same result (1, as it coerces to boolean too). but actually first expression is processed like this ($b = $a) or 'b';, so $b would be empty.

thus, if you use more than one language with "familiar" C-style syntax (PHP + JS combination is quite popular), you're even in worse situation as it gets more difficult to remember what languages have what precedence rules and quirks. with inconsistent PHP, freaky Perl and uber-complex C++ it gets out of control.

so (i hope) it's now easy to see why people appreciate uniform Lisp syntax, and why they make translators like Parenscript -- to make everything uniform and guard themselves from syntax quirks. unfortunately, it doesn't work perfectly all the time, but i think still better than pure JavaScript.

but is this syntax stuff really important? i'm pretty sure most programmer folks simply do not care: they prefer using simplier programming constructs (such as temporary variables) -- that makes code more verbose, but more "safe"; and they are not confident with their code anyway -- they always test what they write, and if it doesn't work, they look for a workaround.

also i suspect there are hardcore folks who actually know all the syntax rules, and it is not a problem for them. haven't seen them in a real life, though.

so, my conclusion is -- Lisp syntax is quite objectively more robust and less error prone than, um, most other syntaxes out there, and people who find this qualities being important are likely to find it great. (conclusion was updated after debates on reddit)

P.S.: oops, this ended being a rant, while i just inteded to give a small example..

P.P.S.: if you think such JS code is atypic, here's what i've found in some JS-related blog:

 function $(id){
  return !cache[id]?cache[id] = document.getElementById(id):cache[id];
 };

it's even more complex, and more verbose same time.

UPDATE:it appears some people understood this as if it is all about operator precedence rules -- no, actually it's not, it was just my example. there's much more about complex syntax rules, for example, C++ is notoriously difficuly.

Wednesday, September 24, 2008

Lisp web tutorial?

"PHP vs. Lisp: Unfortunately, it's true..." article initiated quite active discussion on reddit, one fellow asking:

Can someone post a tutorial for taking a clean install of Ubuntu (or windows or anything) to finish with serving a basic CRUD application using lisp? Maybe a TODO list with entires consisting of: incomplete/complete boolean, due date, subject, body?

actually i had an impression that there are more than enough such tutorials, but as nobody replied i've tried finding one myself, starting with Hunchentoot tutorials. surprisingly, none of them covered a short path from clean OS install to working examples. neither i've found my ABCL-web  tutorial suitable for this, so i decided to try myself. 

my idea was that Linux distros like Debian and Ubuntu contain a lot of Lisp packages, and it should be fairly easy to install them, as it automatically manages dependencies etc. i've decided to try Hunchentoot -- i'm not using it myself, but it's known to be pretty lean, unlike other bloated frameworks. indeed, installing Hunchentoot via apt-get was pretty straightforward, and it even worked quite fine out of the box! so i've posted this comment, and it seems people found it sort of useful. so was followup on Emacs/SLIME installation.

so i wonder -- is there a lack of up-to-date installing-lisp-web-server-from-scratch tutorials indeed? if so i'll consider making one.. it seems there is a widespread opinion  that Common Lisp "learning curve at the beginning is steep as hell" and "Just setting a sane development environment is a huge pita" -- and that is opinion of people who actually succeeded in using Lisp! so maybe i can prove otherwise?

Sorry, no manpages available for db_open.

today trying to find a manual page for db_open function of BerkeleyDB in Google gave me sort of surprise -- first 6 links were broken! that's a bit unusual -- often you get one or more broken page, but six in a row is some kind of anomaly. first working link was on Oracle site, so I wonder -- was it Oracle pulling BDB docs from other sites? 

so here's what Google returned to me:

Berkeley DB: db_open The db_open function opens the database represented by file for both reading and writing. ... Also, calling db_open is a reasonably expensive operation. ... pegasus.cs.csubak.edu/docs/berkeley_debugger/api_c/Db/open.html

site fails to open 

Проект OpenNet: MAN db_open (3) Библиотечные вызовы (FreeBSD и Linux) db_open (3). Руководство не найдено. - 1. Команды и прикладные программы пользовательского уровня, русские | linux | freebsd | solaris | разные | posix ... www.opennet.ru/cgi-bin/opennet/man.cgi?topic=db_open&category=3

text says manual not found -- but why is there a link on it?

UNIX man pages : db_open (3) www.nsc.ru/cgi-bin/www/unix_help/unix-man?db_open+3

blank page..

SGI TPL View (3 db_open) Unable to find a manual page for: db_open. home/search | what's new | help techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?cmd=getdoc&coll=0650&db ...3%20db_open

DragonFly On-Line Manual Pages : db_open(3) DragonFly On-Line Manual Pages. Manual page could not be found, please try again. leaf.dragonflybsd.org/cgi/web-man?command=db_open&section=3

Index to db_open manpages. Index to db_open manpages. Sorry, no manpages available for db_open. www-linux.gsi.de/cgi-bin/man2html?db_open+3

Berkeley DB: DB->open Berkeley DB: An embedded database programmatic toolkit. www.oracle.com/technology/documentation/berkeley-db/db/api_c/db_ open.html

that's where i've found it..