Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does elm's compilation differ from Java's checked exceptions?

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.

like image 731
Uri Goren Avatar asked Mar 15 '26 15:03

Uri Goren


2 Answers

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.

like image 155
Chad Gilbert Avatar answered Mar 18 '26 05:03

Chad Gilbert


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.

like image 23
Alex Lew Avatar answered Mar 18 '26 05:03

Alex Lew



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!