"Dorai Sitaram" <d...@goldshoe.gte.com> wrote in message news:ank5kf$gbq$1@news.gte.com... > BTW, I've only ever seen CL specials thrown up as the > sticking point. What, if any, are the others?
Another, for me, is what does it matter? I write my code, it runs whether it does tail-call-whatever or not. I should not have to be concerned if a function if tail-call-whatevered. When I use iteration I know everything is safe, but how do I know what the compiler has done unless I dissassemble the code? Will the compiler act the same from version to version, if I make a slight change, will it still do it? If write a large function, make 20-50 mods over a few day period, it will waste my time deciding.
Sure you can eventually define tail-call-whatever, but just because you can does not mean you should do it. Keep it simple.
* Tim Josling | It would indeeed be nice to have tail recursion guaranteed in specific | known circumstances, but maybe that's not reasonable.
The remaining question is who should pay for what you think "would be nice" and why. Not only implementation costs, but just like a world where you went to the food depot to pick up free food would have a different supply and kinds of food from a world where you have to pay for it, a world where tail recursion is costless would have consequences that you may not be aware of. Likewise, if you are used to them, but can no longer have them, what do you do? Squatting in front of your grocery store and demanding free food like you were used to won't cut it.
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
* Tim Josling | Why Erik misunderstood, I don't know. Perhaps I was not clear, perhaps his | English let him down, perhaps his apparent enthusiasm for seeing others as | 'untermensch' blinded him to what I said. Just to be clear here, I don't know | which of these is true, or even if any of these explanations are true.
I do not know if you are a child molestor, but if you were, it would explain some fairly odd things in your defensive behavior. Not that I claim that you are, of course, but it would just explain some things.
Let's see if you get the point this time. I kind of doubt it.
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
* Geoff Miller | I don't see how this adds to your posted contribution. It's rude | frankly. You could stand be a little more constructive.
In what edition of your etiquette standard is it /not/ rude to behave the way you do in public? You are a rude and unconstructive arrogant snot. If you really think you are constructive, then I was to begin with. OK?
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
* Dorai Sitaram wrote: > BTW, I've only ever seen CL specials thrown up as the > sticking point. What, if any, are the others?
UNWIND-PROTECT, CATCH / THROW, HANDLER-BIND / HANDLER-CASE. Many WITH-x constructs (which probably use UNWIND-PROTECT in their implementation). Probably some others.
> > BTW, I've only ever seen CL specials thrown up as the sticking > > point. What, if any, are the others?
> unwind-protect and catch, at least.
Here are the specific instances where CMUCL doesn't do tail-call merging. From the CMUCL users manual:
Tail Recursion Exceptions
Although Python is claimed to be "properly" tail-recursive, some might dispute this, since there are situations where tail recursion is inhibited:
* When the call is enclosed by a special binding, or
* When the call is enclosed by a `catch' or `unwind-protect', or
* When the call is enclosed by a `block' or `tagbody' and the block name or `go' tag has been closed over.
These dynamic extent binding forms inhibit tail recursion because they allocate stack space to represent the binding. Shallow-binding implementations of dynamic scoping also require cleanup code to be evaluated when the scope is exited.
CMU Lisp merges calls in the tail-call position, recursive or not, as part of what it calls its `local call' optimization. Local call is not as general as full lisp calls but much more efficient. It's used to implement block compilation, among other things.
-- Fred Gilham gil...@csl.sri.com "Come to me, all who labor and are heavy laden, and I will give you rest. Take my yoke upon you, and learn from me, for I am gentle and lowly in heart, and you will find rest for your souls. For my yoke is easy, and my burden is light." --Jesus of Nazareth
Tim Bradshaw <t...@cley.com> writes: > * Duane Rettig wrote:
> > Why does foo have to do anything? It would no longer even be on the > > stack! Why can't the mechanism that returns from a function see to > > it that bindstacks are kept consistent? I don't know the Lisp Machine > > architectures intimately, so I don't know if they ever had this > > capability, but I could easily envision such an architecture, and it > > could even be emulated in GP hardware. In short, if the unbinding > > of specials were part of the Lisp calling convention, then the above > > example would indeed describe a tail-position situation.
> It might in some annoying technical sense be in tail-position, but it > isn't in the useful sense that a recursion through this tail-position > call will not use up unbounded memory. The memory eaten will be > stored restorations of special variables, not stack, but who cares?
Right, and I would never offer to do such an implementation, but this continues to strengthen the whole point of my argument which has always been that it _is_ an optimization decision to exclude specials definitionally from tail position.
> I suppose that a very smart system might be able to keep a record of > whether the previous restoration was a `tail restoration' and if both > it and the current one are, then don't add a new one, since there is > no purpose in doing so. This test has to be done at runtime as far as > I can see, because you can't know statically who is calling you.
The bindstack we implement has depth, and the current depth is saved at various times, for example, it is one of the values saved in a catchframe before a catch is done, so that the process of throwing to that catch tag can know how far to unbind. I could envision (but only if it were mandated - I would probably never do something like this voluntarily) that the Lisp calling sequence would mandate storing the bindstack in the stack before every call, and then the return to that function would need to ensure that the bindstack is the proper size, and uunbind some number of bindings if not. Thus, if FOO calls BAR, which then binds *print-pretty* and then tail-jumps to BAS, then FOO will have saved the bindstack index (size) in its frame, and when when BAS returns, FOO's call cleanup (or some utility returning-routine) would have to unbind one special to get the bindstack to the right size.
> (I apologise for the somewhat made-up terminology in this article).
No problem; it is all theoretical, and the point is the possibility vs the practicality of such theory.
>> Yes, the call to `bar' is a tail call, unless I'm >> thoroughly misunderstanding what (declare >> (dynamic-extent ...)) does.
>dynamic-extent doesn't have anything to do with special >variables. It tells the compiler that it can allocate >the object(s) refered to by x on the stack instead of on >the heap. If the ... were, say, (list 10), then this list >could be stack allocated.
Thank you very much for the explanation. You have just taught me that (declare dynamic-extent) is a second problem area (after specials) for identifying tail-calls in CL.
I did thoroughly misunderstand the nature of dynamic-extent, and I think now that the call to (bar x) can't afford to be a tail call after all -- because the part of the stack representing the value of x can't afford to be erased until bar has returned.
There may be heroic or even easy ways out of this, which impl experts may be better positioned to tell about. An unheroic way I can think of is for the impl to prefer to make it a valid tail call and simply ignore the dynamic-extent decl, which (the ignoring part, I mean) I think is currently allowed for all declare's except (declare special).
Tim Josling <t...@melbpc.org.au> wrote in message <news:3D9CB65B.143C487E@melbpc.org.au>... > Erik Naggum wrote: > > None of us know Scheme at all, so thanks for this lecture.
> No, but some may not know scheme to the extent of knowing call/cc. Therefore I > included a brief description.
> I can't see any rational reason for objecting to that. I knew from experience > that some people object to having the obvious explained to them, so I put the > explanation in parentheses.
Right, so the readership's affinity for parentheses would counterbalance its hatred of lectures. I see!
> >> My reason is that the call to bar wouldn't be the last > >> thing that the enclosing call to foo does.
> >Why does foo have to do anything? It would no longer even be on the > >stack! Why can't the mechanism that returns from a function see to > >it that bindstacks are kept consistent? I don't know the Lisp Machine > >architectures intimately, so I don't know if they ever had this > >capability, but I could easily envision such an architecture, and it > >could even be emulated in GP hardware. In short, if the unbinding > >of specials were part of the Lisp calling convention, then the above > >example would indeed describe a tail-position situation.
> That would of course be all right. If specials were > indeed "neat" wrt the merging of tail-calls, then the > number of recursively definable iterative processes > effectively increases. Impls that do this would > still be conforming to a spec that didn't require it.
Correct. My whole argument is not about conformance to a spec, but instead how that spec was derived in the first place. Thus, whatever the spec requires, the user can count on. In Scheme, some tail calls can be counted on to be merged, but not all (by reason of performance, as above). In CL, the spec doesn't try to decide what kinds of tail calls should be optimizable, so that if someone suddenly discovers a way to optimize tail-calls in the presence of specials, or if they build a Lisp Machine that does so in hardware, that optimization would not go against the definitional notation that the language has given to what a tail-call is.
> At the same time, mandating this in a spec would > put at a disadvantage those impls that don't or can't > do this trick -- no doubt the motivation for folks to > have put forward the example (similar to the) above in > the first place -- and for other folks to realistically > fail such calls as tail-calls. Is tail-call merging > without keeping specials neat still of worth to the > user? I don't know. There may not be a definitive > answer.
Precisely my point! Although I would not word it as possibly not having a definitive answer; I would prefer to say that the pure definition of tail-call is too hard to implement, and so the places where tail-call-merging is done are and should be decided in an optimizational tradeoff, just as many good things are done in computing.
> BTW, I've only ever seen CL specials thrown up as the > sticking point. What, if any, are the others?
Binding of specials is certainly the most up-front and obvious. Others are:
1. Catches (including unwind-protects). A catch-frame is established and must be preserved for as long as the catch is active. Thus, in something like
(defun foo () (catch 'blarg (bas)))
the tail-call to bas cannot be optimized unless the 'blarg catchframe is saved, because all of the state saved in that catch must be restored (e.g. stack, bindstack, any callee-saves registers, etc)
2. Any stack allocations. This includes stack-allocated &rest arguments (i.e. a &rest with a dynamic-extent declaration), any conses or arrays that have been declared dynamic-extent and are allocated on the stack, and in the case of Allegro CL, we also stack-allocate flets/labels and/or their environments when they are determined or declared to be dynamic-extent. All of these must be evacuated in some way if a tail-call "optimization" is to be performed. (Obviously, we make the call _not_ to perform the merging, because the optimization tradeoffs are not good in most cases for stack-allocated objects.
3. Argument count. We like to track the standard calling convention of each architecture as much as possible; many times it saves a lot of headaches when dealing with debuggers and system exception-handlers. Some calling conventions specify a pre-allocated frame (many RISC architectures do this) where enough stack is allocated for the worst-case function call. For example, if FOO calls BAR with 1 argument, and BAS with 10 arguments, then enough stack is allocated when FOO is entered to call with 10 arguments. This static call-frame allows the stack pointer to be moved exactly twice in a function; once at the beginning to allocate the stack space, and once at the end to deallocate it. It is philosophically different than the CISC-based architectures, which have to carefully optimize all push/pop instructions in order to achieve decent performance (I muust say that Intel have done an impressive job, buut I digress...). Because the stack frames are pre-calculated, any tail-call to a function with more arguments than have been allocated would require extra work to set up the stack frame; this is especially cumbersome when some of the arguments passed are in the stack frame being reused/destroyed. Thus, in the example above, BAR could easily tail-jump to any function with up to 10 arguments and still reuse FOO's argument-space. But if BAR wants to call a function with 11 arguments, then some rearranging of FOO's argument space (FOO still being an active function) would be required and would carry with it some issues.
Sorry about this last one; I know of no way to describe it more simply.
> > BTW, I've only ever seen CL specials thrown up as the > > sticking point. What, if any, are the others? > 1. Catches (including unwind-protects). A catch-frame is established
I should mention that others have included GO tags that have been "closed over". I presume that this means that there is some runtime environment that needs to be adjusted between the GO and its tag location (otherwise the GO would want to turn into just a jump instruction). For such situations, we treat these tags as catch nodes (and their GOs as throws), even if later optimization is done on them. However, I should have mentioned these situations, which we regard as if they are catches, for the purposes of tail-call-optimization decisions.
In article <4zntunr95....@beta.franz.com>, Duane Rettig <du...@franz.com> wrote:
> 1. Catches (including unwind-protects). A catch-frame is established >and must be preserved for as long as the catch is active. Thus, >in something like
>(defun foo () > (catch 'blarg > (bas)))
>the tail-call to bas cannot be optimized unless the 'blarg catchframe >is saved, because all of the state saved in that catch must be restored >(e.g. stack, bindstack, any callee-saves registers, etc)
Thank you for the rest of your post also! Snipped only in the interest of OCR.
Re the above quoted part: If you will permit a small eyebrow raise here: I never would have considered the (bas) above a tail call (of foo). I can't even discern a potential ambiguity about it (as was the case with the specials and the dynamic-extent). Perhaps you are being a smidg too liberal in identifying tail calls?
d...@goldshoe.gte.com (Dorai Sitaram) writes: > In article <4zntunr95....@beta.franz.com>, > Duane Rettig <du...@franz.com> wrote: > > 1. Catches (including unwind-protects). A catch-frame is established > >and must be preserved for as long as the catch is active. Thus, > >in something like
> >(defun foo () > > (catch 'blarg > > (bas)))
> >the tail-call to bas cannot be optimized unless the 'blarg catchframe > >is saved, because all of the state saved in that catch must be restored > >(e.g. stack, bindstack, any callee-saves registers, etc)
> Thank you for the rest of your post also! > Snipped only in the interest of OCR.
You're welcome.
> Re the above quoted part: If you will permit a > small eyebrow raise here: I never would have considered > the (bas) above a tail call (of foo). I can't even > discern a potential ambiguity about it (as was the case > with the specials and the dynamic-extent). Perhaps you > are being a smidg too liberal in identifying tail > calls?
No. It's exactly the same situation. FOO has nothing more to do by the time it is calling BAR, and BAR's return value(s) is(are) FOO's return value(s). Any throw to 'blarg must be able to identify that catch, and that information must be saved somewhere (just as the special binding has to be saved somewhere, or a stack-alocated object must be saved somewhere). In all cases, the amount of storage required to save the extra information might be (and probably is) less than the storage required by FOO for its stack. So at the possibly perverse cost of huge amounts of code executed, some stack could be optimized. However, the perversity of the cost of this optimization does not remove the conceptual purity of the fact that this call is indeed in tail position.
I should, however, correct myself with respect to unwind-protects. Any unwind-protect that has non-null cleanup forms by definition cannot make a tail-call in its protected form (because the cleanup form must run afterwards, and thus there is more to do after the tail call candidate returns).
Tim Bradshaw <t...@cley.com> writes: > * Duane Rettig wrote:
> > Why does foo have to do anything? It would no longer even be on the > > stack! Why can't the mechanism that returns from a function see to > > it that bindstacks are kept consistent? I don't know the Lisp Machine > > architectures intimately, so I don't know if they ever had this > > capability, but I could easily envision such an architecture, and it > > could even be emulated in GP hardware. In short, if the unbinding > > of specials were part of the Lisp calling convention, then the above > > example would indeed describe a tail-position situation.
> It might in some annoying technical sense be in tail-position, but it > isn't in the useful sense that a recursion through this tail-position > call will not use up unbounded memory. The memory eaten will be > stored restorations of special variables, not stack, but who cares?
> I suppose that a very smart system might be able to keep a record of > whether the previous restoration was a `tail restoration' and if both > it and the current one are, then don't add a new one, since there is > no purpose in doing so. This test has to be done at runtime as far as > I can see, because you can't know statically who is calling you.
> (I apologise for the somewhat made-up terminology in this article).
Hmm. If you're designing a system where you really care about tail call merging, I don't see what's so crazy about being sure to reuse all stack frames (control and binding). If I were designing such a system, I'd have the value slot of symbols contain the value, a pointer to the value-frame to restore when this one is undone, and a pointer that the next frame should use for its restore pointer. That way, if you know you're setting up a "tail binding", you set the next-restoration pointer to the same frame as your resotration pointer.
-- /|_ .-----------------------. ,' .\ / | No to Imperialist war | ,--' _,' | Wage class war! | / / `-----------------------' ( -. | | ) | (`-. '--.) `. )----'
> Tim Josling wrote: > > "Jens Axel Søgaard" wrote:
> >> Erik Naggum wrote: > >>> * Tim Josling
> >>>> Three possibilities as to why call/cc is not in lisp > >>>> occur to me:
> >>>> 3. It can be implemented efficiently in scheme,
> > So in no sense was I 'ignoring' the possible inefficiency > > of call/cc in scheme.
> Then I must have misunderstood 3.
> -- > Jens Axel Søgaard
Possibility (3) posited that it can be done OK is scheme but not in lisp. (1) posited that it was not useful and (2) that it could not be implemented efficiently in lisp or scheme. So I provided 3 possibilities I had thought of, without necessarily saying one of the other was true or valid.
It was not (3) that you misunderstood but the overall context.
If you misunderstood it, that means I may not have explained it sufficiently clearly. Or perhaps this occurred because Erik only quoted a fragment of what I wrote.
Barry Margolin wrote: > In article <ey3n0pwsbo3....@cley.com>, Tim Bradshaw <t...@cley.com> wrote:
>>And I think your take on `the Lisp approach' is basically completely >>backward, at least as regards CL. The CL approach is to be pragmatic >>- implement what can be agreed on and what can be seen to be >>efficiently implementable and useful: don't implement stuff that >>suddenly opens huge questions about what everything means, or whether >>it can be implemented efficiently.
> I agree with Tim here. The CL philosophy is to provide a library of > high-level, proven facilities that are directly useful in applications, > like hash tables and sequence functions. The Scheme approach is to provide > basic mechanisms that can be used as building blocks for any programming > paradigm. Common Lisp was intended for industrial programming, while > Scheme was designed for academics. That doesn't mean they're only fitted > for those environments, but their general approaches are based on the needs > of those different types of uses.
I agree that what you say is roughly how the two camps have divided in a rather general way. But that certainly was not the intention.
I believe that Steele intended Scheme to be the bullet-proof base language for system implementors. Then all those CL libraries and funky language features would simply be a big toolbox of Scheme for any sort of "industrial" purpose.
This is illustrated clearly by this whole discussion of control structures in CL and how making any systematic changes is effectively impossible.
In contrast, Scheme has exactly the necessary set of control structures needed to implement *all* of CL's control structures *and* have nifty extras like call/cc and TCE.
"Jim White" <j...@pagesmiths.com> wrote in message news:3D9E32EF.2080705@pagesmiths.com... > I agree that what you say is roughly how the two camps have divided in a > rather general way. But that certainly was not the intention.
> I believe that Steele intended Scheme to be the bullet-proof base > language for system implementors. Then all those CL libraries and funky > language features would simply be a big toolbox of Scheme for any sort > of "industrial" purpose.
> This is illustrated clearly by this whole discussion of control > structures in CL and how making any systematic changes is effectively > impossible.
> In contrast, Scheme has exactly the necessary set of control structures > needed to implement *all* of CL's control structures *and* have nifty > extras like call/cc and TCE.
The way I see it is that the people on the Common Lisp side see the programmer as more important than the language and the Scheme side considers the language more important than the programmer.
CL has been accommodating of many programming styles and practical issues, while Scheme will not bend for anyone.
Jim White wrote: > In contrast, Scheme has exactly the necessary set of control structures > needed to implement *all* of CL's control structures *and* have nifty > extras like call/cc and TCE.
Sorry, I have been listening with only one ear, but I thought I read a few articles detailing how call/cc was incompatible with *all* of CL, ie, certain specific very cool features. I note you say "*all* of CL's /control structures/ [emphasis added]". Are we playing word games here?
>> In contrast, Scheme has exactly the necessary set of control >> structures needed to implement *all* of CL's control structures *and* >> have nifty extras like call/cc and TCE.
> Sorry, I have been listening with only one ear, but I thought I read a > few articles detailing how call/cc was incompatible with *all* of CL, > ie, certain specific very cool features. I note you say "*all* of CL's > /control structures/ [emphasis added]". Are we playing word games here?
No word games. I haven't read all the arguments about the problems with CL features either, but I feel reasonably confident in relying on Guy Steele's analysis as he is the author of both of the original specifications and that was his conclusion. Scheme arose as the answer of how to have a well defined semantics for what a system like CL does. Kent Pitman does quibble with the the current Scheme specification, but that is something else entirely.
One thing Kent mentions is that Scheme's model of concurrency has problems with parallel processors using shared memory. But that is inherent in the architecture. People continue to try and use threading and shared memory models for parallel processors, but there is no way to arrive at a useful and correct semantic model that way. The only model I'm aware of that can deal successfully with that type of implementation is message passing.
My solution is to use Kawa, the Java-based Scheme system. It is also being extended to implement Elisp and CL. Being based on Java and useful with all code for the JVM, integration with even the largest systems is easy and reliable. The grief with this approach is that continuations don't really work and the tragedy is that the JVM could have specified continuations (many JVM's actually have the necessary internal structure) instead of the usual ad-hoc threads model which lacks rigor and hence got largely deprecated (but essential for many systems).
While Java (as does CL) presently accepts not having a concurrency model that is well specified with respect to parallel processors and memory, eventually there will be such a specification for the JVM. It will be interesting to see how they solve the problem as people are going to want to continue using their familiar threads-and-memory code. Given that Java is a *very* "industrial" system and community, chances are they will work out a design that specifies the tricks a VM must do to meet that expectation (as opposed to taking an "academic" of using continuations and message passing).
Jim White wrote: > I haven't read all the arguments about the problems with CL features > either, but I feel reasonably confident in relying on Guy > Steele's analysis as he is the author of both of the original > specifications and that was his conclusion.
I would humbly suggest that you should do so as I am resonably confident that your confidence is misplaced.
> People continue to try and use threading and shared memory models for > parallel processors, but there is no way to arrive at a useful and > correct semantic model that way.
I disagree. Is this statement again based on some form of personal belief? Or could you provide some justification for this statement?
> Given that Java is a *very* "industrial" system and community, chances > are they will work out a design that specifies the tricks a VM must > do to meet that expectation...
We live in hope. However, my experience of "industrial" java systems has been that in the industrial context it is lacking. I again would hope that you are not confusing "industrial" with "popular."
>> I haven't read all the arguments about the problems with CL features >> either, but I feel reasonably confident in relying on Guy Steele's >> analysis as he is the author of both of the original specifications >> and that was his conclusion.
> I would humbly suggest that you should do so as I am resonably confident > that your confidence is misplaced.
Do you have any specific pointers? I've looked at all the messages in this thread, and they only refer to the problems of extending CL, and are not disputing the assertion that CL can be implemented in Scheme.
>> People continue to try and use threading and shared memory models for >> parallel processors, but there is no way to arrive at a useful and >> correct semantic model that way.
> I disagree. Is this statement again based on some form of personal > belief? Or could you provide some justification for this statement?
There is plenty of support for this view. No formal language correctness system has been developed that supports the semantics of threads-and-memory (with the attendant locking and cache coherency warranties) as used in systems like CL (or Java) on parallel processors and memory.
In contrast, message passing has been successful in exactly that application dating back more than twenty years (Thoth and subsequent proof systems for network communications) and is used directly in Mach kernels for this very reason.
>> Given that Java is a *very* "industrial" system and community, >> chances are they will work out a design that specifies the tricks a VM >> must >> do to meet that expectation...
> We live in hope. However, my experience of "industrial" java systems has > been that in the industrial context it is lacking. I again would hope > that you are not confusing "industrial" with "popular."
Well, the term "industrial" was used (not by me) to distinguish CL's ready-to-do-convenient-application-development-work character from Scheme implementations' tendency to be ala carte with respect to many of those features. Certainly Java is not lacking in comparison to CL in terms of its readiness or features for development of any application.
Java has even become the language for most RDF Schema-based (Semantic Web) knowledge engineering applications, an area in which Lisp (or other even less popular languages) used to be dominant.
And speaking of CL, Scheme, and Java, it is odd that (AFAIK) there is still no complete CL implementation for the JVM, even though there are several for Scheme. Although Kawa will probably get there one day, it seems that the advantages for those interested in developing and deploying CL applications would have made it a priority long before now.
>>>>> On Sun, 06 Oct 2002 02:47:55 GMT, Jim White ("Jim") writes:
Jim> Java has even become the language for most RDF Schema-based Jim> (Semantic Web) knowledge engineering applications, an area in Jim> which Lisp (or other even less popular languages) used to be Jim> dominant.
Are you saying that Lisp was widely used for the Semantic Web project, and then JAVA took over? I think it's more likely that Java was always the language widely used by most or all people to do that work. Lisp had already fallen from popularity more than a decade before that work was started, and Java was on the rise when it started.
Lisp certainly has a long history of being the language used for programming semantic networks, and is doubtless a better choice than Java in most or all respects. (But we're talking popularity contests here, not technical considerations.)
On Sun, 06 Oct 2002 02:47:55 GMT, Jim White <j...@pagesmiths.com> said:
[...] JW> And speaking of CL, Scheme, and Java, it is odd that (AFAIK) there is JW> still no complete CL implementation for the JVM, even though there are JW> several for Scheme. Although Kawa will probably get there one day, it JW> seems that the advantages for those interested in developing and JW> deploying CL applications would have made it a priority long before now.
I guess not. I don't have a complete descriptions of all reasons why, but one technical reason I can see is this. If I implement (Common) Lisp in Java, I would want^1 to use the JVM's garbage collector to collect Lisp objects, including cons cells. This practically requires that cons cells be represented as instances of a Java class (with, say, two instance variables for the car and the cdr), which on its turn would IMO make consing too expensive. Arithmetic would be slower, too, because all integers would have to be boxed, and even if some (say, -1023 to 1024) are `interned' to decrease the amount of fixnum consing, this would help only so much. _________ ^1 probably; there might be sophisticated reasons why a Java implementation of Common Lisp cannot actually make use of the JVM's garbage collector
---Vassil.
-- Garbage collection is charged at 0.19e-9 cents a cons. Bulk rates are also available: please contact memory management for details.