在 Ada 中使用异常

Chr*_*bbs 6 ada

我正在寻找风格指导。在 Python 中,异常被用作“正常”操作:

try:
    z = x/y
except ZeroDivisionError:
    z = 73.0    # set z if y is zero
Run Code Online (Sandbox Code Playgroud)

我们不是检查 y 是否接近零,而是进行除法并捕获异常。

这种类型的方法在 John Barnes 的“Programming in Ada 2012”中的 Ada 中有说明:

begin
    Tomorrow := Day'Succ(Today);
exception
    when Constraint_Error =>
        Tomorrow := Day'First;
Run Code Online (Sandbox Code Playgroud)

但是,这本书接着说“这是一个非常糟糕的例子。异常应该用于很少发生的情况......”。

我是 Ada 的新手,像我们在 Python 中所做的那样,使用异常来避免 if 语句是一种好的 Ada 编程风格吗?或者异常真的只是在 Ada 中用于令人讨厌的事情?

fly*_*lyx 6

与 Python 的主要区别在于,在 Ada 中,异常不是数据类型。您可以与异常实例关联的唯一数据是字符串:

raise My_Exception with "some string";
Run Code Online (Sandbox Code Playgroud)

因此,在捕获异常时,我们只能知道抛出了哪种异常,并获取一些可能对日志有用的字符串,但对于以编程方式更详细地分析出了什么问题就没有那么多了。

这也意味着我们没有办法链接异常,就像它经常在 Java 中完成的那样,其中一个异常通常被包装在另一个异常中以隐藏细节,同时仍然能够在堆栈跟踪中看到到底出了什么问题.

这样做的原因是该语言是为几乎不使用异常而设计的。与 Python 不同,Ada 旨在针对裸机,您可能出于性能原因想要禁用运行时检查。如果你这样做,你不会得到Constraint_Error除以零,程序将有未定义的行为。因此,使用异常会对代码可移植性产生负面影响。

一些编译器提供了额外的选项,比如No_Exception_PropagationGNAT 中的限制,它只允许在同一子例程中捕获异常时才允许异常。

尽管如此,异常仍然是一种有用的工具,可以在不完全阻碍代码中的正常程序流程的情况下传达失败信息(如果您曾经编写过 Go 或 C,就会明白我的意思)。但总的来说,Ada 风格指南建议

异常应用作抽象的一部分,以指示抽象无法防止或纠正的错误情况。因为抽象无法纠正这样的错误,所以它必须向用户报告错误。

这意味着,如果您确实有可能在不使用异常的情况下纠正问题,那么您应该这样做,因为它应该是正常的、非异常的程序流程的一部分。


Jim*_*ers 4

Ada 异常处理语法不使用 try-catch 机制。因此,异常处理程序通常与引发异常的代码通过多行源代码分开。Ada 异常预计将用于真正异常的问题。Ada 更容易接受的样式如下所示。

  if Today < Day'Last then
     Tomorrow := Day'Succ(Today);
  else
     Tomorrow := Day'First;
  end if;
Run Code Online (Sandbox Code Playgroud)

此 Code Pattern 保留了源代码中两个非常接近的条件之间的关系。这两种情况都不是错误情况或异常情况。

从历史上看,Ada 风格更注重可读性而不是书写的紧凑性,但是 Ada 2012 标准确实允许条件表达式,例如

Tomorrow := (if Today < Day'Last then Day'Succ(Today) else Day'First);
Run Code Online (Sandbox Code Playgroud)

是否使用条件表达式可能是个人喜好的问题。

  • 我想说 `begin`-`exception`-`end` 在语法和语义上都非常接近 try-catch。 (4认同)
  • 我并没有反对其中的含义。我只是不明白 try-catch 与 begin-exception-end 有何不同。如果没有“声明”,新作用域无论如何都不包含任何符号。 (2认同)