4 ms·
I think most of what people call Rust's "ugliness" is actually just Rust's explicitness. You have to chain a lot of method calls for things that might happen im
by brundolf 4y ago
I think most of what people call Rust's "ugliness" is actually just Rust's explicitness. You have to chain a lot of method calls for things that might happen implicitly in other languages; you have to annotate lifetimes and constrain generic type params; sometimes you have to manually parameterize the generics you're using; etc. But I think most of that is unavoidable without shifting some of Rust's core values.
The only piece of surface-level syntax that I'm really truly bothered by is the closure syntax:
fn_with_a_callback_1(|param| param + 2);
fn_with_a_callback_2(|param| {
println!("{}", param);
});
- The fact that the | | is the same character on each side
- The lack of directionality from the args -> to the body
- The lack of any kind of overlap with the normal function syntax fn foo()
Especially compared with something like JavaScript which has a really lovely lambda syntax, this one's hard to look at. I'm sure there were good reasons around ambiguity with other syntaxes or something, but... eesh.
- lifthrasiir 4y agoTo my knowledge, this closure syntax was a direct Ruby influence mainly because this syntax was also supposed to work like Ruby blocks: `array.each |e| { ... }`. Originally owned and shared closures had a different syntax (`fn~() { ... }` or `fn@() { ... }`)---this was back when Rust had a built-in shared reference, roughly equivalent to `std::sync::Arc` in the modern Rust---and it was pointed out that they should be harmonized at some point [1]. It was that time when people realized that then-loop-only syntax can be generalized into any closures, and this semi-decision got stuck even after the "internal" iterator that accepts a closure has long gone. [1] https://github.com/rust-lang/rust/issues/1864 https://github.com/rust-lang/rust/issues/1864
- fsckboy 4y ago> I think most of what people call Rust's "ugliness" is actually just Rust's explicitness. I think most of what people call C's ugliness is actually just C's power. Some of it is C's age: we can't blame C for being born in the very early 1970s (when sensible ISAs were just born), but when you update C, don't try to make it be something that it's not. You see the beauty of UTF-8? People who could not have invented UTF-8 can at least see the beauty of UTF-8. Unfortunately, people who could not have invented C, are updating C. When you try to update C, not only don't wreck it, don't try to replace it with something emo, weak, and overwrought, which is what Rust is. C is powerful, natural, and concise. It doesn't wipe your ass for you. Wiping your ass neatly is not something you want to entrust to a bulletproof syntax, not when you can always just wash your hands. Rust? Rust has the color of not washing your hands because Rust imagines that it made it unnecessary.
- Already__Taken 4y agoI'm just surprised anonymous fn () { } wasn't the obvious choice for closure.
- majewsky 4y agoThis is pretty much the closure syntax used by Go, and it's one of its biggest issues (IMHO). Even if you had map/filter/etc. methods on slices, it would still look like: squares := numbers. filter(func(x int) bool { return x >= 0 }). map(func(x int) int { return x * x }) With what I understand to be your suggested Rust syntax, this would still me: let squares: Vec<_> = numbers.iter() .filter(fn(x: i64) -> bool { x >= 0 }) .map(fn(x: i64) -> i64 { x * x }) .collect(); which is a lot of noise compared to let squares: Vec<_> = numbers.iter().filter(x => x >= 0).map(x => x * x).collect();
- shakow 4y agoThere is no reason changing only the syntax would prevent the compiler from inferring in/out types. It would be something more akin to: let squares: Vec<_> = numbers.iter().filter(fn(x) { x >= 0 }).map(fn(x) { x * x }).collect();
- arp242 4y agoWhat makes the Go code so verbose isn't so much that you have to type "func()", but rather that you need to list out all the types, as well as the need for an explicit return. squares := numbers. filter(func(x) { x >= 0 }). map(func(x) { x * x }) let squares: Vec<_> = numbers.iter() .filter(fn(x) -> { x >= 0 }) .map(fn(x) -> { x * x }) .collect(); You don't necessarily need new syntax for this, although it may help with clarity. The Rust => code is still a bit shorter, but not much and I don't think it matters much.
- sivizius 4y agoFor the record: let squares: Vec<_> = numbers.iter().filter(x => x >= 0).map(x => x * x).collect(); is not valid Rust, but this is: let squares: Vec<_> = numbers.iter().filter(|&&x| x >= 0).map(|x| x * x).collect();
- edflsafoiewq 4y ago> But I think most of that is unavoidable without shifting some of Rust's core values. Well yes. Turns out beauty is not just skin deep. Semantics actually matter. You can't make a beautiful language by slapping some magical surface syntax on top of any language you like.