Eiffel 中关于跨语法的 Ensure 子句

Ensure clause in Eiffel regarding across syntax

 find(c: CHARACTER; position: INTEGER): INTEGER

此功能通过从位置 i 开始并搜索来查找字符。一旦找到索引,它就会输出它。但是,如果单词中不存在这样的字符,则输出 0

问题: post条件必须断言查询 returns 字符 c 在范围 pos .. word.count 中的索引,如果没有这样的字符则为零。

我的代码:

find(c: CHARACTER; position: INTEGER): INTEGER
   require
            .....
   do

            .....
   ensure 
        across word as w
        some
             (w.item = c and w.cursor_index >= position)
        end
   end

此布尔等式的问题在于,当使用 find(c,pos) 并且未找到任何内容时,该功能会引发 post 条件违规。

我试图让它仅在单词中不存在给定的 c 字符时才允许该功能输出

假设应该是一个完整的后置条件,让我们在case-by-case的基础上看问题:

  1. 问。允许的输出值范围是多少?
    A. 结果可以是 0word 中从 position:

    开始的任何有效位置
    valid_result_range: Result = 0 or position <= Result and Result <= word.count
    

    这里我们假设position是non-negative(希望在前置条件中指定)。

  2. 问。如果没有匹配的字符,输出值是多少?
    A. 输出是 0。索引从 position 开始的所有字符都不匹配:

    zero_if_not_found: (Result = 0) =
        across word as wc all
            position <= wc.target_index implies wc.item /= c
        end
    
  3. 问。如果有匹配的字符,输出值是多少?
    A.是从position:

    开始的对应字符的第一个位置
    non_zero_if_found: (Result /= 0) implies
       (
          word [Result] = c
       and
          across word as wc all
             (position <= wc.target_index and w.target_index < Result) implies
             wc.item /= c
          end
       )
    

    这个后置条件有两部分。一个检查是否找到了该字符。另一个检查在该位置之前没有匹配的字符。
    编辑: 原始代码以 (Result /= 0) = ... 而不是 (Result /= 0) implies ... 开头。当 Result = 0 时,这将导致 word [Result] 中的断言冲突。 implies if 的代码没有这个问题,因为如果 implies 之前的表达式是 False 那么它之后的表达式不会被计算。

最后的后置条件是上述所有断言的组合。断言的顺序很重要,因为 non_zero_if_found 依赖于 Resultword.

的有效索引这一事实

我会略微更改亚历山大的回答:

zero_if_not_found: (Result = 0) 意味着... non_zero_if_found: (Result /= 0) 表示 ...

要了解原因,请考虑当 Result = 0 时会发生什么,我们计算 Alexander 的 non_zero_if_found:

(Result /= 0) 计算结果为 False 然后 word [Result] = c 评估为先决条件失败(valid_index - 我假设 word 是 STRING 类型)。 (将 w [Result] 改为单词 [Result],我认为这是 Alexander 的错字)

使用 imply 可以保护您免受这种情况的影响,因为 RHS 不会被评估。