Eiffel: локальное объявление в или и и не удалось скомпилировать

Компилятор жалуется на неизвестный идентификатор, кажется, что он не распознает ни одно из моих многочисленных объявлений, где я не прав?

if attached {INTEGER_REF} field.item as l_int
        or attached {INTEGER_64} field.item as l_int
        or ( attached {TUPLE} field.item as l_tuple and then attached {INTEGER_64} l_tuple.item (1) as l_int ) then
    Result.put_integer (l_int.to_integer_64, primary_key_db_column_name)
elseif attached {STRING} field.item as l_s then
    Result.put_string (l_s, primary_key_db_column_name)
end

введите здесь описание изображения

Обновлять

Поскольку это выражение кажется допустимым, я подумал, что если в каждой ветке моего или объявлено l_int, я смогу использовать его в области then.

Но кажется, что это выражение действительно

if attached a.b as l_b and then attached l_b.c as l_c then
    l_c.is_available_in_this_scope
    l_b.is_available_in_this_scope
else
    io.putstring ("you are wrong dear and either l_b and l_c are not available!")
end

А этот нет!

if attached a.b as l_b and then attached l_b.c as l_c
        or attached a.x as l_b and then attached l_x.d as l_c then
    l_c.is_available_in_this_scope -- Compiler complain about l_c
    l_b.is_available_in_this_scope -- Compiler complain about l_b
else
    io.putstring ("you are wrong dear and either l_b and l_c are not available!")
end

С моим кодом

Это компилирует

    if attached {INTEGER_REF} field.item as l_int then
        Result.put_integer (l_int.to_integer_64, primary_key_db_column_name)
    elseif attached {INTEGER_64} field.item as l_int then
        Result.put_integer (l_int, primary_key_db_column_name)
    elseif attached {TUPLE} field.item as l_tuple and then attached {INTEGER_64} l_tuple.item (1) as l_int then
        Result.put_integer (l_int, primary_key_db_column_name)
    elseif attached {STRING} field.item as l_s then
        Result.put_string (l_s, primary_key_db_column_name)
    else
        logger.write_error ("to_json-> Type not found in matching:" + field.item.out)
        check
            not_found_item_type: False
        end
    end

Хотя это не

if attached {INTEGER_REF} field.item as l_int then
    Result.put_integer (l_int.to_integer_64, primary_key_db_column_name)
elseif attached {INTEGER_64} field.item as l_int
        or attached {TUPLE} field.item as l_tuple and then attached {INTEGER_64} l_tuple.item (1) as l_int then
    Result.put_integer (l_int, primary_key_db_column_name) -- Unknown identifier `l_int`
elseif attached {STRING} field.item as l_s then
    Result.put_string (l_s, primary_key_db_column_name)
else
    logger.write_error ("to_json-> Type not found in matching:" + field.item.out)
    check
        not_found_item_type: False
    end
end

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


Ответы (2)


Объектные тесты имеют области видимости. Обозначая тест объекта с помощью OT, его область для

if OT         then A else B end
if OT and ... then A else B end
if OT or  ... then C else B end

только A. Следовательно, для дизъюнкции область видимости пуста, и вы не можете использовать соответствующий объектный тест локально ни в одной из ветвей.

Если в условном выражении есть две объектные проверки, их области действия могут пересекаться или нет:

if OT1 and      OT2 then A else B end
if OT1 and then OT2 then A else B end
if OT1 or       OT2 then C else B end

Здесь, как и прежде, локальная переменная объекта OT1 имеет область видимости A. Кроме того, для and then область действия включает OT2, в частности, OT2 может использовать локал OT1. По той же причине OT2 не может использовать тот же объектный тест, что и OT1.

Для дизъюнкции области локальных тестов объекта как OT1, так и OT2 пусты. Для большей информативности тот же код с мнемоническими именами выглядит так:

if attached e1 as x and      attached e2_without_x as y then use_x_and_y else B end
if attached e1 as x and then attached e2_with_x    as y then use_x_and_y else B end
if attached e1 as x or       attached e2_without_x as y then no_x_no_y   else B end

Можно было бы переписать пример только с одной первой ветвью, если бы тип всех задействованных выражений был одинаковым (это не так, потому что есть типы INTEGER_64 и INTEGER_REF):

if attached
       if attached {INTEGER_64_REF} field.item as i then
           i
       elseif
           attached {TUPLE} field.item as t and then
           t.count > 0 and then
           attached {INTEGER_64_REF} t.item (1) as i
       then
           i
       else
           Void
       end
   as j
then
   -- Use j
...

но это становится слишком громоздким, и использование нескольких ветвей или временных локальных переменных кажется лучшей альтернативой.

person Alexander Kogtenkov    schedule 09.10.2018
comment
Большое спасибо, это помогло мне, но я отредактировал свой вопрос, потому что в этом случае у меня все еще есть сомнения ... компилятор жалуется здесь, потому что l_int может быть либо INTEGER_REF, либо INTEGER_64? - person Pipo; 09.10.2018
comment
@Pipo Это потому, что для дизъюнкции область локальной переменной тестового объекта пуста. При этом каждый объектный тест рассматривается отдельно, т.е. два локала объектного теста не могут рассматриваться как один. Итак, для дизъюнкции у вас есть две пустые области видимости, и вы не можете использовать ни одну из переменных. - person Alexander Kogtenkov; 09.10.2018
comment
Извините, даже читая вас около 10 раз, я все еще не понимаю сути :-( вы видели мою правку? Может быть, вы могли бы добавить правку в свой ответ, если у вас есть мотивация! - person Pipo; 09.10.2018
comment
@Pipo Не существует правила, объединяющего локальные переменные объектного теста из двух объектных тестов в одну переменную. Кроме того, область действия локальной переменной проверки объекта пуста, если проверка объекта используется в дизъюнкции. Я обновил ответ дополнительными примерами. - person Alexander Kogtenkov; 10.10.2018
comment
На этот раз получилось!!! or и INTEGER_64/INTEGER_REF сделали его недоступным, что имеет смысл. Теперь не из-за ограничений компиляции, а из-за моей ошибки, Маааааааааааааааааааааааааааааааааааааааааааааааааааааа… - person Pipo; 10.10.2018

Ну, во-первых, вы не можете использовать один и тот же идентификатор (l_int) для нескольких локальных тестов объекта в одной и той же области.

person user2783273    schedule 09.10.2018
comment
Спасибо, но это то, что я не сделал? что бы мой случай с вашим советом? - person Pipo; 09.10.2018
comment
см. мое редактирование и вопрос Александру для большей точности, спасибо! - person Pipo; 09.10.2018