Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/doc/LPC/closures-example b/doc/LPC/closures-example
new file mode 100644
index 0000000..f50fd35
--- /dev/null
+++ b/doc/LPC/closures-example
@@ -0,0 +1,202 @@
+CONCEPT
+ closures example
+
+DESCRIPTION
+ This document contains small examples of the usage of
+ (lambda-)closures. For technical details see the closures(LPC)
+ doc. For hints when to use which type of closure, see the end
+ of this doc.
+
+
+ Many Muds use 'details' to add more flavour. 'Details' are
+ items which can be looked at, but are not implemented as own
+ objects, but instead simulated by the environment.
+ Lets assume that the function
+
+ AddDetail(string keyword, string|closure desc)
+
+ adds the detail 'keyword' to the room, which, when look at,
+ returns the string 'desc' resp. the result of the execution of
+ closure 'desc' as the detail description to the player.
+
+ Now imagine that one wants to equip a room with magic runes,
+ which read as 'Hello <playername>!\n" when looked at.
+ Obviously
+
+ AddDetail("runes", sprintf( "Hello %s!\n"
+ , this_player()->QueryName()));
+
+ is not sufficient, as the 'this_player()' is executed to early
+ and just once: for the player loading the room.
+
+ The solution is to use closures. First, the solution using
+ lfun-closures:
+
+ private string _detail_runes () {
+ return sprintf("Hello %s!\n", this_player()->QueryName());
+ }
+ ...
+ AddDetail("runes", #'_detail_runes);
+
+ or with an inline closure:
+
+ AddDetail("runes"
+ , (: sprintf("Hello %s!\n", this_player()->QueryName()) :)
+ );
+
+
+ Simple? Here is the same code, this time as lambda-closure:
+
+ AddDetail( "runes"
+ , lambda(0
+ , ({#'sprintf, "Hello %s!\n"
+ , ({#'call_other, ({#'this_player})
+ , "QueryName" })
+ })
+ ));
+
+ Why the extra ({ }) around '#'this_player'? #'this_player
+ alone is just a symbol, symbolizing the efun this_player(),
+ but call_other() needs an object as first argument. Therefore,
+ the #'this_player has to be interpreted as function to
+ evaluate, which is enforced by enclosing it in ({ }). The same
+ reason also dictates the enclosing of the whole #'call_other
+ expression into ({ }).
+ Note also the missing #'return: it is not needed. The result
+ of a lambda-closure is the last value computed.
+
+
+ Another example: Task is to reduce the HP of every living in a
+ room by 10, unless the result would be negative.
+ Selecting all livings in a room is simply
+
+ filter(all_inventory(room), #'living)
+
+ The tricky part is to reduce the HP. Again, first the
+ lfun-closure solution:
+
+ private _reduce_hp (object liv) {
+ int hp;
+ hp = liv->QueryHP();
+ if (hp > 10)
+ liv->SetHP(hp-10);
+ }
+ ...
+
+ map( filter(all_inventory(room), #'living)
+ , #'_reduce_hp)
+
+ or as an inline closure:
+
+ map( filter(all_inventory(room), #'living)
+ , (: int hp;
+ hp = liv->QueryHP();
+ if (hp > 10)
+ liv->SetHP(hp - 10);
+ :) );
+
+ Both filter() and map() pass the actual array item
+ being filtered/mapped as first argument to the closure.
+
+ Now, the lambda-closure solution:
+
+ map( filter(all_inventory(room), #'living)
+ , lambda( ({ 'liv })
+ , ({'#, , ({#'=, 'hp, ({#'call_other, 'liv, "QueryHP" }) })
+ , ({#'?, ({#'>, 'hp, 10 })
+ , ({#'call_other, 'liv, "SetHP"
+ , ({#'-, 'hp, 10 })
+ })
+ })
+ })
+ ) // of lambda()
+ );
+
+ It is worthy to point out how local variables like 'hp' are
+ declared in a lambda-closure: not at all. They are just used
+ by writing their symbol 'hp . Same applies to the closures
+ parameter 'liv .
+ The lambda-closure solution is not recommended for three
+ reasons: it is complicated, does not use the powers of
+ lambda(), and the lambda() is recompiled every time this
+ statement is executed!
+
+
+ So far, lambda-closures seem to be just complicated, and in
+ fact: they are. Their powers lie elsewhere.
+
+ Imagine a computation, like for skill resolution, which
+ involves two object properties multiplied with factors and
+ then added.
+ The straightforward solution would be a function like:
+
+ int Compute (object obj, string stat1, int factor1
+ , string stat2, int factor2)
+ {
+ return call_other(obj, "Query"+stat1) * factor1
+ + call_other(obj, "Query"+stat2) * factor2;
+ }
+
+ Each call to Compute() involves several operations (computing
+ the function names and resolving the call_other()s) which in
+ fact need to be done just once. Using lambda-closures, one can
+ construct and compile a piece of code which behaves like a
+ Compute() tailored for a specific stat/factor combination:
+
+ closure ConstructCompute (object obj, string stat1, int factor1
+ , string stat2, int factor2)
+ {
+ mixed code;
+
+ // Construct the first multiplication.
+ // The symbol_function() creates a symbol for the
+ // lfun 'Query<stat1>', speeding up later calls.
+ // Note again the extra ({ }) around the created symbol.
+
+ code = ({#'*, ({ symbol_function("Query"+stat1, obj) })
+ , factor1 });
+
+ // Construct the second multiplication, and the addition
+ // of both terms.
+
+ code = ({#'+, code
+ , ({#'*, ({ symbol_function("Query"+stat2, obj) })
+ , factor2 })
+ });
+
+ // Compile the code and return the generated closure.
+ return lambda(0, code);
+ }
+
+ Once the closure is compiled,
+
+ str_dex_fun = ConstructCompute(obj, "Str", 10, "Dex", 90);
+
+ it can be used with a simple 'funcall(str_dex_fun)'.
+
+
+DESCRIPTION -- When to use which closure?
+ First, a closure is only then useful if it needn't to live any
+ longer than the object defining it. Reason: when the defining
+ object gets destructed, the closure will vanish, too.
+
+ Efun-, lfun- and inline closures should be used where useful, as they
+ mostly do the job and are easy to read. The disadvantage of lfun- and
+ inline closures is that they make a replace_program() impossible
+ - but since such objects tend to not being replaceable at all, this is
+ no real loss.
+
+ Lambda closures are needed if the actions of the closure are
+ heavily depending on some data available only at runtime, like
+ the actual inventory of a certain player.
+ If you use lfun-closures and find yourself shoving around
+ runtime data in arguments or (gasp!) global variables, it is
+ time to think about using a lambda-closure, compiling the
+ value hard into it.
+ The disadvantages of lambda closures are clear: they are damn
+ hard to read, and each lambda() statement requires extra time to
+ compile the closure.
+
+
+SEE ALSO
+ closures(LPC), closure_guide(LPC), closures-abstract(LPC)