I read this all the time about Elm, but did you actually try Elm for a real world project?
I did, and Elm error messages were one of the most painful point of the compiler: they're beautiful but very often completely unrelated to what's actually going wrong. They actually drove me away from the actual errors more than once.
I'm actually writing Elm at work and we have two separate Elm apps in production.
YMMV but Elm with elm-graphql has been the most productive and confident I've ever been writing frontend code.
Both those technologies have well-earned reputations for having not-so-shallow learning curves, but that's almost not an issue when the tools always make it clear what has gone wrong.
One similarity to this post that sticks out:
> Maybe you just try the JavaScript way to see if it works:
Given that the final syntax for async/await was a bit controversial (postfix .await), the compile folks implemented parsing for (at least) the JavaScript way of doing it, and so you get a good error message telling you the correct way:
error: incorrect use of `await`
--> src/lib.rs:2:5
|
2 | await bar()
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
This kind of thing can really help polyglots, as well as people new to the language.A human/e interface to compiler errors is critical to me. It means the difference between the compiler being an ally and the compiler being an enemy (or maybe a teacher who thinks you're just a bad student and is going to give you a bad grade no matter what, not that there's any scar tissue there).
Matters the world to me personally in terms of my enjoyment and flow and represents the kind of computing I want to do.
I have not personally had the usecase for Rust just yet, but it is the only language I have never heard a negative thing about. That's huge, with how opinionated developers are.
The arguments for the language and general consensus are so strongly positive that without having used it myself I frequently recommend it (I passively follow the language's progress online).
A huge part of it is the developer ergonomics, a large amount of which comes from your compiler error messages.
When I talk to people about the gold standards, Rust and Elm are the examples I give.
Thank you guys for all your work!
Still in spite of that, I think it's an awesome project with a lot of enthusiasm behind it, and I'm happy to see languages exploring new ideas getting so much attention.
I suppose you can't have everything, but in my experience top level inference makes code a lot easier to read because it removes a lot of noise and redundant information while largely leaving the "intent" of the code in place.
fn foo() {
String::new()
}
fn bar() {
foo()
}
fn main() {
let s: String = bar();
}
Imagine you modify foo, and now you're accidentally returning a Vec, not a String: fn foo() {
Vec::new()
}
fn bar() {
foo()
}
fn main() {
let s: String = bar();
}
You'd get an error like this: error[E0308]: mismatched types --> src/main.rs:10:21
|
10 | let s: String = bar();
| ^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
|
= note: expected type `std::string::String`
found type `std::vec::Vec<i32>`
You changed foo, but the error points to bar, in main. None of this is related to the code you changed. But in Rust today, you'd get error[E0308]: mismatched types
--> src/main.rs:2:9
|
1 | fn foo() -> String {
| ------ expected `std::string::String` because of return type
2 | Vec::new()
| ^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
|
= note: expected type `std::string::String`
found type `std::vec::Vec<_>`
This points right to the issue: you're returning a vec, and not a string, in foo.There are other issues too; global inference and subtyping have problems. While Rust doesn't have subtyping generally, we do in lifetimes...
Beyond all of that though:
> it removes a lot of noise and redundant information while largely leaving the "intent" of the code in place.
Rust's perspective on this is that the type signature is what communicates your intent. It's like a unit test. You write down what you expect, and then the compiler's job is to check that your code does what you said you were going to do. This seems like philosophically at odds with what you expect, which is fine of course, but is probably where a lot of the divergence comes from.