/
lib/banish/
lib/d/
lib/doc/
lib/doc/domains/
lib/doc/efun/
lib/doc/examples/
lib/doc/examples/armour/
lib/doc/examples/contain/
lib/doc/examples/food/
lib/doc/examples/magic/
lib/doc/examples/monster/
lib/doc/examples/room/
lib/doc/examples/weapons/
lib/function/
lib/include/
lib/include/fn_specs/
lib/include/skills/
lib/info/
lib/inherit/base/
lib/log/
lib/manuals/312/
lib/news/
lib/obj/party/
lib/objects/components/
lib/open/
lib/open/library/
lib/open/party/
lib/players/
lib/players/zilanthius/
lib/room/
lib/room/city/arena/
lib/room/city/creator/
lib/room/city/garden/monst/
lib/room/city/obj/
lib/room/city/shop/
lib/room/death/
lib/room/registry/
lib/secure/
lib/secure/UDP_CMD_DIR/
lib/skills/
lib/skills/fighter/
lib/skills/thief/
lib/usr/
lib/usr/creators/
lib/usr/players/
CONCEPT
	closures

DESCRIPTION
	Closures provide a means of creating code dynamically and
	passing pieces of code as parameters, storing them in
	variables. One might think of them as a very advanced form of
	process_string(). However, this falls short of what you can
	actually do with them.

	The simplest kind of closures are efuns, lfuns or operators.
	For example, #'this_player is an example of a closure. You can
	assign it to a variable as in

		closure f;
		object p;
		f = #'this_player;

	and later use either the funcall() or apply() efun to evaluate
	it. Like

		p = funcall(f);

	or

		p = apply(f);
	
	In both cases there p will afterwards hold the value of
	this_player().	Of course, this is only a rather simple
	application. More useful instances of closures can be created
	using the lambda() efun. It is much like the lambda function
	in LISP. For example, you can do the following:
	
		f = lambda( ({ 'x }), ({ #'environment, 'x }) );
	
	This will create a lambda closure and assign it to f. The
	first argument to lambda is an array describing the arguments
	(symbols) passed to the closure upon evaluation by funcall()
	or apply(). You can now evaluate f, for example by means of
	funcall(f,this_object()). This will result in the following
	steps:
	
		1. The value of this_object() will be bound to symbol x.
		2. environment(x) evaluates to environment(this_object())
		   and is returned as the result of the funcall().
	
	One might wonder why there are two functions, funcall() and
	apply(), to perform the seemingly same job, namely evaluating
	a closure. Of course there is a subtle difference. If the last
	argument to apply() is an array, then each of its elements
	gets expanded to an additional paramater. The obvious use
	would be #'call_other as in:
	
		mixed eval(object ob,string func,mixed *args) {
		  return apply(#'call_other,ob,func,args);
		}
	
	This will result in calling
	ob->func(args[0],args[1],...,args[sizeof(args)-1]).  Using
	funcall() instead of apply() would have given us
	ob->func(args).
	
	Of course, besides efuns there are closures for operators,
	#like #'+, '-, #'<, #'&&, etc.
	
	Well, so far closures have been pretty much limited despite
	their obvious flexibility. This changes now with the
	introduction of conditional and loop operators. For example,
	try:
	
		closure max;
		max = lambda( ({ 'x, 'y }),
			      ({ #'? ,({ #'>, 'x, 'y}), 'x, 'y }) });
		return funcall(max,7,3);
	
	The above example will return 7. What happened? Of course #'?
	is the conditional operator and its 'syntax' is as follows:
	
		({ #'?, cond1, val1, cond2, val2, ..., condn, valn,
		  valdefault });
	
	It evaluates cond1, cond2, ..., condn successively until it
	gets a nonzero result and then returns the corresponding
	value. If there is no condition evaluating to a nonzero
	result, valdefault gets returned. If valdefault is omitted, 0
	gets returned. #'?! works just like #'?, except that the !
	operator is applied to conditions before testing. Therefore,
	while #'? is somewhat like an if statement, #'?! resembles an
	if_not statement if there were one.
	
	There are also loops:

		({ #'do, loopbody, loopcond, loopresult	})

	will evaluate loopbody until loopcond evaluates to 0 and
	then return the value of loopresult. Symbols my be used as
	variables, of course.
	
		({ #'while, loopcond, loopresult, loopbody })

	works similar but evaluates loopcond before loopbody.
	
	There are, however, some questions open:
	
	a) How do I write down an array within a lambda closure to
	   avoid interpretation as a subclosure? 

	   ({ #'member_array, 'x, ({ "abc", "xyz }) }) will obviously
	   result in an error as soon as lambda() tries to interpret
	   "abc" as a closure operator. The solution is to quote the
	   array, as in: ({ #'member_array, 'x, '({ "abc", "xyz }) }).
	   Applying lambda() to this will not result in an error.
	   Instead, the quote will be stripped from the array and the
	   result regarded as a normal array literal. The same can be
	   achieved by using the efun quote(), e.g.:

	   ({ #'member_array, 'x, quote( ({ "abc", "xyz }) ) })

	b) Isn't it a security risk to pass, say, a closure to the
	   master object which then evaluates it with all the
	   permissions it got?

	   Luckily, no. Each closure gets upon compilation bound to
	   the object defining it. That means that executing it first
	   sets this_object() to the object that defined it and then
	   evaluates the closure. This also allows us to call lfuns
	   which might otherwise be undefined in the calling object.

	   There is however, a variant of lambda(), called
	   unbound_lambda(), which works similar but does not allow
	   the use of lfuns and does not bind the closure to the
	   defining object. The drawback is that trying to evaluate it
	   by apply() or funcall() will result in an error. The
	   closure first needs to be bound by calling bind_lambda().
	   bind_lambda() normally takes one argument and transforms an
	   unbound closure into a closure bound to the object
	   executing the bind_lambda().

	   Privileged objects, like the master and the simul_efun
	   object (or those authorized by the privilege_violation()
	   function in the master) may also give an object as the
	   second argument to bind_lambda(). This will bind the
	   closure to that object. A sample application is:
	
	   dump_object(ob)
	   // will dump the variables of ob to /dump.o
	   {
	     closure save;
	     save = unbound_lambda( ({ }),
				    ({ #'save_object, "/open/dump" }) );
	     bind_lambda(save,ob);
	     funcall(save);
	   }
	
	   bind_lambda() can also be used with efun closures.
	
	c) It might be an interesting application to create closures
	   dynamically as an alternative to writing LPC code to a file
	   and then loading it.	 However, how do I avoid doing exactly
	   that if I need symbols like 'x or 'y?

	   To do that one uses the quote() efun. It takes a string as
	   its argument and transforms it into a symbol. For example,
	   writing quote("x") is exactly the same as writing 'x.
	
	d) How do I test if a variable holds a closure?

	   Use the closurep() efun which works like all the other type
	   testing efuns. For symbols there is also symbolp()
	   available.
	
	e) That means, I can do:
	   if (closurep(f)) return funcall(f); else return f; ?

	   Yes, but in the case of funcall() it is unnecessary. If
	   funcall() gets only one argument and it is not a closure it
	   will be returned unchanged. So return funcall(f); would
	   suffice.
	
	f) I want to use a function in some object as a closure. How do I do
	   that?

	   There are several ways. If the function resides in
	   this_object(), just use #'func_name. If not, or if you want
	   to create the function dnynamically, use the efun
	   symbol_function(). It takes a string as it first and an
	   object as its second argument and returns a closure which
	   upon evaluation calls the given function in the given
	   object (and faster than call_other(), too, if done from
	   inside a loop, since function search will be done only when
	   calling symbol_function().
	
	g) Can I create efun closures dynamically, too?

	   Yes, just use symbol_function() with a single argument.
	   Most useful for marker objects and the like. But
	   theoretically a security risk if not used properly and from
	   inside a security relevant object.  Take care, however,
	   that, if there is a simul_efun with the same name, it will
	   be preferred as in the case of #'function. Use the efun::
	   modifier to get the efun if you need it.
	
	h) Are there other uses of closures except using them to store
	   code?

	   Lots. For example, you can use them within almost all of
	   the efuns where you give a function as an argument, like
	   filter_array(), sort_array() or walk_mapping().
	   sort_array(array,#'>) does indeed what is expected. Another
	   application is set_prompt(), where a closure can output
	   your own prompt based on the current time and other stuff
	   which changes all the time.
	
	Finally, there are some special efun/operator closures:
	
	#'[ indexes an array.
	#'[< does the same, but starting at the end.
	#'negate is for unary minus.
	#', may be followed by any number of closures,
	e.g.: ({ #', ({#'= 'h, 'a, }), ({#'=, 'a, 'b }), ({#'=, 'b, 'h }) })
	will swap 'a and 'b when compiled and executed.
	
	------------

	An example from Amylaar:
	
	#I have tested the replace_program() functionality with one
	#example, which I include below. The room is commonly known as
	#/room/orc_valley.c .  A prerequisite to make this work is to
	#have valued properties in room.c .

	#The property C_EXTRA_RESET, if defined, is evaluated at reset
	#time in the reset() of the used room.c .  Moreover, you need
	#a function to query an unprocessed property to use
	#orc_valley.c from fortress.c (That is, don't do an automatic
	#funcall there.)  If you can't supply such a function, you
	#have to set the property "get_orc" at the end of orc_valley.c
	#'s extra_reset() with: add_prop("get_orc", lambda(0, get_orc)
	#); which will set the property to a function that returns the
	#function that is in the variable get_orc at the time you do
	#the add_prop() call.
	#
	#Back to fortress.c : Assume you have the function
	#successfully queried and stored in the variable get_orc. Now
	#you can compute your extra_reset() function by: get_orc =
	#lambda( 0, ({#'funcall, get_orc, 8, 40}) ); which creates the
	#usual 8 orcs with an a_chat chance of 40.
	#
	#Here comes the orc_valley.c source:
	#
	#    ----------- cut here ------- cut here -------- cut here ---
	#
	##include "room.h"
	##include "/sys/stdproperties.h"
	##undef EXTRA_RESET
	##define EXTRA_RESET extra_reset();
	#
	#extra_reset() {
	#    closure get_orc;
	#
	#    replace_program("room/room"); /* Must come first. */
	#    get_orc = lambda( ({'num_orcs, 'chat_chance}),
	#	({#'?!, ({#'present, "orc", ({#'previous_object}) }),
	#	    ({#'do,
	#		({#'=, 'orc, ({#'clone_object, "obj/monster"}) }),
	#		({#'=, 'i, 9}),
	#		({#'do,
	#		    ({#'call_other, 'orc, "set_level",
	#			({#'+, ({#'random, 2}), 1}) }),
	#		    ({#'call_other, 'orc,
	#			({#'[,
	#			    quote(({"set_aggressive",
	#					"set_ac", "set_short",
	#					"set_al", "set_ep", "set_hp",
	#					"set_race",
	#					"set_alias", "set_name"})),
	#			   ({#'-=, 'i, 1}) }),
	#			({#'[,
	#			    quote(({1, 0, "An orc", -60, 1014,
	#				    30, "orc", 
	#			       "dirty crap", "orc"})), 'i}) }),
	#		'i, 0}),
	#		({#'call_other, 'orc, "load_a_chat", 'chat_chance,
	#		    quote(({ "Orc says: Kill 'em!\n",
	#			"Orc says: Bloody humans!\n",
	#			"Orc says: Stop 'em!\n",
	#			"Orc says: Get 'em!\n",
	#			"Orc says: Let's rip out his guts!\n",
	#			"Orc says: Kill 'em before they run away!\n",
	#			"Orc says: What is that human doing here!\n",
	#		    })) }),
	#		({#'=, 'n, ({#'*, ({#'random, 3}), 5}) }),
	#		({#'=, 'weapon, ({#'clone_object, "obj/weapon"}) }),
	#		({#'=, 'i, 5}),
	#		({#'do,
	#		    ({#'call_other, 'weapon,
	#			({#'[,
	#			    quote(({ "set_alt_name",
	#				"set_weight", "set_value", 
	#				"set_class", "set_name"})),
	#				({#'-=, 'i, 1}) }),
	#			({#'[,
	#			    quote(({ "knife", 1, 8,  5, "knife",
	#				"knife", 1, 15, 7, "curved knife",
	#				"axe",	 2, 25, 9, "hand axe",	})),
	#			    ({#'+, 'n, 'i}) }) }),
	#		'i, 0}),
	#		({#'transfer, 'weapon, 'orc}),
	#		({#'command,
	#		    ({#'+, "wield ",
	#			({#'call_other, 'weapon,
	#			"query_name"}) }), 'orc}), 
	#		({#'move_object, 'orc, ({#'previous_object}) }),
	#	    ({#'-=, 'num_orcs, 1}), 0})
	#	})
	#    );
	#    add_prop("get_orc", get_orc);
	#    get_orc = lambda( 0, ({#'funcall, get_orc, 2, 50}) );
	#    add_prop(C_EXTRA_RESET, get_orc);
	#    funcall(get_orc);
	#}
	#
	#TWO_EXIT("room/slope", "east",
	#	 "room/fortress", "north",
	#	 "The orc valley",
	#	 "You are in the orc valley. This place is inhabited"
	#	 "by orcs.\n" 
	#	 "There is a fortress to the north, with lot of signs
	#	 of orcs.\n", 1)
	#
	#    ----------- cut here ------- cut here -------- cut here ----
	#

	Procedural elements:
	====================
	
	definition of terms:
	  <block>  : zero or more values to be evaluated.
	  <test>   : one value to be evaluated as branch or loop condition.
	  <result> : one value to be evaluated at the end of the
		     execution of the form; the value is returned.
	  <lvalue> : local variable/parameter, global variable, or an
		     indexed lvalue.
	useded EBNF operators:
	{ }	iteration
	[ ]	option
	
	forms:
	  ({#', <body> <result>})
	  ({#'? { <test> <result> } [ <result> ] })
	  ({#'?! { <test> <result> } [ <result> ] })
	  ({#'&& { test } })
	  ({#'|| { test } })
	  ({#'while <test> <result> <body>})	loop while test
						evaluates non-zero.
	  ({#'do <body> <test> <result>})	loop till test
						evaluates zero.
	  ({#'= { <lvalue> <value> } })		assignment
						other assignment
						operators work, too.
	
	lisp similars:
	  #',		progn
	  #'?		cond
	  #'&&		and
	  #'||		or
	  #'while	do	/* but lisp has more syntactic candy here */
	  #'=		setq
	
	A parameter / local variable 'foo' is referenced as 'foo , a
	global variable as ({#'foo}) . In lvalue positions
	(assignment), you need not enclose global variable closures in
	arrays.
	
	Call by reference parameters are given with ({#'&, <lvalue>})
	
	Some special efuns:
	#'[		indexing
	#'[<		indexing from the end
	#'negate	unary -
	
	Unbound lambda closures
	=======================
	
	These closures are not bound to any object. They are created
	with the efun unbound_lambda() . They cannot contain
	references to global variables, and all lfun closures are
	inserted as is, since there is no native object for this
	closure.  You can bind and rebind unbound lambda closures to
	an object with efun bind_lambda() You need to bind it before
	it can be called. Ordinary objects can obly bind to
	themselves, binding to other objects causes a privilege
	violation().  The point is that previous_object for calls done
	from inside the closure will reflect the object doing
	bind_lambda(), and all object / uid based security will also
	refer to this object.
	
	
	The following is mostly vapourware. 

	Well, another application would be that some things in the
	driver can be, sort of, microprogrammed.  The master object
	could set some hooks in inaugurate_master(), like creating the
	code for move_object(), using a primitive low_move_object() or
	__move_object() or such. All calls of init(), exit(), etc. can
	thus be controlled on mudlib level.  The driver would do an
	implicit bind_lambda() to the victim when the closure is used.
	
	e.g.
	({#'?, ({#'=, 'ob, ({#'first_inventory, 'destination}) }),
	    ({#'do,
		({#'call_other, 'ob, "init"}),
	    ({#'=, 'ob, ({#'next_inventory, 'ob}) }), 0 })
	})
	
	or
	
	({#'filter_objects, ({#'all_inventory, 'destination}), "init"})
	/* Won't show init failures due to move/destruct */
	
	is equivalent to
	
	if (ob = first_inventory(destination) ) {
	    do {
		ob->init();
	    } while(ob = next_inventory(ob) );
	}
	
	and it's speed is mainly determined by the call_other. Thus,
	it shouldn't be noticably slower than the current C code in
	move_object().
	
AUTHOR
	MacBeth, Amylaar, Hyp