【问题标题】:What's the point of the local variable in Eiffel's attached-statement?埃菲尔附加语句中的局部变量有什么意义?
【发布时间】:2016-05-06 20:36:52
【问题描述】:

在 Eiffel 中,Void Safety 是一种静态防止取消引用未初始化(“null”)对象的方法。它的工作方式是,首先,必须将对象声明为可拆卸,然后您需要在 if 块中检查该对象是否实际 附加(即有一些价值),然后才能使用它。

这是我一直使用到现在的方式:

some_object: detachable TYPE

...

if attached some_object then
  some_object.method
end

工作得很好:没有附加检查,编译失败并出现“Object_call 的目标可能无效”错误。 然而,在实际阅读了关于 Void Safety 的documentation 之后,我了解到它实际上应该是这样的:

some_object: detachable TYPE

...

if attached some_object as l_some_object then
  l_some_object.method
end

在这种形式中,l_some_object 是一个 if 块的局部变量,它与 some_object 指向同一个对象,但静态保证为非 void。

但是,我看不出这个 as-clause 存在的原因。正如我上面所指出的,显然原始的some_object 在 if 块中已经静态保证为非 void,那么引入另一个变量有什么意义呢?

some_objectl_some_object 除了作用域之外有什么区别?

【问题讨论】:

    标签: void eiffel void-safety


    【解决方案1】:

    简答

    如果some_object是一个局部变量,那么引入一个object test local 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(这可以间接完成),代码又是无效不安全的。

    最后,在多线程环境中,即使没有任何中间功能调用,另一个线程也可以在检查之后和在“then”部分使用之前更改attr 的值:

    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总是被附加。

    【讨论】:

    • 哦,任意表达式,但是当然.. 出于某种原因,我假设在“附加”之后只允许对象。感谢您的详尽解释!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 2018-12-11
    相关资源
    最近更新 更多