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?
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.
Förster vom Silberwald <chain_l...@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 Sullivan wrote: > Förster vom Silberwald <chain_l...@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.
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.
robert.tho...@antenova.com wrote: > Raffael Cavallaro wrote: > > 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).
> 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.
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
(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)))
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...
"Rob Thorpe" <robert.tho...@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.
> "Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message > news:WqfMe.1588$Dd.6727@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).
^^^^^^^^^^^^ at least at the slime REPL anyway <oops>
> 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...
Jamie Border wrote: > "Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message > news:WqfMe.1588$Dd.6727@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?
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 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.
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.
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!
/Jon
-- 'j' - a n t h o n y at romeo/charley/november com
Jon Harrop wrote: > 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.
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.
In article <43021e94$0$97107$ed261...@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>
>> 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.tho...@antenova.com>
> Some people find it readable, some don't. I personally don't find it > very easy or very difficult. > Brian Downing <see-signat...@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.
Brian Downing wrote: > In article <43021e94$0$97107$ed261...@ptn-nntp-reader03.plus.net>, > Jon Harrop <use...@jdh30.plus.com> wrote: > > Consider the example:
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.
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.
> 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.
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.)
> Jamie Border wrote: >> "Hartmann Schaffer" <h...@hartmann.schaffernet> wrote in message >> news:WqfMe.1588$Dd.6727@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?
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.
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.
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.
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.
>> (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?