Какой смысл локальной переменной в присоединенном выражении Эйфеля?

В Eiffel Void Safety - это способ статически предотвратить разыменование неинициализированных ("нулевых") объектов. Это работает так, что сначала объект должен быть объявлен как отделяемый, а затем вам нужно проверить в блоке if, действительно ли объект присоединен (то есть имеет какое-то значение), прежде чем вы сможете его использовать.

Вот как я использовал его до сих пор:

some_object: detachable TYPE

...

if attached some_object then
  some_object.method
end

Работает отлично: без вложенной проверки компиляция завершается с ошибкой "Target of the Object_call может быть недействительным". Однако, после прочтения документации по Void Safety, я узнал, что на самом деле это выглядит так:

some_object: detachable TYPE

...

if attached some_object as l_some_object then
  l_some_object.method
end

В этой форме l_some_object является локальной переменной для блока if, который указывает на тот же объект, что и some_object но статически гарантированно не является недействительным.

Тем не менее, я не вижу причины существования этого пункта. Как я уже говорил выше, по-видимому, оригинал some_object уже статически гарантировано, что он не является пустым в блоке if, так какой смысл вводить другую переменную?

Каковы различия между some_object а также l_some_object кроме области?

1 ответ

Решение

Короткий ответ

Если some_object является локальной переменной, нет смысла вводить локальный объектный тест l_some_object,

Длинный ответ

Общая форма объектного теста

attached {SOME_TYPE} expr as var

где {SOME_TYPE} а также var являются необязательными. Когда тип ({SOME_TYPE} в приведенном выше примере) не используется, объектный тест просто проверяет, expr прикреплен или нет и присваивает его значение var когда он прикреплен.

В теории можно ожидать, что что-то вроде следующего будет безопасным для пустот:

if attached expr then
    expr.do_something
end

Однако это не допускается в общем случае, потому что expr может иметь побочные эффекты, так что при втором вычислении возвращается другое значение, и это значение может быть void сделать код недействительным:

if attached foo then -- On first call function foo returns non-void value.
    foo.do_something -- On second call function foo returns void: BOOM!
end

Другой возможностью является промежуточный вызов, который изменяет значение выражения, например,

if attached attr then -- Attribute attr is attached here.
    bar               -- bar sets attr to Void.
    attr.do_something -- BOOM!
end

Если bar устанавливает атрибут attr в void (это может быть сделано косвенно), код снова становится небезопасным.

Наконец, в многопоточной среде другой поток может изменить значение attr после проверки и перед ее использованием внутри части "then" даже без какого-либо промежуточного вызова функции:

if attached attr then -- Attribute attr is attached here.
                      -- Another thread sets attr to Void.
    attr.do_something -- BOOM!
end

Чтобы предотвратить эти ситуации, var часть используется. Этот локальный объектный тест доступен только для чтения и не зависит от оценки того же выражения, какого-либо промежуточного вызова функции или другого потока. Другими словами это всегда прилагается.

Тем не менее, в некоторых ситуациях на выражение объектных тестов не влияют следующие факторы:

  1. Аргументы доступны только для чтения, поэтому всегда достаточно использовать краткую форму

    attached arg
    

    и нет смысла вводить объектный тест локально, потому что он всегда будет равен аргументу.

  2. Локальные переменные и Result может только стать Void если им присваивается отрывное выражение. Если такого назначения нет, то же

    attached local_var
    

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

    if attached local_var then
        ... -- OK to use local_var as attached.
        local_var := detachable_expression
        ... -- No guarantees about local_var attachment status.
    end
    

    Если этот сценарий нежелателен, можно использовать длинную форму объектного теста

    attached local_var as attached_local_var
    

    и это гарантирует, что attached_local_var всегда прилагается

Другие вопросы по тегам