Remix.run Logo
kelnos 13 hours ago

This is one of the (several?) things that make me very worried about Rust long-term. I love the language, and reach for it even when it sometimes isn't the most appropriate thing. But reading some of the made-up syntax in the "Removing Coherence" section makes my head hurt.

When I used to write Scala, I accepted the fact that I don't have a background in type/set/etc. theory, and that there were some facets of the language that I'd probably never understand, and some code that others had written that I'd probably never understand.

With a language like Rust, I feel like we're getting there. Certain GAT syntxes sometimes take some time for me to wrap my head around when I encounter them. Rust feels like it shouldn't be a language where you need to have some serious credentials to be able to understand all its features and syntax.

On the other end we have Go, which was explicitly designed to be easy to learn (and, unrelatedly, I don't like for quite a few reasons). But I was hoping that we could have a middle ground here, and that Rust could be a fully-graspable systems-level language.

Then again, for more comparison, I haven't used C++ since before they added lambdas. I wonder if C++ has some hairy concepts and syntax today on par with Rust's more difficult parts.

jandrewrogers 10 hours ago | parent | next [-]

> I wonder if C++ has some hairy concepts and syntax today

Both better and worse.

The current version of idiomatic C++ is much cleaner, more concise, and more powerful than the version of C++ you are familiar with. You don't need C-style macros anymore. The insane template metaprogramming hacks are gone. Some important things that were problematic to express in C++ (and other systems languages to be fair) are now fully defined e.g. std::launder. C++ now has expansive compile-time programming features, which is killer for high-performance systems code, and is more expressive than Rust in important ways.

The bad news is that this was all piled on top of and in addition to the famous legacy C++ mess for backward compatibility. If you are mixing and matching ancient C++ with modern C++, you are going to have a bad time. That's the worst of all worlds.

But if you are lucky enough to work with e.g. an idiomatic C++20 code base, it is a much simpler and better language than legacy C++. I've done a few major C++ version upgrades to code bases over the years; the refactored code base was always smaller, cleaner, safer, and easier to maintain than the old version.

fc417fc802 7 hours ago | parent [-]

It's much simpler and better than it used to be but it's still pretty bad. As just one example off the top of my head consider the meaning of curly braces for initialization. There's several different things they can mean depending on the context. Good luck figuring out which set is currently in effect.

jandrewrogers 6 hours ago | parent | next [-]

The initialization situation in C++ is indefensibly broken. It is near the top of my list of things I hate about C++.

You can mitigate it with some practices but that this is even necessary is a crime. Initialization is one of the most basic things in software development. How do you fuck it up so badly?

On a day to day basis it doesn’t cause me issues but it offends me just on principle.

germandiago 3 hours ago | parent | prev [-]

Use static analyzers and move on. Almost all the complaints I see about C++ nowadays are removed by max warning levels. Set them as error.

Certainly initialization is the single most confusing feature in C++, I can give you that.

But still doable with s few patterns to remember. And warnings always max level.

bayindirh 2 hours ago | parent [-]

I still use Eclipse CDT and its static analysis is running in real time, as you type code, which is killer. Combined with Valgrind integration, I don't see myself moving on anytime soon.

Aurornis 11 hours ago | parent | prev | next [-]

> But reading some of the made-up syntax in the "Removing Coherence" section makes my head hurt.

Articles discussions new features always have difficult syntax. There have been proposals like this going on from the start.

Fortunately the language team is cognizant of the syntax and usability issues with proposals. There have been a lot of proposals that started off as very unwieldy syntax but were iterated for years until becoming more ergonomic.

kelnos 6 hours ago | parent [-]

I think it's more than the syntax, it's just the number of concepts you need to keep in your head to read a type signature, or a trait declaration, or whatever. There's only so much you can pack into a limited language before it becomes too much to keep in your head at once.

ifwinterco 4 hours ago | parent [-]

And then someone declares "this language is a mess! I'll take the good parts and create a new one without all this cruft!" and the cycle continues

jcranmer 12 hours ago | parent | prev | next [-]

> I wonder if C++ has some hairy concepts and syntax today on par with Rust's more difficult parts.

… … … … Unqualified name lookup has been challenging in C++ since even before C++11. Overload resolution rules are so painful that it took me weeks to review a patch simply because I had to back out of trying to make sense of the rules in the standard. There's several slightly different definitions of initialization. If you really want to get in the weeds, starting playing around with std::launder and std::byte and strict aliasing rules and lifetime rules, and you'll yearn for the simplicity of Rust.

C++ is the absolute most complex of any of the languages whose specifications I have read, and that's before we get into the categories of things that the standard just gives up on.

jandrewrogers 10 hours ago | parent | next [-]

> starting playing around with std::launder and std::byte and strict aliasing rules and lifetime rules, and you'll yearn for the simplicity of Rust

Annotations like std::launder, lifetime manipulation, etc solve a class of problems that exist in every systems language. They inform the compiler of properties that cannot be known by analyzing the code. Rust isn't special in this regard, it has the same issues.

Without these features, we either relied on unofficial compiler-specific behavior or used unnecessarily conservative code that was safe but slower.

tialaramex 7 hours ago | parent [-]

> Rust isn't special in this regard, it has the same issues.

This is both fundamentally true and misleading. Rust has to solve the same issues but isn't obliged to make all the same bad choices to do that and so the results are much better.

For example C++ dare not perform compile time transmutations so, it just forbids them and a whole bunch of extra stuff landed to work around that, but in Rust they're actually fine and so you can just:

    const FOO: bool = unsafe { core::mem::transmute::<i8, bool>(2) };
That blows up at compile time because we claimed the bit pattern for the integer 2 is a valid boolean and it isn't. If we choose instead 0 (or 1) this works and we get the expected false (or true) boolean instead of a compiler diagnostic.

C++ could allow this but it doesn't, rather than figure out all the tricky edge cases they just said no, use this other new thing we made.

jandrewrogers 6 hours ago | parent | next [-]

> For example C++ dare not perform compile time transmutations

I am confused by this assertion. You can abuse the hell out of transformations in a constexpr context. The gap between what is possible at compile-time and run-time became vanishingly small a while ago.

I think your example is not illustrative in any case. Many C++ code bases work exactly like your example, enforced at compile-time. That this can be an issue is a hangover from retaining compatibility with C-style code which conflates comparison operators and cast operators. It is a choice.

C++ can enforce many type constraints beyond this at compile-time that Rust cannot, with zero effort or explicit type creation. No one should be passing ints around.

germandiago 2 hours ago | parent | prev | next [-]

In my experience conversions is one of the things that maximum warning levels do excellent static analysis for nowadays. In the last 15 years I hardly had a couole problems (init vs paren initialization). All narrowing etc. is caught out of the box with warnings.

poppadom1982 3 hours ago | parent | prev [-]

I'm not sure what you're getting at but

const bool z = (const bool)((int8_t)2);

Is perfectly valid C++.

debugnik 3 hours ago | parent [-]

That's a conversion, not the same. The naive equivalent to transmute would be

    int8_t x = 2;
    bool y = *reinterpret_cast<bool *>(&x);
But reinterpret_cast isn't valid in a constexpr scope.
poppadom1982 2 hours ago | parent | next [-]

My point is, in your exact example both reinterpret_cast and C-style casts have the exact same behavior, making the example bad. If you want to showcase a deficiency of C++, it would make sense to pick something where the difference between cast types actually matters.

TuxSH an hour ago | parent | prev [-]

> But reinterpret_cast isn't valid in a constexpr scope.

std::bit_cast is

debugnik an hour ago | parent [-]

Oh cool, and it behaves like memcpy, not like pointer aliasing! I'm stuck with C++14 at work so I missed that one.

germandiago 2 hours ago | parent | prev | next [-]

The right strategy to use C++ efficiently is to set warnings to the maximum as errors and take the core guidelines or similar and avoid past cruft.

More often than not (except if you inherit codebases but clang has a modernize tool) most of the cruft is either avoidable or caught by analyzers. Not all.

But overall, I feel that C++ is still one of the most competitive languages if you use it as I said and with a sane build system and package manager.

pocksuppet 9 hours ago | parent | prev [-]

Unless you're writing a compiler, you should require the author of the patch to explain why it works.

jcranmer 9 hours ago | parent [-]

This was a patch for the compiler implementation of the changes to the standard.

staticassertion 10 hours ago | parent | prev | next [-]

I really wouldn't worry much. Over the last decade of rust, very few of the articles exploring new syntax have turned into anything controversial by the time they were merged (I can't even think of big rust syntax changes other than `impl T` in arguments etc). The singular example really is async/await and, having been quite worried about it / against it at the time, it was really nothing to be concerned with at all.

maccard 12 hours ago | parent | prev | next [-]

> I wonder if C++ has some hairy concepts and syntax today

https://tartanllama.xyz/posts/cpp-initialization-is-bonkers/

dap 7 hours ago | parent | prev | next [-]

Having used Rust professionally for six years now, I share your fear. Like many of the commenters below, coherence just hasn't been a big problem for me. Maybe there are problem spaces where it's particularly painful?

How does the Rust language team weigh the benefits of solving user problems with new language features against the resulting increased complexity? When I learned Rust, I found it to be quite complex, but I also got real value from most of the complexity. But it keeps growing and I'm not always sure people working on the language consider the real cost to new and existing users when the set of "things you have to know to be competent in the language" grows.

PaulDavisThe1st 11 hours ago | parent | prev | next [-]

Reflection syntax (C++26 I think) has made my 30+ years-of-C++ brain melt.

It's not insane, it's just ... melt-inducing.

jandrewrogers 10 hours ago | parent [-]

Yeah, for me reflection and coroutines were the first changes to C++ where the implementation and use mechanics weren't immediately obvious by reading a few references. It requires a bit of proper study to wrap your head around it.

egorelik 12 hours ago | parent | prev | next [-]

Rust opened the door to innovation in the low-level languages space, but as long as it is already the most theoretically advanced practical language there, it will always attract the audience that actually wants to push it further. I don't know if there is a way to satisfy both audiences.

layer8 11 hours ago | parent | next [-]

A similar thing happened with C++: The fact that it had a relatively high complexity of interacting features (already 30+ years ago) that you could use to do smart things, did attract smart people with a high tolerance for complexity. And with such an audience, complexity tends to expand up to the limits of tolerance (or even a little beyond).

Rust had a better start, not the least because it wasn’t designed on top of an existing language like C++ was, but who knows what it will look like in 30 years.

estebank 11 hours ago | parent | prev [-]

I think there is: a schism. Another language, inspired, intelligible and interoperable with Rust, but with other goals, likely ease of use or surface simplicity. In my mind it would be pretty much the same as Rust, but whenever a compile error gives you a suggestion in rustc would instead compile (and at most be a warning in this hypothetical language). Migrating from Rust to this language would be changing a single setting in Cargo.toml. The other way around would be fixing a bunch of compile errors. You could use the entire crate ecosystem in a native way. This language could also serve as a test bed for features that might or might not be suitable for Rust. It can also have a more aggressive evolution schedule, meaning that it wouldn't be perma-1.x, so it can be bolder on what is attempted.

teh 19 minutes ago | parent | next [-]

There is precedent: with type checkers like pyright you can opt into specific checks, or have a basic, standard, strict setting, each expanding the set of checks done.

How would dependencies work in this schism? E.g. if serde starts using named impls, do all dependencies have to use named impls?

simonask 10 hours ago | parent | prev [-]

I mean… Sure, if we’re just making stuff up, a compiler that can magically understand whatever you were trying to do and then do that instead of what you wrote, I guess that’s a nice fantasy?

But out here on this miserable old Earth I happen to think that Rust’s errors are pretty great. They’re usually catching things I didn’t actually intend to do, rather than preventing me from doing those things.

nicoburns 8 hours ago | parent [-]

> But out here on this miserable old Earth I happen to think that Rust’s errors are pretty great. They’re usually catching things I didn’t actually intend to do, rather than preventing me from doing those things.

As it happens, you are replying to the person who made Rust's errors great! (it wasn't just them of course, but they did a lot of it)

simonask an hour ago | parent [-]

I bow to them and thank them for their service!

5 hours ago | parent | prev | next [-]
[deleted]
fridder 12 hours ago | parent | prev [-]

I wonder how Zig compares here