Hacker News new | ask | show | jobs
by Bekwnn 2282 days ago
I find this to be one of the reasons I didn't find rust that appealing as an C++ alternative. Its safety is something I admire and is highly valuable to many domains, but the two main things I want to abandon with C++ are its complexity and its compile times. Rust doesn't seem to get away from either of those.

As someone who doesn't really use Rust, does anyone who does find the complexity detracts from it a bit as a language? Is there effort to reduce complexity with the language or does it mostly embrace it?

At this point I find myself mostly looking at modern C alternatives—ones which manage to stay relatively simple the way C does, but with a few additional features and better designs (Zig, Odin, maybe Jai, etc).

All that said, I work with C++ and so I could see myself potentially working with Rust in the future, so I'm curious how people feel about its complexity, especially given that its complexity will presumably only increase with time.

6 comments

From my perspective, Rust is a lot less complex than C++. It does still have a lot of features, but there are a couple of mitigating factors:

1. The features tend to be intuitive to use, and work in the way you expect them to. 2. If you do make a mistake, this tends to be a compile time error with a helpful error message that explains what you've done wrong. 3. The most complicated features are rarely used. Most of my Rust reads like TypeScript.

Part of the problem with C++'s complexity is not only is it difficult to work out the correct incantation, but it's difficult to know whether you have or not. Rust almost completely takes away that uncertainty.

The compile times are definitely an issue unfortunately.

The problem is that there's no standard definition of "complexity," and so not only is it really hard to answer your question, it's also really hard to compare one language's complexity to another.

I personally subscribe to the "waterbed theory of complexity", that is, I believe that the world is complex, and often, attempts to remove complexity cause it to pop up somewhere else. Rust's goals have an inherent level of complexity to them, and so require a certain degree of complexity to accomplish. There is an argument that if we had dropped one or two of those goals, we could have made a language that is much simpler, but I'm also not sure Rust would be as popular if we did.

One thing we strive for with Rust is that features are reasonably orthogonal and work well together, without weird corner cases. We also try to only add more features when the cost is actually justified. We have said "no" to a lot of things. We have also tried and rejected a lot of things.

You also may enjoy this blog post of mine: https://words.steveklabnik.com/the-language-strangeness-budg...

(I should also note that I'm not actually on the lang team, so this is more of a statement about what I observe and my own opinion rather than policy, strictly speaking.)

> attempts to remove complexity cause it to pop up somewhere else

Yes, but sometimes the average brain is better at dealing with certain types of complexity. C++, IMO, puts the complexity in the wrong places. Programming is inherently complex, but it shouldn't be any more so than it needs to be and the complexity should be of the type humans can manage, as much as possible anyway.

I don't disagree! Well, I might disagree that they put it in the "wrong" place exactly; I think that the committee is doing the best that they can given their goals and constraints. I do not have the same goals and constraints, and therefore prefer to use other languages.
> Is there effort to reduce complexity with the language or does it mostly embrace it?

You're right that it isn't a "simple" language (in the Rich Hickey sense of the word). And I don't think there's any effort to actively simplify it.

However, I do expect the rate of complexity growth to taper off fairly soon. Every feature that gets added to Rust is added carefully and with a clear vision in mind. Up until now they've still been building out the foundations of what most people will need when using Rust in different contexts. Recently a lot of this has been ergonomics (like async/await). But I think the rate of features being added is an S-curve, and I think we're nearing the top. Given that, I have hope that it won't follow the same path as C++ in terms of sprawl; it's certainly not as complicated as C++ yet, and if it doesn't keep growing at this rate, I don't think it will become that way.

Part of why C++ is so complicated is that it's had to tack-on decades of language advancements, after the fact, as they were invented/became prevalent. Heck, C++ itself is already a tack-on of C. There wasn't a clear initial vision for the past couple decades of "stuff".

Rust, on the other hand, a) has those decades of ideas to incorporate from the outset in a cohesive way, and b) was started from scratch, not an extension of an existing language. This has so far meant a much clearer sense of vision and big-picture design. These features were made to work together; the roadmap was fairly clear from the beginning.

This. Exactly. Also, there is definitely an ongoing effort to make the language simpler, not in the type system which arguably is getting more complex, but in the way the borrow checker is getting smarter. Might be imperceptible at first but really brings a lot in term of ergonomics and productivity.
Simplifying the borrow checker is a slightly different question than simplifying "the language" (meaning the syntax and/or behavior of the syntax), because the latter can break backwards-compatibility (which is why it likely won't happen).

But the borrow checker is an interesting case because simplifying its rules in such a way that they're more tolerant (without sacrificing safety) might reduce cognitive overhead while still being fully backwards-compatible.

The thing is, in some sense, the borrow checker got more complex. But because it accepts more programs, it makes programming in Rust feel less compex. This is related to the waterbed stuff I was talking about elsewhere in the thread.

There is a fine balance here, for example: https://news.ycombinator.com/item?id=22465409

Yeah ! That's was the point I was trying to make. It was a breath of fresh air when I switched from Rust 2015 to Rust 2018, without obvious change in the language from my point of view.
Rust is not a complex language; it's otherwise: Rust has higher-level abstractions that makes it much easier to program with.

Actually, I was trying to explain this a few days ago: https://users.rust-lang.org/t/any-possible-improvements-to-t...

Rust has an Iterator type. It might be a bit "complex" to understand at first sight, but once you grasp the concept, it makes programming much easier. And your code is much more readable too. I try to avoid loops/conditionals these days; if I'm using them, I probably can express that in a Type and have a descriptive name/functions for that type.

There are many more types/syntax that makes programming with Rust a marvel: Result/Option types, generics, macros, async/await, error chaining, etc...

I write Rust as my day job and I still consider it a complex language. There's a lot of non trivial things encoded in the type system. Send/Sync, Pin, async/await, object safety, borrowing, ownership, I could go on.

It's also pretty different to what most people are used to. I found it a approach to polymorphism refreshing, coming from Haskell, but that's not a typical pathway. The average Java dev will need some time to get used to how extensive generics are in the language.

I find that I rarely touch the most complicated parts. Sure, it has a rich type system with all kinds of magic you can do with generics and such, but if you’re just making an application you often don’t have to futz with it. You can also often get away without even providing a type. If you’re working on deep data structures and libraries it gets more complicated, as it should. It’s a language that allows you to specify the behavior of your program quite precisely, and in many cases you don’t have to worry much. Little things like allowing a clone here or there when it isn’t a tight loop go a long way towards simplicity.
A little weird that you didn't mention Go, which seems to fall exactly in the category of "a simple, modern, well-designed C"