Saturday, June 2, 2007

Why I am a knee-jerk anti-loopist.

I've made these points before in different forums, but talking about LOOP has become popular again, so I'll just post a blog entry and point people at it. Here are the reasons I hate LOOP: 1. It is hard to predict what the resulting code will look like after it is expanded. You may *think* you know what it is doing, but you will probably be fuzzy about the details. This leads to bugs. 2. Loop makes it extremely difficult to write meta-level code that can manipulate loop expressions. A MAP expression is just a function call, but LOOP requires a serious state-machine to parse. You can macro-expand the LOOP away, but the resulting expansion is almost as hard to understand as the original. 3. LOOP operates at a low level of abstraction. One very frequent use of iteration is when you wish to apply an operation to a collection of objects. You shouldn't have to specify how the collection is traversed, and you certainly shouldn't have to specify a serial traversal algorithm if it doesn't matter. LOOP intertwines the operation you wish to perform with the minutiae of traversal --- finding an initial element, stepping to the next element, stopping when done. I don't care about these details. I don't care if the program LOOPs, uses recursion, farms out the work to other processors, or whatever, so long as it produces the answer I want. 4. LOOP encourages users to think linearly, sequentially, and iteratively. They start trying to flatten everything into a single pass, first-to-last, state-bashing mess. Suddenly they forget about recursion. I've seen this happen over and over again. It literally damages the thought process. (which is why I'm suspicious of named-let style loops)

5 comments:

Jack Unrue said...

Is your 4th issue really a LOOP issue, or is it more about Common Lisp in general? Because it seems to me that recursion is not emphasized in CL, since as I'm sure you know well TCO is not mandated (although some implementations do have it, e.g., CLISP).

Or are you thinking in terms of Scheme with some LOOP add-on library?

foof said...

You may find the following of interest:

http://groups.google.com/group/comp.lang.scheme/browse_thread/thread/cb91974bc35a86c/060dcac5ea812398?lnk=gst&q=loop+macros+are+loopy&rnum=1

The latest version of the LOOP macro discussed at the end of that
article is available as an extension for Chicken Scheme, though it
should port directly to any R5RS implementation. A derivative work with
slightly different syntax is also available from

http://mumble.net/~campbell/scheme/foof-loop.scm
http://mumble.net/~campbell/scheme/foof-loop.txt

--
Alex

j.oke said...

He, and I thought to be some strange and unique relict of a CL user.

Great and convincing (at least for someone already convinced...)

jrm said...

The last comment wasn't about Common Lisp in general, but about looping in general. I originally wrote this in a response on the PLT Scheme list, and Matthias Felleisen mentioned that I'd have to argue against all looping if I felt this way. I thought a bit and decided that I'd try the radical stance for a while until I found out better.

I'm not however, arguing that LOOP should be replaced by tail recursion. I think a lot of looping can be replaced by mapcar or reduce or something similar.

sburson said...

Hear hear! I think `loop' is the product of a conspiracy to make Lisp look like Cobol :-)

I am pretty fond of my GMap macro. Despite it having a few rough spots -- it was the first serious macro I wrote -- I find that for the cases it handles, which are numerous, it's elegant and convenient. If you're interested, do (asdf-install:install :misc-extensions) and look for file `gmap.lisp'.