Hacker News new | ask | show | jobs
by nuancebydefault 1119 days ago
The whole discussion about constexpr (even though a useful feature), is one example, out of many, of what a f up language C++ is/has become. It's astonishing how many people have to say... I don't like the language but there's no good alternative for the context we are working in.
6 comments

Especially with embedded applications, the issue is lack of tooling and sluggish vendors. For them, even C++ is "too new" in some cases to properly support.

Rust is making good progress despite these issues but it's still a pain to use in anything but the most common systems. As soon as you're using SoCs that have an FPGA part, for example, you're forced to use proprietary vendor tools and good luck getting Rust to work with those in the next few decades...

TBH Rust in the deep embedded space -- like MCUs, not MPUs -- when I looked at it a bit ago, it was fairly dubious how much intense effort would be required to a) trim fat to get reasonable binary sizes b) keep the fat under control. I'm used to doing much of this with C++, but it seemed way easier to end up with a bloated binary in Rust <I'm looking at you, panic handler!>

Starting a job in a week which is embedded Rust, but more on the Linux-on-SoC side, we'll see it goes.

I do embedded development in rust on severely limited/constrained MCUs and agree with that being the biggest hurdle. There are resources to detect any panics in the resulting binary and bail as well as the compiler option to halt rather than unwind on panic. Together with a custom panic handler you can get most of that in check. Oh and you really have to compile in release mode or a profile derived from it - debug is just too damn big.

The bigger issue is that you are at the whims of llvm as to what your codegen looks like. Regressions as llvm versions are upgraded are routine and can sometimes result in significant regressions on micro benchmarks. The good news is the rust team treats these pretty seriously even if they do take time (and several versions) to get fixed but you’ll never see the issue closed out in the issue tracker. All of performance regressions, codegen bloat regressions, and llvm optimization failures (eg not stripping out a panic handler in safe rust when it should be possible to deduce that the panic cannot be reached) are all tagged and monitored and tests are often added to catch regressions once fixes land. The good news is that when you run into these in safe rust you can usually work around them with unsafe rust - unreachable_unchecked() is your best friend here and is amazingly easy to use either with an if or with a match to disavow a potential state before the code that handles it.

I’d suspect I has to do more with familiarity than it does intrinsic differences between the two. My team does this kind of work, and it’s not difficult. It is worth tracking, paying attention to, and making changes if you’ve done something wrong, but what things cause these issues is generally pretty straightforward.
the only astonishing thing is how pathetic rustafarians are. Whenever someone writes something positive about a c++ feature the squad is working extra time to diminish the article/opinion. You are trying so hard, lol.... "constexptr if" is brilliant, simplifies a lot template code.
> of what a f up language C++ is/has become

I believe this misconception on your part stems from a lack of awareness (or understanding) of C++ design goals as a language.

Have a look at this writeup: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p21... (caveat: not formally adopted)

constexpr supports the following goals:

* Provide the programmer control over every aspect of performance: Compile-time vs run-time execution is an aspect of performance.

* Excellent ergonomic: Using constexpr/consteval improves on earlier mechanisms for achieving compile-time evaluation, such as macros, template meta-programming etc. Those are unwieldy, often difficult to read, and inflexible (without jumping through hoops). constexpr is not.

etc. etc.

and marginally supports the following goals:

* Code should perform predictably: Control over what exactly runs at run-time improves predictability.

* Leave no room for a lower level language: While constexpr is neither low nor high as a language feature, one can argue that having it undercuts the potential for, say, a "C + constexpr"-like language, or another lower-level language with a more elaborate macro system.

etc. etc.

I could go on naming goals constexpr supports, there are lots more. I challenge you to find goals from which it detracts.

> (caveat: not formally adopted)

Not only was P2137 "not formally adopted" it was purposefully written so that the committee could say explicitly "No" to these goals. It's in some sense a manifesto for one of the 2022 "C++ successor" languages, Carbon not for C++.

If you want to cite actual goals, you won't get much from WG21, which prefers not to get tied down by having any principles to speak of. Bjarne himself however wrote a book in 1994 "Design & Evolution of C++" which might help you determine some goals.

I don't see constexpr functions in particular as a success. There are too many caveats, it's easy to find C++ programmers who've written what they assume is a constant evaluated expression but it isn't, for one of many reasons their compiler has decided it's runtime evaluated, and the programmer was surprised.

The reason the standard doesn't guarantee constant evaluation of constexpr is that it would be hard, because of the as-if rule, to specify it in an good way other than a non-normative comment. Remember that as long as the sequence of side effects is preserved (and even that, concurrency introduce non-determinism), any translation is compliant (even no translation in case of interpretation).

In practice you do get guaranteed evaluation wherever the result is required at compile time (for example as a non-type template parameter or as an array size).

Your first point is important, and now that you mention it, I do remember similar names from the Carbon introduction and this paper. I should probably look to D&E for a less presumptive set of goals.

As for constexpr - you only get ambiguity if you assign a constexpr expression/function call to a non-constexpr value. If you use constexpr variables to hold the results of your computation, compile-time evaluation is guaranteed. I don't think it's that confusing.

I wrote that constexpr is useful. In fact that is just my point, a useful feature brings controverse. My take on it is that it is because the language is f up.

constexpr, amongst other uses, cleans up code that was hard-to-understand templated code.

Static assert cleans up other complicated constructs.

Make_unique together with heaps of other primitives tries to clean up cumbersome memory management.

[[fallthrough]] tries to solve the fact that break is easily forgotten, but this time not forgotten, but explicitly not there...

You can name so many of new constructs that solve an earlier problem.

If you went through all the cpp standards upgrades, and knew the history, you understand why all these improvements exist. If not, it all looks overly complicated, which in fact, if you look at it objectively, it is.

Nim works well in embedded contexts. It can compile to C89 or C++ and integrates easily with most any C compiler. I’ve used it with FreeRTOS, Zephyr, and bare metal. It’s a smallish community but there’s a few shipping products using it and the language is really easy to learn if you know C/C++/Python.

Executables from Nim also tend to stay pretty lightweight even when using generics / templates.

The language is not fucked up. Come back to Rust in 40 years and see what has become of it if it still not Cobol type legacy. Also I do not think you can compare it to C++, it is too limited for that in my opinion. I would rather consider it as "fixed" C that satisfies some safety constraints.

What is fucked up is us not being perfect machines and not producing ideal design from the first try and then having to deal with compatibility. Well duh.

Rust. The alternative is Rust.
I don't think Rust has an equivalent to C++17 constexpr, it is more limited.

Zig may be a better option when it comes to compile-time evaluation.

The `if` part of the quoted example, you can do in Rust; the `else` part is coming with the specialization feature soon. Everything you can't do with traits, including specialization, you should probably not be doing; modern C++ tends to be an incomprehensible template forest.
I hope you will be proven right!