Message from discussion Lisp vs. Java vs. C++ speed comparison time? [LONG]
From: Antonio Menezes Leitao <Antonio.Lei...@evaluator.pt>
Subject: Re: Lisp vs. Java vs. C++ speed comparison time? [LONG]
Date: Sat, 03 Jul 2004 14:03:25 +0100
References: <firstname.lastname@example.org> <email@example.com>
Content-Type: text/plain; charset=iso-8859-1
X-Trace: news.uni-berlin.de /lDUfAFDLZGtSrRhNTKCBg3CcRKAs9opIPvOZAVtV3acBslkiC
User-Agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)
Pascal Costanza <costa...@web.de> writes:
> Antonio Menezes Leitao wrote:
>> I know about thread-locals. I even have some ideas about introducing
>> syntax in Linj just to deal with thread-locals. However, the problem
>> regarding dynamic scope is a bit different as Common Lisp doesn't even
>> define the semantics of dynamic scope in the presence of different
>> threads of execution. I know that there's a kind of agreement about
>> what should be done in this case but, IMHO, being a thread-local
>> variable and being a dynamically scoped variable are two different
>> concepts. You might want one or the other or both.
> Well, I think that new bindings of special variables shouldn't affect
> other threads, and that this is clearly the right thing. I don't see
> how affecting other threads randomly would yield useful
> behavior. (This means that I don't think that this is just some kind
> of accidental agreement.)
It might not yield useful behavior but automatically making all
special variables also thread-local might give you bad performance.
Sometimes you want dynamic behavior that you know that doesn't cause
problems with threads. In this case, you might not want to pay the
price for something that you don't use. It is good have the choice.
This is also the perfect example of the situation that occurred in the
RICHARDS benchmark. Juho Snellman profiled it in SBCL and discovered
that the bootleneck was accessing the special variables that happen to
be there just because they needed globally scoped variables. It would
be better if we could distinguish (as you suggested with ISLISP)
between the different uses of defvar/defparameter.
>>>The straightforward way to implement special variables would be to
>>>store a List in a ThreadLocal, and to push a new value for each
>>>dynamic scope to that list.
>> In my experience, being straighforward to implement usually means
>> the generate code that doesn't look like it was written by a human
> Have you tried this with thread locals? I think they are readable,
> especially in the generically-typed variant.
>> We must not forget that Linj's goal is to produce readable Java code.
>> If you are not concerned about readability, then there are lots of
>> things that you can implement but, in this case, I would recomend
>> something that compiles directly to JVM such as ArmedBear Lisp.
> Sure, I understand your concerns, and I am thinking about your
> questions especially from that perspective. I have seen (prominent!)
> Java code in which dynamic scoping was simulated in a very cumbersome
> way. (Actually, it's the Java compiler provided by Sun.) I think
> expressing these things with thread locals would be much more readable.
>> I did look at ISLISP when I was thinking about Linj. In the
>> beginning, Linj was modeled as a mixture between Scheme and Java but,
>> although I like Scheme a lot, I became convinced that the real benefit
>> was on those nice Common Lisp features that might not be theoretically
>> essential but that are pragmatically fundamental: lambda lists,
>> macros, method combination, etc. I could invent new syntax for all
>> this stuff but what's the point? These concepts have been distilled
>> for a very long time and are perfectly expressed in Common Lisp. In
>> the end, I decided to make Linj look like Common Lisp as much as I
>> could, even though I would have to assign different semantics to some
>> things. Whenever I changed the semantics of some form (as in the
>> defvar/defparameter case), I tried that the new semantics would cover
>> its pragmatical use in Common Lisp.
> Well, I think you have made the wrong choice here, and the fact that
> you are using fluid-let for dynamically-scoped variables is an
> indication that you are still too much of a Schemer. ;)
As paradoxically as it might seem to you, before I learned Scheme I
was both a FranzLisp programmer and an EmacsLisp programmer.
Franzlisp is a dynamically scoped language (unless you compiled your
programs) just like EmacsLisp so I was quite used to
dynamically-scoped variables without ever using fluid-let.
The rational for introducing fluid-let in Linj was precisely for the
programmer to understand that a fluid-let is completely different from
a let and that it generates completely different Java code. A
fluid-let in your program is a sign that the Java code doesn't look
nice. If I just decide to amalgamate fluid-let with the normal let,
the programmer wouldn't get this feedback.
I could have chosen a different name (e.g., dynamic-let or
with-temporary-value or whatever) but I have the feeling that the
large majority of Common Lispers also happen to know a bit of Scheme
so it seemed simpler to use an already known form than to use
something from a lesser-known language or to invent something new.
> I think it's better to go all the way either in the direction of
> Scheme or in the direction of Common Lisp, but not stop somewhere in
> between, because then you are creating unnecessary problems. The
> example of global variables is likely to create problems when people
> choose to port existing Lisp code to Linj, and these would be
> gratuitous problems.
I think that, with the requirement of readable Java code generation,
you can't go all the way in either direction. Of course, if you drop
this requirement and accept a different one such as targeting
unreadable Java code or even targeting Java bytecode, then you don't
need Linj at all and you should be using Kawa (or Bigloo) or Armed
Bear Lisp, depending on the direction you want to go.
Anyway, I don't think that Linj is in-between Common Lisp or Scheme.
The fluid-let is the only form (as far as I remember) that Linj took
from Scheme. And I took it from Scheme because there was nothing
similar (I mean, with the requirement of being syntactically different
from a let) that I could use from Common Lisp.
Moreover, Linj was not made to allow porting existing Lisp code. It
might be used for that purpose and I might decide to change Linj in
order to simplify that task (I had to make a few changes in Linj to
allow easier translation of the boyer and richard benchmarks). Its
main purpose, however, is to allow one to use the huge Java APIs with
a Lisp flavor.
> ISLISP is a Lisp dialect that Kent Pitman has described as culturally
> compatible to Common Lisp, i.e. it is much closer to Common Lisp than
> to Scheme in spirit (being a Lisp-2, using essentially a subset of
> CLOS, and so on). IIUC, it was designed so that ISLISP programs can be
> relatively easily ported to Common Lisp. The only thing that I am
> suggesting is to use ISLISP's defglobal for lexically scoped globals
> and defdynamic for dynamically scoped globals. The effect would be
> that someone whose goal is just to create readable Java programs would
> use defglobal, someone who wants to use dynamic scoping would use
> defdynamic (and because of dynamic-let for binding and dynamic for
> lookup, you wouldn't have a hard time to detect those cases in your
> compiler, just as is the case for fluid-let), and using defvar and
> defparameter with possibly surprising results wouldn't be possible.
I agree with you that you might get strange errors due to the
different semantics between Common Lisp's defvar and Linj's defvar.
And, to be honest, I must say that in the beginning, Linj didn't have
defvar or defparameter or defconstant but a few other forms named
defshared and defconst (I didn't pick them from Scheme :-). Then, to
simplify the translation to Linj of all those Common Lisp programs
that were using defvar or defparameter just to define global
variables, I decided to introduce macros that would translate those
forms to defshared. The other option would have been to change the
original Common Lisp forms but I was (am) too lazy.
> It's all about just using different names, that's all.
But that's not so simple. I agree with you that theoretically it
would be better to have different names for different concepts but
this would make it impossible to translate even the simplest Common
Lisp program to Linj as there's nothing in Linj that has the exact
same semantics as in Common Lisp. You have to make compromises and I
think that most of the compromises done in Linj reflect the common use
of the forms in Common Lisp. The same thing happens in other
contexts. If you look, e.g., at the Common Lisp compatibility package
for EmacsLisp, you will see that there are some fundamental elements
(e.g., the let) that have completely different semantics. In most
cases, it will not cause you any problems but there will always be
situations where you will have to change your Common Lisp code (and
use the lexical-let or whatever different name they introduced) in
order for it to run in EmacsLisp the same way it did in Common Lisp.
As Kent Pitman once said, there are no solutions, just compromises.