next up previous contents index
Next: await Statement Up: Events Previous: Send Expressions

whenever Statement

 

  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 eventtex2html_wrap_inline15496, eventtex2html_wrap_inline15498, tex2html_wrap_inline15512 do statement
where 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 executes statement. Thus a whenever statement can refer to several different events generated by several different agents.

Event Syntax

 

You can specify an event for a whenever statement in     one of three forms:

expr -> name

exprtex2html_wrap_inline15496 -> [ exprtex2html_wrap_inline15498 ]

expr -> *

As when sending events (§ 7.4, page gif), 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 exprtex2html_wrap_inline15498 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 $value
will print 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 $value
The third form indicates interest in every event generated by the agent. For example,        
    whenever a->* do
        print $value
prints the value of every event a generates.

Execution of whenever

  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 gif, 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
        }
will print 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.

Similarly, a single call to:  

    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 § 11.1.2, page gif, for a complete discussion of how Glish proceeds in executing programs and processing events.

$agent, $name, and $value

 

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 $name
always 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 gif), after Glish receives an event the following is always true:
    $agent[$name] == $value
Here $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 gif). 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 § 9.10, page gif.

activate and deactivate Statements

       

Ordinarily, once a whenever statement is executed, it remains active from then on. 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

deactivate

which indicate that the currently-executed 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 expr

Here 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 § 9.10, page gif). The corresponding whenever bodies are then activated or deactivated. For example, the following allows response to one of a's foo events only 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 § 9.10, page gif). Given an index, it will return T only if the statement is currently active.

See the discussion of the active_agents() function (§ 9.10, page gif) for an example of using deactivate with a vector argument.

 


next up previous contents index
Next: await Statement Up: Events Previous: Send Expressions

Thu Nov 13 16:44:05 EST 1997