6 ms·
and this is how rust gains its reputation as an ugly to read language with inconsistent syntax: design by committee
by arccy 1y ago
and this is how rust gains its reputation as an ugly to read language with inconsistent syntax: design by committee
- wtetzner 1y agoUgly is subjective, but which part of the syntax is inconsistent?
- arccy 1y ago.await something that looks like a field access but actually does something else
- pornel 1y agoDesigns have trade-offs. In this case, it was important for await and error handling with the ? operator to be readable together. The order of operations in `await foo()?` is ambiguous, but `foo()?.await` and `foo().await?` have an obvious and clearly visible order. As a bonus, the syntax supports chaining multiple async operations without parenthesis. `fetch().await.body().await` is much nicer to write than `await (await fetch()).body()`. Since `await` is a reserved keyword, `.await` can't be a field access. Editors with syntax highlighting can easily color it like a keyword. The problem looking like a field has proven to be total a non-issue in practice. OTOH the syntax avoided major pitfall of visually unclear operator precedence, inconvenience of mixing of prefix and postfix operators, and ended up being clear and concise. It's been such a success, that users have since asked to have more keywords and macros usable in a postfix form.
- Macha 1y agoIt's also worth considering that many editors have default snippets that transform something.await into (await something) for languages with prefix await, so it kind of makes sense to cut out the middle man and just make that the syntax to me.
- maleldil 1y agoThat transformation makes writing both variants similar, but you still need to read `await (await fetch()).body()`, which IMO is much worse.
- dlisboa 1y agoI don't know if this qualifies as inconsistent, but: `impl T for for<'a> fn(&'a u8) {}` The `for` word here is used in two different meanings, both different from each other and from the third and more usual `for` loop. Rust just has very weird syntax decisions. All understandable in isolation but when put altogether it does yield a hard to read language.
- steveklabnik 1y agoAll three have the same underlying idea: do this for every thing of that. In the first case, it's implement a trait for a type. In the second case, it's "for all choices of the lifetime" and for a for loop, it's do something for each element of a collection.
- dlisboa 1y agoI understand how that seems logical in isolation but it's just not how syntax is usually read by people. It's done so as part of a reading context instead of as separate syntatical tokens. The underlying idea is not the same for the reader because the context is vastly different.
- wtetzner 1y agoThis feels disingenuous. I have a hard time imagining a case where someone would find this confusing.
- steveklabnik 1y agoSure, and I think that's insightful: what you may consider a mess, I may consider orthogonal!
- NobodyNada 1y agoRust tends to prefer reusing keywords (in unambiguously different contexts) rather than introducing new ones, because adding a new keyword is a backwards compatibility break that requires a new language edition and creates migration pain for anyone who had an identifier with the same name as the new keyword.
- selfmodruntime 1y agoI tended to disagree on this discussion in the past, but I increasingly no longer do. For example, let's have a look at the new `implicit lifetime capturing` syntax: fn f(x: &()) -> impl Sized + use<'_> { x } It's weird. It's full of sigils. It's not what the Rust team envisioned before a few key members left.
- joshuamorton 1y agoThe only parts of this that I (as someone who has dabbled in rust, but barely interacted with explicit lifetimes, ever) am confused by is "&()". And I assume it is similar to some kind of implicit capture group in cpp ("[&]") and "`_", which is a lifetime of some kind. I don't know what the "use" keyword does, but it's not a sigil, and "->", "impl Sized", and "{"/"}" are all fairly self-explanatory. I will say https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifetime-capture.html https://doc.rust-lang.org/edition-guide/rust-2024/rpit-lifet... does not answer any of my questions and only creates more.
- Macha 1y agoIt's a reference to a unit type. unit is pretty useless (like void in Java). It's sort of a silly thing you wouldn't do in real production code, just whoever wrote this example picked a type that is short to type, would be understood by a Rust programmer, and doesn't require any external context.
- 1y ago
- xigoi 1y agoJust some examples I thought of: * Array types have completely different syntax from other generic types * &mut T has a space between the qualifier and the type, &T doesn’t * The syntax for anonymous functions is completely different from a function declaration
- jeremyjh 1y agoWhereas Go has taken the approach of designing everything "later".
- mseepgood 1y agoIt's good to have languages with different approaches to design and and with different design philosophies.
- 9rx 1y agoTo be fair, Go, under the watch of Google, deemed it a finished product as far as the language goes. "Later" wasn't expected to happen. It was complete already. Only when the outside community took control of the project did it start considering new features.
- zaptheimpaler 1y agoThis is the kind of criticism made by people who've spent less than a few days working with a language. Just glancing at some code from a distance. There's nothing actually wrong with it besides being foreign from what you are used to. After you gain some familiarity, it doesn't look ugly or beautiful it just looks like syntax.
- codedokode 1y agoGolang is also ugly, for example some fields start with a capital letter and some do not. Also I don't understand how to implement transparent proxies in Go for reactive UI programming.
- arccy 1y agoyou don't Go is explicit about things. maybe caps for export is ugly, it's not much different from how python hides with _
- callc 1y agoI find both the golang uppercase lowercase naming scheme and python underscores for private (and __ for *extra* private) to be terrible design choices. They are hidden functionality, a set of rules which must be remembered. “Make sure to do <weird trick> because that mean <X> in <PL>” Leave identifier names alone. Packing extra info inside is unnecessary mental burden
- arccy 1y agothe other option seems worse, i dunno if i can use this identifier unless i have an IDE or i look up the definition every time
- mdaniel 1y agoAlso, I recently learned that only leading __ are considered special, whereas both sets of __ go back to being a public method due to the dunder magic methods such as __add__, __eq__, etc
- olalonde 1y agoIsn't "design by popular vote" an extreme version of "design by committee"? Go won't implement error handling syntax because it can't reach community consensus.
- arccy 1y agoGo may take community opinion into account, but just because something is popular doesn't mean the team will accept it. the language designers have the final say, and they will reject popular but bad ideas.
- dcow 1y agoThis might be a valid point if Go wasn’t an atrociously ugly and verbose language with some of the worst design out there.