Getting Started | Documentation | Glish | Learn More | Programming | Contact Us |
Version 1.9 Build 1556 |
|
You specify what to do when an agent generates an event using a whenever statement. As discussed above and in § 5.10.2, these look like:
whenever event1, event2, ... do statementwhere at least one event must be listed.
When executed, Glish evaluates the event specifiers listed after the whenever keyword, and subsequently whenever any of those events are generated Glish executes statement. Thus a whenever statement can refer to several different events generated by several different agents.
You can specify an event for a whenever statement in one of three forms:
expr -> name
expr1 -> [ expr2 ]
expr -> *As when sending events (See § 7.4, page ), Glish evaluates the expression to the left of the
->
operator to determine which
agent you're talking about.
With the first form, name then specifies the name of the event
of interest. With the second form, Glish evaluates expr2 to
produce a string value. Each element of
that value then designates an
event produced by the agent. For example,
whenever a->["foo bar bletch"] do print $valueprints the value of each foo, bar, and bletch event generated by the agent a; it is equivalent to:
whenever a->foo, a->bar, a->bletch do print $valueThe third form indicates interest in every event generated by the agent. For example,
whenever a->* do print $valueprints the value of every event a generates.
When a whenever is executed, each of the event's is evaluated to see which events of which agents they designate. Whenever any of those events subsequently occurs, statement is executed. We refer to statement as the body of the whenever statement.
As noted in § 6.6.2, page , if a function executes a whenever and then exits, its variables persist after the function call finishes, and the whenever body can access and modify the variables. For example, a call to:
func report_foo(x) { y := 3 whenever x->foo do { print y y +:= 1 } y := 7 }prints 7 the first time x generates a foo event, 8 the next time, and so on.
Glish does not define the order of execution of two or more whenever statements that match the same event.
An important point is that each time you execute a whenever, a connection is made between the arrival of the given events and executing the whenever's body. If you called report_foo twice with the same x argument, then the first time x generated a foo event Glish would print 7 twice, the second time 8 twice, and so on. Furthermore, if x generated a foo event between the first and second calls to report_foo then the next time it generated a foo event Glish would print 8 and 7 (perhaps in the opposite order), and the next time 9 and 8.
func announce_bar(x) { for ( i in 1:3 ) whenever x->bar do print "x did bar" }will result in Glish printing "x did bar" three times every time x generates a bar event.
A final note: when Glish receives an event it only executes the corresponding whenever bodies at well-defined times (in particular, not when it is in the middle of executing any other statements). (See § 13.1.2, page , for a complete discussion of how Glish proceeds in executing programs and processing events.)
Each time Glish receives an event it sets three special variables: $agent is the agent associated with the event, $name the event's name, and $value the event's value. For example, the body of the following whenever
whenever x->foo do print $namealways prints foo, since a foo event is the only possible event that can result in the body executing. The following prints the value of each foo event generated by x or y, but only prints the name of the event if y generated it:
whenever x->foo, y->foo do { print $value if ( $agent == y ) print $name }Because agent values are also records (See § 7.2.2, page ), after Glish receives an event the following is always true:
$agent[$name] == $valueHere $name provides a string index for the agent's record, designating the field with the same name as the new event.
$name is particularly useful in conjunction with the * event designator (See § 7.5.1, page ). For example, the following whenever ``relays" every event generated by x to y, with the same name and value:
whenever x->* do y->[$name]( $value )Glish provides a number of functions for doing this sort of relaying. (See § 10.9, page .)
Ordinarily, once a whenever statement is executed, it remains active. That is, whenever an event arrives corresponding to one designated when the statement was executed, Glish executes the body of the whenever statement. Sometimes, though, other events may occur leading you to want to deactivate a whenever statement so its body no longer executes. Glish provides a deactivate statement for turning off execution of a whenever's body, and a corresponding activate statement for turning it back on. The simplest form of these statements is simply:
activate
deactivateThese indicate that the ``currently executing'' whenever body (or the most-recently executed one, if none is current) should be activated or deactivated, respectively. For example,
count := 0 whenever a->foo do { do_stuff() count +:= 1 if ( count >= 5 ) deactivate }will call do_stuff() upon receiving a's first 5 foo events, but then will quietly ignore the remainder.
You can also give the activate and deactivate statements an optional argument specify which whenever statement(s) to affect:
activate expr
deactivate exprHere expr must evaluate to an integer (possibly a vector) built out of values returned using the current_whenever(), last_whenever_executed(), and whenever_stmts() functions (See § 10.9, page ). The corresponding whenever bodies are then activated or deactivated. For example, the following only responds to a's foo events (by calling
do_foo()
) if one or
more intervening bar events have been received since the last
foo event:
whenever a->foo do { do_foo() deactivate # wait for bar } a_foo := last_whenever_executed() whenever a->bar do { do_bar() activate a_foo }The state of a whenever statement can be checked with the builtin function whenever_active() (See § 10.9, page ). Given an index, it will return T only if the statement is currently active.
See the discussion of the active_agents() function (§ 10.9, page ) for an example of using deactivate with a vector argument.