Eiffel: передача аргумента агенту, полученному в качестве аргумента

Я действительно застрял в том, как передать аргумент на второй уровень вызова агента Eiffel. Надеюсь, мой пример достаточно понятен:

main_call
    do
        b (agent d(?, ?))
    end

b (a_proc: PROCEDURE[STRING])
    local
        l_something_else: INTEGER
    do
        l_something_else := 1
--        z("a_line", a_proc(l_something_else)) -- How can I pass at this stade l_something_else to the d procedure!!!
    end

d (line: STRING; something_else: INTEGER)
    do
--        do_some_stuff_with_line (line, something_else)
        do_nothing
    end

z (a_line: STRING; a_proc: PROCEDURE[STRING])
    do
        a_proc.call([a_line])
    end

Я хотел бы иметь возможность сделать что-то вроде

z("a_line", a_proc(?, something_else))

Но это невозможно, поскольку я пытаюсь использовать ключевое слово агента, аргумент a_proc не распознается!

Итак, каким должен быть синтаксис? Я даже пытался добавить аргумент в a_proc с помощью a_proc.set_operands, но теряюсь с классом OPEN_ARGS

Случай реализации

Если вам нужна цель... просто представьте, что я хотел бы иметь 2 разные реализации функции d, и в моем случае это использование UT_CSV_HANDLER, что я хотел бы иметь 2 разные функции для каждой строки CVS

Следующий код дает Non-compatible actual argument in feature call

Feature: import_from_csv_impl
Called feature: import_from_csv_impl (a_rest_request: REST_REQUEST; a_procedure: PROCEDURE [DS_ARRAYED_LIST [STRING_8], INTEGER_64, STRING_8]): [detachable like items] detachable SIT_LINKED_LIST [MEASURING_POINT] from MEASURING_POI...
Argument name: ia_name
Argument position: 2
Formal argument type: STRING_8
Actual argument type: INTEGER_64
Line: 258
                ia_procedure.call (ia_measuring_point_id, ia_name)
->            end (?, l_measuring_point_id, l_s)
            l_csv_handler.read_file (l_is, l_partially_closed)

Полный пример:

-- Main call
import_from_abb_csv (a_rest_request: REST_REQUEST): detachable like items 
    do
        Result := import_from_csv_impl (a_rest_request, agent impl_for_each_csv_line_import_from_abb_csv)
    end

-- Second call
import_from_csv_impl (a_rest_request: REST_REQUEST; a_procedure: PROCEDURE[DS_ARRAYED_LIST [STRING_8], INTEGER_64, STRING]): detachable like items
    local
        l_csv_handler: UT_CSV_HANDLER
        l_is: KL_STRING_INPUT_STREAM
        l_measuring_point_id: INTEGER_64
        l_s: STRING
        l_partially_closed: PROCEDURE[DS_ARRAYED_LIST[STRING]]
    do
        l_s := "whatever"
        l_measuring_point_id := 12
        create l_csv_handler.make_with_separator (',')

        l_partially_closed := agent (i_al: DS_ARRAYED_LIST[STRING]; ia_measuring_point_id: INTEGER_64; ia_name: STRING; ia_procedure: PROCEDURE[INTEGER_64, STRING])
            do
                ia_procedure.call (ia_measuring_point_id, ia_name)
            end (?, l_measuring_point_id, l_s)

        l_csv_handler.read_file (l_is, l_partially_closed)

    end

-- end call
impl_for_each_csv_line_import_from_abb_csv (a_csv_line: DS_ARRAYED_LIST [STRING_8]; a_measuring_point_id: INTEGER_64; l_cu_name: STRING)
    do
        -- do_my_business
    end


-- for information signature of read_file is:
--     read_file (a_file: KI_TEXT_INPUT_STREAM; a_action: PROCEDURE [DS_ARRAYED_LIST [STRING]])

person Pipo    schedule 28.03.2019    source источник


Ответы (1)


agent d или agent d (?,?) (они оба эквивалентны) производят PROCEDURE [STRING, INTEGER], при этом оба операнда d все еще открыты. Из-за ковариантности кортежей PROCEDURE [STRING, INTEGER] соответствует PROCEDURE [STRING], поэтому ваша реализация a компилируется, но попытка вызвать агент только с TUPLE [STRING] вместо TUPLE [STRING, INTEGER] в качестве операндов (что делает b) вызовет исключение во время выполнения (вероятно, освистывание).

Один из способов постепенного закрытия операндов агента состоит в том, чтобы обернуть его другим агентом с одним открытым операндом меньше:

b (a_procedure: PROCEDURE [STRING, INTEGER])
local
    l_something_else: INTEGER
    l_partially_closed: PROCEDURE [STRING]
do
    l_something_else := 1

    l_partially_closed := agent (ia_operand_1: STRING; ia_operand_2: INTEGER; ia_procedure: PROCEDURE [STRING, INTEGER])
    do
        ia_procedure.call (ia_operand_1, ia_operand_2)
    end (?, l_something_else, a_procedure)
        -- Notice how only one operand is left open

    z ("a_line", l_partially_closed)
end

В качестве альтернативы l_something_else можно было бы объявить внутри встроенного агента:

b (a_procedure: PROCEDURE [STRING, INTEGER])
local
    l_partially_closed: PROCEDURE [STRING]
do
    l_partially_closed := agent (ia_operand_1: STRING; ia_procedure: PROCEDURE [STRING, INTEGER])
    local
        il_something_else: INTEGER
    do
        il_something_else := 1
        ia_procedure.call (ia_operand_1, il_something_else)
    end (?, a_procedure)

    z ("a_line", l_partially_closed)
end

Вы также можете использовать {ROUTINE}.set_operands и {ROUTINE}.apply, но, на мой взгляд, это менее гибко и более подвержено ошибкам, а также не является потокобезопасным.

b (a_procedure: PROCEDURE [STRING, INTEGER])
local
    l_something_else: INTEGER
    l_partially_closed: PROCEDURE [STRING]
do
    l_something_else := 1
    a_procedure.set_operands ("some string you will override later", l_something_else)
    z ("a_line", a_procedure)
end

z (a_line: STRING; a_proc: PROCEDURE [STRING]) -- or PROCEDURE [STRING, INTEGER]
do
    -- You have no guarantee that `a_proc' has any operands set (though you could make it a precondition)
    -- This is why it is less safe and less reusable than the previous approach
    check attached a_proc.operands as la_operands then
        la_operands [1] = a_line
    end
    a_proc.apply
end

ОБНОВИТЬ

Учитывая ваш вариант реализации, см. комментарии, начинающиеся с «ЗДЕСЬ»:

-- Main call
import_from_abb_csv (a_rest_request: REST_REQUEST): detachable like items
    do
        Result := import_from_csv_impl (a_rest_request, agent impl_for_each_csv_line_import_from_abb_csv)
    end

-- Second call
import_from_csv_impl (a_rest_request: REST_REQUEST;
a_procedure: PROCEDURE[DS_ARRAYED_LIST [STRING_8], INTEGER_64, STRING]): detachable like items
    local
        l_csv_handler: UT_CSV_HANDLER
        l_is: KL_STRING_INPUT_STREAM
        l_measuring_point_id: INTEGER_64
        l_s: STRING
        l_partially_closed: PROCEDURE[DS_ARRAYED_LIST[STRING]]
    do
        l_s := "whatever"
        l_measuring_point_id := 12
        create l_csv_handler.make_with_separator (',')

        l_partially_closed := agent (i_al: DS_ARRAYED_LIST[STRING];
                                    ia_measuring_point_id: INTEGER_64;
                                    ia_name: STRING;
                                    ia_procedure: PROCEDURE[DS_ARRAYED_LIST [STRING_8], INTEGER_64, STRING]) -- HERE, change the declared type of `ia_procedure' to match `a_procedure'
            do
                ia_procedure.call (i_al, ia_measuring_point_id, ia_name) -- HERE, add `i_al' to `call'
            end (?, l_measuring_point_id, l_s, a_procedure) -- HERE, add `a_procedure'

        l_csv_handler.read_file (l_is, l_partially_closed)

    end

-- end call

impl_for_each_csv_line_import_from_abb_csv (a_csv_line: DS_ARRAYED_LIST [STRING_8]; a_measuring_point_id: INTEGER_64; l_cu_name: STRING)
    do
        -- do_my_business
    end


-- for information signature of read_file is:
--     read_file (a_file: KI_TEXT_INPUT_STREAM; a_action: PROCEDURE [DS_ARRAYED_LIST [STRING]])
person obnosim    schedule 29.03.2019
comment
Большое спасибо за ваш ОЧЕНЬ полный ответ, после промывания мозгов я действительно не могу применить этот случай к моей реализации, не могли бы вы применить первый пример @least к моей реализации?! Я застрял в каком-то Non-compatible actual argument in feature call - person Pipo; 29.03.2019
comment
ia_procedure по-прежнему должен иметь тот же тип, что и a_procedure, и вы должны передать ему i_al из встроенного агента: l_partially_closed := agent (i_al: DS_ARRAYED_LIST[STRING]; ia_measuring_point_id: INTEGER_64; ia_name: STRING; ia_procedure: PROCEDURE[DS_ARRAYED_LIST[STRING], INTEGER_64, STRING]) do ia_procedure.call (i_al, ia_measuring_point_id, ia_name) end (?, l_measuring_point_id, l_s) - person obnosim; 30.03.2019
comment
пытался, но потом получил non-compatible actual argument in feature call. , потому что формальный: detachable separate TUPLE [DS_ARRAYED_LIST [STRING_8], INTEGER_64, STRING_8] фактический: attached TUPLE [INTEGER_64, STRING_8], поэтому замена на ваше предложение не работает - person Pipo; 30.03.2019
comment
Вы также передали i_al ia_procedure.call? ia_procedure.call (i_al, ia_measuring_point_id, ia_name) - person obnosim; 30.03.2019
comment
Выполнение ` l_partially_closed := agent (ia_l: DS_ARRAYED_LIST[STRING]; ia_measuring_point_id: INTEGER_64; ia_name: STRING; ia_procedure: PROCEDURE[DS_ARRAYED_LIST[STRING], INTEGER_64, STRING]) do ia_procedure.call (ia_l, ia_measuring_point_id end, ia_measuring_point_id) , l_measuring_point_id, l_s) l_csv_handler.read_file (l_is, l_partially_closed)` Дает мне wrong number of actual arguments in feature call. - person Pipo; 04.04.2019