【问题标题】:Examples of error handling in EiffelEiffel 中的错误处理示例
【发布时间】:2014-11-16 12:08:01
【问题描述】:

我在 Eiffel 中找不到任何实质性的错误处理示例。我只找到了一些例子,要么是微不足道的,要么完全忽略错误,或者将错误处理留给读者。我有兴趣知道在没有异常的情况下错误如何通过调用堆栈。例如,我想知道发送网络请求的应用程序如何通知用户在调用链中检测到的网络问题。类似的东西。

--

编辑:我知道 Eiffel 中错误处理的基础知识(状态和异常)。但是,我找不到任何关于应用程序如何通过状态处理错误的大量示例。故障状态如何链接?

【问题讨论】:

  • 你可以用一种没有异常的语言做同样的事情。 异常是为编程错误保留的。例如对象具有has_error 集。程序调用带有前置条件(需要)not has_error 的功能。 (使用异常是因为担心返回码等可能会被忽略。其他一些语言有警察,我们通过异常是因为它们不能被忽略,但它们可以而且经常是。埃菲尔有抛出异常的警察,如果你忽略错误。)

标签: exception error-handling eiffel


【解决方案1】:

Eiffel 提倡使用对象状态而不是异常。在这种情况下,客户可能会弄​​清楚他们在发生错误时的期望并正确处理它。例如,

has_error: BOOLEAN
        -- Has operation terminated with an error?

error_code: INTEGER
        -- Last error code or `no_error'.

is_closed: BOOLEAN
        -- Is connection closed?

response: detachable RESPONCE
        -- Last response if `not has_error'.

send_request (data: REQUEST)
    require
        is_open: not is_closed
    do
        ...
    ensure
        is_closed: is_closed implies (has_error and not connection.is_open)
        is_successful: not has_error implies attached response
    end

然后,客户端可以推断供应商对象的状态并以可预测的方式继续使用它:

interface.send_request (...)
if interface.is_closed then
    ... -- The connection is unusable and should be reestablished.
elseif interface.has_error then
    ... -- Inspect `interface.error_code', possibly trying to resend the request.
else
    ... -- Use `interface.response' to continue processing.
end

在出现异常的情况下,除了一些文档之外,无法推断在什么情况下应该做什么。此外,它还阻止使用可以轻松检查response 的使用在上面的代码中是否完全有效的自动工具。

如果在堆栈的深处发生错误,则可以将异常机制与rescue/retry 一起使用。然而,它可能会在低级网络组件和与网络故障细节无关的用户界面之间引入紧密耦合。在最简单的情况下,网络类将调用{EXCEPTIONS}.raise 并带有适当的消息。更具体的方法是创建EXCEPTION(或后代)类型的对象,通过调用set_description 来设置相应的消息,并通过调用raise 引发异常。处理异常的用户代码可能如下所示。

local
    is_retried: BOOLEAN
    e: EXCEPTIONS
do
    if is_retried then
            -- There was an exception, handle it.
        create e
        if e.developer_exception_name ~ "This error" then
            ... -- Do something.
        elseif e.developer_exception_name ~ "That error" then
            ... -- Do something else.
        else
            ... -- Report yet another error.
        end
    else
        ... -- Some code that may fail with an exception.
    end
rescue
    if not is_retried then
        is_retried := True
        retry
    end
end

编辑

处理嵌套错误的特定方法取决于应用程序设计,并且似乎与语言无关。可能的替代方案是:

  1. 如果使用异常机制,不推荐。)在捕获(低级)异常并处理它以恢复类不变量后,会引发新异常而不取消前一个。然后可以(递归地)使用查询{EXCEPTION}.cause 来访问嵌套的异常对象。

  2. 可以使用与前一种类似的机制。但是,一个类可以将详细信息请求委托给较低级别​​的类,而不是创建新对象。例如,

    class A feature
        has_error: BOOLEAN
            do
                Result := nested.has_error
            end
        error: STRING
            do
                Result := "Cannot complete operation X. Reason: " + nested.error
            end
    feature {NONE}
        nested: B
    end
    
    class B feature
        has_error: BOOLEAN
            do
                Result := nested.has_error
            end
         error: STRING
            do
                Result := "Cannot complete operation Y. Reason: " + nested.error
            end
    feature {NONE}
       nested: C
    end
    
  3. 可以使用日志记录工具。他们可以区分错误严重性、指定来源等。

    class A feature
        do_something
            do
                nested.whatever
                if nested.has_error then
                    log.error ("Cannot complete operation X.")
                end
            end
        has_error: BOOLEAN do Result := nested.has_error end
    feature {NONE}
        nested: B
    end
    
    class B feature
        whatever
            do
                nested.try_something
                if nested.has_error then
                    -- An error has been reported by "nested".
                elseif something_else_goes_wrong then
                    has_inner_error := True
                    log.error ("Something goes wrong.")
               elseif has_minor_issues then
                     log.warning ("Be careful.")
                end
            end
        has_error: BOOLEAN do Result := nested.has_error or has_inner_error end
        has_inner_error: BOOLEAN
                -- Some error that is not one of the errors reported by `nested'.
    feature {NONE}
       nested: C
    end
    

【讨论】:

  • 谢谢,但不幸的是,这是一个“微不足道”的例子,因为只涉及两个例程。我忘了提到我知道 Eiffel 中的错误处理是如何工作的。我的问题是我找不到涉及多个例程的大量样本。例如,在您的代码中,假设错误无法解决,interface 是否会以相同的方式(通过状态)报告错误?它的调用者会(反过来)报告错误(通过状态)吗?错误是如何链接的?对于故障排除,单独的低级错误可能是晦涩难懂的,但同样也可能是单独的高级错误。
  • @Elena,更具体地说,您想使用异常或对象状态传播错误信息吗?另外,您能否提供更多有关您想到的示例的详细信息,以便答案也更具体?
  • 我想知道错误信息是如何在 Eiffel 中传播的。您说“埃菲尔提倡使用对象状态而不是异常”,我知道这一点,但我想知道当应用程序必须提供详细的诊断消息时,这种策略在实践中的表现如何,除了琐碎的例子。出于这个原因,我建议了一个使用网络设施的应用程序(很多事情可能会出错),但我不介意实际的例子。是否有我可以阅读其来源的 Eiffel 应用程序?
  • @Elena,没有通用的传播机制 - 由应用程序设计人员决定如何传播错误信息。我将在我的答案中添加一些示例。至于来源,你可以看看EiffelStudio 并寻找一个类ERROR 及其后代和客户。
  • @Elena,在EiffelStudio source code 中,您可以通过链接获取trunk/Src/Eiffel/eiffel/interface/external_class_c.etrunk/Src/framework/configuration/compiler/interface/conf_consumer_manager.e 类的来源并查找last_error。第一个类从特定于配置的错误中创建一个新的特定于编译器的错误。由于涉及异常(但仅用于指示错误,而不是转移其含义),因此这是基于答案中提到的方法1和2的混合解决方案。
【解决方案2】:

除了 Alexander 的回答之外,有时使用异常也很方便。在 Eiffel 中,我们不倾向于捕获它们(通常类不变量已变得无效),但对于某些应用程序,您只是不想处理错误。如果出现错误,您只需停止,并依靠程序外部的东西重试。使用这种方法的库的例子是 ecli 和 eposix。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2015-11-06
    相关资源
    最近更新 更多