Difference between revisions of "Agent Calls"

(Finalized code)
(Finalized code)
Line 91: Line 91:
 
Whenever an agent is created with a closed target, the actual '''agent callee''' is calculated at '''agent creation''' time.
 
Whenever an agent is created with a closed target, the actual '''agent callee''' is calculated at '''agent creation''' time.
 
*Two wrappers are generated:
 
*Two wrappers are generated:
**one which expects the closed arguments as a tuple (encapsulated as in frozen code). The only difference is the whay in which the '''agent callee''' is calculated.
+
**one which expects the closed arguments as a tuple (encapsulated). The only difference to the frozen wrapper is how the '''agent callee''' is calculated.
 
**and one that expects them as separate parameters.
 
**and one that expects them as separate parameters.

Revision as of 16:55, 21 August 2006

Work in progress!

Terminology

In the following text the place where an agent is created (with the agent keyword or the tilde operator) is called the agent creation. The feature to which the agent points is the agent callee and the place (or places) where the agent is called is denoted agent call.

class 
    TERMINOLOGY
 
feature
 
    f1
        local
            p: PROCEDURE [ANY, TUPLE]
        do
            p := agent target   -- agent creation
        end
 
    f2 (p: PROCEDURE [ANY, TUPLE])
        do
            p.call ([])         -- agent call
        end
 
    target                      -- callee
        do
        end
end

Wrapper generation

Frozen code

Lets look first at frozen code. Class C is used throughout the following examples.

class
    C
 
feature
    f (p1, p2: INTEGER; p3: STRING): STRING
        do
            ...
        end   
end

For everly agent creation a c-function is generated. This wrapper function does the following:

  • Reorder the closed and open arguments.
  • Calculate the proper agent callee based on the dynamic type of the target.
  • Call the agent callee

For the agent creation:

agent c.f (?, 1, ?)

the following wrapper function is generated:

EIF_REFERENCE _fAaatpmf_2_4 (EIF_REFERENCE (*f_ptr)(EIF_REFERENCE, EIF_INTEGER_32, EIF_INTEGER_32, EIF_REFERENCE), 
                             EIF_TYPED_ELEMENT* closed, EIF_TYPED_ELEMENT* open)
{
    return (FUNCTION_CAST(EIF_REFERENCE, (EIF_REFERENCE, EIF_INTEGER_32, EIF_INTEGER_32, EIF_REFERENCE)) 
        RTVF(350, 30, "f", closed [1].element.rarg))(
            closed [1].element.rarg, 
            open [1].element.i32arg, 
            closed [2].element.i32arg, 
            open [2].element.rarg);
}

And for this agent creation:

agent {C}.f (1, ?, "hello")

The wrapper function looks like:

EIF_REFERENCE _fAaatpmf_1_3 (EIF_REFERENCE (*f_ptr)(EIF_REFERENCE, EIF_INTEGER_32, EIF_INTEGER_32, EIF_REFERENCE), 
                             EIF_TYPED_ELEMENT* closed, EIF_TYPED_ELEMENT* open)
{
    return (FUNCTION_CAST(EIF_REFERENCE, (EIF_REFERENCE, EIF_INTEGER_32, EIF_INTEGER_32, EIF_REFERENCE)) 
        RTVF(350, 30, "f", open [1].element.rarg))(
            open [1].element.rarg, 
            closed [1].element.i32arg, 
            open [2].element.i32arg, 
            closed [2].element.rarg);
}

Finalized code

In finalized code things are only slightly different.

Whenever an agent is created with a closed target, the actual agent callee is calculated at agent creation time.

  • Two wrappers are generated:
    • one which expects the closed arguments as a tuple (encapsulated). The only difference to the frozen wrapper is how the agent callee is calculated.
    • and one that expects them as separate parameters.