Maybe it's my recent living in the Erlang/Elixir community, but writing code that is not possible to crash doesn't make sense to me. Servers die, machines get unplugged, network partitions happen, etc. I don't discount that the type system allows you to specify segments of your program that can be provably impossible to crash, but doing that for entire nontrivial programs seems like an impossible ask to me.
The general aim of error handling in languages like Elm is for types to not lie. If you can either return a result, or an error, the type represents that. The more places that can return an error: the more complex the types, and the more complicated the error handling. You can always pass the error value up through layers, but as people would say, it's just easier to make illegal states unrepresentable.
It's not an aim to pretend that failures don't happen, especially when doing remote calls, and the types will be transparent in showing where this occurs.
> Servers die, machines get unplugged, network partitions happen, etc
These things happen in backend / distributed systems. They don't really happen in the browser, which is basically a self-contained sandbox that can make network requests. The browser code needs to handle those network requests maybe failing, but that's about it in terms of dealing with unpredictability. So, it's totally reasonable to think that a web-app should never be able to crash.
So if I make two API requests and get some nonsensical data that comes back, (say v1 from the first request, and v2 comes back from the second because of some bug in the backend). The program can certainly prepare itself for validating that data, and reject the v2 if it's not prepared for it, but then what do you do? To me "crashing" that entire page is a reasonable way to get around that for some programs. You as a browser can also lose Internet, in which case you also need to be prepared for things that happen on the other end depending on the circumstances of disconnection (did my request go out before it died? should I retry?). The problem is certainly more constrained, to your point, by being in a browser, but it's trivial to get your program in a nonsensical state that such that you cannot render as soon as you introduce external APIs. Perhaps Elm gets around this somehow, but I'm failing to see how.
> The program can certainly prepare itself for validating that data, and reject the v2 if it's not prepared for it, but then what do you do? To me "crashing" that entire page is a reasonable way to get around that for some programs.
Such stuff is mostly handled via types like `Maybe APIResponse` or `Either ErrorMsg APIResponse`, so the type systems can guarantee that you handle both cases. And handling the error case (even if it's just a simple message to the user like "Error: Unable to fetch new weather data for location X/Y") is better then just crashing.
I mean it depends on your definition of crashing, but I consider it similar to undefined behaviour. So I greatly prefer
$ ./fetch_weather $location
panic: unable to fetch new weather data for location X/Y
to
$ ./fetch_weather $location
Segmentation fault
and I guess most people do (where segfault is similar to 500 Internal Server Error which is equally bad).
Browser code often hangs forever and then the user has to reload the page. There might not be an error message, but this is still a bad user experience.
You’re describing errors. Errors do occur in Elm, but they rarely lead to crashing.
The type system forces the developer to deal with the error, so that, hopefully, the user of the app has a better experience than a non-responsive web page.
Crashes we cannot avoid through the type system is stuff like stack overflow or running out of memory.
I could not agree more - and in fact, have no recourse when a developer tells me with a straight face that their code "cannot crash". The worlds best type system doesn't prevent timeouts, running out of disk space, memory, etc. The attitude I typically receive when trying to push pragmatism instead of idealism is usually a "you just don't understand". Throwing an exception is _not_ the worst thing a program can do, by a hell of a long shot!
«Cannot crash» != «cannot fail». There are a bunch of things in Elm that can fail, but the language forces you, «through types», to deal with those situations.
That doesn’t mean developers make apps that deal with errors reasonably, but the developers should be aware of every part of the application that can fail.
Exception, of course, beeing stavk overflows as we haven’t solved the halting problem yet.