【问题标题】:How does elm's compilation differ from Java's checked exceptions?elm 的编译与 Java 的检查异常有何不同?
【发布时间】:2017-10-17 22:17:23
【问题描述】:

elm声称zero-runtime-exceptions是其主要卖点之一(见official website),

但如果你停下来想一想,没有什么能阻止你除以零或内存不足。

elm 编译器的基本作用是强制您覆盖所有可能导致异常的路径。

例如:

import String exposing (toInt)
toIntOrZero s = case toInt s of
                          Err e -> 0
                          Ok val -> val

但这与java 中的infamous“检查异常”功能有何不同?

public static Integer toIntOrZero(String s) {
    try { return Integer.valueOf(s); }
    catch (NumberFormatException e) { return 0; }
}

我从未听说过任何声称 java 是零运行时异常的语言。

【问题讨论】:

  • Java 仍然有未经检查的异常。充其量你可以声称Java“具有成为零运行时异常语言的能力。
  • 公平点,elm 中的所有大惊小怪都是关于程序员讨厌的“检查异常”功能,而微软选择不包含在 c# 中?
  • 不能说。不知道Elm,太久没用Java评论了。刚看到一个逻辑缺陷。对不起。
  • @UriGoren 您的问题是关于“零运行时异常语言”的。榆树并没有声称自己是那样的。他们使用“基本上”和“在实践中”等短语来表示接近于零。您的问题以 "elm's claim of zero-runtime-exceptions" 开头,这是不正确的,因为他们实际上并没有声称拥有 zero 运行时例外。
  • 在 elm repl 中,1 / 0 产生 Infinity : Float,不是例外。

标签: java elm checked-exceptions


【解决方案1】:

请不要过于关注本质上是营销夸张的东西。 当然有些错误是你永远无法用任何编译器完全排除的。

因此,我一直对这些零运行时异常声明持保留态度,但我想我理解支持者的意图。 Elm 是作为用 Javascript 开发前端应用程序的替代方案而创建的,这是一个混乱的世界,异常比比皆是,只是日常生活的一部分。 Elm 让自己更难自爆,而且如果您在应用程序上运行基本的健全性测试,则无需太多努力,您可能不会在生产中遇到运行时异常 .

Elm 在几个方面大大降低了异常的可能性。

  1. 除了Debug.crash,语言中没有可抛出异常的概念,顾名思义,它实际上应该只用于调试和排除不完整的逻辑路径。

    由于没有可抛出的异常,处理问题通常通过ResultMaybe 等类型来完成。

    这可以被认为是类似于 Java 的检查异常,但在概念上它们与我的感觉非常不同。面对现实吧。例外被滥用。您提到了 Java 中的一个示例,其中Integer.valueOf() 表示它将返回一个 int 但如果您将其传递给其他任何内容,它就会展开堆栈并冒泡,直到某个函数有望捕获它。这让我感觉很混乱,当然,检查的异常可以帮助减少故障传播的窗口,但基本事实是异常是业务逻辑的错误工具。

    抛出异常的另一种方法是让类类似于 ResultMaybe Elm 类型,但在 Java 的早期,这几乎不可能干净地完成,即使使用泛型,编写这样的类型比 Elm 的简单类型更乏味且容易出错。而且由于 Elm 的封闭类型系统,

  2. 非详尽的模式匹配导致编译失败

    在 Java 和 Javascript 中,没有办法进行详尽的模式匹配检查,因为类型系统不允许这样做。当然,Typescript 已经引入了一些功能,但你必须选择加入它。在 Elm 中,您必须明确处理所有情况。当然,我想你可能会争辩说 Elm 让你选择退出详尽的模式匹配,方法是用一个包罗万象的 _ 结束所有 case 语句,但这只是对语言的愚蠢滥用。这些检查可以为您提供帮助,而且我没有选择加入 Elm 中的错误检查这一事实让我感到更安全 - 默认情况下它就在那里!

  3. 不变性

    不变性避免了许多潜在的错误类型,这里太多了。

  4. Elm 架构提供了 Javascript 和 Elm 之间的清晰分离

    Elm 可以编译为 Javascript,但 Elm 架构提供了一个很好的干净屏障,可以让所有讨厌的 Javascript 部分远离 Elm 编写的纯代码。 Javascript 中可能发生的任何异常都应由该屏障处理,这样 I/O 错误将始终转换为 Elm 友好的无异常类型。

最后,运行时异常仍然是可能的(例如:next tagged Elm question 处理了由递归 JSON 解码器定义引起的众所周知的运行时异常),每当我听到有人说这是不可能在 Elm 中获得例外。事实上,异常是可能的,但您在日常 Javascript 开发中遇到的几乎所有异常基本上在 Elm 中都是不可能的。

【讨论】:

    【解决方案2】:

    正如评论者指出的那样,Java 有未经检查的异常,因此会发生运行时错误确实。 Elm 也有未经检查的异常,比如除以零,但去掉了实践中最常见的异常。正如 Chad 的回答所提到的,Elm 的 Maybe/Result 类型在实践中的工作方式与 Java 的检查异常完全不同。有经验的 Elm 程序员不会编写像 toIntOrZero 这样的函数(如果他们这样做了,他们可能不会使用 case ... of,而是更喜欢 toIntOrZero = String.toInt >> Result.withDefault 0 这样的函数)。

    将多个操作与Result.mapResult.andThen 等链接在一起提供了一种处理错误情况的非常有表现力的方法,而不会迫使程序员深入杂草。例如,如果我们想编写一个函数,通过将 ID 转换为 Int 来验证 ID,在某些数据结构中查找它(当它可能不存在时),然后验证与该用户关联的某些属性,我们可以编写像这样:

    lookupUser : Int -> Result String User
    lookupUser intId = ...
    
    userInGoodStanding : User -> Bool
    userInGoodStanding user = ...
    
    isValidId : String -> Bool
    isValidId id = 
      String.toInt id 
      |> Result.andThen lookupUser 
      |> Result.map userInGoodStanding
      |> Result.withDefault False
    

    其内容为“将 ID 转换为 int,然后查找关联的用户,然后验证用户,如果有任何失败,则返回 False。”你的里程可能会有所不同,但是一旦你习惯了它,我(我认为还有许多 Elm 程序员!)发现这是编写对错误具有鲁棒性的代码的一种非常好的方法。

    【讨论】:

      猜你喜欢
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 2012-08-07
      • 1970-01-01
      • 2010-11-05
      • 2011-09-01
      相关资源
      最近更新 更多