Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Very poor Lisp performance

385 views
Skip to first unread message

Jon Harrop

unread,
Aug 12, 2005, 8:50:10 PM8/12/05
to

Several people have kindly ported my ray tracer from this page:

http://www.ffconsultancy.com/free/ray_tracer/languages.html

to Lisp. Some of them are reporting competitive performance. However, when I
try to run their programs with either CMUCL or SBCL they are two orders of
magnitude slower. Given the number of people claiming similarly good
performance, I'd like to know what the possible cause of the relative
slowdown on my computer is?

My system is an unladen 900MHz Athlon T-bird with 768Mb RAM running Debian
testing with SBCL 0.8.16 and CMUCL "19b-release-20050628-3 + minimal debian
patches". Other people have both slower and faster CPUs and more and less
RAM but all are consistently much faster than mine.

I believe SBCL always compiles to native code and I am asking CMUCL to
compile to native code with:

(compile-file "ray4.lisp")
(load "ray4.x86f")
(time (main 6.0 "image.pgm" 256.0 4.0))

Any ideas?

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com

Jon Harrop

unread,
Aug 12, 2005, 9:55:39 PM8/12/05
to
Jon Harrop wrote:
> ... when

> I try to run their programs with either CMUCL or SBCL they are two orders
> of magnitude slower.

Slight correction - CMUCL is only 1 order of magnitude slower.

Also, I just tried running the ackermann and harmonic tests from the
shootout and they run at the same (fast) speed on my machine as on the
shootout's machine. So it seems the problem is specific to raytracing-like
code.

I'm completely stumped.

M Jared Finder

unread,
Aug 12, 2005, 11:58:09 PM8/12/05
to

Post the ported code and we can take a look at it. Without the code, we
can only make shots in the dark.

-- MJF

wrig...@hotmail.com

unread,
Aug 13, 2005, 4:40:34 AM8/13/05
to
A cautionary note..

Have a look over in c.l.scheme for the uproar around this topic /
poster

chris

Jon Harrop

unread,
Aug 13, 2005, 7:18:40 AM8/13/05
to
M Jared Finder wrote:
> Post the ported code and we can take a look at it. Without the code, we
> can only make shots in the dark.

Here is Nathan Baum's port for CMUCL and SBCL:

(declaim (optimize (speed 3) (space 0) (debug 0) (safety 0)))

(defconstant infinity most-positive-single-float)
(defconstant delta (the single-float (sqrt single-float-epsilon)))

(declaim (inline vec v* v+ v- dot unitise ray vec make-ray make-sphere x y z
ray_trace))

(defstruct (vec (:conc-name nil) (:constructor vec (x y z)))
(x 0.0 :type single-float)
(y 0.0 :type single-float)
(z 0.0 :type single-float))

(defun v* (s r)
(declare (single-float s))
(the vec (vec (* s (x r)) (* s (y r)) (* s (z r)))))

(defmacro defvfun (name op)
`(defun ,name (a b)
(vec (,op (x a) (x b))
(,op (y a) (y b))
(,op (z a) (z b)))))

(defvfun v+ +)
(defvfun v- -)

(defun dot (a b)
(+ (* (x a) (x b)) (* (y a) (y b)) (* (z a) (z b))))

(defun unitise (r)
(the vec (v* (/ 1 (the single-float (sqrt (dot r r)))) r)))

(defstruct (ray (:conc-name nil))
(orig (vec 0.0 0.0 0.0) :type vec)
(dir (vec 0.0 0.0 0.0) :type vec))

(defun ray (orig dir) (make-ray :orig orig :dir dir))

(defstruct (sphere (:conc-name nil))
(center (vec 0.0 0.0 0.0) :type vec)
(radius 0.0 :type single-float))

(shadow 'group)
(defstruct (group (:conc-name nil) (:include sphere))
(children () :type list))

(defun ray_sphere (ray sphere)
(let* ((v (v- (center sphere) (orig ray)))
(b (dot v (dir ray)))
(disc (+ (- (* b b) (dot v v)) (* (radius sphere) (radius
sphere)))))
(if (< disc 0.0) infinity
(let ((disc (sqrt disc)))
(let ((t2 (+ b disc))
(t1 (- b disc)))
(cond ((< t2 0.0) infinity)
((> t1 0.0) t1)
(t t2)))))))

(defun intersect (ray scene)
(labels ((aux (hit scene)
(destructuring-bind (lam . _) hit
(declare (ignore _) (single-float lam))
(etypecase scene
(group
(if (>= (ray_sphere ray scene) lam)
hit
(reduce #'aux (children scene) :initial-value hit)))
(sphere
(let ((lamt (ray_sphere ray scene)))
(if (>= lamt lam) hit
(cons lamt (unitise (v- (v+ (orig ray) (v* lamt (dir
ray))) (center scene)))))))))))
(aux `(,infinity . (vec 0.0 0.0 0.0)) scene)))

(defun ray_trace (light ray scene)
(destructuring-bind (lam . normal) (intersect ray scene)
(declare (single-float lam))
(if (= lam infinity) 0.0
(let ((g (dot normal light)))
(if (>= g 0.0) 0.0
(let ((p (v+ (v+ (orig ray) (v* lam (dir ray))) (v* delta
normal))))
(destructuring-bind (lam . _)
(intersect (ray p (v* -1.0 light)) scene)
(declare (ignore _) (single-float lam))
(if (< lam infinity) 0.0 (- g)))))))))

(defun create (n c r)
(declare (single-float r)
(fixnum n))
(let ((obj (make-sphere :center c :radius r)))
(if (= n 1)
obj
(let ((rt (* 3.0 (/ r (sqrt 12.0)))))
(labels ((aux (x z) (create (1- n) (v+ c (vec x rt z)) (/ r
2.0))))
(make-group :center c
:radius (* 3.0 r)
:children (list* obj (mapcar #'aux
(list (- rt) rt (- rt)
rt)
(list (- rt) (- rt) rt
rt)))))))))

(defun main (level file-name n ss)
(declare (fixnum level n ss))
(let ((scene (create level (vec 0.0 -1.0 0.0) 1.0))
(light (unitise (vec -1.0 -3.0 2.0)))
(-n/2 (- (/ (float n) 2.0)))
(1-n/2 (1- (/ (float n) 2.0))))
(with-open-file (s
file-name :if-exists :supersede :if-does-not-exist :create :direction :output)
(format s "P5~%~A ~A~%255~%" n n))
(with-open-file (s file-name :element-type '(unsigned-byte
8) :if-exists :append :direction :output)
(loop for y of-type single-float from 1-n/2 downto -n/2
;;do (sb-ext:gc-off)
do (print y)
do (loop for x of-type single-float from -n/2 to 1-n/2
do (let ((g 0.0))
(declare (single-float g))
(loop for dx of-type single-float from x below (1+ x) by (/
1.0 ss)
do (loop for dy of-type single-float from y below (1+
y) by (/ 1.0 ss)
do (let ((d (unitise (vec dx dy (float
n)))))
(incf g (ray_trace light (ray (vec 0.0
0.0 -4.0) d) scene)))))
(let ((g (+ 0.5 (* 255.0 (/ g (* (float ss) (float
ss)))))))
(write-byte (floor g) s))))))))

#+sbcl (setf (sb-ext:BYTES-CONSED-BETWEEN-GCS) 100000000)

(time (main 6 "image.pgm" 160 4))
(quit)

Richard Fateman

unread,
Aug 13, 2005, 11:46:22 AM8/13/05
to
Time for running in Allegro CL 7.0 on a 933 MHz Pentium II.
as given:

; cpu time (non-gc) 60,202 msec (00:01:00.202) user, 421 msec system
; cpu time (gc) 33,623 msec user, 10 msec system
; cpu time (total) 93,825 msec (00:01:33.825) user, 431 msec system
; real time 105,632 msec (00:01:45.632)
; space allocation:
; 967,240 cons cells, 3,719,472,272 other bytes, 4,472 static bytes


But converting all "single-float" to double-float:

; cpu time (non-gc) 4,446 msec user, 120 msec system
; cpu time (gc) 2,524 msec user, 0 msec system
; cpu time (total) 6,970 msec user, 120 msec system
; real time 7,961 msec
; space allocation:
; 418,422 cons cells, 292,782,544 other bytes, 0 static bytes
The compiler complained about the "shadow" statement
warning: compile-file found "SHADOW" at the top-level -- see the
documentation for
comp:*cltl1-compile-file-toplevel-compatibility-p*

My guess is that much of the verbosity for the sbcl version could be struck
out of the allegro cl version without any loss in speed, and that careful attention
to other potential optimizations/ declarations could squeeze out better performance.

It could be that this single/double issue relates to your AMD64 timings.
Most of it may be converting single to double and back.

RJF

Jon Harrop

unread,
Aug 13, 2005, 1:24:25 PM8/13/05
to
Richard Fateman wrote:
> Time for running in Allegro CL 7.0 on a 933 MHz Pentium II.
> as given:
>
> ; cpu time (non-gc) 60,202 msec (00:01:00.202) user, 421 msec system
> ; cpu time (gc) 33,623 msec user, 10 msec system
> ; cpu time (total) 93,825 msec (00:01:33.825) user, 431 msec system
> ; real time 105,632 msec (00:01:45.632)
> ; space allocation:
> ; 967,240 cons cells, 3,719,472,272 other bytes, 4,472 static bytes

These times agree with my own.

> But converting all "single-float" to double-float:
>
> ; cpu time (non-gc) 4,446 msec user, 120 msec system
> ; cpu time (gc) 2,524 msec user, 0 msec system
> ; cpu time (total) 6,970 msec user, 120 msec system
> ; real time 7,961 msec
> ; space allocation:
> ; 418,422 cons cells, 292,782,544 other bytes, 0 static bytes
> The compiler complained about the "shadow" statement
> warning: compile-file found "SHADOW" at the top-level -- see the
> documentation for
> comp:*cltl1-compile-file-toplevel-compatibility-p*

Very interesting - thanks for that. Unfortunately replacing single-float
with double-float causes SBCL to spew out a lot of error messages. I'll see
if I can figure out why and I'll try CMUCL.

> My guess is that much of the verbosity for the sbcl version could be
> struck out of the allegro cl version without any loss in speed, and that
> careful attention to other potential optimizations/ declarations could
> squeeze out better performance.

Right. Is Allegro CL free?

> It could be that this single/double issue relates to your AMD64 timings.
> Most of it may be converting single to double and back.

Yes. I've no idea what CL says about coercions. The other languages may well
be much more lax in this respect.

It is interesting that single vs double precision has such bizarre and (for
me) unexpected performance implications...

Juho Snellman

unread,
Aug 13, 2005, 2:31:27 PM8/13/05
to
<use...@jdh30.plus.com> wrote:
>>> My system is an unladen 900MHz Athlon T-bird with 768Mb RAM running Debian
>>> testing with SBCL 0.8.16 and CMUCL "19b-release-20050628-3 + minimal
>>> debian patches".

That's a rather ancient version of SBCL, you might want to upgrade.
For example:

> (defstruct (vec (:conc-name nil) (:constructor vec (x y z)))
> (x 0.0 :type single-float)
> (y 0.0 :type single-float)
> (z 0.0 :type single-float))

This is using about 2x the memory of what you'd expect for each
instance, and doing an extra memory indirection for each slot access.
Proper support for storing the floats "raw" in the struct was added in
0.9.2 by David Lichteblau.

Another possible pitfall on older SBCLs (<0.8.21) is that they don't
honor the compiler policy for code entered on the repl, but compile it
with low speed, high debug/safety. If you've been pasting the code
into the repl instead of LOADing it, performance would indeed be
horrible.

--
Juho Snellman
"Premature profiling is the root of all evil."

Harald Hanche-Olsen

unread,
Aug 13, 2005, 3:01:20 PM8/13/05
to
+ Jon Harrop <use...@jdh30.plus.com>:

| Right. Is Allegro CL free?

It has a free trial version. <http://www.franz.com/>.

--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Debating gives most of us much more psychological satisfaction
than thinking does: but it deprives us of whatever chance there is
of getting closer to the truth. -- C.P. Snow

Jon Harrop

unread,
Aug 13, 2005, 4:21:35 PM8/13/05
to
Juho Snellman wrote:
> <use...@jdh30.plus.com> wrote:
>>>> My system is an unladen 900MHz Athlon T-bird with 768Mb RAM running
>>>> Debian testing with SBCL 0.8.16 and CMUCL "19b-release-20050628-3 +
>>>> minimal debian patches".
>
> That's a rather ancient version of SBCL, you might want to upgrade.

Debian unstable has 0.9.3. It's upgrading now... :-)

> For example:
>
>> (defstruct (vec (:conc-name nil) (:constructor vec (x y z)))
>> (x 0.0 :type single-float)
>> (y 0.0 :type single-float)
>> (z 0.0 :type single-float))
>
> This is using about 2x the memory of what you'd expect for each
> instance, and doing an extra memory indirection for each slot access.
> Proper support for storing the floats "raw" in the struct was added in
> 0.9.2 by David Lichteblau.

I see.

> Another possible pitfall on older SBCLs (<0.8.21) is that they don't
> honor the compiler policy for code entered on the repl, but compile it
> with low speed, high debug/safety. If you've been pasting the code
> into the repl instead of LOADing it, performance would indeed be
> horrible.

Aha! Yes indeed. I just tried (load (compile-file "...")) and it runs in
only 20secs compared to ~250secs from the top-level and 2.5secs for C++.

Thanks for the help. I'll repost when I get results with the new compiler.

Raffael Cavallaro

unread,
Aug 13, 2005, 9:01:32 PM8/13/05
to
On 2005-08-13 07:18:40 -0400, Jon Harrop <use...@jdh30.plus.com> said:

> Here is Nathan Baum's port for CMUCL and SBCL:

just as an additional data point, this code runs in just over 6 seconds
in sbcl 0.9.3 on a dual 2.0 GHz G5 (though sbcl only uses one
processor).

Juho Snellman

unread,
Aug 14, 2005, 2:56:20 AM8/14/05
to
<fat...@cs.berkeley.edu> wrote:
> ; 967,240 cons cells, 3,719,472,272 other bytes, 4,472 static bytes
[...]

> ; 418,422 cons cells, 292,782,544 other bytes, 0 static bytes

Cute. I presume Allegro can completely optimize away the allocation of
temporary structs consisting of only double-floats, but doesn't do
this for single-floats?

Svenne Krap

unread,
Aug 14, 2005, 4:51:44 AM8/14/05
to

On a single Xeon 3.4 GHz with sbcl 0.9.3:

Evaluation took:
3.783 seconds of real time
3.305498 seconds of user run time
0.477927 seconds of system run time
0 page faults and
509,576,768 bytes consed

Jon Harrop

unread,
Aug 14, 2005, 6:24:20 AM8/14/05
to
Svenne Krap wrote:

> Raffael Cavallaro wrote:
>> just as an additional data point, this code runs in just over 6 seconds
>> in sbcl 0.9.3 on a dual 2.0 GHz G5 (though sbcl only uses one processor).
>
> On a single Xeon 3.4 GHz with sbcl 0.9.3:
>
> Evaluation took:
> 3.783 seconds of real time
> 3.305498 seconds of user run time
> 0.477927 seconds of system run time
> 0 page faults and
> 509,576,768 bytes consed

On my 1.8GHz AMD64 in 32-bit mode with SBCL 0.9.3 I'm now getting:

5.21 seconds of real time
4.15 seconds of user run time
0.62 seconds of system run time
0 page faults and
509,569,248 bytes consed

This seems to be on-par with other people's observations.

This compares to 1.037s for OCaml and 0.987s for C++, so SBCL is now much
more competitive.

Thanks for all the help!

Ulrich Hobelmann

unread,
Aug 14, 2005, 11:19:53 AM8/14/05
to
Jon Harrop wrote:
> On my 1.8GHz AMD64 in 32-bit mode with SBCL 0.9.3 I'm now getting:
>
> 5.21 seconds of real time
> 4.15 seconds of user run time
> 0.62 seconds of system run time
> 0 page faults and
> 509,569,248 bytes consed
>
> This seems to be on-par with other people's observations.
>
> This compares to 1.037s for OCaml and 0.987s for C++, so SBCL is now much
> more competitive.

I wouldn't consider 5 times as slow as a *functional* language very
competitive, but it might be fast enough for many problems.

--
I believe in Karma. That means I can do bad things to people
all day long and I assume they deserve it.
Dogbert

Jon Harrop

unread,
Aug 14, 2005, 11:38:55 AM8/14/05
to
Ulrich Hobelmann wrote:
> I wouldn't consider 5 times as slow as a *functional* language very
> competitive, but it might be fast enough for many problems.

Well, it's relative. Most of the other Lisp/Scheme implementations were two
orders of magnitude slower. Stalin gets even closer than SBCL.

Also, MLton often beats g++, so functional languages aren't slow coaches any
more...

jayessay

unread,
Aug 14, 2005, 12:04:18 PM8/14/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> Ulrich Hobelmann wrote:
> > I wouldn't consider 5 times as slow as a *functional* language very
> > competitive, but it might be fast enough for many problems.
>
> Well, it's relative. Most of the other Lisp/Scheme implementations were two
> orders of magnitude slower. Stalin gets even closer than SBCL.

Which Lisps are you talking about? We've already seen where Allegro
is faster than this SBCL timing and it hadn't even been optimized yet.
I would be surprised if Lispworks were much different in this regard
as well.

> Also, MLton often beats g++, so functional languages aren't slow coaches any
> more...

So do many CL implementations on many benchmarks when "properly"
written. Several have been shown here in the past. Typically this
starts with the original posting "showing" how bad CL is supposed to
be when comparing optimized C/C++ with naively written CL. It also
often ends with the CL version beating the optimized C/C++ version.

Most typical of all is that such benchmarks (including this ray
tracing thing) don't have much of anything interesting to say about
anything.


/Jon

--
'j' - a n t h o n y at romeo/charley/november com

Jon Harrop

unread,
Aug 14, 2005, 12:24:59 PM8/14/05
to
jayessay wrote:
> Jon Harrop <use...@jdh30.plus.com> writes:
>> Ulrich Hobelmann wrote:
>> > I wouldn't consider 5 times as slow as a *functional* language very
>> > competitive, but it might be fast enough for many problems.
>>
>> Well, it's relative. Most of the other Lisp/Scheme implementations were
>> two orders of magnitude slower. Stalin gets even closer than SBCL.
>
> Which Lisps are you talking about?

Primarily CMUCL and SBCL.

> We've already seen where Allegro
> is faster than this SBCL timing and it hadn't even been optimized yet.
> I would be surprised if Lispworks were much different in this regard
> as well.

Is Lispworks free?

>> Also, MLton often beats g++, so functional languages aren't slow coaches
>> any more...
>
> So do many CL implementations on many benchmarks when "properly"
> written. Several have been shown here in the past.

What kinds of tasks is Lisp best at, in terms of performance? I Googled for
information on this but most of the sites I found were no longer up.

> Typically this
> starts with the original posting "showing" how bad CL is supposed to
> be when comparing optimized C/C++ with naively written CL. It also
> often ends with the CL version beating the optimized C/C++ version.

Can you point me to some examples of this? I heard of a benchmark written
long ago where some Lisp gurus managed to code an equivalently-efficient
implementation in Lisp. However, it is important to know how easily an
efficient version can be written. LOC is a very rudimentary measure of
development time.

> Most typical of all is that such benchmarks (including this ray
> tracing thing) don't have much of anything interesting to say about
> anything.

I think my conclusions were interesting. In particular, I was surprised to
see modern functional language implementations doing so well at what is
arguably their weakest point.

I'd like to do another benchmark with an example from scientific computing
next...

Ulrich Hobelmann

unread,
Aug 14, 2005, 1:03:09 PM8/14/05
to
Jon Harrop wrote:
> What kinds of tasks is Lisp best at, in terms of performance? I Googled for
> information on this but most of the sites I found were no longer up.

Why performance at all? Lisp is good at many things, most notably good
error recovery (interactive debugger, restarts...), but not for
high-performance computing. There you probably want Fortran or C (and
maybe link them to Lisp).

For symbolic processing, or anything non-number-chrunchy I wouldn't be
surprised if an application written in Lisp (compiled) isn't a bit
slower than the same app written in C++ or Java. But of course nobody
writes an app in several languages...

Jon Harrop

unread,
Aug 14, 2005, 1:27:19 PM8/14/05
to
Ulrich Hobelmann wrote:
> Jon Harrop wrote:
>> What kinds of tasks is Lisp best at, in terms of performance? I Googled
>> for information on this but most of the sites I found were no longer up.
>
> Why performance at all?

I became interested in Lisp's performance because several people advocated
Lisp to me for these kinds of tasks, claiming that it was suitably
efficient. I wanted to test that.

> Lisp is good at many things, most notably good
> error recovery (interactive debugger, restarts...), but not for
> high-performance computing. There you probably want Fortran or C (and
> maybe link them to Lisp).

My background is in computational science. Fortran is fine for trivial
programs that just loop over arrays of floats. Mathematica is great for
symbolic computation. But there is a huge gap between those where Fortran
isn't expressive enough and Mathematica isn't efficient enough. Languages
like OCaml, SML, Haskell and Lisp fill that gap.

> For symbolic processing, or anything non-number-chrunchy I wouldn't be
> surprised if an application written in Lisp (compiled) isn't a bit
> slower than the same app written in C++ or Java. But of course nobody
> writes an app in several languages...

I think it is productive to choose suitable tasks and implement them in
several different languages. It helps other people to learn, e.g. by
comparing C++ code to the equivalent OCaml, and it gives us all an idea of
how efficient and expressive the different languages are.

Jens Axel Søgaard

unread,
Aug 14, 2005, 2:54:29 PM8/14/05
to
jayessay wrote:
> Jon Harrop <use...@jdh30.plus.com> writes:

>>Well, it's relative. Most of the other Lisp/Scheme implementations were two
>>orders of magnitude slower. Stalin gets even closer than SBCL.

> So do many CL implementations on many benchmarks when "properly"


> written. Several have been shown here in the past. Typically this
> starts with the original posting "showing" how bad CL is supposed to
> be when comparing optimized C/C++ with naively written CL. It also
> often ends with the CL version beating the optimized C/C++ version.
>
> Most typical of all is that such benchmarks (including this ray
> tracing thing) don't have much of anything interesting to say about
> anything.

The comp.lang.lisp thread on Almabench comes into mind.
Rif summed it up pretty nicely:

So what have we learned? We confirmed what we pretty much
knew: you can write a C program in CL, at which point the
relative speed of your C and CL versions will depend on the
relative quality of the code generation.

I am sure Jon can pick up some nice tricks in the thread.

<http://groups.google.com/group/comp.lang.lisp/msg/ae59ca28867ced78?hl=en&lr=&ie=UTF-8&rnum=110>

--
Jens Axel Søgaard

Matthias Buelow

unread,
Aug 14, 2005, 5:23:38 PM8/14/05
to
Ulrich Hobelmann <u.hob...@web.de> wrote:

>I wouldn't consider 5 times as slow as a *functional* language very
>competitive, but it might be fast enough for many problems.

For a runtime typed language vs. a statically typed one it is quite
competitive. Generally, the compiler can never resolve all the runtime
typing at compile time, unless you declare all and everything in your
program (which would be nothing but a major PITA).

mkb.

Jon Harrop

unread,
Aug 14, 2005, 7:47:20 PM8/14/05
to
Jens Axel Søgaard wrote:
> The comp.lang.lisp thread on Almabench comes into mind.
> Rif summed it up pretty nicely:

Almabench. That's the one I'd heard of before.

> So what have we learned? We confirmed what we pretty much
> knew: you can write a C program in CL, at which point the
> relative speed of your C and CL versions will depend on the
> relative quality of the code generation.
>
> I am sure Jon can pick up some nice tricks in the thread.
>
>
<http://groups.google.com/group/comp.lang.lisp/msg/ae59ca28867ced78?hl=en&lr=&ie=UTF-8&rnum=110>

I hadn't actually read the implementation before now but I've got to say
that my ray tracer is a whole lot more fun. :-)

I'll check out the thread in more detail - thanks for the link.

Luke J Crook

unread,
Aug 15, 2005, 1:29:16 AM8/15/05
to
Jon Harrop wrote:

> jayessay wrote:
>>We've already seen where Allegro
>>is faster than this SBCL timing and it hadn't even been optimized yet.
>>I would be surprised if Lispworks were much different in this regard
>>as well.
>
>
> Is Lispworks free?

How many implementations of Ocaml are there? One. So every developer
working on Ocaml is hammering that one version. If you want to compare
Ocaml to an open source language then choose a language for which there
is but a single implementation; Perl, Python, Parrot, PHP, Ruby etc.

If you want to compare Ocaml to a specific implementation of Lisp, then
target CMUCL, SBCL, CLISP, Lispworks etc. However, if you want to
compare the performance of Lisp to the performance of Ocaml then choose
the fastest implementation of Lisp available and run that. Allego,
Lispworks and Corman (Corman is Windows only) are all free to you for
this purpose.

-Luke

robert...@antenova.com

unread,
Aug 15, 2005, 4:43:51 AM8/15/05
to

I've also written a version of Jon's raytracer benchmark. Unlike the
one given here I've used "simple-vector", to do the vectors.

I've also being using GCL to compile it so far.

It will be interesting to see how the performance compares.

Jon Harrop

unread,
Aug 15, 2005, 6:18:27 AM8/15/05
to
Luke J Crook wrote:
> How many implementations of Ocaml are there? One. So every developer
> working on Ocaml is hammering that one version. If you want to compare
> Ocaml to an open source language then choose a language for which there
> is but a single implementation; Perl, Python, Parrot, PHP, Ruby etc.

That doesn't really make any sense.

Firstly, the language comparison is with C++, Java and SML as well, all of
which have multiple implementations. Indeed, two implementations of SML are
already on the language comparison. Secondly, of the languages you listed,
at least Perl and Python have multiple implementations. Finally, the number
of implementations is irrelevant.

> If you want to compare Ocaml to a specific implementation of Lisp, then
> target CMUCL, SBCL, CLISP, Lispworks etc. However, if you want to
> compare the performance of Lisp to the performance of Ocaml then choose
> the fastest implementation of Lisp available and run that. Allego,
> Lispworks and Corman (Corman is Windows only) are all free to you for
> this purpose.

We're Linux only, so Corman is out the window. Which of the other Lisp
implementations do you expect to do well at this task?

I'll have a look at Lispworks...

Förster vom Silberwald

unread,
Aug 15, 2005, 8:08:11 AM8/15/05
to

Jon Harrop wrote:
> Ulrich Hobelmann wrote:
> > I wouldn't consider 5 times as slow as a *functional* language very
> > competitive, but it might be fast enough for many problems.
>
> Well, it's relative. Most of the other Lisp/Scheme implementations were two
> orders of magnitude slower. Stalin gets even closer than SBCL.
>
> Also, MLton often beats g++, so functional languages aren't slow coaches any
> more...

Jon: You may not forget that you are testing for micro benchmarks.
Surely, a Python will never become faster in the long run. However, all
the things will change if we were benchmarking really complicated code
of many thousand of lines.

When I was younger (now I am 31) I also believed benchmarking is a
must. However, in the meantime it is even this: if your ray-tracer in
OCaml were 100000 times faster than the Bigloo-Scheme version I would
not opt for OCaml quickly. Perfromance is important, no question, but
in a code project it is a rather tiny part.


Schneewittchen

Förster vom Silberwald

unread,
Aug 15, 2005, 8:12:45 AM8/15/05
to
Jon Harrop wrote:
> Jens Axel Søgaard wrote:
> > The comp.lang.lisp thread on Almabench comes into mind.
> > Rif summed it up pretty nicely:
>
> Almabench. That's the one I'd heard of before.

Only for the record: google around in comp.lang.scheme and see my
version for Bigloo of the Almabench if you are interested.

Schneewittchen

Michael Sullivan

unread,
Aug 15, 2005, 12:43:03 PM8/15/05
to
Förster vom Silberwald <chain...@hotmail.com> wrote:

> When I was younger (now I am 31) I also believed benchmarking is a
> must. However, in the meantime it is even this: if your ray-tracer in
> OCaml were 100000 times faster than the Bigloo-Scheme version I would
> not opt for OCaml quickly. Perfromance is important, no question, but
> in a code project it is a rather tiny part.

Depends on the code project, doesn't it? If you're doing primarily
heavy duty (but medium complexity) mathematical manipulations, then
speed is a big factor.

I agree that in most problem domains, constant time speed factors are
pretty much irrelevant for 95% of code, and we should be very skeptical
about judging "language speed" by simple benchmarks like this, because
an easier to program language, often leads to better algorithms, as well
as a lot less programming time (and less downside variation in program
speed -- cf: Erann's lisp-java-c experiment: the fastest C programs just
beat the fastest lisp programs, but many of the C programs were *much*
slower than the slowest lisp programs).

But those tradeoffs aren't the same for all problem domains. In those
rare problem domains where there's always lots time to optimize relative
to the runtime available, bare speed matters.

The problem is that it's still hard to tell the difference between a
faster language and better writers of optimized code, as the almabench
thread demonstrates. How much time do you spend on optimization before
you abandon the project and say "It's easier to make this fast in X".
And obviously some things will be easier to optimize in language Y than
others. All this makes any given benchmark or set of benchmarks suspect
as an absolute measure of speed, but it doesn't completely invalidate
their potential usefulness, as long as one understands what they mean
and what they do not mean.


Michael

Jon Harrop

unread,
Aug 15, 2005, 4:31:32 PM8/15/05
to
Michael Sullivan wrote:
> Förster vom Silberwald <chain...@hotmail.com> wrote:
>> When I was younger (now I am 31) I also believed benchmarking is a
>> must. However, in the meantime it is even this: if your ray-tracer in
>> OCaml were 100000 times faster than the Bigloo-Scheme version I would
>> not opt for OCaml quickly. Perfromance is important, no question, but
>> in a code project it is a rather tiny part.
>
> Depends on the code project, doesn't it? If you're doing primarily
> heavy duty (but medium complexity) mathematical manipulations, then
> speed is a big factor.

Yes, absolutely. I am primarily interested in the middle ground between slow
but hugely expressive languages like Mathematica and "fast" but archaic
languages like Fortran. Functional languages are great for this middle
ground and they are improving at such a rate that they've been eating into
the remits of Mathematica and Fortran a lot.

> I agree that in most problem domains, constant time speed factors are
> pretty much irrelevant for 95% of code, and we should be very skeptical
> about judging "language speed" by simple benchmarks like this, because
> an easier to program language, often leads to better algorithms, as well
> as a lot less programming time (and less downside variation in program
> speed -- cf: Erann's lisp-java-c experiment: the fastest C programs just
> beat the fastest lisp programs, but many of the C programs were *much*
> slower than the slowest lisp programs).

This is exactly why I measure LOC. From my results, the LOC measurements
indicate that code size will become a limiting factor much more quickly for
Java than for OCaml, for example. Although this is a very crude measure
(there are a huge number of language features, like a decent type system,
that aid productivity), my quantitative result reflect my experience.

However, LOC overly penalises Lisp and Scheme, IMHO. Specifically, Lisp and
Scheme programs are virtually unreadable unless the parentheses are
staggered by spreading expressions over several lines and using an
automatic indenter. So if I were to put a Lisp implementation of the ray
tracer on my site then I'd either state that, or I'd give results using
some other measure of verbosity, like characters. I do think Lisp deserves
to be somewhat penalised in this way, but LOC goes too far.

> But those tradeoffs aren't the same for all problem domains. In those
> rare problem domains where there's always lots time to optimize relative
> to the runtime available, bare speed matters.

I think it is also important to measure the performance of "natural" code.
In Lisp, natural code is often understood very generically by the compiler.
In most other languages, you have to work to get that generality.

> The problem is that it's still hard to tell the difference between a
> faster language and better writers of optimized code, as the almabench
> thread demonstrates. How much time do you spend on optimization before
> you abandon the project and say "It's easier to make this fast in X".
> And obviously some things will be easier to optimize in language Y than
> others. All this makes any given benchmark or set of benchmarks suspect
> as an absolute measure of speed, but it doesn't completely invalidate
> their potential usefulness, as long as one understands what they mean
> and what they do not mean.

Yes, absolutely. I do think my ray tracer is a suboptimal benchmark, of
course, but I was astonished that so many people put so much effort into
that almabench benchmark when (IMHO) it was an appalingly narrow and badly
coded test that isn't representative of any real programs, in my experience
as a computational physicist. I'm glad that this hasn't descended into a
"Lisp sux0rz" conversation though.

In contrast, my ray tracer involves integer and floating point arithmetic,
3D vectors, trees, tagged unions, recursion/iteration, naturally functional
(e.g. vector ops and ray_sphere) and imperative (e.g. for loops) style. So
it tests quite a lot using very little code and it is fun to play with.
This diversity also makes the collection of ray tracers a better
educational tool - people can glance at the code and see how different
things are implemented in different languages.

Hartmann Schaffer

unread,
Aug 16, 2005, 2:10:06 AM8/16/05
to
Jon Harrop wrote:
> ...

> However, LOC overly penalises Lisp and Scheme, IMHO. Specifically, Lisp and
> Scheme programs are virtually unreadable unless the parentheses are
> staggered by spreading expressions over several lines and using an
> automatic indenter. So if I were to put a Lisp implementation of the ray
> tracer on my site then I'd either state that, or I'd give results using
> some other measure of verbosity, like characters.

i doubt lisp or scheme will gain anything there: the language defined
words tend to be quite lengthy, and afaict that seems to encourage
programmers to use pretty length identifiers for their own identifiers,
so character count might penalize lisp even worse. otoh, the lengthy
identifiers make lisp code quite easy to read and understand.

token count probably would be better

> ...

hs

Rob Thorpe

unread,
Aug 16, 2005, 4:31:15 AM8/16/05
to

Here is my version. For some reason it doesn't work, the "g" variable
sticks at 0.5. Have I missed something obvious, can anyone see what's
wrong with it?


; Jon Harrops little raytracer
; With bits from Jan Van Lint's version and Nathan Baum's version
; Currently not working

(defconstant delta (sqrt long-float-epsilon))
(defconstant infinity most-positive-long-float)

(defun v* (s r) (map 'simple-vector #'(lambda (x) (* s x)) r))
(defun v+ (a b) (map 'simple-vector #'+ a b))
(defun v- (a b) (map 'simple-vector #'- a b))
(defun dot (a b) (apply #'+ (map 'list #'* a b)))
(defun unitise (r) (v* (/ (sqrt (dot r r))) r))

(defstruct ray orig dir)
(defstruct sphere center rad)
(defstruct group sphere scenes)

(defun ray-sphere (ray sph)
(let* (t1 t2
(v (v- (sphere-center sph) (ray-orig ray)))
(b (dot v (ray-dir ray)))
(disc (+ (- (* b b) (dot v v)) (expt (sphere-rad sph) 2))))
(if (minusp disc) infinity
(progn (setq disc (sqrt disc))
(if (minusp (setq t2 (+ b disc))) infinity
(progn (setq t1 (- b disc))
(if (plusp t1) t1 t2)))))))

(defun intersect (ray scene)
(labels
((lp (hit scene) ; car hit is a lam, cdr a simple-vector normal
(if (sphere-p scene)
(let ((lam (ray-sphere ray scene)))
(if (>= lam (car hit)) hit
(cons lam (unitise
(v- (v+ (ray-orig ray) (v* lam (ray-dir ray)))
(sphere-center scene))))))
(if (group-p scene)
(if (>= (ray-sphere ray (group-sphere scene)) (car hit)) hit
(reduce #'lp (group-scenes scene) :initial-value hit))
(error "not a group or sphere in intersect")))))
(lp (cons infinity #(0.0 0.0 0.0)) scene)))

(defun ray-trace (light ray scene)
(let* ((hit (intersect ray scene))
(lam (car hit))
(normal (cdr hit)))
(if (= lam infinity) 0.0
(let (g (dot normal light))
(if (plusp g) 0.0
(let ((p (v+ (v+ (ray-orig ray) (v* lam (ray-dir ray)))
(v* delta normal))))
(if (< (car (intersect (make-ray :orig p :dir (v* -1.0 light))
scene)) infinity) 0.0 (- g))))))))

(defun create (n c r)
(let ((obj (make-sphere :center c :rad r)))
(if (= n 1) obj
(let ((rt (* 3.0 (/ r (sqrt 12.0)))))
(labels ((aux (x z) (create (1- n) (v+ c (vector x rt z)) (* 0.5 r))))
(make-group :sphere (make-sphere :center c :rad (* 3.0 r))
:scenes (list obj (aux (- rt) (- rt)) (aux rt (- rt))
(aux (- rt) rt) (aux rt rt))))))))

(defun main ()
(let* ((level 6)
(n 512) (ss 4) (light (unitise #(-1.0 -3.0 2.0)))
(scene (create level #(0.0 -1.0 0.0) 1)))
(format *terminal-io* "P5~%~D ~D ~%255~%" n n)
(do ((y (1- n) (1- y))) ((< y 0))
(do ((x 0 (1+ x))) ((>= x n))
(let ((g 0))
(dotimes (dx ss)
(dotimes (dy ss)
(let* ((aux (lambda (x d) (+ (- x (/ n 2)) (/ d ss))))
(d (unitise (vector (funcall aux x dx)
(funcall aux y dy) n))))
(incf g (ray-trace
light
(make-ray :orig #(0.0 0.0 -4.0) :dir d) scene)))))
(setq g (+ 0.5 (* 255.0 (/ g (* ss ss)))))
(write-byte (floor g) *terminal-io*))))))

Jamie Border

unread,
Aug 16, 2005, 5:01:10 AM8/16/05
to

"Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message
news:WqfMe.1588$Dd....@newscontent-01.sprint.ca...
> Jon Harrop wrote:
>> ...
JH>> However, LOC overly penalises Lisp and Scheme, IMHO. Specifically, Lisp
and
JH>> Scheme programs are virtually unreadable unless the parentheses are
JH>> staggered by spreading expressions over several lines and using an
JH>> automatic indenter. So if I were to put a Lisp implementation of the
ray
JH>> tracer on my site then I'd either state that, or I'd give results using
JH>> some other measure of verbosity, like characters.

Hmm. What would you (JH) be measuring here?

a) Keystrokes required to produce the code (see below, though)
b) Some kind of 'intrinsic verbosity', which would require some *serious*
thinking about idiomaticity, relevance of formatting and massive, massive
sampling to make it statistically relevant.


> i doubt lisp or scheme will gain anything there: the language defined
> words tend to be quite lengthy, and afaict that seems to encourage
> programmers to use pretty length identifiers for their own identifiers,

Yes

> so character count might penalize lisp even worse. otoh, the lengthy
> identifiers make lisp code quite easy to read and understand.

Yes, and using a decent editor with auto-completion (Emacs) means that I hit
less keys to produce the token 'DESTRUCTURING-BIND' ( DE-B <META-TAB> ) than
you might think.

Oh, and all the ')))))' you see probably didn't get typed by hand (
<META-RET> closes all open parens).

>
> token count probably would be better

Yep, although (because I am biased) I would like to see
'keystroke/mouse-click' count instead. I think that with the requirement
for idiomatic variable naming, CL might not come out as 'verbose' as you
think...

>
>> ...
>
> hs


Joe Marshall

unread,
Aug 16, 2005, 8:32:03 AM8/16/05
to
"Rob Thorpe" <robert...@antenova.com> writes:

> Here is my version. For some reason it doesn't work, the "g" variable
> sticks at 0.5. Have I missed something obvious, can anyone see what's
> wrong with it?

Try setting delta to something *much* larger than long-float-epsilon.

Jamie Border

unread,
Aug 16, 2005, 8:31:57 AM8/16/05
to

"Jamie Border" <ja...@jborder.com> wrote in message
news:ddsa0j$fk6$1...@nwrdmz02.dmz.ncs.ea.ibs-infra.bt.com...

^^^^^^^^^^^^ at least at the slime REPL anyway <oops>

Jon Harrop

unread,
Aug 16, 2005, 12:38:30 PM8/16/05
to
Jamie Border wrote:
> "Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message
> news:WqfMe.1588$Dd....@newscontent-01.sprint.ca...
>> Jon Harrop wrote:
>>> ...
> JH>> However, LOC overly penalises Lisp and Scheme, IMHO. Specifically,
> Lisp and
> JH>> Scheme programs are virtually unreadable unless the parentheses are
> JH>> staggered by spreading expressions over several lines and using an
> JH>> automatic indenter. So if I were to put a Lisp implementation of the
> ray
> JH>> tracer on my site then I'd either state that, or I'd give results
> using JH>> some other measure of verbosity, like characters.
>
> Hmm. What would you (JH) be measuring here?
>
> a) Keystrokes required to produce the code (see below, though)
> b) Some kind of 'intrinsic verbosity', which would require some *serious*
> thinking about idiomaticity, relevance of formatting and massive, massive
> sampling to make it statistically relevant.

Both. As you say, it is so inherently flawed that there is little point
wasting time thinking about it. For the time being, I don't believe LOC can
be significantly improved upon.

>> so character count might penalize lisp even worse. otoh, the lengthy
>> identifiers make lisp code quite easy to read and understand.
>
> Yes, and using a decent editor with auto-completion (Emacs) means that I
> hit less keys to produce the token 'DESTRUCTURING-BIND' ( DE-B <META-TAB>
> ) than you might think.
>
> Oh, and all the ')))))' you see probably didn't get typed by hand (
> <META-RET> closes all open parens).

Cool. :-)

>> token count probably would be better
>
> Yep, although (because I am biased) I would like to see
> 'keystroke/mouse-click' count instead. I think that with the requirement
> for idiomatic variable naming, CL might not come out as 'verbose' as you
> think...

Is Lisp code not made less maintainable because of all those brackets?

Christophe Rhodes

unread,
Aug 16, 2005, 12:54:02 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> Jamie Border wrote:
>> Yep, although (because I am biased) I would like to see
>> 'keystroke/mouse-click' count instead. I think that with the requirement
>> for idiomatic variable naming, CL might not come out as 'verbose' as you
>> think...
>
> Is Lisp code not made less maintainable because of all those brackets?

No, it is made more maintainable because of all those brackets,
because it is straightforward to write tools which can manipulate the
textual representation of your program, and because human programmers
do not read the brackets.

Christophe

Jon Harrop

unread,
Aug 16, 2005, 1:10:13 PM8/16/05
to
Christophe Rhodes wrote:
> Jon Harrop <use...@jdh30.plus.com> writes:
>> Is Lisp code not made less maintainable because of all those brackets?
>
> No, it is made more maintainable because of all those brackets,
> because it is straightforward to write tools which can manipulate the
> textual representation of your program, and because human programmers
> do not read the brackets.

I don't think that makes sense. Continuing that line of thinking, Whitespace
and Brainf*** are the most maintainable languages.

Consider the example:

(defun fib (x)
(if (<= x 2)
1
(+ (fib (- x 2))(fib (1- x)))))

In ML this is:

let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)

That may be easier to parse for the machine (I don't think it is though) but
maintainability is about how easily a human can parse it.

Christophe Rhodes

unread,
Aug 16, 2005, 1:16:35 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> Christophe Rhodes wrote:
>> Jon Harrop <use...@jdh30.plus.com> writes:
>>> Is Lisp code not made less maintainable because of all those brackets?
>>
>> No, it is made more maintainable because of all those brackets,
>> because it is straightforward to write tools which can manipulate the
>> textual representation of your program, and because human programmers
>> do not read the brackets.
>
> I don't think that makes sense. Continuing that line of thinking, Whitespace
> and Brainf*** are the most maintainable languages.

Did you read just the first half of my sentence? Human programmers do
not read the brackets, but instead read the indentation.

> Consider the example:
>
> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))

This is not production-quality maintainable lisp code, because it
ignores the conventions that have developed and are supported by the
tools. However, if I take your mangled example, place it in a lisp
buffer and ask my editor to reformat it (C-M-q in emacs, for
instance), I get

(defun fib (x)
(if (<= x 2)
1
(+ (fib (- x 2))(fib (1- x)))))

and the code obeys more of the conventions: it is much easier to read.
(Still not perfect, because there should be a space between the "))"
and the "(", but good enough).

If you are counting or reading brackets manually when writing lisp
code, you are doing something wrong.

Christophe

jayessay

unread,
Aug 16, 2005, 1:36:41 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> >> token count probably would be better
> >
> > Yep, although (because I am biased) I would like to see
> > 'keystroke/mouse-click' count instead. I think that with the requirement
> > for idiomatic variable naming, CL might not come out as 'verbose' as you
> > think...
>
> Is Lisp code not made less maintainable because of all those brackets?

Less??? LOL!

Rob Thorpe

unread,
Aug 16, 2005, 2:52:49 PM8/16/05
to

The text of a program in lisp is -more or less- a direct representation
of a tree.

When the lisp reader sees the first paren above it begins a new list,
and puts each symbol it meets in the list. When it hits a closing
paren it closes the list and goes back to the previous one it was
processing. There are a few exceptions, but this is generally how it's
done.

In BNF this can be represented like this:

s_expression = atomic_symbol | "(" s_expression "."s_expression ")" |
list
list = "(" s_expression < s_expression > ")"

There are many list functions that handle the language. Of those there
are 3 main ones:
* "read" brings the textual form into memory (s-expressions -> trees)
* "print" does the reverse, (trees-> s-expressions)
* "eval" interprets code, executing the functions specified in the
trees

This has some interesting repercussions.

Firstly, at the language level, since everything - data and code - is
represented as above the language becomes more amenable to automatic
operations.
Some examples:-

1. If I load my buggy version of your raytracer into lisp and do:

(setq foo (ray-sphere ray sph))

foo now contains a huge tree. Should I want this tree in the future
(for more debugging f.e.g) I can print it to a file with print, then
later read it back with read.

2. Emacs does not have to guess things about lisp. With other
languages it occasionally has to guess, because it cannot understand
the syntax in reasonable time. When it tells you all the parens match,
they match.

3. In a place (a fearful place :) ) that doesn't have emacs all is not
lost. If lisp can read the code it can print it. So, I can quote the
list with a quote mark*, and watch it:

'((defun fib (x) (if (<= x 2) 1 (+ (fib (- x 2))(fib (1- x)))))

It will then spit it back with whatever default formatting the lisp
printer uses for lists (there may also be an option for printing
functions in the printer). The formatting may not be very nice, but if
the code is truely hairy it will be more understandable than it was.
You can use this sort of this to do things like substituting sub-trees
in your code.
(* quote marks are one of the few true bits of syntax)

4. It makes macros easier to understand since they act on trees.


All of the above describes benefits in automatic formatting, not
readability.
Some people find it readable, some don't. I personally don't find it
very easy or very difficult. There are a number of tricks to reading
it and writing it.
What I find most effective is to do this:

When reading this for example:


(defun fib (x)
(if (<= x 2)
1
(+ (fib (- x 2))(fib (1- x)))))

The meaning of the first line is fairly simple, as are the next two.
The problem is the last line. "fib" is obviously called recursively
twice and the results are supposed to be added, but are they?

The easiest way to find out is to delete all the closing parens at the
end with Emacs. You then replace them one by one, the cursor will
highlight the opening paren as this happens. You can then watch them
and check they go in the right places. Once you've finished closing
the parens on the line you're on, the rest should match on the lines
above to each left-most paren.

Occasionally I do spend a minute or so staring at the parens and
wondering what's wrong with them though. It's not perfect for my own
reading.

There are a few other reading advantages that come with abandoning
syntax though. For example you don't have to worry where in the manual
it is described, there's no page 53. I've always had this problem with
Perl, I know something's wrong with it, but I can't remember the place
in the manual that explains it. For a lisp the manual/standard need
only describe forms and what they do.

It also means errors can't leak syntactically: the error is in one
form. They can certainly leak semantically though.

Brian Downing

unread,
Aug 16, 2005, 3:10:31 PM8/16/05
to
In article <43021e94$0$97107$ed26...@ptn-nntp-reader03.plus.net>,

Jon Harrop <use...@jdh30.plus.com> wrote:
> Consider the example:
>
> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))
>
> In ML this is:
>
> let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)
>
> That may be easier to parse for the machine (I don't think it is
> though) but maintainability is about how easily a human can parse it.

Here's your example reformatted correctly:

(defun fib (x)
(if (<= x 2)
1
(+ (fib (- x 2)) (fib (1- x)))))

Now consider the following transformations:

(defun fib (x)
(if (<= x 2)

(+ (fib (- x 2)) (fib (1- x)))
1))

(defun fib (x)
(+ (fib (- x 2)) (fib (1- x))))

I can perform both of those with one command (both three keystrokes in
this case) in Emacs, and without marking any extents at all. How many
keys must you hit in your editor to perform the equivalents, and does
your editor understand enough of the syntax to figure out what the
extents of the if and else cases are without you explicitly marking
them?

(If this seems trivial, which it is in this case, consider that it can
work on any size and complexity of expression.)

Also, I consider the reformatted Lisp to be more readable than the ML,
but then, it's what I'm used to.

-bcd
--
*** Brian Downing <bdowning at lavos dot net>

Joe Marshall

unread,
Aug 16, 2005, 3:38:18 PM8/16/05
to
> Jon Harrop <use...@jdh30.plus.com> writes:
>>
>> Is Lisp code not made less maintainable because of all those brackets?

Christophe Rhodes <cs...@cam.ac.uk> writes:

> No, it is made more maintainable because of all those brackets,


> Jon Harrop <use...@jdh30.plus.com> writes:
>
> Consider the example:
>
> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))
>
> In ML this is:
>
> let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)
>
> That may be easier to parse for the machine (I don't think it is though) but
> maintainability is about how easily a human can parse it.


> "Rob Thorpe" <robert...@antenova.com>


>
> Some people find it readable, some don't. I personally don't find it
> very easy or very difficult.

> Brian Downing <see-si...@lavos.net>


>
> Also, I consider the reformatted Lisp to be more readable than the ML,
> but then, it's what I'm used to.


Is readability simply a subjective measure, then? If so, and if
maintainability is about how easily a human can parse it, then
maintainability is also a subjective measure (and not particularly
interesting for comparing computer languages).

It seems likely to me that languages that require complex parsers are
harder for humans to understand as well.

Rob Thorpe

unread,
Aug 16, 2005, 3:41:44 PM8/16/05
to
Brian Downing wrote:
> In article <43021e94$0$97107$ed26...@ptn-nntp-reader03.plus.net>,
> Jon Harrop <use...@jdh30.plus.com> wrote:
> > Consider the example:
> >
> > (defun fib (x)
> > (if (<= x 2)
> > 1
> > (+ (fib (- x 2))(fib (1- x)))))
> >
> > In ML this is:
> >
> > let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)
> >
> > That may be easier to parse for the machine (I don't think it is
> > though) but maintainability is about how easily a human can parse it.
>
> Here's your example reformatted correctly:
>
> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2)) (fib (1- x)))))
>
<snip>

For what it's worth the code first shown would be correctly formatted
were it Scheme. I think this is where the misunderstanding comes from.

Stefan Nobis

unread,
Aug 16, 2005, 3:40:48 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))

> In ML this is:

> let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)

The ML code is not easier to read because there are less
parens. In fact, I don't read the parens in Lisp (even some weeks
ago when I started learning Lisp) -- i really had to get used to
the prefix notation (reading and writing). This is also what makes
the ML code easer to read for someone who isn't trained in prefix
notation. But IMHO prefix notation is not very hard to read or to
get used to and it's no maintainance problem either.

--
Stefan.

Peter Seibel

unread,
Aug 16, 2005, 5:24:13 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

Hmmm. I think I'm with Joe Marshall--this is subjective. When I look
at the ML I immediately get a little worried thought bubbling up
saying, crap, a string of undelimited tokens; now I have to start
thinking about precedence rules. In this simple case it's not a big
problem because I assume the precedence rules are sane and that the ML
is not equivalent to say:

(defun fib (x)
(+ (if (<= x 2) 1 (fib (-x 2))) (fib (- x 1))))

But the fact that I have to think about that just makes me wish for
some easy to understand and maintain Lisp code. ;-)

-Peter

P.S. Which is not to say that the mental effort of dealing with
precedence rules is overwhelming--just that it's another cost that (to
me) is higher than the cost (if any) of dealing with parens (which
also come with lots of other benefits, as others in this thread have
pointed out.)

--
Peter Seibel * pe...@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/

Jamie Border

unread,
Aug 16, 2005, 5:55:14 PM8/16/05
to

"Jon Harrop" <use...@jdh30.plus.com> wrote in message
news:43021724$0$97107$ed26...@ptn-nntp-reader03.plus.net...

> Jamie Border wrote:
>> "Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message
>> news:WqfMe.1588$Dd....@newscontent-01.sprint.ca...
>>> Jon Harrop wrote:
>>>> ...
>> JH>> However, LOC overly penalises Lisp and Scheme, IMHO. Specifically,
>> Lisp and
>> JH>> Scheme programs are virtually unreadable unless the parentheses are
>> JH>> staggered by spreading expressions over several lines and using an
>> JH>> automatic indenter. So if I were to put a Lisp implementation of the
>> ray
>> JH>> tracer on my site then I'd either state that, or I'd give results
>> using JH>> some other measure of verbosity, like characters.
>>
>> Hmm. What would you (JH) be measuring here?
>>
>> a) Keystrokes required to produce the code (see below, though)
>> b) Some kind of 'intrinsic verbosity', which would require some *serious*
>> thinking about idiomaticity, relevance of formatting and massive, massive
>> sampling to make it statistically relevant.
>
> Both. As you say, it is so inherently flawed that there is little point
> wasting time thinking about it. For the time being, I don't believe LOC
> can
> be significantly improved upon.

How would you enforce formatting for your hypothetical LOC measurements?

Compare:

(defun foo (some-number)
(list (1- some-number)
some-number
(1+ some-number)))

with something like:


int* foo (int num) {int* temp = (int*)malloc(3 * sizeof(int); temp[0] =
num-1; temp[1] = num; temp[2] = num+1; return temp; }


Example 1 has 2 LOC. Example 2 has 1 LOC. Does this mean C 'wins' here?

>
>>> so character count might penalize lisp even worse. otoh, the lengthy
>>> identifiers make lisp code quite easy to read and understand.
>>
>> Yes, and using a decent editor with auto-completion (Emacs) means that I
>> hit less keys to produce the token 'DESTRUCTURING-BIND' ( DE-B <META-TAB>
>> ) than you might think.
>>
>> Oh, and all the ')))))' you see probably didn't get typed by hand (
>> <META-RET> closes all open parens).
>
> Cool. :-)

Incidentally I argued against the verbosity of CL a while ago, when I was
green. Now I've written more code, I know better.

At 2am I can understand MULTIPLE-VALUE-BIND better than MVB. Verbosity is
good.

>
>>> token count probably would be better
>>
>> Yep, although (because I am biased) I would like to see
>> 'keystroke/mouse-click' count instead. I think that with the requirement
>> for idiomatic variable naming, CL might not come out as 'verbose' as you
>> think...
>
> Is Lisp code not made less maintainable because of all those brackets?

No. It is *more* maintainable. I am new (a few months) to CL, and I can
fix my code faster* than with C (seven years).

Difficult to explain really, but I get a visceral sense of 'stack pop' as I
type the closing parens.

This is probably due to Emacs highlighting each open-paren that my typed
close-paren balances.

What I am trying to say is that I get this feeling for the *whole* language,
whereas with C, i see curly braces, square brackets, periods,
hypen-greater-than, ampersand, etc, etc.

My thinking goes "erm-close-squre-bracket erm-close-paren erm-semicolon"
instead of "done-done-done"

Of course, it would be absurd to suggest that C code is less maintainable
because of all that _syntax_... Wouldn't it? :-)

Jamie

* This is a lie: sometimes I just stare at it for hours, because I am still
adjusting to the CL way of thinking. But this happens less and less often.
If I compare with the transition from C++ to C# (the most recent addition, I
guess), I am winning *big time* with Common Lisp.

Jon Harrop

unread,
Aug 16, 2005, 6:45:50 PM8/16/05
to
Rob Thorpe wrote:
> Firstly, at the language level, since everything - data and code - is
> represented as above the language becomes more amenable to automatic
> operations.

Yes. But is that related to the grammar?

> Some examples:-
>
> 1. If I load my buggy version of your raytracer into lisp and do:
>
> (setq foo (ray-sphere ray sph))
>
> foo now contains a huge tree. Should I want this tree in the future
> (for more debugging f.e.g) I can print it to a file with print, then
> later read it back with read.

That's cool. I guess the nearest in OCaml is to use the compiler's lexer and
parser to input the code and then marshall it to disc. Not very elegant...

> 2. Emacs does not have to guess things about lisp. With other
> languages it occasionally has to guess, because it cannot understand
> the syntax in reasonable time. When it tells you all the parens match,
> they match.

Ok. Can you give an example of a time when emacs has to guess?

> 3. In a place (a fearful place :) ) that doesn't have emacs all is not
> lost. If lisp can read the code it can print it. So, I can quote the
> list with a quote mark*, and watch it:
>
> '((defun fib (x) (if (<= x 2) 1 (+ (fib (- x 2))(fib (1- x)))))
>
> It will then spit it back with whatever default formatting the lisp
> printer uses for lists (there may also be an option for printing
> functions in the printer). The formatting may not be very nice, but if
> the code is truely hairy it will be more understandable than it was.
> You can use this sort of this to do things like substituting sub-trees
> in your code.

Right, I saw that in Sussman's lecture (IIRC).

> (* quote marks are one of the few true bits of syntax)

Yes, "#" and ";" seem to be others. I don't know what "#" does.

> 4. It makes macros easier to understand since they act on trees.

So you predict that Lisp macros are easier to understand than OCaml's
macros?

> All of the above describes benefits in automatic formatting, not
> readability.
> Some people find it readable, some don't. I personally don't find it
> very easy or very difficult. There are a number of tricks to reading
> it and writing it.

I'm finding prefix notation readable but overly verbose. Counting
parentheses is a real pain though. Assuming the Lisp advocates here also
know conventional languages then there is plenty of evidence that one can
learn to read Lisp.

> The easiest way to find out is to delete all the closing parens at the
> end with Emacs. You then replace them one by one, the cursor will
> highlight the opening paren as this happens. You can then watch them
> and check they go in the right places. Once you've finished closing
> the parens on the line you're on, the rest should match on the lines
> above to each left-most paren.

Yes. That is almost exactly what I am doing.

> It also means errors can't leak syntactically: the error is in one
> form. They can certainly leak semantically though.

Yes. I think that the majority of the errors I get in other languages are
already semantic though.

Jon Harrop

unread,
Aug 16, 2005, 6:18:44 PM8/16/05
to
Joe Marshall wrote:
> Is readability simply a subjective measure, then? If so, and if
> maintainability is about how easily a human can parse it, then
> maintainability is also a subjective measure (and not particularly
> interesting for comparing computer languages).

Yes. Readability and maintainability are inherently subjective. However,
they are both very important when comparing computer languages.

For example, nobody in their right mind would consider writing production
code in Whitespace or Brainf*** because they are clearly less readable and
maintainable, even though it is subjective. That is a clear-cut case, but
with Lisp vs ML it is not so simple, IMHO.

> It seems likely to me that languages that require complex parsers are
> harder for humans to understand as well.

There is unquestionably a huge amount of evidence to the contrary. Most
natural and programming languages have complicated grammars precisely
because it simplifies their use and makes them easier to understand.

Additionally (pun intended), we were all taught operator precedences in
conventional mathematics at a very young age. It seems at best odd and at
worst stupid to disregard this.

Jon Harrop

unread,
Aug 16, 2005, 6:27:43 PM8/16/05
to
Christophe Rhodes wrote:
> Jon Harrop <use...@jdh30.plus.com> writes:
>> I don't think that makes sense. Continuing that line of thinking,
>> Whitespace and Brainf*** are the most maintainable languages.
>
> Did you read just the first half of my sentence? Human programmers do
> not read the brackets, but instead read the indentation.

If every bracket in Lisp were indented separately (i.e. on a separate line),
as braces are typically in C/C++/Java then I would agree. However, they are
not. In this case you have 12 brackets nested 3 levels deep on a single
line, where indentation cannot help.

>> Consider the example:
>>
>> (defun fib (x)
>> (if (<= x 2)
>> 1
>> (+ (fib (- x 2))(fib (1- x)))))
>
> This is not production-quality maintainable lisp code, because it
> ignores the conventions that have developed and are supported by the
> tools. However, if I take your mangled example, place it in a lisp
> buffer and ask my editor to reformat it (C-M-q in emacs, for
> instance), I get
>
> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))
>
> and the code obeys more of the conventions: it is much easier to read.

Can I just clarify - the only difference is the constant indentation on the
lines after defun? Unless I'm missing something, I can't see how this makes
it much easier to read.

> (Still not perfect, because there should be a space between the "))"
> and the "(", but good enough).

Yes, I would have expected that.

> If you are counting or reading brackets manually when writing lisp
> code, you are doing something wrong.

Surely if your constructs require ((...)) then you must count brackets to
ensure that there are two sets of nested brackets?

Jon Harrop

unread,
Aug 16, 2005, 6:54:34 PM8/16/05
to
Jamie Border wrote:
> How would you enforce formatting for your hypothetical LOC measurements?

I would make no attempt to do so beyond disciplining myself to write in a
natural style.

> Compare:
>
> (defun foo (some-number)
> (list (1- some-number)
> some-number
> (1+ some-number)))
>
> with something like:
>
> int* foo (int num) {int* temp = (int*)malloc(3 * sizeof(int); temp[0] =
> num-1; temp[1] = num; temp[2] = num+1; return temp; }
>
>
> Example 1 has 2 LOC. Example 2 has 1 LOC. Does this mean C 'wins' here?

Yes, exactly. But the C isn't in my natural style.

The problem with Lisp and Scheme is that I am a total newbie and have no
idea how Lisp code is normally formatted. C++ and OCaml I know. SML I
thought I knew but had a big debate on c.l.functional about it. And I
assumed that Java = C++ for formatting.

>> Is Lisp code not made less maintainable because of all those brackets?
>
> No. It is *more* maintainable. I am new (a few months) to CL, and I can
> fix my code faster* than with C (seven years).

Sure. I am in the same situation with C++ and OCaml. But I want to know how
ML and Lisp compare. Syntax is clearly one of the major differences between
Lisp and ML.

> Difficult to explain really, but I get a visceral sense of 'stack pop' as
> I type the closing parens.

Interesting. :-)

> This is probably due to Emacs highlighting each open-paren that my typed
> close-paren balances.

Yep. That's a real life saver.

> My thinking goes "erm-close-squre-bracket erm-close-paren erm-semicolon"
> instead of "done-done-done"
>
> Of course, it would be absurd to suggest that C code is less maintainable
> because of all that _syntax_... Wouldn't it? :-)

No, not at all. Both sides of the argument have valid justifications, IMHO.

> * This is a lie: sometimes I just stare at it for hours, because I am
> still
> adjusting to the CL way of thinking. But this happens less and less
> often. If I compare with the transition from C++ to C# (the most recent
> addition, I guess), I am winning *big time* with Common Lisp.

I can well believe that.

Hartmann Schaffer

unread,
Aug 16, 2005, 7:39:23 PM8/16/05
to

i was considering pointing out that most lisp development environments
have features that would reduce the amount of keystrokes required to
type in the program, but decided against it because i suspect that that
is harder to measure than a token count

hs

Greg Buchholz

unread,
Aug 16, 2005, 7:56:53 PM8/16/05
to
Jamie Border wrote:
>int* foo (int num) {int* temp = (int*)malloc(3 * sizeof(int); temp[0] = num-1; temp[1] = num; temp[2] = num+1; return temp; }

Should be able to chop a few characters off of that...

int* foo(int n)
{memcpy(malloc(3*sizeof(int)),(int[]){n-1,n,n+1},3*sizeof(int));}

Pascal Bourguignon

unread,
Aug 16, 2005, 8:15:19 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:
> Additionally (pun intended), we were all taught operator precedences in
> conventional mathematics at a very young age. It seems at best odd and at
> worst stupid to disregard this.

In mathematics, there are two precedence levels ({+,-} vs. {*,/} (and
even, division is usually written as an horizontal bar, that is
essentially just a big parenthesis). In C there are 28 levels. Do you
know a lot of C programmer who know the exact precendence levels of
each of C operators? I knew those of Wirth's Pascal, but never those
of C: it was easier to use a lot of parentheses in C.

--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush

Tayssir John Gabbour

unread,
Aug 16, 2005, 8:36:39 PM8/16/05
to
Jon Harrop wrote:
> Additionally (pun intended), we were all taught operator precedences in
> conventional mathematics at a very young age. It seems at best odd and at
> worst stupid to disregard this.

I hope there's little disregarding or idiocy going on. Many Lisp users
use other languages regularly, so it's understandably hard for Lisp's
unusual syntax to be lost on them.

I recall that early programming languages were designed to save money
(increase programmer supply) by opening the door to less skilled
programmers. A natural way to attempt this is by offering them an
interface similar to what they've already encountered in school. Like
highschool math notation, for instance.

But what happens when we stray from highschool textbook Fibonacci
implementations? Some languages look great for solving Tower of Hanoi,
but not so enviable in other domains. This is why people look towards
"domain specific languages," and Lisp creeps into the conversation.

Now despite all this, Lisp DOES respect other traditions. Observe LOOP,
which is like every for(;;) loop in every language rolled into one.
Dirty and rewarding, the sort of thing which probably makes Haskellers
and MLers scream indignantly. Also, there are infix parsers and whatnot
floating around the net, for when conventional syntax is appropriate.


> > It seems likely to me that languages that require complex parsers are
> > harder for humans to understand as well.
>
> There is unquestionably a huge amount of evidence to the contrary. Most
> natural and programming languages have complicated grammars precisely
> because it simplifies their use and makes them easier to understand.

Would you please point us to evidence in this direction?


Jon Harrop wrote:
> Joe Marshall wrote:
> > Is readability simply a subjective measure, then? If so, and if
> > maintainability is about how easily a human can parse it, then
> > maintainability is also a subjective measure (and not particularly
> > interesting for comparing computer languages).
>
> Yes. Readability and maintainability are inherently subjective. However,
> they are both very important when comparing computer languages.

Writing honest language vs. language benchmarks is notoriously full of
landmines. Comparing readability sounds like its own Iraq.

Lisp is different, there's no question about that. It may be outflanked
in specific areas; and today's Common Lisp is simply one little
milestone in its evolution. Once, it was believed that an M-expression
syntax would replace the current S-expressions, but many liked sexps.
In the future, and given enough funding, we can wishfully predict human
interface improvements where IDEs project Lisp code in some
conventional way to the user, just as webpages don't look like HTML
markup.

Or perhaps sexps lead the way to a more sensible syntax than the weaker
one which mathematicians developed. Many claim that Newton's calculus
notation is less flexible than Leibniz's, and no doubt various number
systems have varying disadvantages. Perhaps Fermat's margin wouldn't
have been a problem if he had Lisp macros.


Tayssir

Jon Harrop

unread,
Aug 16, 2005, 9:24:32 PM8/16/05
to
Tayssir John Gabbour wrote:
> Jon Harrop wrote:
>> Additionally (pun intended), we were all taught operator precedences in
>> conventional mathematics at a very young age. It seems at best odd and at
>> worst stupid to disregard this.
>
> I hope there's little disregarding or idiocy going on. Many Lisp users
> use other languages regularly, so it's understandably hard for Lisp's
> unusual syntax to be lost on them.

Yes. This brings me to my next question: what other FPLs do Lispers know?

> Now despite all this, Lisp DOES respect other traditions. Observe LOOP,
> which is like every for(;;) loop in every language rolled into one.
> Dirty and rewarding, the sort of thing which probably makes Haskellers
> and MLers scream indignantly.

Not really. OCaml has (more restricted) for loops and both SML and OCaml can
implement customised for loops.

> Also, there are infix parsers and whatnot
> floating around the net, for when conventional syntax is appropriate.

I heard that infix parsers are rarely used not because infix is worse but
because infix is unusual in Lisp code and increases incompatibility. Would
you agree with that?

>> There is unquestionably a huge amount of evidence to the contrary. Most
>> natural and programming languages have complicated grammars precisely
>> because it simplifies their use and makes them easier to understand.
>
> Would you please point us to evidence in this direction?

Firstly, do you agree that languages are evolving to be more concise?
Secondly, do you agree that more concise languages tend to have more
complicated grammars? Finally, what other reason could drive this
association?

I believe that languages are evolving to be more concise and to have more
complicated grammars. I can see no reason for complicating grammars unless
it aids brevity/elegance/comprehensibility. So I see the evolution of
natural and programming languages as a huge amount of evidence that
complicated grammars are used to simplify the use of languages.

IMHO, humans are very good at deciphering expressions written in complicated
grammars, and this is why we make things easier for ourselves by
complicating grammars. In particular, we are better at understanding many
short expressions written in the context of a complicated grammar, rather
than many long expressions written with a very simple grammar.

>> Yes. Readability and maintainability are inherently subjective. However,
>> they are both very important when comparing computer languages.
>
> Writing honest language vs. language benchmarks is notoriously full of
> landmines. Comparing readability sounds like its own Iraq.

Yes, absolutely.

> Lisp is different, there's no question about that. It may be outflanked
> in specific areas; and today's Common Lisp is simply one little
> milestone in its evolution. Once, it was believed that an M-expression
> syntax would replace the current S-expressions, but many liked sexps.
> In the future, and given enough funding, we can wishfully predict human
> interface improvements where IDEs project Lisp code in some
> conventional way to the user, just as webpages don't look like HTML
> markup.

Several people have now mentioned IDEs and I think that is something that I
have ignored until now and should probably spend some time on...

> Or perhaps sexps lead the way to a more sensible syntax than the weaker
> one which mathematicians developed. Many claim that Newton's calculus
> notation is less flexible than Leibniz's, and no doubt various number
> systems have varying disadvantages. Perhaps Fermat's margin wouldn't
> have been a problem if he had Lisp macros.

:-)

Thomas A. Russ

unread,
Aug 16, 2005, 8:45:59 PM8/16/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

>
> Christophe Rhodes wrote:
> >> Consider the example:
> >>
> >> (defun fib (x)
> >> (if (<= x 2)
> >> 1
> >> (+ (fib (- x 2))(fib (1- x)))))
> >
> > This is not production-quality maintainable lisp code, because it
> > ignores the conventions that have developed and are supported by the
> > tools. However, if I take your mangled example, place it in a lisp
> > buffer and ask my editor to reformat it (C-M-q in emacs, for
> > instance), I get
> >
> > (defun fib (x)
> > (if (<= x 2)
> > 1
> > (+ (fib (- x 2))(fib (1- x)))))
> >
> > and the code obeys more of the conventions: it is much easier to read.
>
> Can I just clarify - the only difference is the constant indentation on the
> lines after defun? Unless I'm missing something, I can't see how this makes
> it much easier to read.

It actually does, because of convention. The alignment of the body of
the function is more "natural" to an experienced lisp programmer.

Seeing the function body closer to the left edge makes a difference,
precisely because one gets used to reading the whitespace/indentation
instead of counting the parentheses.

Actually, my preferred format for that example would use one additional
line:

(defun fib (x)
(if (<= x 2)
1
(+ (fib (- x 2))
(fib (1- x)))))

and thus more clearly allows quick identification of the two arguments
to the + function.


> Surely if your constructs require ((...)) then you must count brackets to
> ensure that there are two sets of nested brackets?

Only at the beginning. At the end, your Lisp-aware editor kindly
matches the parentheses for you. It is, in fact, the same with C-style
languages where you have all of those {} pairs to match up when you
combine loops, conditionals and function bodies. But in some ways it
gets a bit harder BECAUSE of the separate line convention, since it is
more likely that the matching part is off screen.

--
Thomas A. Russ, USC/Information Sciences Institute

Tayssir John Gabbour

unread,
Aug 16, 2005, 10:43:03 PM8/16/05
to
Jon Harrop wrote:

> Tayssir John Gabbour wrote:
> > Now despite all this, Lisp DOES respect other traditions. Observe LOOP,
> > which is like every for(;;) loop in every language rolled into one.
> > Dirty and rewarding, the sort of thing which probably makes Haskellers
> > and MLers scream indignantly.
>
> Not really. OCaml has (more restricted) for loops and both SML and OCaml can
> implement customised for loops.

If this is true, MLers may be more mature (or some might say twisted)
than many Lisp users, as LOOP is offensive to a percentage of Lisp
users for being "unlispy." Maybe too hedonistic. ;)

I think comparing LOOP to a for-loop is like comparing [insert apt
mountain vs. molehill comparison here]. I like it a lot though.


> > Also, there are infix parsers and whatnot
> > floating around the net, for when conventional syntax is appropriate.
>
> I heard that infix parsers are rarely used not because infix is worse but
> because infix is unusual in Lisp code and increases incompatibility. Would
> you agree with that?

Well, almost every domain-specific language is unusual. But Lisp
invites people to craft such languages when appropriate for readability
and maintenance.

For example, times and dates don't look "lispy" (8:34 at 8-2-2005, or
RFC 2445's 19980118T230000), but I have "read-macros" which allow me to
use this unusual syntax in sourcecode when performing datetime
calculations.

People shouldn't go nuts though. Any given paradigm has a sweet spot
past which it becomes increasingly questionable to push:
http://lisp.tech.coop/lisp-user-meeting-amsterdam-april-2004#macros-and-codewalkers


> >> There is unquestionably a huge amount of evidence to the contrary. Most
> >> natural and programming languages have complicated grammars precisely
> >> because it simplifies their use and makes them easier to understand.
> >
> > Would you please point us to evidence in this direction?
>
> Firstly, do you agree that languages are evolving to be more concise?
> Secondly, do you agree that more concise languages tend to have more
> complicated grammars? Finally, what other reason could drive this
> association?

I feel I'm expected to be in some role debating you (maybe a weird
spidey-sense left over from debate team), but I'm genuinely interested
in the evidence you mentioned. So I'm still curious what evidence there
exists, and don't feel suited to analytical debates.

That said, there are examples of languages designed both towards and
away from syntactic concision.

APL/J/K seem to beautifully use concision. If Alan Kay is to be
believed, one screen or so essentially holds short-term memory, and
concise languages certainly help here. (I hope I'm not butchering his
point.)
http://www.archive.org/details/AlanKeyD1987_2

On the other end of the scale, I recall natural languages are quite
verbose, relative to information content. Java is also quite verbose,
more than I like, but it seems to be very popular...

Lisp is a bit tricky to place on this spectrum, since it contains
uncommon abstraction tools like macros and whatnot. Many people (I
think convincingly) point out that many of Lisp's features don't make
much sense in small codebases; they spread their wings in large ones.
So there are different paths to judging concision.


Tayssir

M Jared Finder

unread,
Aug 17, 2005, 1:06:09 AM8/17/05
to
Pascal Bourguignon wrote:
> Jon Harrop <use...@jdh30.plus.com> writes:
>
>>Additionally (pun intended), we were all taught operator precedences in
>>conventional mathematics at a very young age. It seems at best odd and at
>>worst stupid to disregard this.
>
>
> In mathematics, there are two precedence levels ({+,-} vs. {*,/} (and
> even, division is usually written as an horizontal bar, that is
> essentially just a big parenthesis). In C there are 28 levels. Do you
> know a lot of C programmer who know the exact precendence levels of
> each of C operators? I knew those of Wirth's Pascal, but never those
> of C: it was easier to use a lot of parentheses in C.

C's precedence is easy! Just remember:

C's precedence does exactly what you want. Except when it doesn't.

(Especially with regard to a = b == c.)

-- MJF

Hartmann Schaffer

unread,
Aug 17, 2005, 1:13:45 AM8/17/05
to
Peter Seibel wrote:
> ...

> P.S. Which is not to say that the mental effort of dealing with
> precedence rules is overwhelming

i am not so sure about that. sure, as long as you have only a few
operators and only a few precedence levels, it's fine. but you only
have to look at typical C code to see that quite a few programmers feel
uncertain about C's precedence rules. you very often see unnecessary
parentheses. i am not quite sure whether it is because the writers feel
uncertain about the precedence rules or whether they fear that later
maintainers are overwhelmed

hs

M Jared Finder

unread,
Aug 17, 2005, 1:15:43 AM8/17/05
to
Jon Harrop wrote:

> Rob Thorpe wrote:
>
>>3. In a place (a fearful place :) ) that doesn't have emacs all is not
>>lost. If lisp can read the code it can print it. So, I can quote the
>>list with a quote mark*, and watch it:
>>
>>'((defun fib (x) (if (<= x 2) 1 (+ (fib (- x 2))(fib (1- x)))))
>>
>>It will then spit it back with whatever default formatting the lisp
>>printer uses for lists (there may also be an option for printing
>>functions in the printer). The formatting may not be very nice, but if
>>the code is truely hairy it will be more understandable than it was.
>>You can use this sort of this to do things like substituting sub-trees
>>in your code.
>
> Right, I saw that in Sussman's lecture (IIRC).
>
>>(* quote marks are one of the few true bits of syntax)

Not quite. Common Lisp has a feature called "reader macros" that allow
you to execute arbitrary parsing code when a specific character is hit.
Assuming I had some other way to give the Lisp environment syntax
trees, left parenthesis (, right parenthesis ), quote ', double-quote "
and nearly all other syntax could be defined in Lisp. See
SET-MACRO-CHARACTER.

The only thing that can't be defined is the core reader algorithm as
described in <http://www.lisp.org/HyperSpec/Body/sec_2-2.html>, which
parses symbols and numbers. Also possibly : and :: for naming symbols
in other packages.

> Yes, "#" and ";" seem to be others. I don't know what "#" does.

# is a dispatching macro character that executes different parsing code
depending on the next non-numeric character. See
SET-DISPATCH-MACRO-CHARACTER. Some dispatching macro characters are:

#( for reading arrays, as in #(1 2 3)
#\ for reading characters, as in #\a
#< for signaling an error, as in #<FUNCTION CAR>

>>4. It makes macros easier to understand since they act on trees.
>
> So you predict that Lisp macros are easier to understand than OCaml's
> macros?

Is this a fair comparison? Can OCaml's macros do the same things Lisp's
macros can do? All the Lisp looping operations can be implemented as
macros on top of if, tagbody, and goto. CLOS can be implemented
entirely in CLOS-free Lisp using macros and functions. I don't know of
any other language that has macros this powerful.

I can't imagine anyone having any more difficulty learning Lisp's DO
than they would learning C's for. Nor finding DEFUN or DEFSTRUCT or
DEFCLASS any more complicated than their equivalents in other languages.
I find IF a bit irritating because you have to just remember that the
first parameter is the test, the second is the "then" and the third is
the "otherwise", but it's easy enough to make your own macro that fixes
that:

(defmacro if+ (test &key then else)
(list 'if test then else))

Which can be used like this:

(if+ (string= str1 str2)
:then "equal"
:else "different")

>>All of the above describes benefits in automatic formatting, not
>>readability.
>>Some people find it readable, some don't. I personally don't find it
>>very easy or very difficult. There are a number of tricks to reading
>>it and writing it.
>
> I'm finding prefix notation readable but overly verbose. Counting
> parentheses is a real pain though. Assuming the Lisp advocates here also
> know conventional languages then there is plenty of evidence that one can
> learn to read Lisp.

Only for math or for all operations? It would be quite neat to have a
language that allowed me to say:

if( a collidesWith b ) then
bounce a offOf b

but would that be significantly better than the equivalent Lisp? I
don't think so.

I find it funny that people constantly want infix, but only for
mathematical operations. Even in the most mathematical intensive code I
wrote, a general CSG library, I found that very few operations I did
were supported by the built-in mathematical syntax.

However, if you feel you *must* have infix for some arbitrary set of
mathematical operations, you can always write your own parser in Lisp,
and then use macro characters to read it in. See
<http://www.cliki.net/infix> for one such parser.

>>The easiest way to find out is to delete all the closing parens at the
>>end with Emacs. You then replace them one by one, the cursor will
>>highlight the opening paren as this happens. You can then watch them
>>and check they go in the right places. Once you've finished closing
>>the parens on the line you're on, the rest should match on the lines
>>above to each left-most paren.
>
> Yes. That is almost exactly what I am doing.

Yuck. I suggest you find an editor that can auto indent Lisp code, like
Emacs can. It is so much easier to find mismatched braces when the code
is indented.


It's hard for me to describe what I enjoy so much about writing Lisp
code. The best I can say is that Lisp is the first language I've used
where every thing that should be simple to code up was actually simple
to code up. For sure, closures, macros, and a simple (but extendable)
syntax all help.

-- MJF

Pascal Bourguignon

unread,
Aug 17, 2005, 1:35:21 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:
> Firstly, do you agree that languages are evolving to be more concise?

No. Hebrew is more concise than English. Even Latin is more concise.

> Secondly, do you agree that more concise languages tend to have more
> complicated grammars?

Yes, somewhat.

> Finally, what other reason could drive this
> association?

Mu.

> I believe that languages are evolving to be more concise and to have more
> complicated grammars. I can see no reason for complicating grammars unless
> it aids brevity/elegance/comprehensibility. So I see the evolution of
> natural and programming languages as a huge amount of evidence that
> complicated grammars are used to simplify the use of languages.

If that was true, you'd still be speaking Latin, or even some older language.

$ wc <<EOF
Our Father, Who art in heaven,
Hallowed be Thy Name.
Thy Kingdom come.
Thy Will be done, on earth as it is in Heaven.
Give us this day our daily bread.
And forgive us our trespasses,
as we forgive those who trespass against us.
And lead us not into temptation,
but deliver us from evil. Amen.
EOF
9 56 294

$ wc <<EOF
Pater noster qui est in caelis,
sanctificetur nomen tuum;
adveniat regnum tuum;
fiat voluntas tua, sicut in caelo et in terra.
Panem nostrum cotidianum da nobis hodie,
et dimitte nobis debita nostra,
sicut et nos dimittimus debitoribus nostris;
et ne nos inducas in tentationem
Sed libera nos a malo. Amen
EOF
9 50 306


English seems to be 11% less concise than Latin (in word count; it
probably would be in character count too if it had a more phonetic
orthography). Let's switch to Latin!


> IMHO, humans are very good at deciphering expressions written in complicated
> grammars, and this is why we make things easier for ourselves by
> complicating grammars. In particular, we are better at understanding many
> short expressions written in the context of a complicated grammar, rather
> than many long expressions written with a very simple grammar.

I'm not so sure.

--
__Pascal Bourguignon__ http://www.informatimago.com/

-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d? s++:++ a+ C+++ UL++++ P--- L+++ E+++ W++ N+++ o-- K- w---
O- M++ V PS PE++ Y++ PGP t+ 5+ X++ R !tv b+++ DI++++ D++
G e+++ h+ r-- z?
------END GEEK CODE BLOCK------

Hartmann Schaffer

unread,
Aug 17, 2005, 1:39:15 AM8/17/05
to
Jon Harrop wrote:
> ...

> There is unquestionably a huge amount of evidence to the contrary.

i have my doubts

> Most
> natural and programming languages have complicated grammars precisely
> because it simplifies their use and makes them easier to understand.

if you believe chomsky, the human brain is hardwired for a certain style
of grammar (at least that's what i read somewhere), so natural languages
probably have a syntax that goes along with with this hardwiring. it
might be complicated to describe formally, but isn't for people's
everyday needs. if you go beyond that, things begin to look different.
the mathematical notation (also a kind of syntax) was developed
because natural language is woefully inadequate to describe mathematical
problems without support of a more concise notation

> Additionally (pun intended), we were all taught operator precedences in
> conventional mathematics at a very young age.

as far as i know, lukasiewicz invented the polish notation long before
computers were invented (according to wikipedia in 1920). i couldn't
fins anything about his motivation, but wouldn't be surprised that it
had something to do with problems with the conventional notation once
you begin to add operators and precedence levels

> It seems at best odd and at
> worst stupid to disregard this.

that would depend on whether the conventional notation approaches its
limitations or not

hs

ram...@bigpond.net.au

unread,
Aug 17, 2005, 2:18:20 AM8/17/05
to
Pascal Bourguignon <sp...@mouse-potato.com> writes:

> Jon Harrop <use...@jdh30.plus.com> writes:
> > Firstly, do you agree that languages are evolving to be more concise?
>
> No. Hebrew is more concise than English. Even Latin is more concise.

Right.
B: in
'a (ha if in isolation): the
cheder : room

Thus bacheder means "in the room"

ram...@bigpond.net.au

unread,
Aug 17, 2005, 2:24:46 AM8/17/05
to
> as far as i know, lukasiewicz invented the polish notation long before
> computers were invented (according to wikipedia in 1920). i couldn't
> fins anything about his motivation

He appears to have been working on multivalued logics and
wanted to avoid parentheses.

Christophe Rhodes

unread,
Aug 17, 2005, 2:37:32 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> Christophe Rhodes wrote:
>> Jon Harrop <use...@jdh30.plus.com> writes:
>> Did you read just the first half of my sentence? Human programmers do
>> not read the brackets, but instead read the indentation.
>
> If every bracket in Lisp were indented separately (i.e. on a separate line),
> as braces are typically in C/C++/Java then I would agree. However, they are
> not. In this case you have 12 brackets nested 3 levels deep on a single
> line, where indentation cannot help.

The line (+ (fib (- x 2)) (fib (1- x))) is approximately maximally
complex in terms of nesting: any more would definitely be frowned
upon, and indeed I would prefer to see


(+ (fib (- x 2))
(fib (1- x)))

even in such "simple" cases.

>> If you are counting or reading brackets manually when writing lisp
>> code, you are doing something wrong.
>
> Surely if your constructs require ((...)) then you must count brackets to
> ensure that there are two sets of nested brackets?

You must trivially count opening parens as you type them, yes. You
will never have to count closing parens: if you are composing this
code, your editor will tell you what paren you have just closed; if
you are editing this code later, the wrong number of closing parens
will announce itself by the indentation of the rest of the code being
wrong.

Christophe

Matthias Buelow

unread,
Aug 17, 2005, 4:10:25 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> wrote:

>(defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))
>

>In ML this is:
>let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)
>
>That may be easier to parse for the machine (I don't think it is though) but

>maintainability is about how easily a human can parse it.

Lisp simply trades in human readability for macros; you decide
whether it's worth it. Some people argue that s-exps are actually
more readable (well, I guess if you see nothing else for years or
even decades, that might actually be true at some time) whereas
others prefer to have compilers generate the parse trees for them.
However, you lose the power of macrology in the latter case. Then
again, while macros are certainly cool, I've never felt the need
for them when writing SML programs... I don't know why, but maybe
it's because the syntax is already there.

mkb.

Matthias Buelow

unread,
Aug 17, 2005, 4:14:26 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> wrote:

>Ok. Can you give an example of a time when emacs has to guess?

Have you never tried to use Emacs with C, C++, Standard ML, awk,
perl, sh, ksh, Pascal, or actually any language other than (Emacs-)
Lisp? It can be a rather frustrating experience, especially since
the editor insists on knowing better than you, and sometimes even
"correcting" indentation even if you don't hit TAB.

mkb.

Matthias Buelow

unread,
Aug 17, 2005, 4:29:06 AM8/17/05
to
Pascal Bourguignon <sp...@mouse-potato.com> wrote:

>In mathematics, there are two precedence levels ({+,-} vs. {*,/} (and
>even, division is usually written as an horizontal bar, that is
>essentially just a big parenthesis). In C there are 28 levels. Do you
>know a lot of C programmer who know the exact precendence levels of
>each of C operators? I knew those of Wirth's Pascal, but never those
>of C: it was easier to use a lot of parentheses in C.

Plus, part of the precedence is erratic, as even BWK admits. On
*BSD, theres an operator(7) manpage, which is very handy for cases
when you're puzzling about precedence.

mkb.

Jamie Border

unread,
Aug 17, 2005, 4:46:12 AM8/17/05
to

"Jon Harrop" <use...@jdh30.plus.com> wrote in message
news:43026f49$0$17486$ed2e...@ptn-nntp-reader04.plus.net...

> Jamie Border wrote:
>> How would you enforce formatting for your hypothetical LOC measurements?
>
> I would make no attempt to do so beyond disciplining myself to write in a
> natural style.
>
>> Compare:
>>
>> (defun foo (some-number)
>> (list (1- some-number)
>> some-number
>> (1+ some-number)))
>>
>> with something like:
>>
>> int* foo (int num) {int* temp = (int*)malloc(3 * sizeof(int); temp[0] =
>> num-1; temp[1] = num; temp[2] = num+1; return temp; }
>>
>>
>> Example 1 has 2 LOC. Example 2 has 1 LOC. Does this mean C 'wins' here?
>
> Yes, exactly. But the C isn't in my natural style.

My point exactly. Whose 'style' should be used for a LOC comparison?

I could format source equally badly for any other language, thereby fatally
skewing your analyses.

How do you seek to avoid this?


>
> The problem with Lisp and Scheme is that I am a total newbie and have no
> idea how Lisp code is normally formatted. C++ and OCaml I know. SML I
> thought I knew but had a big debate on c.l.functional about it. And I
> assumed that Java = C++ for formatting.
>
>>> Is Lisp code not made less maintainable because of all those brackets?
>>
>> No. It is *more* maintainable. I am new (a few months) to CL, and I can
>> fix my code faster* than with C (seven years).
>
> Sure. I am in the same situation with C++ and OCaml. But I want to know
> how
> ML and Lisp compare. Syntax is clearly one of the major differences
> between
> Lisp and ML.
>
>> Difficult to explain really, but I get a visceral sense of 'stack pop' as
>> I type the closing parens.
>
> Interesting. :-)
>
>> This is probably due to Emacs highlighting each open-paren that my typed
>> close-paren balances.
>
> Yep. That's a real life saver.
>
>> My thinking goes "erm-close-squre-bracket erm-close-paren erm-semicolon"
>> instead of "done-done-done"
>>
>> Of course, it would be absurd to suggest that C code is less maintainable
>> because of all that _syntax_... Wouldn't it? :-)
>
> No, not at all. Both sides of the argument have valid justifications,
> IMHO.

Indeed. I think probably this statement is the problem I have with the
'shootout'.

If your comparison was telling me:

* For low-level hardware access - ASM, C,...
* ...
* For high-level nondeterministic programming: Prolog,Lisp,...

I would probably be experiencing less friction.

Jamie Border

unread,
Aug 17, 2005, 4:48:47 AM8/17/05
to

"Greg Buchholz" <sleeping...@yahoo.com> wrote in message
news:1124236612.9...@f14g2000cwb.googlegroups.com...

> Jamie Border wrote:
>>int* foo (int num) {int* temp = (int*)malloc(3 * sizeof(int); temp[0] =
>>num-1; temp[1] = num; temp[2] = num+1; return temp; }
>
> Should be able to chop a few characters off of that...

Yes, but I was trying to lose in every way that matters (# tokens, #
characters, amount of syntax, etc), and win in the one way that makes no
odds (# LOC).

>
> int* foo(int n)
> {memcpy(malloc(3*sizeof(int)),(int[]){n-1,n,n+1},3*sizeof(int));}
>

That notwithstanding, the above is very neat :-)

Jamie


Jamie Border

unread,
Aug 17, 2005, 4:55:56 AM8/17/05
to

"Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message
news:HOuMe.1658$Dd....@newscontent-01.sprint.ca...
[snip]

JB>> Yes, and using a decent editor with auto-completion (Emacs) means that
I hit
JB>> less keys to produce the token 'DESTRUCTURING-BIND' ( DE-B <META-TAB> )
than
JB>> you might think.

[snip]

> i was considering pointing out that most lisp development environments
> have features that would reduce the amount of keystrokes required to type
> in the program, but decided against it because i suspect that that is
> harder to measure than a token count

It undoubtedly is, but I would find it _very_ interesting to compare the
following environments in this way:

Common Lisp + Emacs + SLIME
Java + Eclipse
C# + Visual Studio.NET
C++ + Visual Studio 6

Perhaps it is more-or-less meaningless to compare the language alone without
a good development tool?

For instance, although I could write C# in Notepad, I wouldn't want to.

Jamie

>
> hs


Jamie Border

unread,
Aug 17, 2005, 5:04:42 AM8/17/05
to

"Matthias Buelow" <m...@incubus.de> wrote in message
news:3mg9v2F...@news.dfncis.de...

Emacs knows better.

You, me and everybody else are *wrong*.

Resistance is futile.

Jamie


>
> mkb.


Jens Axel Søgaard

unread,
Aug 17, 2005, 5:14:17 AM8/17/05
to
Matthias Buelow wrote:

> Then
> again, while macros are certainly cool, I've never felt the need
> for them when writing SML programs... I don't know why, but maybe
> it's because the syntax is already there.

I missed them the other day. For each of the base types Int8.int,
Int16.int, Int32.int, Int64.int, Real32.real, Real64.real, Word8.word,
Word16.word, Word32.word, and Word64.word I had to for each of the
constructors ref, vector and array to define three functions
(one to register a, say, Int8.int vector with the garbage collector,
one to look up a previously registered vector/array/reference cell, and
one to unregister a root), which subsequently were to be exported by the
FFI. In total I needed to define and export 90 functions.

I bailed out and write a Scheme programme that generated the functions,
but if SML had macros that wouldn't have been neccessary.

--
Jens Axel Søgaard

Förster vom Silberwald

unread,
Aug 17, 2005, 5:32:03 AM8/17/05
to

Jon Harrop wrote:

> Consider the example:


>
> (defun fib (x)
> (if (<= x 2)
> 1
> (+ (fib (- x 2))(fib (1- x)))))
>
> In ML this is:
>
> let fib x = if x<=2 then 1 else fib(x-2) + fib(x-1)

The first one is easier to read.

I noticed in your code snippets (not only here) that you are sometimes
after very packed code structures. Your programming style of one-liners
is maybe good for writing down quickly code in an afternoon. However,
are you sure that one liners are predistend for re-using code in the
long run?

Schneewittchen

Förster vom Silberwald

unread,
Aug 17, 2005, 5:35:28 AM8/17/05
to

Jon Harrop wrote:

> Surely if your constructs require ((...)) then you must count brackets to
> ensure that there are two sets of nested brackets?

Even when I was a beginner in Scheme I never counted
parentheses/brackets. Let me kindly ask: why the hell do you want to
count brackets? Heh? Emacs or your favorite Lisp/Scheme editor does
your work for you when formatting and indenting.

Schneewittchen

Förster vom Silberwald

unread,
Aug 17, 2005, 5:44:49 AM8/17/05
to

Jon Harrop wrote:

> For example, nobody in their right mind would consider writing production
> code in Whitespace or Brainf*** because they are clearly less readable and
> maintainable, even though it is subjective. That is a clear-cut case, but
> with Lisp vs ML it is not so simple, IMHO.

That is not true if we are not talking at cross points. The Clean
langauge uses whitespace-formatting (it resembles a lot Python).
However, I felt never impeded by the Clean language as opposed to
Python. The Clean language had one of the best syntax I know of.

Schneewittchen

Alain Picard

unread,
Aug 17, 2005, 5:47:43 AM8/17/05
to
Matthias Buelow <m...@incubus.de> writes:

> Lisp simply trades in human readability for macros;

Readability is a function of expertise. This is true
in all languages, computer or human languages.

Lisp is, quite honestly, by FAR the most readable
computer language I have ever worked with. Interestingly
enough, the next most readable language is probably FORTH.
Maybe I just owned an HP calculator too early in my life...


Matthias Buelow

unread,
Aug 17, 2005, 5:49:11 AM8/17/05
to
Jamie Border <ja...@jborder.com> wrote:

>Resistance is futile.

M-x we-are-the-borg

mkb.

Förster vom Silberwald

unread,
Aug 17, 2005, 5:52:51 AM8/17/05
to

Jon Harrop wrote:

> Firstly, do you agree that languages are evolving to be more concise?
> Secondly, do you agree that more concise languages tend to have more
> complicated grammars? Finally, what other reason could drive this
> association?
>
> I believe that languages are evolving to be more concise and to have more
> complicated grammars. I can see no reason for complicating grammars unless
> it aids brevity/elegance/comprehensibility. So I see the evolution of
> natural and programming languages as a huge amount of evidence that
> complicated grammars are used to simplify the use of languages.
>
> IMHO, humans are very good at deciphering expressions written in complicated
> grammars, and this is why we make things easier for ourselves by
> complicating grammars. In particular, we are better at understanding many
> short expressions written in the context of a complicated grammar, rather
> than many long expressions written with a very simple grammar.

If you are speaking of OCaml I guess. What was your biggest program in
concise OCaml code you have ever completed?

I for myself write only short programs (a few thousand lines of code in
Scheme/Bigloo) since I am in academia.

But I am not convinced that OCaml will shine when you have to cope with
100000 lines of Ocaml code.

May short expressions and one liners are good for writing small
programs and benchmarks and algorithms. However, what are they good for
in really big projects. How easy is it to adapt one-liners and short
expressions? I mean what will you do your whole structure of program
has changed?

Schneewittchen

Jamie Border

unread,
Aug 17, 2005, 5:54:31 AM8/17/05
to

"Matthias Buelow" <m...@incubus.de> wrote in message
news:3mg9v2F...@news.dfncis.de...

You *can* customise a lot of Emacs' indentation behaviour, though:

http://www.cs.utah.edu/dept/old/texinfo/emacs18/emacs_25.html#SEC150

>
> mkb.


Matthias Buelow

unread,
Aug 17, 2005, 6:20:42 AM8/17/05
to

I know.. that doesn't help much. The problem is that Emacs tries
to infer syntactical structure of the source text without actually
parsing it but instead relies on voodoo heuristics combined with
regular expressions on how to do it. Which, as often as not, fails
miserably. "Modern IDEs" (Eclipse afa I have heard, I've never
used it) contain actual incremental parsers that do a much better
job at understanding the syntax, and hence, provide better results.
However, I personally am deeply suspicious of an editor that tries
to "understand" what I'm typing in. I've never seen it work properly,
and even if it works ok most of the time for some language, it
breaks as soon as the syntax is extended (for example, if I use
some preprocessor on it first), if several languages are mixed
within one file, or if the source is unfinished or deliberately
ungrammatical, or if I simply am using a different style than what
the editor prefers. That whole indentation stuff is probably an
outgrowth of the hey-deys of AI at where Emacs was written (MIT),
where people thought that with simple means they could create
"intelligent" software (DWIM-style). Whereas I personally don't
like "intelligent" software that's making (sometimes invalid)
assumptions but instead prefer dumb programs that do exactly what
they're told. Language-sensitive indenting should work by hinting
the user (for example, providing commands to move the cursor to a
certain level that coincides with opening parentheses or so) but
never to guess by itself how the text ought to be formatted (and
even worse, more or less force the user into this scheme by
"correcting" the given indentation. A program, especially one for
creating stuff, should be designed according to the dictum that the
user is always right and always knows better, and not the other way
round.

mkb.

Rob Thorpe

unread,
Aug 17, 2005, 6:23:27 AM8/17/05
to

Emacs will indent if you press tab or at the end of a line.
If you don't like the way it does it you have to customize it. It's
not different from many other syntax sensitive editors in this regard.

Rob Thorpe

unread,
Aug 17, 2005, 8:14:02 AM8/17/05
to
Pascal Bourguignon wrote:
> Jon Harrop <use...@jdh30.plus.com> writes:
> > Additionally (pun intended), we were all taught operator precedences in
> > conventional mathematics at a very young age. It seems at best odd and at

> > worst stupid to disregard this.
>
> In mathematics, there are two precedence levels ({+,-} vs. {*,/} (and
> even, division is usually written as an horizontal bar, that is
> essentially just a big parenthesis). In C there are 28 levels. Do you
> know a lot of C programmer who know the exact precendence levels of
> each of C operators? I knew those of Wirth's Pascal, but never those
> of C: it was easier to use a lot of parentheses in C.

For all normal intents and purposes there are 20 levels of precedence
in C. C programs only use some of them to make their code
understandable. But the situation is still far from ideal.

Regarding teaching precedence in School. If I was taught it I don't
remember it. I learnt it in the first year of my degree from the shop
assistant selling me a graphical calculator.

Rob Thorpe

unread,
Aug 17, 2005, 8:48:23 AM8/17/05
to
Jon Harrop wrote:
> Rob Thorpe wrote:
> > Firstly, at the language level, since everything - data and code - is
> > represented as above the language becomes more amenable to automatic
> > operations.
>
> Yes. But is that related to the grammar?

It could be done with a different grammar, yes, though it may be
slightly more difficult. But it's very obvious when done with the
grammar of lisp, because a human can predict the behaviour of the
automatic operations mentally.

> > Some examples:-
> >
> > 1. If I load my buggy version of your raytracer into lisp and do:
> >
> > (setq foo (ray-sphere ray sph))
> >
> > foo now contains a huge tree. Should I want this tree in the future
> > (for more debugging f.e.g) I can print it to a file with print, then
> > later read it back with read.
>
> That's cool. I guess the nearest in OCaml is to use the compiler's lexer and
> parser to input the code and then marshall it to disc. Not very elegant...

It's quite useful, it can eliminate the need for data-file
parsers/lexers sometimes.

> > 2. Emacs does not have to guess things about lisp. With other
> > languages it occasionally has to guess, because it cannot understand
> > the syntax in reasonable time. When it tells you all the parens match,
> > they match.


>
> Ok. Can you give an example of a time when emacs has to guess?

Things like s%regex%regex% in Perl are one example, lots of syntax
highlighters get them wrong. In general any situation where the syntax
of the language masks or buries parens or brackets. Syntax recognition
programs make all kinds of hidden assumptions about code, such as
assuming that the indentation is locally correct when adding more.

> > 3. In a place (a fearful place :) ) that doesn't have emacs all is not
> > lost. If lisp can read the code it can print it. So, I can quote the
> > list with a quote mark*, and watch it:
> >
> > '((defun fib (x) (if (<= x 2) 1 (+ (fib (- x 2))(fib (1- x)))))
> >
> > It will then spit it back with whatever default formatting the lisp
> > printer uses for lists (there may also be an option for printing
> > functions in the printer). The formatting may not be very nice, but if
> > the code is truely hairy it will be more understandable than it was.
> > You can use this sort of this to do things like substituting sub-trees
> > in your code.
>
> Right, I saw that in Sussman's lecture (IIRC).
>
> > (* quote marks are one of the few true bits of syntax)
>

> Yes, "#" and ";" seem to be others. I don't know what "#" does.

The most common syntax is:
"." - pair
"'" - quote
"#'" - function call
"#" - make simple-vector
"#S" - structure

There are several more not often used. These are all reader-macros.
I describe "read" as though it is simple, because for most purposes of
understand it is. But underneath it's rather complicated, see
http://www.lisp.org/HyperSpec/Body/sec_2-2.html if you're interested.
Complex reader macro aren't that commonly used thankfully.

> > 4. It makes macros easier to understand since they act on trees.
>
> So you predict that Lisp macros are easier to understand than OCaml's
> macros?

No, I wasn't predicting anything.
I was just say that it's easy to understand what is does because the
text is a tree itself. I'll have a look at ML macros.

> > All of the above describes benefits in automatic formatting, not
> > readability.
> > Some people find it readable, some don't. I personally don't find it
> > very easy or very difficult. There are a number of tricks to reading
> > it and writing it.
>
> I'm finding prefix notation readable but overly verbose. Counting
> parentheses is a real pain though. Assuming the Lisp advocates here also
> know conventional languages then there is plenty of evidence that one can
> learn to read Lisp.

Lots of indentation is needed, that's most of what makes it more
verbose.
Also, in Common lisp, the fact that the function names are so long.

> > The easiest way to find out is to delete all the closing parens at the
> > end with Emacs. You then replace them one by one, the cursor will
> > highlight the opening paren as this happens. You can then watch them
> > and check they go in the right places. Once you've finished closing
> > the parens on the line you're on, the rest should match on the lines
> > above to each left-most paren.
>
> Yes. That is almost exactly what I am doing.

As far as I know that's the main trick to it, that and knowing how many
parens certain constructs start with, for example
(let ((<- two parens
(defun (<- one paren
(labels ((<- two parens

There are probably other tricks old lispers know.

> > It also means errors can't leak syntactically: the error is in one
> > form. They can certainly leak semantically though.
>
> Yes. I think that the majority of the errors I get in other languages are
> already semantic though.

Me too, it doesn't gain you much.

Joe Marshall

unread,
Aug 17, 2005, 9:48:23 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> I'm finding prefix notation readable but overly verbose.

Huh? Infix notation generally allows only two arguments to an
operator.

a + b + c + d + e

vs.

(+ a b c d e)

Tayssir John Gabbour

unread,
Aug 17, 2005, 10:09:43 AM8/17/05
to

Aren't most languages prefix anyway? Most of their function calls are
like:

f(x,y,z)

instead of the similar

(f x y z)


Incidentally, I think there are also syntaxes hidden in plain view, in
Lisp. Numbers have unlispy syntax, for example.

And we could probably simplify Lisp's syntax even further -- for
example, only having special operators in the first position, so
someone would have to use FUNCALL or MACROCALL if they wanted functions
and macros, respectively. (I wonder if that makes sense...)


Tayssir
--
http://www.zmag.org/znetaudio.html

Jon Harrop

unread,
Aug 17, 2005, 10:08:03 AM8/17/05
to
Förster vom Silberwald wrote:

> Jon Harrop wrote:
>> IMHO, humans are very good at deciphering expressions written in
>> complicated grammars, and this is why we make things easier for ourselves
>> by complicating grammars. In particular, we are better at understanding
>> many short expressions written in the context of a complicated grammar,
>> rather than many long expressions written with a very simple grammar.
>
> If you are speaking of OCaml I guess.

No, I meant in general.

> What was your biggest program in concise OCaml code you have ever
> completed?

I'm still working on one that is ~20kLOC. That was originally written in C++
but the C++ version became too difficult to maintain. Even with the benefit
of hindsight, I do not know of any better way that I could have structured
the C++ program in order to make it maintainable.

> I for myself write only short programs (a few thousand lines of code in
> Scheme/Bigloo) since I am in academia.

Yes, most of my programs are probably ~2kLOC. For my PhD (in computational
physics), I wrote 1-10kLOC programs in C++. If I were to do it again, I
would write much smaller programs in OCaml to save time.

> But I am not convinced that OCaml will shine when you have to cope with
> 100000 lines of Ocaml code.

I think the OCaml compilers themselves are the first evidence to the
contrary. There are probably many other OCaml programs that exceed 100kLOC.
It won't be long before mine does and it is a high-performance graphics
application (i.e. not your typical FPL program).

> May short expressions and one liners are good for writing small
> programs and benchmarks and algorithms. However, what are they good for
> in really big projects. How easy is it to adapt one-liners and short
> expressions? I mean what will you do your whole structure of program
> has changed?

The main reasons that OCaml is more concise than C++, say, are type
inference for small programs and modules, functors and higher-order
functions for large programs.

Similar arguments apply more generally to OCaml/SML/Haskell/Clean/Lisp vs
C/C++/Java/C#. I believe that functional languages require asymptotically
less code thanks to the extra "dimension" of factoring allowed by HOFs. I'm
sure everyone here will agree... :-)

As for OCaml vs Lisp, I don't know Lisp well enough to comment. All I can
say is that I'm finding it really easy to maintain ~20kLOC OCaml programs.

Pascal Bourguignon

unread,
Aug 17, 2005, 10:26:24 AM8/17/05
to
Joe Marshall <j...@ccs.neu.edu> writes:

Mathematicians write it as:

∑ i
i in {a,b,c,d,e}

or:

4
∑ x_i
i=0


> vs.
>
> (+ a b c d e)

(defun ∑ (&rest args) (apply (function +) args))
(∑ a b c d e)

--
__Pascal Bourguignon__ http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.

Jon Harrop

unread,
Aug 17, 2005, 10:39:01 AM8/17/05
to

You mean "a+b+c+d+e", which is shorter. For slightly more complicated
expressions, the gap widens:

-a+b*c/d
(+ (- a) (* b (/ c d)))

Jon Harrop

unread,
Aug 17, 2005, 9:43:58 AM8/17/05
to
Jamie Border wrote:
> "Jon Harrop" <use...@jdh30.plus.com> wrote in message
> news:43026f49$0$17486$ed2e...@ptn-nntp-reader04.plus.net...
>> Yes, exactly. But the C isn't in my natural style.
>
> My point exactly. Whose 'style' should be used for a LOC comparison?

For my language comparison, my style.

> I could format source equally badly for any other language, thereby
> fatally skewing your analyses.

I would reformat it.

> How do you seek to avoid this?

Just common sense. I don't believe this can be significantly improved upon
so there is no point in over analysing it.

>>> Of course, it would be absurd to suggest that C code is less
>>> maintainable
>>> because of all that _syntax_... Wouldn't it? :-)
>>
>> No, not at all. Both sides of the argument have valid justifications,
>> IMHO.
>
> Indeed. I think probably this statement is the problem I have with the
> 'shootout'.

My main objection to the shootout is that most of the tests are trivially
reducible. So the optimisations performed by compilers has a huge effect on
performance but is mostly unrelated to the optimisation of real programs.

> If your comparison was telling me:
>
> * For low-level hardware access - ASM, C,...
> * ...
> * For high-level nondeterministic programming: Prolog,Lisp,...
>
> I would probably be experiencing less friction.

My language comparison really only looks at the middle of the clarity vs
performance trade-off in the context of non-trivial algorithms.

Jens Axel Søgaard

unread,
Aug 17, 2005, 10:58:26 AM8/17/05
to
Jon Harrop wrote:
> You mean "a+b+c+d+e", which is shorter. For slightly more complicated
> expressions, the gap widens:
>
> -a+b*c/d
> (+ (- a) (* b (/ c d)))

One can always cheat and use infix.cl which allows one to write e.g.

#I( x^^2 + y^^2 ) in stead of (+ (expt x 2) (expt y 2))

and

#I(if x<y<=z then f(x)=x^^2+y^^2 else f(x)=x^^2-y^^2)

in stead of

(IF (AND (< X Y) (<= Y Z))
(SETF (F X) (+ (EXPT X 2) (EXPT Y 2)))
(SETF (F X) (- (EXPT X 2) (EXPT Y 2))))

See

<http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/syntax/infix/infix.cl>

for a complete list of operators and their precedence.

--
Jens Axel Søgaard

ana...@earthlink.net

unread,
Aug 17, 2005, 10:58:57 AM8/17/05
to
> -a+b*c/d
> (+ (- a) (* b (/ c d)))

Of course, the spaces could be dropped from the second if the two
examples used the same definition of "variable name".

However, the ambiguity of the first remains. The amount of time and
money that such ambiguity costs dwarfs any savings.

Joe Marshall

unread,
Aug 17, 2005, 11:23:38 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> Joe Marshall wrote:
>> Is readability simply a subjective measure, then? If so, and if
>> maintainability is about how easily a human can parse it, then
>> maintainability is also a subjective measure (and not particularly
>> interesting for comparing computer languages).
>
> Yes. Readability and maintainability are inherently subjective. However,
> they are both very important when comparing computer languages.


>
> For example, nobody in their right mind would consider writing production
> code in Whitespace or Brainf*** because they are clearly less readable and
> maintainable, even though it is subjective. That is a clear-cut case, but
> with Lisp vs ML it is not so simple, IMHO.

I would point to Whitespace, Brainf***, Unlambda, Intercal, and
machine code as evidence that readability has an objective component.
Who could deny that `clear-screen' is more readable than `21 00 43 11
20 80 01 00 3D ED B0'

>> It seems likely to me that languages that require complex parsers are
>> harder for humans to understand as well.
>
> There is unquestionably a huge amount of evidence to the contrary. Most
> natural and programming languages have complicated grammars precisely
> because it simplifies their use and makes them easier to understand.

I disagree with your conclusion.

Most natural language have complicated grammars because it increases
the bandwidth and decreases the error rate in spoken communication.
Languages with very complex grammars (like Navajo) take much longer to
learn than those with simple grammars (like Esperanto). If the more
complicated grammar is simpler to use and easier to understand, then
the opposite should be the case.

Programming languages with complex grammars have proven quite
difficult to use and understand. Most computer languages have (more
or less) context-free grammars. Computer languages that are
context-sensitive turn out to be hard to understand and hard to use.
As an obvious example, consider C++. (Ed Willink gives these
examples.)

int(x), y, *const z;

int(x), y, new int;

int(x), y, z = 0;

The meaning of the `int(x)' subcomponent cannot be determined until
you parse the meaning of what is to the right of the y.

> Additionally (pun intended), we were all taught operator precedences in
> conventional mathematics at a very young age.

I think this is the root of the issue. Between standard algebraic
forms and the way computer languages have attempted to mimic them,
people get used to parsing these.

> It seems at best odd and at worst stupid to disregard this.

I don't disregard it, but there are *many* things we get taught at a
young age that are at best suboptimal and at worst wrong and
dangerous. It isn't considered odd to try to remedy this.

~jrm

Marco Antoniotti

unread,
Aug 17, 2005, 11:23:53 AM8/17/05
to

Matthias Buelow wrote:


> Jon Harrop <use...@jdh30.plus.com> wrote:
>
>
>>Ok. Can you give an example of a time when emacs has to guess?
>
>

> Have you never tried to use Emacs with C, C++, Standard ML, awk,
> perl, sh, ksh, Pascal, or actually any language other than (Emacs-)
> Lisp? It can be a rather frustrating experience, especially since
> the editor insists on knowing better than you, and sometimes even
> "correcting" indentation even if you don't hit TAB.

How do you dare?!? You, a mere mortal, pretend knowing how to indent
code? The Emacs God is throwing parentheses at you!

Cheers
--
Marco

jayessay

unread,
Aug 17, 2005, 11:34:29 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> Joe Marshall wrote:
> > Jon Harrop <use...@jdh30.plus.com> writes:
> >> I'm finding prefix notation readable but overly verbose.
> >
> > Huh? Infix notation generally allows only two arguments to an
> > operator.
> >
> > a + b + c + d + e
> >
> > vs.
> >
> > (+ a b c d e)
>
> You mean "a+b+c+d+e", which is shorter.

But actually more _verbose_.


> For slightly more complicated
> expressions, the gap widens:
>
> -a+b*c/d
> (+ (- a) (* b (/ c d)))

In _some_ contexts this can be true, which is why there is infix
available (as noted earlier).


/Jon

--
'j' - a n t h o n y at romeo/charley/november com

Marco Antoniotti

unread,
Aug 17, 2005, 11:27:25 AM8/17/05
to

Jon Harrop wrote:
> Joe Marshall wrote:
>
>>Jon Harrop <use...@jdh30.plus.com> writes:
>>
>>>I'm finding prefix notation readable but overly verbose.
>>
>>Huh? Infix notation generally allows only two arguments to an
>>operator.
>>
>> a + b + c + d + e
>>
>> vs.
>>
>> (+ a b c d e)
>
>
> You mean "a+b+c+d+e", which is shorter. For slightly more complicated
> expressions, the gap widens:
>
> -a+b*c/d
> (+ (- a) (* b (/ c d)))
>

Not using spaces in infix code is evil. Have you seen the GNU coding
guidelines?

Cheers
--
Marco

jayessay

unread,
Aug 17, 2005, 11:37:18 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:


> > If you are counting or reading brackets manually when writing lisp
> > code, you are doing something wrong.


>
> Surely if your constructs require ((...)) then you must count brackets to
> ensure that there are two sets of nested brackets?

Absolutely not. That is what the IDE/editor is doing for you. You
_never_ think about (let alone _count_) the parens.

Joe Marshall

unread,
Aug 17, 2005, 11:56:40 AM8/17/05
to
Jon Harrop <use...@jdh30.plus.com> writes:

> I heard that infix parsers are rarely used not because infix is worse but
> because infix is unusual in Lisp code and increases incompatibility. Would
> you agree with that?

Infix parsers are rarely used for several reasons. The increase in
incompatibility is one reason, but there are others:

Infix macros are *hard*.

You need to learn the prefix notation *anyway* (because code that
operates on code needs to operate at the abstract syntax level,
which in lisp is naturally prefix-notated lists).

Infix only works well on binary operations (consider the
popularity of ternary ? : operator).

>>> There is unquestionably a huge amount of evidence to the contrary. Most
>>> natural and programming languages have complicated grammars precisely
>>> because it simplifies their use and makes them easier to understand.
>>

>> Would you please point us to evidence in this direction?


>
> Firstly, do you agree that languages are evolving to be more concise?

No.

> Secondly, do you agree that more concise languages tend to have more
> complicated grammars?

Possibly. They may simply have larger vocabularies.

> Finally, what other reason could drive this association?

Languages drift. And as I mentioned before, bandwidth and error
correction are importand factors.

Joe Marshall

unread,
Aug 17, 2005, 12:13:32 PM8/17/05
to
Marco Antoniotti <mar...@cs.nyu.edu> writes:

From my grimoire:

(put 'multiple-value-bind 'scheme-indent-function 2)

(defconst jrm-c-style
(setq jrm-c-style
'((c-basic-offset . 4)
(c-comment-only-line-offset . (0 . 0))
(c-offsets-alist . ((block-close . c-lineup-whitesmith-in-block)
(defun-block-intro . *)
(inclass . *)
(inline-open . 0)
(namespace-open . 0)
(namespace-close . 0)
))
(c-hanging-braces-alist . ((substatement-open after) (block-open after)))
(c-echo-syntactic-information-p . t)))
"Jrm's C style.")


It is loading more messages.
0 new messages