2

elm's claim of zero-runtime-exceptions is one of its major selling point (see official website),

But if you stop to think about it, nothing stops you from dividing by zero or running out of memory.

What the elm compiler basically does, is forcing you to cover all possible paths that can lead to an exception.

For example:

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

But how does this differ from the infamous "checked-exceptions" feature in java ?

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

I never heard any claims that java is a zero-runtime-exceptions language.

Uri Goren
  • 13,386
  • 6
  • 58
  • 110
  • Java still has unchecked exceptions though. At best you could claim Java "has the capability of being a zero-runtime-exception language. – Carcigenicate Oct 17 '17 at 22:19
  • Fair point, so is all the fuss in `elm` is about the "checked-exceptions" feature that programmers hate and Microsoft chose not to include in `c#` ? – Uri Goren Oct 17 '17 at 22:23
  • Can't say. Don't know Elm, and it's been too long since I've used Java to comment on it. Just saw a logic flaw. Sorry. – Carcigenicate Oct 17 '17 at 22:25
  • 'Programmers hate'? I don't. – user207421 Oct 17 '17 at 22:33
  • You are misreading the article. The article does say that Elm claim it has zero-runtime-exceptions. Richard Feldman says that their **production system** has been running for 2 years without any runtime exceptions, mostly thanks to the language taking away the most common cause of runtime exceptions. If you take away the `null` value and the `throw` statement, there is very little left to cause an exception. Doesn't mean the code is error-free, just that it won't throw runtime exceptions. – Andreas Oct 17 '17 at 22:50
  • *"I never heard any claims that java is a zero-runtime-exceptions language"* Of course not, because it isn't. You also haven't heard any claims that java is a schoolbus. – Andreas Oct 17 '17 at 22:52
  • [Elm's claim](https://guide.elm-lang.org/error_handling/) is: *"One of the guarantees of Elm is that you will not see runtime errors **in practice**."* They don't claim "zero runtime exceptions”. Question down-voted as "not useful", since it's based on a misread of an article. – Andreas Oct 17 '17 at 22:54
  • @Andreas, it's not a misread, see this interview with the creator of elm, Evan Czaplicki. https://changelog.com/podcast/218. This is a short quote: """ Essentially, what we realized is you can just say, "These programs don’t get runtime errors." That’s the summary of all the theory that people have been working on for decades. So we took that core idea, and that’s just a part of Elm. """ – Uri Goren Oct 18 '17 at 07:51
  • 1
    @UriGoren Your question is about "zero-runtime-exceptions languages". Elm doesn't claim to be that. They use phrases like "essentially" and "in practice" to mean close-to-zero. Your question starts with *"`elm`'s claim of zero-runtime-exceptions"*, and that is not correct, because they don't actually claim to have **zero** runtime exceptions. – Andreas Oct 18 '17 at 22:58
  • elm's official website (http://elm-lang.org) says "No runtime exceptions" on the front page in bold. – Uri Goren Oct 19 '17 at 10:45
  • My question is, if that's the case, is it only because of the reinvention of checked-exception ? – Uri Goren Oct 19 '17 at 10:46
  • 1
    In the elm repl, `1 / 0` yields `Infinity : Float`, not an exception. – Matt McHenry Oct 21 '17 at 17:41
  • @Uri Goren hi. Your example is too contrived (I hope). Would you really ever consider conflating an Err code with the result of the correct input "0" ? Yuk. It shows IMO the problem with exceptions : they form a separate return path from your call stack (the exception stack). And it is just too bothersome to handle the exceptions right. Which creates the temptation of reintegrating the normal return stack by such hideous ack as replacing an error by a default value. – Titou Nov 09 '17 at 21:34

2 Answers2

5

Please don't get too caught up on what is essentially marketing hyperbole. Of course there are classes of errors that you will never be able to fully rule out with any compiler.

As such, I've always taken these zero-runtime-exceptions claims with a grain of salt, but I think I understand the proponent's intent. Elm was created as an alternative to developing front-end applications in Javascript, which is a messy world where exceptions abound and are just part of everyday life. Elm makes it much harder to shoot yourself in the foot, and without too much effort, if you run through basic sanity testing on your app, you probably won't ever have runtime exceptions in production.

Elm drastically reduces the possibility of exceptions in a few ways.

  1. There is no notion of a throwable exception in the language aside from Debug.crash, which, as its name implies, should really only be used for debugging and stubbing out incomplete logic paths.

    Since there are no throwable exceptions, handling problems is most often done through types like Result and Maybe.

    This could be thought of as loosely analagous to Java's checked exceptions but conceptually they feel very different than me. Let's face it. Exceptions have been abused. You mention an example in Java, where Integer.valueOf() says that it is going to return an int but if you pass it anything else, it unrolls the stack and bubbles up until some function hopefully catches it. This feels very messy to me, and sure, checked exceptions can aid in reducing the window for failure propagation, but the underlying fact is that an exception is the wrong tool for business logic.

    An alternative to throwing an exception would be to have classes analagous to the Result and Maybe Elm types, but that would have been nearly impossible in the early days of Java to do cleanly, and even with Generics, writing such types is more tedious and error prone than the simplicity of Elm's types. And because of Elm's closed type system,

  2. Non-exhaustive pattern matches cause a compilation failure

    In Java and Javascript, there is no way to have exhaustive pattern match checking because the type system does not allow it. Sure, Typescript has introduced some functionality but you have to opt into it. In Elm, you have to explicitly handle all cases. Sure, I suppose you could argue that Elm let's you opt out of exhaustive pattern matching by ending all case statements with a catch-all _, but that would just be a silly abuse of the language. Those checks are there to help you, and I feel much safer with the fact that I don't get to opt-in to error checking in Elm - it's there by default!

  3. Immutability

    Immutability avoids loads of potential types of errors, too many to get into here.

  4. The Elm Architecture offers a clean separation between Javascript and Elm

    Elm compiles down to Javascript, but the Elm Architecture offers a nice clean barrier to keep all the nasty bits of Javascript away from the pure code written by Elm. Any exception that may happen in Javascript should be handled by that barrier, such that I/O errors will always be translated into an Elm-friendly, exceptionless type.

In the end, runtime exceptions are still possible (case in point: the next tagged Elm question dealt with a well-known runtime exception caused by a recursive JSON Decoder definition), and I cringe a little any time I hear someone say it's impossible to get an exception in Elm. The fact of the matter is that exceptions are possible, but nearly every exception you'd run across in day-to-day Javascript development is essentially impossible in Elm.

pyrmont
  • 225
  • 5
  • 12
Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
4

As a commenter pointed out, Java has unchecked exceptions, so runtime errors do occur. Elm also has unchecked exceptions, for things like division by zero, but gets rid of the ones most commonly seen in practice. And as Chad's answer mentions, Elm's Maybe/Result types work quite differently in practice than Java's checked exceptions. An experienced Elm programmer would not write a function like toIntOrZero (and if they did, they would probably not use case ... of, preferring instead something like toIntOrZero = String.toInt >> Result.withDefault 0).

Chaining multiple operations together with Result.map, Result.andThen, and so on gives a very expressive way of handling error cases without forcing the programmer to get too deep in the weeds. For example, if we want to write a function that validates an ID by converting it to an Int, looking it up in some data structure (when it might not be there), and then verifying some property associated with that user, we can write something like this:

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

This reads, "convert the ID to an int, then look up the associated user, then verify the user, and if anything failed, return False." Your mileage may vary, but once you get to used to it, I (and many Elm programmers, I think!) find this to be a really nice way of writing code robust to errors.

Alex Lew
  • 2,064
  • 14
  • 17