Short: Inline-Closures with runtime arguments From: d-chat Date: 2002-05-28 (actually one year earlier) Type: Feature State: Done - implemented in 3.3.271 See also: f-991104-1 Generische Syntax: func mixed (int a, int b, ...) {} func (int a, int b, ...) {} func {} -> implicite parameters $1.. To pass parameters from the generating function to the lfun, a special kind of lfun closure is used internally which adds an array of initial values: void caller() { int i; return func int (int a) { return a + i; } } is compiled as int _func_1(mixed * _vals, int a) { return a + _vals[i]; } void caller() { int i; return context_lfun(#'_func_1, ({ i })); } A funcall()/apply() on this special lfun then executes internally: _func_1( ({ i }), a); On VM level, the VM gets a new svalue_t* 'context' which points to the inherited context variables (i in this example). The storage area is in the closure_t, similar to how arrays are stored. The context variables are accessed using special bytecodes similar to the F_LOCAL bytecodes. In effect, a context lfun has three variable spaces: global, local, and context. As a result, assignments to the inherited vars are possible, but effect just this closure, not the creating function. The '==' and '!=' operators need to be extended to compare two inlines with identical context values as equal. Note: with this context (and linking of contexts through a 'parent_context' pointer in the VM control record) it would be possible to use implement local functions as in Oberon. Creating an lfun from a local function would be legal, however the context pointer would be NULL and any attempt to access a context variable would cause a runtime error. How to implement with a one-pass compiler and without lexer hacks: Lexer recognizes keyword 'func' as L_FUNC, value is the synthetic name of the function. Parser upon receipt of L_FUNC remembers the current program address and starts a new function. Once the inline function is complete, the block is stored in a list, and the program size is set back to the stored address. Now the assignment of the local variables to the context is done. When the creating function is complete, all stored inline functions are inserted back into the program block. Be careful though with the backpatching lists. The problem is recognizing the locals: every rule recognizing a local would have to check if an inline closure is parsed and if yes generate the code to reference the _vals[] array instead instead. Value-returning Smiley-closures could be implemented like this: (: ... :) -> L_BEGIN_INLINE ... L_END_INLINE Statement smiley-closures might be supportable if the terminating ';' is taken out of the statement rule and written explicitely whereever a statement is used (block, statements). statement would have to return a flag if the statement left a value on the stack, and the ';' recognition would have to insert the F_POP instruction (see current handling of comma_expr in statement). No idea about the linenumber information yet. Maybe record names, lines and program sizes and replay when the inline closures is inserted? ------------------------------------------------------------------------- [d-chat:Alfe@Tubmud] nee, im ernst mal mateese: die smiley-notation fuer closures hat noch einen grossen nachteil: man kann keine werte in eine solche closure reinnehmen, die zur laufzeit erst bekannt werden. dafuer muss man dann doch immer wieder lambdas bauen. kannst du daran nicht mal was aendern? [d-chat:Alfe@Tubmud] beispiel: closure adder(int x) { return (: $1 + x :); } [d-chat:Dan@GueldenLand] Das was Alfe will geht prinzipiell nicht weil Inlines zur Compilezeit uebersetzt werden, wie alle anderen lfuns auch. [d-chat:Alfe@Tubmud] und ugh@tubmud meinte sofort, als er die smiley-notation gesehen hat, die sei ja nicht rekursiv einsetzbar (also eine closure, die eine closure liefert), weil dann innen drin nicht klar sei, auf welchen scope sich ein $1 usw. bezoege. [d-chat:Mateese@OSB-aquarius] closure adder (int i) { return lambda(({'x}), ({ (: $1 + $2 :), 'x, i }) ); } [d-chat:Alfe@Tubmud] das liefert ja ne closure, die dann erst noch ne closure liefern wuerde, die nen int liefert. das will ich auch nicht. ich will nur ein smiley-equivalent fuer [d-chat:Alfe@Tubmud] closure adder (int i) { return lambda(({'x}),({ #'+,'x,i })); } [d-chat:Perle@Tubmud] wenn man argumentnamen festlegt, ist man doch genau wieder bei lambda. [d-chat:Alfe@Tubmud] ugh schlug was in der art vor: (: a,b,c; a+b+c :) [d-chat:Alfe@Tubmud] also namen vergeben statt $1 usw. [d-chat:Alfe@Tubmud] (waere ja ohnehin schoener)( [d-chat:Dan@GueldenLand] Alfe, denk doch mal drueber nach was Du willst: Du willst eine Closure auf einen *Clon einer LFUN*. Wie soll das ins Konzept passen? [d-chat:Alfe@Tubmud] wenn man das dann noch mit der version von python-lambdas kombiniert, dann koennte man auch closure adder(int i) { return (: a,b=i; a+b :); } schreiben und haette dadurch auch noch mein erstes problem erschlagen. [d-chat:Alfe@Tubmud] oh, dan, glaub mir, ich weiss, wovon ich rede, ich weiss das es geht und dass es ins konzept passt. es ist nur nicht so trivial umzusetzen, da geb ich dir recht. [d-chat:Dan@GueldenLand] Man muesste die Inlines teileweise neu implementieren (das allerdings wuerde ich unterstuetzen ;) [d-chat:Perle@Tubmud] mixing declarations with initializations considered harmful. [d-chat:Alfe@Tubmud] perle, du schwarzmaler ;-) [d-chat:Mateese@OSB-aquarius] Perle, huh? [d-chat:Alfe@Tubmud] ich haette auch nichts dagegen, wenn smiley-notierte closures keine lfun-closure, sondern eine lambda-closure wuerden (wohl zwangslaeufig, wenn laufzeit-werte reingebracht werden sollen). [d-chat:Dan@GueldenLand] das meine ich mit nicht ins Konzept passen (und ich bin auch dafuer dass sie wie lambdas gehandhabt werden, aber dann muesste man die zur Laufzeit uebersetzen...) [d-chat:Alfe@Tubmud] nein, dan, das nicht, man muesste ihnen nur argument versteckt uebergeben koennen. der code kann zur compile-zeit gebaut werden. [d-chat:Dan@GueldenLand] du kannst ne lambda closure bauen die die argumente weitergibt + ein paar versteckte ;) das geht alles mit nem macro wenn Du Glueck hast ;)