3

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

这就是我到目前为止一直在使用它的方式:

some_object: detachable TYPE

...

if attached some_object then
  some_object.method
end

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

some_object: detachable TYPE

...

if attached some_object as l_some_object then
  l_some_object.method
end

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

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

除了范围之外,some_object和之间有什么区别?l_some_object

4

1 回答 1

4

简短的回答

如果some_object是局部变量,则没有必要引入对象 test local l_some_object

长答案

对象测试的一般形式是

attached {SOME_TYPE} expr as var

where{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将属性设置attrvoid(这可以间接完成),则代码再次为 void-unsafe。

最后,在多线程环境中,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始终连接。

于 2016-05-06T21:39:17.803 回答