使用Checked Exceptions设计语言

时间:2010-02-09 12:18:32

标签: exception language-design

我很清楚关于检查异常是否是一个好主意的整个论点,我认为它们是......但这不是这个问题的重点。我正在设计一个相当简单的编译OOP语言,我决定使用已检查的异常作为一种返回错误的方法,而不会返回返回错误代码的C路径。

我正在寻找一些见解,了解如何改进已检查异常的Java模型,以消除大多数不良方面,可能是语法更改或稍微改变实际功能。对已检查异常的主要批评之一是,懒惰的程序员可能会吞下它们,因此不会出现错误。

也许它可以是可选的捕获异常,因此如果没有捕获,程序会崩溃?或者也许可以有特定的表示法来表示没有处理异常(比如C ++虚函数'= 0'表示法)?或者,如果异常处理程序为空,我甚至可能导致程序崩溃(虽然这可能会让语言新手的程序员感到惊讶)?

try ... catch语法怎么样,你认为可以用更简洁的方式表达异常被捕获吗?该语言将使用垃圾收集器,就像Java一样,所以是否需要finally子句?最后,还有哪些其他缺点可以检查异常以及可能存在哪些解决方案(如果有的话)?

7 个答案:

答案 0 :(得分:13)

答案 1 :(得分:2)

我认为您应该阅读jdk7中的Neil Gafters post regarding the improved exception handling和C#中的异常处理interview with Anders Hjelsberg

答案 2 :(得分:2)

我认为你应该考虑使用像Lift的Box类型这样的三态monad来处理错误。然后你根本不需要使用例外。

http://github.com/dpp/liftweb/blob/master/framework/lift-base/lift-common/src/main/scala/net/liftweb/common/Box.scala

答案 3 :(得分:1)

  

我很清楚关于检查异常是否是一个好主意的整个论点,我认为它们是......

FWIW,我同意 - 总的来说,他们是一件好事(tm)。程序员使用功能的坏习惯并不一定意味着功能不好。在大多数情况下,我认为程序员不明白他们可以通过异常并将其推上链。

  

也许可以选择捕获异常,因此如果没有捕获异常,程序会崩溃吗?

Java具有该功能(RuntimeException,其子类是未经检查的异常)。

  

或者可能有特定的符号表示没有处理异常......

Java有这个;方法声明中的throws子句。

  

try ... catch语法怎么样,你认为可以用更简洁的方式表达异常被捕获吗?

当然,它可能会感觉有点笨拙,但目标是将主要逻辑中的异常情况考虑在内。

但是,我对try..catch提出了一些建议:

catch..from

这是我在Java和相关语言中长期需要的东西(真的需要正确编写并提交JSR):catch...from

以下是一个例子:

FileOutputStream    output;
Socket              socket;
InputStream         input;
byte[]              buffer;
int                 count;

// Not shown: Opening the input and output, allocating the buffer,
// getting the socket's input stream

try
{
    while (/* ... */)
    {
        count = input.read(buffer, 0, buffer.length);
        output.write(buffer, 0, count);

        // ...
    }
}
catch (IOException ioe from input)
{
    // Handle the error reading the socket
}
catch (IOException ioe from output)
{
    // Handle the error writing to the file
}

正如您所看到的,此处的目标是分离对套接字读取错误和文件写入错误的无关错误处理。非常基本的想法,但涉及很多细微之处。例如,套接字或文件输出流实例在被覆盖下使用的其他对象抛出的异常需要被处理,好像被该实例抛出一样(不是很难,只需要确保实例信息在堆栈跟踪中) )。

这是可以对现有机制和严格的编码指南所做的事情,但这非常困难。

单个块中的多个catch表达式

计划的JDK7增强功能。

重试

非常,提供比上述更难,也更容易让人们解决,因此价值低很多。但是:提供“重试”语义:

try
{
    // ...stuff here...

    if (condition)
    {
        foo.doSomething();
    }

    // ...stuff here...
}
catch (SomeException se)
{
    if (foo.takeRemedialAction() == Remedy.SUCCESS)
    {
        retry;
    }

    // ...handle exception normally...
}

在这里,doSomething可能会以特殊方式失败,但takeRemedialAction可以纠正。这继续保持将特殊条件排除在逻辑主线之外的主题。当然,retry将执行返回到失败的操作,这可能在doSomething或其调用的某个子方法深处。你明白我对挑战的意思。

这个团队使用现有机制更容易:只需在异常时创建doSomethingtakeRemedialAction的子例程,然后将该调用放在主线逻辑中。所以,这个名单上的低位,但是嘿......

答案 4 :(得分:0)

我没有看到另一种方法来绑定可能存在错误的代码块。我认为try .. catch块是一致的。 Ruby作为一种改进,有一个关键字允许重复失败的代码块,这是一个很好的改进,我认为

答案 5 :(得分:0)

the programming language CLU的异常处理机制经过全面检查,专为坚如磐石的可靠性而设计。由于几乎所有现代异常机制都是CLU原始模型的更宽松版本,因此值得仔细研究。如果您可以访问一个好的库,paper by Liskov and Snyder非常值得一读。

关于语法,有一个superb paper by Nick Benton and Andrew Kennedy解释了标准语法的弱点,并提出了一个引人注目的新变体。对于在这个领域进行设计的人来说,应该要求阅读。

答案 6 :(得分:0)

恕我直言,检查异常可能是一件好事,但更大的问题是大多数异常层次都非常破碎。问题在于,异常中没有任何内在的东西表明它是否表示“函数调用不起作用”之外的问题。例如,如果一个人调用了一个LoadDocument方法并且抛出了某种类型的异常,那么就没有好的方法来判断正确的事情是报告该文件是否无法加载,但是其他一切都没问题,或者是否会最好是以有序的方式关闭程序,或者就此而言,除了突然退出之外做任何事情都会冒着破坏文件系统的风险。检查异常可能是好的,如果它们暗示一切状态都很好,除非方法不起作用所暗示的程度。不幸的是,我见过的系统没有一个有用的异常层次来区分它。由于异常是由错误组织的,而不是由系统状态的影响组织,因此没有什么好方法可以知道应该捕获和包装哪些异常,以及应该冒出什么异常。

实际上,在许多情况下最好的方法是同时抛出多个异常的方法,一堆异常在堆栈中向上传播直到所有异常被捕获。我想知道是否有任何系统适应这样的事情?