Rust's Ugly Syntax (2023)
Overall reaction to the article
- Several commenters feel the chosen example is not Rust’s “worst”; real pain appears when generics, lifetimes, and async are combined.
- Some are unsure whether the article is tongue‑in‑cheek; others see it as arguing that complaints about syntax are actually about semantics needed for performance and safety.
Rust’s complexity: semantics vs syntax
- One view: people want C/C++‑level speed but then dislike the semantics (ownership, lifetimes) that provide it.
- Others argue most Rust use isn’t about raw speed but about safe, non‑GC systems programming; problems arise when Rust is used “for everything.”
- There’s disagreement on whether Rust is “too complicated,” “as complicated as it needs to be,” or even “not complicated enough.”
Lifetimes and lifetime syntax
- Multiple people struggle with
'a: 'band lifetime subtyping; several mnemonic explanations are proposed, but they’re seen as unintuitive. - Debate over the
'sigil: some find it ugly/confusing and advocate alifetimekeyword; others argue brevity matters and note precedents in other languages. - Many mention that explicit lifetimes are rarely needed in everyday Rust, especially if you lean on heap‑allocating types (
Box,Rc,Arc).
Generics, traits, and async “alphabet soup”
- Complex signatures combining generics, lifetimes, async futures, and trait objects are cited as truly unreadable.
- An example of an async trait method expanded by a macro is widely acknowledged as horrendous, though noted as codegen rather than hand‑written idiom.
- Some suggest that needing such signatures is a sign of over‑engineering or extreme allocation avoidance.
Ergonomics, visibility, and type annotation style
- Discussion around
pub fnand non‑public-by-default: many like the conservative default and parallels withmutusage. - Type‑after‑name (
x: T,fn foo(...) -> T) is defended as easier to parse and more consistent than C‑style declarations. - The
::vs.distinction (namespaces vs fields) is debated; some see it as unnecessary, others say it avoids ambiguity. - Semicolon‑free final expressions as implicit returns are confusing to some but defended as a useful expression‑oriented feature.
Error handling and Result
- The article’s simplification of error types raises concern about losing information; others point out standard type aliases like
io::Result<T> = Result<T, io::Error>preserve it. - The
?operator is described as “unwrap on success, early return on error,” enabling concise chaining.
Comparisons and alternative syntaxes
- Many compare the example to equivalent code in Python, Go, Swift, C#, OCaml/CrabML, Raku, Ada, etc., showing those can be shorter or “prettier.”
- Some argue standard library APIs are inherently more complex due to generality and performance constraints; typical user code often looks closer to the simpler “Rattlesnake/CrabML‑style” versions.
- There is recurring interest in a Rust‑like language with GC or refcounting and a simpler surface syntax.
Async Rust
- Opinions on async Rust are polarized: called both an “abomination” and “marvelous” depending on perspective.
- Recent and upcoming features (async closures, async trait fns,
impl Traitimprovements) are seen as making async code substantially nicer, though ecosystem fragmentation (different async traits in different crates) remains a pain point.