[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: lexical mumblings

From: Miles Bader
Subject: Re: lexical mumblings
Date: 31 Oct 2001 08:44:06 +0900

Andrew Innes <address@hidden> writes:
> (BTW, I would recommend expanding Bstack_ref and Bstack_set to a set of
> 8 opcodes each, mirroring Bvarref and Bvarset - use the opcode ranges I
> chose for Blocalref/set in my version.)

I didn't think very hard about it, so I'm not sure if that's always
going to be worth the extra byte-op space used -- i.e., will many
commonly used variables be the first things pushed on the stack?

Well, actually since the args are the first thing on the stack using my
scheme, maybe it is worth it.  In any case, the _first_ stack position
(0) will hold the parent environment pointer for closure invocations
(since the environment is pushed as a magic first arg), so that's
probably a win.

> Okay, the answer to that is pretty obvious - you could make another
> vector (again once for each iteration of the loop) which then holds the
> other two vectors.  The closures would then dereference through two
> vectors to get to the actual bindings of `base' and `value'.

You got it.  Also, the byte compiler can optionally `unroll' this chain
(well, actually tree, I guess, but probably almost always a simple list)
into the stack when the inner function gets invoked, so that references
only take two steps (stack,vector) no matter how deep the function is

> Also, I took pains in my approach to make closures only include
> references to the specific variables they need, and not entire
> environment blocks.  This is part of the general principle of being
> "safe for space-complexity" in garbage collection terms - ie. not
> holding on to unneeded references that may live much longer than
> expected (and which are inaccessible to the programmer).  I believe this
> is a fairly important principle to follow.

This is a good principle, but I think it can be handled adequately by
the compiler, especially since most places that create closures won't
create lots of different kinds of closures, but just one kind.  E.g.,
the compiler can easily tell that in 

  (let (a b c d e f)
    (lambda (x) (+ x d)))

only `d' need be put in a heap-allocated environment; all the others can
go on the stack.

> I took care to make `let' respect CL-style (declare (foo special))
> declarations, but if you instead introduce `llet' which only makes
> lexical bindings (even if the symbols have been defvar'd?) then you
> don't have that complexity.

My intention was that `llet' be essentiallly `how let would be if elisp
was lexically scoped by default' -- that is, it would respect `defvar's
and dynamically bind such variables just like ordinary let does.

Then for files in `lexically scoped mode' (as discussed recently) would
basically just arrange to transform let->llet and lambda->llambda.

I didn't think about how defvar should record that a variable is
defvar'd; it either could be a bit in the symbol structure, as you
suggest, or simply an entry on the plist.

I'm not sure whether it's desirable or not to support CL-style `declare'
statements, but my feeling is that they're not necessary for the initial

`Cars give people wonderful freedom and increase their opportunities.
 But they also destroy the environment, to an extent so drastic that
 they kill all social life' (from _A Pattern Language_)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]