Hacker News new | ask | show | jobs
by d9fb698e010974b 3909 days ago
Is rust as complicated as it seems to me? I know ML derived languages well so I'm not a stranger to functional programming. And I'm a pretty competent C programmer, but it seems like Rust is about as complicated as C++, which I find offputting.
7 comments

No, it's definitely nowhere near C++-complicated: there's usually one way to do things, no legacy cruft. There's no multiple inheritance nor large type hierarchies. Things tend to "just work" (once you get the code to compile) instead of silently biting you (I haven't found any gotchas or footguns within the safe Rust yet).

It does seem strange, because:

- It has constructs which aren't present in C/C++ in the exact form, like traits or pattern matching (maybe it'd be easier if they were called templates and switch, but they're not quite the same thing, so a different name is good). There's a lot of Rust-specific jargon for things that aren't as complicated as they seem.

- Some constructs (e.g. enums and empty structs) look like C's, but again aren't quite the same.

- It has powerful generics and macros, so people who want to write really clever code, can.

> - It has powerful generics and macros, so people who want to write really clever code, can.

To take a cue from the article: how do you write a generic max() function for an arbitrary number of arguments?

Someone had commented this in a response on the site.

   macro_rules! max {
        ($e: expr) => { $e };
        ($e: expr, $($rest: tt)*) => { max($e, max!($($rest)*)) }
   }
It depends on how you define "complicated." For example, Rust and C++ both have "move semantics," but Rust's is "A move is a memcpy, which the optimizer may or may not elide" and C++'s is http://stackoverflow.com/a/3109981/24817 rvalue references and copy/move constructors and all sorts of other things.

There are three major kinds of backgrounds that Rust programmers come from: functional, systems, scripting.

The functional crowd instantly groks Rust's pattern matching, first-class functions, and expression-based-ness. But they miss some more complex, stronger type system features.

The systems crowd instantly groks Rust's low-level features, but struggles sometimes with the compiler being so strict.

The scripting crowd instantly groks our tooling, and the functional-ish things, but struggles with the low-level.

So really, everyone has a different definition of what "complex" is, because it's based on what you're familiar with. Some people find map to be more complex than for, some people think the exact opposite.

All generalizations are false.

> All generalizations are false.

I believe this sentence is a paradox.

It's not a paradox. It's just false. Compare "all sentences are lies".

It's close enough to true to be useful, but it's false when you treat the word "all" literally.

Heh, the three kinds of backgrounds sounds like the perfect description of what I've found in the Rust community (being of the functional variety myself). However, once I understood ownership and lifetimes, I felt like the whole world opened up. I'm still waiting for more ecosystem and community before I start to use it more seriously, but I'm chomping at the bit for that to happen.
The borrow stuff is what seems to confuse or seem complicated. But if you take this guiding rule: Memory safety, no GC -- a lot of the rules just make sense and in many cases they simply couldn't be another way. And after dealing with complicated multithreaded code in C, I prefer the borrow checker. Let me know up-front where I messed up. In nearly every case where someone is saying the borrow checker is making life hard, it's often because in C, they'd have had a bug. The exceptions mainly seem to be limitations in Rust's checker.

Like any type system, there are programs that are valid that cannot be expressed. This can frustrate people when they can see that their program is OK under the current configuration of it, but there's no easy way to represent that as a guarantee. (Same annoyance dynamic-languages users might feel about static typing.)

FWIW, I prefer ML-ish derived languages, am a mediocre C programmer, and Rust seemed easy enough to learn to the point I enjoyed using it.

It's both less and more complicated than it seems. The borrowing system is quite complicated and it will take time before you can internalize it so that you can trust your code to compile on the first try. However, Rust is the good kind of complex in that when it surprises you, it tends to do so with a compiler error. It's very unlike C++ in that even when you're not a 100% sure of what's going on, the code tends to be quite robust.
Note that for any large C++ codebase, you still have to reason about things like borrows (or equivalent/similar concepts), just that the language doesn't explicitly talk about them. Rust just makes it all explicit from the get-go.

And actually, borrowing isn't really complicated, just _different_.

C++ is the only language I've used, where a collection of completely reasonable decisions led to the situation that "if (a == b)" worked fine, but "if (b == a)" crashed the program due to a failed assertion.

And we weren't even using any templates!

I fail to see how reasonable decisions lead to the situation where a == b works "fine" while b == a effectively crashes the program. Could you elaborate what the reasonable decisions were?
Yeah, this sounds more like a and b are different types but somebody messed up overriding equality operators. I wouldn't blame the language for that.
That's possible in any language that doesn't force you to include a computer-checkable proof that your overridden equality operator forms an equivalence relationship.
I imagine depending on the assumptions, the same could happen in Rust, given Rust allows overriding equality too.
Most of the time in rust, you can just `#[derive(Eq)]` and be done with it, so those kinds of things are far less likely.
> I know ML derived languages well so I'm not a stranger to functional programming. And I'm a pretty competent C programmer, but it seems like Rust is about as complicated as C++, which I find offputting.

Have you used languages with memory safety and no garbage collection before?

I think Rust has no more features than it needs to support its goals, and would be interested to know what features you would like removed.

What gives you the impression that it's complicated? I can assure you that Rust contains an order of magnitude fewer features than C++, and none of C++'s edge cases or C's footguns.
Rust has a very powerful type system, and combining that with lifetimes makes for some crazy signatures that really hurt my brain.

The type system grows more powerful (and more complex) every time I revisit Rust, it seems.

I'm glad, as an increasingly powerful type system facilitates abstractions that were once painful, slow, unsafe, or impossible, but it is complex.

> Rust has a very powerful type system, and combining that with lifetimes

If you don't count lifetimes, Rust's type system isn't really more powerful or complex than, say, that of Swift. There are no dependent types here. There are no type families. There aren't even higher-kinded type parameters.

> The type system grows more powerful (and more complex) every time I revisit Rust, it seems.

What additions are you referring to?

I wouldn't say Swift's type system is particularly simple, I rather like it, but it does have a lot of complexities.

  > The type system grows more powerful (and more complex) 
  > every time I revisit Rust, it seems.
There have been no additions to the type system since well before 1.0. I'm curious where this perception is arising from.