Aaron,

> What is the purpose of the decode(...) function?  I see that it is doing a 
> substitution of symbols for Fixed and Subr where appropriate; why is this not 
> be handled in subr_eval_symbol(...)? 

encode, en(code)list, etc., try to increase performance by finding which 
binding a name refers to at function definition time, removing the need to 
traverse a long association list for every variable access during evaluation.  
For globals they replace a name with a direct reference to its binding's value 
location.  For locals they simulate the stack of local contexts that will be 
created at run time and encode variable accesses as nesting level (number of 
contexts to 'pop') plus offset (into the context you arrived at).

For globals that refer to primitives or functions there is the opportunity to 
short-circuit the call to its final destination without ever indirecting 
through the binding at runtime.  This changes the usual semantics of define and 
set, in which changing the value of a definition during execution normally 
changes the value seen by all references to it.  When functions are 
short-circuited, all references to a function that were made in function 
definitions completed before changing the value with 'set' will continue to 
refer to the original value.  Neither semantic is obviously more correct than 
the other.  The former is 'classic' Lisp and the latter has some appealing 
encapsulation properties.

The contexts and bindings that are created during this process are never used 
for execution.

> Is decode(...) preparing something for eval(...) that would be hard to do 
> from within eval(...)?

It is preparing direct references to associations for globals and to 
level+offset bindings for locals in LIFO contexts, removing (in most cases) the 
need for eval to traverse an alist during execution.

> Continuing, we see that decode(...) must make accommodations for special 
> forms like lambda and let.  In both cases it prepends bindings to the 
> environment that are set to nil.  Presumably the bindings are intended for 
> the recursion that comes from enlist(...); at which point the same process 
> repeats for each element of the lambda/let.  Why are these bindings relevant 
> to the recursive call?

This is tracking the nesting of contexts that are created by let and by the 
parameter list of lambda so that encode can convert names that refer to local 
variables into their level+offset location at runtime.

> This is with respect to the minimal maru available in the google code 
> repository; although maru-2.4 appears to have a very similar but more 
> developed decode(...) mechanism.

The latest version of Maru removes the mechanism entirely because adding a 
small runtime cache of symbol-to-binding mappings to the association list 
lookup is far simpler and performs in almost all cases just as well as the 
complicated pre-encoded version.

Hope that helps.

Regards,
Ian

_______________________________________________
fonc mailing list
[email protected]
http://vpri.org/mailman/listinfo/fonc

Reply via email to