Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'll bite: What specific parts of rust syntax do people find so ugly?

I keep hearing this from decent chunks of people who don't write rust, but the language doesn't seem that far off C to me. It's certainly no haskell.



From what I've asked people, the complaints fall mainly into two categories:

* familiarity and aesthetics. Rust uses fewer round () parens, and more <> and {}. This makes it look alien, and people say it's unreadable when they don't immediately recognize the language constructs they know.

* misattributing difficulty of learning Rust concepts like lifetimes and generics to their syntax. People say they want less syntax, but they mean they don't want to explicitly specify things like ownership and trait bounds.


The more interesting follow up question is: "How would you express the same semantics with a different syntax?" Too often discussions about Rust's ugly syntax lack this crucial component.


> How would you express the same semantics with a different syntax?

This isn't the problem, the problem is "... and keep the syntax C++-like?".


Is it? I don't know if keeping Rust's syntax C++-like is a stated goal of the project, but okay sure we can add that caveat to my question.

The big problem I see is that people will say "Lifetime annotations are ugly and noisy" and when pressed on the issue will eventually concede that they just want GC(which is not about syntax, but semantics)


It was a goal, though lower priority than other goals. You can see this in the way Rust is largely “curly braces and semicolons” but at times when there’s good reasons it diverged from that, like the ML style let syntax.


> I don't know if keeping Rust's syntax C++-like is a stated goal of the project

They won't change the syntax, the whole discussion is hypothetically anyway. What I wanted to express is that most people want a C++-style syntax (of generics), even if they complain about Rust's syntax.


I say this as a Rust enjoyer, but I think what most people mean when they say this is that there's a lot going on, especially in the function definition syntax. When you start adding in lifetimes and generics with bounds, async, &muts, where clauses... it really does become unreadable. I don't really see a way to fix this without making the syntax even more verbose, or aggressively simplifying the type system to the point that function argument inference becomes viable, but then you might end up in a situation like Swift's where type checking a simple expression takes an excessively long time.

That and the colon-colons (::), probably. Those can add a lot of noise.


I suspect the colon-colons were a mistake. Java uses periods for both modules and classes, and it doesn't seem to be a problem there.

Lifetimes are really ugly. You usually don't need to write them explicitly, but that's not a real excuse.


> colon-colons

I prefer "quad-dot". Rolls off the tongue better. :)


https://web.archive.org/web/20230713231438/http://bash.org/?...

  < Andys> oh dear
  < Andys> in ruby, symbols are represented with a prepended colon
  < Andys> eg.   :flag
  < Andys> so some guy tshirt that said ":sex"
  < Andys> which everyone at railscamp knew meant "Sex symbol"
  < Andys> he wore it until someone pointed out that to non-rubyists it said "Colon sex"



I think it's not that much the specific parts as it is the combination of (sometimes obscure) symbols forming dense blocks of sigils that you have to carefully pick apart to understand what the code is doing. It's easier to reason about code if it uses words instead of symbols, and Rust seems to desperately want to avoid using actual words (I don't count "fn" as a word, and "pub" is a word, but for me it's somewhere where you go to have a drink after work). Ok, I know there is a long tradition of doing this in C-family languages, but Rust has driven it to new heights, and it has a lot more concepts (with their attached symbols) that you have to keep in your head.


I hate the unpronounceable sigils of languages like Haskell, but C-style abbreviations don't really bother me somehow. The abbreviations help you remember what the words are, at least, and for me this seems to be enough.


>I keep hearing this from decent chunks of people who don't write rust

That's exactly the people you want to hear from if you're trying to improve adoption.


Here's my litmus test: read the source aloud. Over the phone to a person who doesn't see your screen, if needed. Did you have an obvious, understandable, and simple pronunciation for everything, that wasn't just reading ASCII characters one by one?

Now pretend the other person is a smart and experienced programmer, but has never heard of Rust. How would they write down what you just told them, without any idea of Rust's syntax? That's the non-ugly version of Rust.


    function max with type parameter T
    with arguments
    a of type T and b of type T
    and returns a value of type T
    where T implements trait PartialEq
Vs

    fn max<T>(a: T, b: T) -> T where T: PartialEq


Limiting examples to a subset of Rust syntax will produce more readable answers, sure. You have no lifetimes and no borrows, and very limited generics.


The information density of the "human syntax" Rust syntax both remain linear in size, but with a significant different N.

    function max
    with
        a lifetime a,
        a lifetime b,
        and type parameter T
    with
        argument a of a reference to type T that lives as long as lifetime a
        argument b of a reference to type T that lives as long as lifetime b
    and returns a value of type parameter T
    where T implements trait PartialEq
Vs

    fn max<'a, 'b, T: PartialEq>(a: &'a T, b: &'b T) -> T

If you want a real life example:

    #[stable(feature = "rust1", since = "1.0.0")]
    impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
        type Item = &'a T;
        type IntoIter = slice::Iter<'a, T>;

        fn into_iter(self) -> Self::IntoIter {
            self.iter()
        }
    }


    An implementation of trait IntoIterator
    (that has been stable since Rust 1.0.0)
    with a lifetime a
        a type parameter T
        a type parameter A which implements the trait Allocator
    for a borrow for the duration of lifetime a of type Vec with type parameters T and A
    
        it has an associated type Item, which is a borrow for the duration of lifetime a of type T
        it has an associated type IntoIter, which is type Iter from module slice with parameters lifetime a and type T

        it has a method into_iter
            that consumes the receiver
            and returns associated type IntoIter
            
            the methods body
            calls method iter on the receiver
            and returns its resulting value


I'm not arguing that complex things will somehow become non-complex.

However, none of the human syntax of Rust includes things like :: or '. To a first approximation[1], those are the parts that people can experience as "ugly", and they are not present in the human syntax. This is what people mean when they say "sigil heavy" or "punctuation based" syntax -- things that are generally are not read out as such. This is the space where you can make arguments about beauty.

[1]: Only roughly so because your chosen human syntax still encodes some Rust syntax decisions like predeclaring generic lifetimes and types, and using "where" instead of an inline clause. Those parts of syntax can also be shuffled around for subjective values of "not ugly".


Lifetime bounds on a trait object argument can be confusing.

I have to look up how to write the where part properly every single time.


Fishtail, lifetime and closure syntaxes are rather ugly. Just specifically when combined in practice, not alone in isolated examples.


For what is worth, the turbo fish falls from the decision to use <> for generics (for familiarity for C++ and Java developers) and a desire to make the syntax non-ambiguous (side stepping the C++ problem of having to delay determining if something is a type path or a comparison, mixing parsing and name resolution).


> What specific parts of rust syntax do people find so ugly? ... the language doesn't seem that far off C to me. It's certainly no haskell.

Make that "not far off C++" (C is really beautiful in comparison), and there's your answer.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: