5 ms·
Ugly is subjective, but which part of the syntax is inconsistent?
by wtetzner 1y ago
Ugly 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