Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/doc/LPC/closure_guide b/doc/LPC/closure_guide
new file mode 100644
index 0000000..438ba46
--- /dev/null
+++ b/doc/LPC/closure_guide
@@ -0,0 +1,730 @@
+Closure Guide for LPC
+
+Table of Contents
+
+ 1 Indroduction, Overview and Efun-Closures
+
+ 2 Lfun-, Inline and Lambda-Closures
+ 2.1 Lfun-Closures
+ 2.2 Inline-Closures
+ 2.3 Lambda-Closures
+ 2.3.1 Advantages of Lambda-Closures
+ 2.3.2 Free Variables in Lambda-Closure Constructs
+ 2.3.3 Special Efun-Closures and Operator-Closures for Lambdas
+ 2.4 Closures with Strange Names
+ 2.5 Operator-Closures
+ 2.6 Variable-Closures
+
+ 3 Examples
+ 3.1 Lfun-Closure
+ 3.2 Lambda-Closure
+
+1 Introduction, Overview and Efun-Closures
+
+ A closure is a pointer to a function. That means that it is data like an
+ int or a string are. It may be assigned to a variable or given to anoth-
+ er function as argument.
+
+ To create a closure that points to an efun like write() you can write
+ the name of the efun prepended with "hash-tick": #'. #'write is a clo-
+ sure that points to the efun write().
+
+ I very often put parentheses around such a closure-notation because
+ otherwise my editor gets confused by the hashmark: (#'write). This is
+ especially of interest within lambda-closures (see below).
+
+ A closure can be evaluated (which means that the function it points to
+ is called) using the efuns funcall() or apply(), which also allow to
+ give arguments to the function. Example:
+
+ funcall(#'write,"hello");
+
+ This will result in the same as write("hello"); alone. The string
+ "hello" is given as first (and only) argument to the function the clo-
+ sure #'write points to.
+
+ The return value of the function the closure points to is returned by
+ the efun funcall() or apply(). (Since write() always returns 0 the re-
+ turn value of the example above will be 0.)
+
+ What are closures good for? With closures you can make much more univer-
+ sally usable functions. A good example is the function filter().
+ It gets an array and a closure as arguments. Then it calls the function
+ the closure points to for each element of the array:
+
+ filter(({ "bla","foo","bar" }),#'write);
+
+ This will call write("bla"), write("foo") and write("bar") in any order;
+ the order is undefined.
+ (In the current implementation the given closure is evaluated for all
+ elements from the first to the last, so the output will be "blafoobar".)
+
+ Furthermore the efun filter() examines the return value of each
+ call of the function the closure points to (the return value of the
+ write()s). If the value is true (not 0) then this element is put into
+ another array which filter() builds up. If the return value is
+ false (== 0) then this element is _not_ put into this array. When all
+ calls are done the slowly built up array is returned. Thus,
+ filter() filters from the given array all elements that the given
+ closure evaluates "true" for and returns an array of those. (The array
+ given to filter() itself is _not_ changed!)
+
+ A more sensical example for filterwould be this:
+
+ x = filter(users(),#'query_is_wizard);
+
+ users() is an efun that gets no arguments and returns an array of all
+ logged in players (wizards and players). query_is_wizard() is a
+ simul_efun that gets an object as first (and only) argument and returns
+ true (1) if this object is a wizard and 0 otherwise.
+
+ So, for each element of the array returned by users() the function
+ query_is_wizard() is called and only those for which 1 was returned are
+ collected into the result and then put into the variable x.
+
+ We now have all logged in wizards stored as array in the variable x.
+
+ Another example: We want to filter out all numbers that are greater than
+ 42 from the array a of integers:
+
+ x = filter(({ 10,50,30,70 }),#'>,42);
+
+ (x will now be ({ 50,70 }).)
+
+ Here two things are new: first: we create a closure that points to an
+ operator; second: we use the possibility to give extra arguments to
+ filter().
+
+ Like all efuns the usual operators can be pointed to with a closure by
+ prepending #' to them. funcall(#'>,4,5) is exactly the same as (4>5).
+
+ The extra arguments given as third to last argument (as many as you
+ like) to filter() are given as second to last argument to the
+ function pointed to by the closure each time it is called.
+
+ Thus we now call (({ 10,50,30,70 })[0]>42), (({ 10,50,30,70 })[1]>42) ...
+ (which is (10>42), (50>42) ...) and return an array of all elements this
+ returns true for and store it into x.
+
+ If you want to create a closure to an efun of which you have the name
+ stored in a string you can create such an efun-closure with the efun
+ symbol_function():
+
+ symbol_function("write") // this will return #'write
+
+ funcall(symbol_function("write"),"foobar"); // == write("foobar");
+
+ This function does not very often occur in normal code but it is very
+ useful for tool-programming (eg the robe uses symbol_function() to allow
+ you call any efun you give).
+
+2 Lfun- and Lambda-Closures
+
+ Very often the possibilities closures to efuns offer are not sufficient
+ for the purpose one has. In nearly all cases three possibilities exist in
+ such cases: use an lfun- or inline-closure, or a lambda-closure.
+
+2.1 Lfun-Closures
+
+ The first possibility is rather easy: like with the efun-closures you
+ can create a pointer to a function in the same object you are by using
+ the #' to prepend it to a function name of a function declared above.
+ Example:
+
+ status foo(int x) {
+ return ((x*2) > 42);
+ }
+
+ int *bar() {
+ return filter(({ 10,50,30,70 }),#'foo);
+ }
+
+ Thus, #'foo is used like there was an efun of this name and doing the
+ job that is done in foo().
+
+2.2 Inline Closure
+
+ Inline closures are a variant of lfun closures, the difference being
+ that the function text is written right where the closure is used,
+ enclosed in a pair of '(:' and ':)'. The compiler will then take care
+ of creating a proper lfun and lfun-closure. The arguments passed to
+ such an inline closure are accessible by position: $1 would be the
+ first argument, $2 the second, and so on. With this, the
+ above example would read:
+
+ int * bar() {
+ return filter(({ 10,50,30,70 }), (: ($1 * 2) > 42 :));
+ }
+
+ or alternatively:
+
+ int * bar() {
+ return filter(({ 10,50,30,70 }), (: return ($1 * 2) > 42; :));
+ }
+
+ The difference between the two versions is that in the first form the text
+ of the inline closure must be an expression only, whereas in the second
+ form any legal statement is allowed. The compiler distinguishes the two
+ forms by the last character before the ':)': if it's a ';' or '}', the
+ compiler treats the closure as statement(s), otherwise as expression.
+
+ Inline closures may also nested, so that the following (not very useful)
+ example is legal, too:
+
+ return filter( ({ 10, 50, 30, 70 })
+ , (: string *s;
+ s = map(users(), (: $1->query_name() :));
+ return s[random(sizeof(s))] + ($1 * 2);
+ :));
+
+ The notation of inline closures is modelled after the MudOS functionals,
+ but there are a few important differences in behaviour.
+
+
+2.3 Lambda-Closures
+
+ Lambda-Closures take the idea of 'define it where you use it' one step
+ further. On first glance they may look like inline closures with an uglier
+ notation, but they offer a few increased possibilities. But first things
+ first.
+
+ The efun lambda() creates a function temporarily and returns a closure
+ pointing to this function. lambda() therefor gets two arrays as
+ arguments, the first is a list of all arguments the function shall expect
+ and the second array is the code of the function (in a more or less
+ complicated form; at least not in C- or LPC-syntax). The closure #'foo
+ from the example above could be notated as lambda-closure:
+
+ lambda(({ 'x }),({ (#'>),
+ ({ (#'*),'x,2 }),
+ 42
+ }))
+
+ Now, the first argument is ({ 'x }), an array of all arguments the
+ function shall expect: 1 argument (called 'x) is expected. Notice the
+ strange notation for this argument with one single leading tick. Like
+ The hash-tick to denote closures the leading tick is used to denote
+ things called "symbols". They do not differ much from strings and if
+ you do not want to have a deeper look into closures you can leave it
+ this way.
+
+ The second argument is an array. The first element of such an array
+ must be an efun- or an lfun-closure, the further elements are the
+ arguments for the function this closure points to. If such an argu-
+ ment is an array, it is treated alike; the first element must be a
+ closure and the remaining elements are arguments (which of course
+ also might be arrays ...).
+
+ This leads to a problem: sometimes you want to give an array as an
+ argument to a function. But arrays in an array given to lambda() are
+ interpreted as code-arrays. To allow you to give an array as an argu-
+ ment within an array given to lambda(), you can use the function
+ quote() to make your array to a quoted array (a quoted array is for
+ an array what a symbol is for a string):
+
+ lambda(0,({ (#'sizeof),
+ quote(({ 10,50,30,70 }))
+ }))
+
+ For array constants, you can also use a single quote to the same
+ effect:
+
+ lambda(0,({ (#'sizeof),
+ '({ 10,50,30,70 })
+ }))
+
+ This lambda-closure points to a function that will return 4 (it will
+ call sizeof() for the array ({ 10,50,30,70 })). Another thing: if
+ we want to create a function that expects no arguments, we can give
+ an empty array as first argument to lambda() but we can give 0 as
+ well to attain this. This is just an abbreviation.
+
+ Lambda-closure constructs can become quite large and hard to read. The
+ larger they become the harder the code is to read and you should avoid
+ extreme cases. Very often the possibility to use an lfun or an inline
+ instead of a large lambda shortens the code dramatically. Example:
+
+ status foo(object o) {
+ return environment(o)->query_level()>WL_APPRENTICE;
+ }
+
+ x=filter(a,#'foo);
+
+ does the same as
+
+ x=filter(a,lambda(({ 'o }),
+ ({ (#'>),
+ ({ (#'call_other),
+ ({ (#'environment),'o }),
+ "query_level"
+ }),
+ WL_APPRENTICE
+ })));
+
+ (Note that the syntax with the arrow "->" for call_other()s cannot be
+ used, #'-> does not exist. You have to use #'call_other for this and
+ give the name of the lfun to be called as a string.)
+
+ This example also demonstrates the two disadvantages of lambda closures.
+ First, they are very difficult to read, even for a simple example like
+ this. Second, the lambda closure is re-created everytime the
+ filter() is executed, even though the created code is always the
+ same.
+
+ 'Why use lambdas at all then?' you may ask now. Well, read on.
+
+
+2.3.1 Advantages of Lambda Closures
+
+ The advantages of lambdas stem from the fact that they are created
+ at runtime from normal arrays.
+
+ This means that the behaviour of a lambda can be made dependant on data
+ available only at runtime. For example:
+
+ closure c;
+ c = lambda(0, ({#'-, ({ #'time }), time() }) );
+
+ Whenever you now call this closure ('funcall(c)') it will return the
+ elapsed time since the closure was created.
+
+ The second advantage of lambdas is that the arrays from which they
+ are compiled can be constructed at runtime. Imagine a customizable prompt
+ which can be configured to display the time, the environment, or both:
+
+ mixed code;
+
+ code = ({ "> " });
+ if (user_wants_time)
+ code = ({ #'+, ({ #'ctime }), code });
+ if (user_wants_environment)
+ code = ({ #'+, ({#'to_string, ({#'environment, ({#'this_player }) }) })
+ , code });
+ set_prompt(lambda(0, code));
+
+
+2.3.2 Free Variables in Lambda-Closure Constructs
+
+ You can use local variables in lambda constructs without declaring
+ them, just use them. The only limitation is that you at first have
+ to assign something to them. Give them as symbols like you do with
+ the arguments. This feature does not make much sense without the use
+ of complexer flow controlling features described below.
+
+ The closure #'= is used to assign a value to something (like the
+ LPC-operator = is).
+
+2.3.3 Special Efun-Closures and Operator-Closures for Lambdas
+
+ There are some special closures that are supposed to be used only
+ within a lambda construct. With them you can create nearly all code
+ you can with regular LPC-code like loops and conditions.
+
+ #'? acts like the "if" statement in LPC. The first argument is the
+ condition, the second is the code to be executed if the condition
+ returns true. The following arguments can also be such couples of
+ code-arrays that state a condition and a possible result. If at
+ the end there is a single argument, it is used as the else-case
+ if no condition returned true.
+
+ lambda(({ 'x }),({ (#'?), // if
+ ({ (#'>),'x,5 }), // (x > 5)
+ ({ (#'*),'x,2 }), // result is x * 2;
+ ({ (#'<),'x,-5 }), // else if (x < -5)
+ ({ (#'/),'x,2 }), // result is x/2;
+ 'x // else result is x;
+ }))
+
+ #'?! is like the #'? but it negates all conditions after evaluation
+ and thus is like an ifnot in LPC (if there were one).
+
+ #', (which looks a bit strange) is the equivalent of the comma-operator
+ in LPC and says: evaluate all arguments and return the value of
+ the last. It is used to do several things inside a lambda-closure.
+
+ lambda(({ 'x }),({ (#',), // two commas necessary!
+ // one for the closure and one as
+ // delimiter in the array
+ ({ (#'write),"hello world!" }),
+ ({ (#'say),"Foobar." })
+ }))
+
+ #'while acts like the LPC statement "while" and repeats executing one
+ code-array while another returns true.
+ #'while expects two or more arguments: the condition as first
+ argument, then the result the whole expression shall have after
+ the condition turns false (this is in many cases of no interest)
+ and as third to last argument the body of the loop.
+
+ lambda(0,({ (#',), // several things to do ...
+ ({ (#'=),'i,0 }), // i is a local variable of this
+ // lambda-closure and is
+ // initialized with 0 now.
+ ({ (#'while),
+ ({ (#'<),'i,10 }), // condition: i < 10
+ 42, // result is not interesting,
+ // but we must give one
+ ({ (#'write),'i }), // give out i
+ ({ (#'+=),'i,1 }) // increase i
+ })
+ }))
+
+ The function this closure points to will give out the
+ numbers from 0 to 9 and then return 42.
+
+ #'do is like the do-while statement in LPC and is very much like the
+ #'while. The difference is that #'while tests the condition al-
+ ready before the body is evaluated for the first time, this means
+ that the body might not be evaluated even once. #'do evaluates
+ the body first and then the condition, thus the body is evaluated
+ at least one time.
+ Furthermore, the arguments for #'do are changed in order. #'do
+ expects as first to last but two the body of the loop, then the
+ condition (as last-but-one'th argument) and the result value as
+ last argument. So #'do must have at least two arguments: the
+ condition and the result.
+
+ lambda(0,({ (#',), // several things to do ...
+ ({ (#'=),'i,0 }), // i is a local variable of this
+ // lambda-closure and is initialized
+ // with 0 now.
+ ({ (#'do),
+ ({ (#'write),'i }), // give out i
+ ({ (#'+=),'i,1 }) // increase i
+ ({ (#'<),'i,10 }), // condition: i < 10
+ 42 // result is not interesting
+ })
+ }))
+
+ NOTE: There is no #'for in LPC, you should use #'while for this.
+
+ #'foreach is like the foreach() statement in LPC. It evaluates one or
+ more bodies repeatedly for every value in a giving string, array
+ or mapping. The result of the closure is 0.
+
+ #'foreach expects two or more arguments:
+ - a single variable symbol, or an array with several variable
+ symbols
+ - the value to iterate over
+ - zero or more bodes to evaluate in each iteration.
+
+ The single values retrieved from the given value are assigned
+ one after another to the variable(s), then the bodies are executed
+ for each assignment.
+
+ lambda(0, ({#'foreach, 'o, ({#'users})
+ , ({#'call_other, 'o, "die" })
+ }));
+
+ lambda(0, ({#'foreach, ({'k, 'v}), ({ ...mapping...})
+ , ({#'printf, "%O:%O\n", 'k, 'v })
+ }));
+
+ #'return gets one argument and acts like the "return" statement in LPC
+ in the function that is created by lambda(). It aborts the
+ execution of this function and returns the argument.
+
+ lambda(0,({ (#'while),// loop
+ 1, // condition is 1 ==> endles loop
+ 42, // return value (which will never be used)
+ ({ (#'write),"grin" })
+ ({ (#'?!), // ifnot
+ ({ (#'random),10 }), // (random(10))
+ ({ (#'return),100 }) // return 100;
+ })
+ }))
+
+ This function will enter an endles loop that will in each
+ turn give out "grin" and if random(10) returns 0 (which will
+ of course happen very soon) it will leave the function with
+ "return 100". The value 42 that is given as result of the
+ loop would be returned if the condition would evaluate to 0
+ which cannot be. (1 is never 0 ;-)
+
+ #'break is used like the "break" statement in LPC and aborts the exe-
+ cution of loops and switches.
+ It must not appear outside a loop or switch of the lambda
+ closure itself, it cannot abort the execution of the function
+ the closure points to!
+
+ lambda(0,({ (#'?),
+ ({ (#'random),2 }),
+ ({ (#'break) }), // this will cause the error
+ // "Unimplemented operator break
+ // for lambda()"
+ "random was false!"
+ }));
+
+ You can use ({ #'return,0 }) instead of ({ #'break }) in such
+ cases.
+
+ #'continue is used like the "continue" statement in LPC and jumps to
+ the end of the current loop and continues with the loop
+ condition.
+
+ #'default may be used within a #'switch-construct but be careful!
+ To call symbol_function("default") (which is done usually
+ by tools that allow closure-creation) might crash the
+ driver! So please do only use it within your LPC-files.
+ (NOTE: This driver bug is fixed somewhere below 3.2.1@131.)
+
+ #'.. may be used within a #'switch-construct but is not implemented
+ yet (3.2.1@131). But #'[..] works well instead of it.
+
+ #'switch is used to create closures which behave very much like the
+ switch-construct in LPC. To understand the following you
+ should already know the syntax and possibilities of the
+ latter one (which is mightier than the C-version of switch).
+
+ I will confront some LPC versions and the corresponding clo-
+ sure versions below.
+
+ LPC: Closure:
+ switch (x) { lambda(0,({ (#'switch), x,
+ case 5: ({ 5 }),
+ return "five"; ({ (#'return),"five" }),
+ (#',),
+ case 6..9: ({ 6, (#'[..]), 9 }),
+ return "six to nine"; ({ (#'return),
+ "six to nine" }),
+ (#',),
+ case 1: ({ 1 }),
+ write("one"); ({ (#'write),"one" }),
+ // fall through (#',),
+ case 2: ({ 2,
+ case 10: 10 }),
+ return "two or ten"; ({ (#'return),
+ "two or ten" }),
+ (#',),
+ case 3..4: ({ 3, (#'[..]), 4 }),
+ write("three to four"); ({ (#'write),
+ "three to four" }),
+ break; // leave switch (#'break),
+ default: ({ (#'default) }),
+ write("something else"); ({ (#'write),
+ "something else" }),
+ break; (#'break)
+ } }))
+
+ #'&& evaluates the arguments from the first on and stops if one evalu-
+ ates to 0 and returns 0. If none evaluates to 0 it returns the
+ result of the last argument.
+
+ #'|| evaluates the arguments from the first on and stops if one evalu-
+ ates to true (not 0) and returns it. If all evaluate to 0 it
+ returns 0.
+
+ #'catch executes the closure given as argument, but catches any
+ runtime error (see catch(E)). Optionally the symbols 'nolog,
+ 'publish and 'reserve may be given as additional arguments to
+ modify the behaviour of the catch.
+
+ #'sscanf acts similar to how a funcall would, but passes the third
+ and following arguments as lvalues, that is, values which can
+ be assigned to.
+
+ #'= and the #'<op>= variants are also special because the first
+ argument has to be an lvalue.
+
+2.4 Closures with Strange Names
+
+ #'negate is the unary minus that returns -x for the argument x.
+
+ map(({ 1,2,3 }),#'negate)
+
+ This returns ({ -1,-2,-3 }).
+
+ #'[ is used for the things that in LPC are done with
+ the []-operator (it indexes an array or a mapping).
+
+ lambda(0,({ #'[,quote(({ 10,50,30,70 })),2 })) ==> 30
+ lambda(0,({ #'[,([ "x":10;50, "y":30;70 ]),"x",1 })) ==> 50
+
+ #'[< is the same as #'[ but counts the elements from the
+ end (like indexing with [] and the "<").
+
+ #'[..] returns a subarray of the argument from the one
+ given index to the other given index, both counted from the
+ beginning of the array.
+
+ #'[..<]
+ #'[<..]
+ #'[<..<] same as above, but the indexes are counted from the end,
+
+ lambda(0,({ #'[..<],
+ quote(({ 0,1,2,3,4,5,6,7 })),2,3
+ }))
+
+ This will return ({ 2,3,4,5 }).
+ #'[..
+ #'[<.. same as above, but only the first index is given, the
+ subarray will go till the end of the original (like with
+ [x..]).
+
+ #'({ is used to create arrays (as with ({ }) in LPC). All arguments
+ become the elements of the array.
+
+ lambda(0,({ #'({,
+ ({ (#'random),10 }),
+ ({ (#'random),50 }),
+ ({ (#'random),30 }),
+ ({ (#'random),70 })
+ }))
+
+ This returns ({ random(10),random(50),random(30),random(70) }).
+
+ #'([ is used to create mappings out of single entries (with seve-
+ ral values) like the ([ ]) in LPC. Very unusual is the fact
+ that this closure gets arrays as argument that are not eval-
+ uated, although they are not quoted.
+
+ lambda(0,({ #'([,
+ ({ "x",1,2,3 }),
+ ({ "y",4,5,6 })
+ }));
+
+ This returns ([ "x": 1;2;3,
+ "y": 4;5;6 ]).
+
+ However, the elements of the arrays are evaluated as lambda
+ expressions, so if you want to create a mapping from values
+ evaluated at call time, write them as lambda closures:
+
+ lambda(0, ({ #'([, ({ 1, ({ #'ctime }) }) }) )
+
+ will return ([ 1: <result of ctime() at call time ]).
+
+ Arrays can be put into the mapping by quoting:
+
+ lambda(0, ({ #'([, ({ 1, '({ 2 }) }) }) )
+
+ will return ([ 1: ({ 2 }) ])
+
+
+ #'[,] is nearly the same as #'[. The only difference
+ shows up if you want to index a mapping with a width
+ greater than 1 (with more than just one value per
+ key) directly with funcall(). Example:
+ funcall(#'[,([ 0:1;2, 3:4;5 ]),0,1)
+ This will not work. Use #'[,] and it will
+ work. If you want to use it in a lambda closure you
+ do not have to use #'[,] and #'[ will
+ do fine. On the other hand, #'[,] cannot
+ work with arrays, so in nearly all cases use #'[
+ and just in the described special case, use
+ #'[,].
+ This is a strange thing and I deem it a bug, so it
+ might change in the future.
+
+2.5 Operator-Closures
+
+ Most of the closures that are used for things which are done by opera-
+ tors are in fact not operator-closures but efun-closures. But there are
+ a few which do not have the state of efun-closures but are called
+ "operator-closures". #'return is an example, a complete list of them is
+ given below.
+
+ These closures cannot be called directly using funcall() or apply() (or
+ other efuns like filter()), but must appear only in lambda-con-
+ structs.
+
+ funcall(#'return,4); // does not work! This will raise an
+ // Uncallable-closure error.
+ funcall(lambda(0, // this is a correct example
+ ({ (#'return),4 })
+ ));
+
+ All operator-closures:
+ #'&&
+ #'||
+ #',
+ #'?
+ #'?!
+ #'=
+ #'<op>=
+ #'++
+ #'--
+ #'break
+ #'catch
+ #'continue
+ #'default
+ #'do
+ #'foreach
+ #'return
+ #'sscanf
+ #'switch
+ #'while
+ #'({
+ #'([
+
+ #'.. is very likely to be an operator closure too, but since it is
+ not implemented yet, I cannot say for sure.
+
+2.6 Variable-Closures
+
+ All object-global variables might be "closured" by prepending a #' to
+ them to allow access and/or manipulation of them. So if your object has
+ a global variable x you can use #'x within a closure.
+
+ Normally you will treat those expressions like lfun-closures: put them
+ into an array to get the value:
+
+ object.c:
+ int x;
+ int foo() {
+ return lambda(0,({ (#'write),({ (#'x) }) }));
+ }
+
+ Anybody who now calls object->foo() will get a closure which will, when
+ evaluated, write the actual value of object's global variable x.
+
+ Variable closures do not accept arguments.
+
+3 Examples
+
+ In this section I will give and explain some examples coming out of
+ praxis. If the explanation seems to be in some cases too detailed this
+ can be explained by the trial to allow the reader to read the examples
+ section first ;-)
+
+3.1 Lfun-Closure
+
+ An item with a complex long-description like a watch that shall always
+ show the actual time will usually base upon the complex/item-class and
+ give an lfun-closure as argument to the set_long()-method.
+
+ watch.c:
+ inherit "complex/item";
+
+ string my_long() {
+ return ("The watch is small and has a strange otherworldly"
+ " aura about it.\n"
+ "The current time is: "+ctime()+".\n");
+ }
+
+ void create() {
+ set_short("a little watch");
+ set_id(({ "watch","little watch" }));
+ set_long(#'my_long); // the lfun-closure to the lfun my_long()
+ }
+
+3.2 Lambda-Closure
+
+ The example from 3.1 can also be written using a lambda-closure.
+
+ watch.c:
+ inherit "complex/item";
+
+ void create() {
+ set_short("a little watch");
+ set_id(({ "watch","little watch" }));
+ set_long(lambda(0,({ (#'+),
+ "The watch is small and has a strange"
+ " otherworldly aura about it.\n"
+ "The current time is: ",
+ ({ (#'+),
+ ({ (#'ctime) }),
+ ".\n"
+ })
+ })));
+ }