5 ms·
Elm's primary selling point is "no runtime exceptions". The subheader on Elm's homepage even says this[1]: Generate JavaScript with great performance and n
by fbonetti 9y ago
Elm's primary selling point is "no runtime exceptions". The subheader on Elm's homepage even says this[1]:
Generate JavaScript with great performance and no runtime exceptions.
Type safety doesn't come for free. If you want to build an application that doesn't have runtime exceptions, you have to specify what external data should look like, how to translate that data into a native datatype, and what to do if that expectation fails. With this in mind, you can't just write `JSON.parse(data)` and expect everything to work. What if your data has a different shape? What if it's missing fields? What if field "foo" is a String instead of an Int?
Here's a short example in Typescript:
import fetch from "node-fetch"
interface Post {
user_id: number,
id: number,
title: string,
body: string
}
const postUrl = 'https://jsonplaceholder.typicode.com/posts/1'
const show = function(post: Post) {
console.log(post.user_id)
console.log(post.id)
console.log(post.title)
console.log(post.body)
}
function getJSON(): Promise<Post> {
return fetch(postUrl).then(x => x.json())
}
getJSON().then(show)
Do you see the bug? `user_id` is supposed to be `userId`, yet this example will compile without an issue. When you run it, `post.user_id` will be undefined, even though our interface clearly states that a Post most have a `user_id` field of type `number`. The compiler won't catch this even with `--strictNullChecks` enabled.
Everything in programming is about tradeoffs. If you don't care about strong type correctness, use something like Typescript. If you do care, Elm is a great choice.
[1]: http://elm-lang.org/ http://elm-lang.org/
- hudon 9y agoElm's type system will not catch this bug at compile time, it will still be a runtime exception, unless you're saying Elm's compiler does an HTTP call to that endpoint to verify that the interface matches the response object?? The only difference in your example probably is that Elm will force you to handle the case where your interface doesn't match the response object (missing field, in this case). But nothing in Elm forces you to handle it well, so if the programmer forgot to handle it well in TypeScript, they will do the same in Elm, and the end result will be the exact same: a runtime failure.
- fbonetti 9y ago> Elm's type system will not catch this bug at compile time This is completely false. Elm's type system will force you to handle the decoding failure at compile time. The `decodeString` function has the following type: decodeString : Decoder a -> String -> Result String a Which means that when you call `decodeString`, it will return a Result containing either the decoded value or a String describing the error. This is not a "runtime failure". This is the compiler forcing you to explicitly spell out what you want to happen the case of a decoding problem. The difference between Typescript and Elm is that Typescript's compiler will happily let your program crash when this type of issue occurs, whereas Elm's compiler won't.
- hudon 9y agoYou're just rewording what I said. The coder can simply ignore that string or make it empty, which can lead to a runtime failure if another module depends on a value being returned (think a runtime failure from a non-exhaustive pattern match). If they were a lazy coder in TypeScript, they'll be lazy in Elm (: So, no, what I said is not "completely false"
- Exolon 9y agoI would dispute the idea that "if they were a lazy coder in TypeScript, they'll be lazy in Elm". The fact that Elm forces you to at least think for a moment about how handle the failure case is a good thing. Even if you're inclined to take the path of least resistance, as probably most of us programmers are, what does that actually look like? You have one case branch that looks like: GotUserList (Ok userList) -> ... and another that looks like: GotUserList (Err _) -> ... Since we need to pattern match on both types of the Result structure in our update cycle, there isn't really an opportunity to implicitly gloss over a failure to parse. Of course you can try to make the decoder super permissive, but this is harder than doing it the right way. If you're REALLY lazy, you can throw in "Debug.crash" in the failure case, but there's no general solution for throwing grenades at your foot :D
- Skinney 9y ago