Search code examples
lambdaagenteiffel

How do I get agents to work in {ARRAY}.do_if in Eiffel?


I am trying to iterate an array in Eiffel. And select some elements, using do_if.

What I have tried.

my_method (list:ARRAY[INTEGER])
    local
        low : ARRAYED_LIST[INTEGER]
        piv : INTEGER
    do
    create low.make(0)

    --works for all, but not what I need
    list.do_all ( agent low.extend )
    --I can't get these to work
    list.do_if ( agent low.extend, agent piv > ? )
    list.do_if ( agent low.extend, agent piv.is_greater_equal (?) )
    list.do_if ( agent low.extend, agent piv.is_greater_equal )
    list.do_if ( agent low.extend, agent (v:INTEGER):BOOLEAN do Result := v<piv end )

I know why the last one does not work (piv is in outer scope), but not how to fix. I don't know why the others don't work.


Version = EiffelStudio 19.5 (19.05.10.3187 GPL Edition - linux-x86-64)


Solution

  • The error messages say:

    1. Invalid syntax.
    2. Implementation constraint: an agent target cannot be of a basic type.
    3. Same as above.
    4. Unknown identifier piv.

    Explanation:

    1. The expression is interpreted as (agent piv) < ? and this is not a valid syntax. (An alternative interpretation agent (piv < ?) is invalid either: agents can be based on features or be inline, they cannot be based on arbitrary expressions.)

    2. The language allows such a construct, but the compiler does not support it yet. Probably, in the future, a suitable implementation would be provided and the code would compile without an error. At the moment something else needs to be used.

    3. Same as above.

    4. Inline agents do not capture surrounding local variables. If values of some local variables/arguments/Result need to be used inside an inline agent, they need to be passed via explicit arguments of the inline agent.

    So, the last version can be fixed by adding a closed agent argument:

    agent (v, limit: INTEGER): BOOLEAN do Result := v < limit end (?, piv)
    

    An alternative is to use a loop instead of do_if although it is a bit less declarative:

    across list as x loop if x.item < piv then low.extend (x.item) end end