I only recently investigated rust, and was hugely impressed with it. I regret not investigating it earlier. Language support for ownership and lifetime of variables is such a huge step up for writing code. Trying to do this through as hoc conventions in C, or through RAII in C++, is a lot harder.
I haven't yet had a chance to write anything significant in rust beyond a few small test projects, but next time I want to beat Python performance on something I'll be using Rust instead of Cython or C or C++.
It's largely the realm of C, with some industries working in Ada/SPARK. In terms of its profile, Rust fits the bill for being a good system/embedded programming language some day, but I don't know if it's mature and stable enough yet to be what you'd pick for a really serious job.
As for C++, I don't really see the point if you don't have technical debt.
For some industries where security or correctness guarantees are necessary, you see things like MISRA C used rather than Rust (or cpp).
[1] https://en.wikipedia.org/wiki/Ravenscar_profile
[2] https://en.wikipedia.org/wiki/SPARK_(programming_language)
[&] https://docs.adacore.com/sparkdocs-docs/Examiner_Ravenscar.h...
But, say, if you don't have a good support for your platform Rust is not useful. Ditto for most existing codebases. And in any case I don't see why your primary concern should be being modern vs getting things to work well
Debugging C++ when your compiler for weird target (SH4, or worse) contains bugs, or when you have some relaxed memory consistency model, is quite a challenge because mapping C++ to assembler is definitely non-trivial. C, even with heavy optimizations, is a breeze comparatively.
I would happily join a team that uses Rust in an embedded setting. It shows that they care deeply about doing better than average, and that probably means they are better than average in everything.
I don’t agree that C++ automatically prevents bugs, even though using e.g. RAII can help a bit and leads to maintainable code.
If you use exceptions (you probably shouldn’t) there is one more code-path out from your code. That together with constructors/destructors being called and using STL instead of more trivial data-structures often leads to a lot bigger assembler output to trawl through if you need to.
By STL I guess you mean std::string and std::vector. That is wholly optional. I would not use those in a small embedded project, except maybe at startup, and then with a custom, non-freeing bump allocator.
That's a big set of ifs, though. It's possible that the compiler errors are discouraging enough that C++ might feel like a more comfortable choice (I would encourage you to not let this be your reason unless you're just interested in solving a one-time problem). I keep checking in on Rust to see how small and dependency free I can get the compiled binary, and I usually need a mess of nightly features. The ecosystem is also still a mess. There are a few great libraries, but otherwise it's a minefield of 0.x releases for most dependencies (admittedly, some of the most important ones are autogenerated bindings where the version number is meaningless). Bindings are really easy to write with Rust, however, and it's one of the few languages that really gets that right, but it's nowhere near as convenient as calling/using C or C++ from C++. Most of these issues are consequences of C and C++ having the existing inertia, but it is what it is. Some people want to ship things and not join a community.
If you're trying to get a job or just learn: learn both. C++ isn't going to go away completely any time soon, but, with every month that passes, there are fewer and fewer technical reasons to justify starting a new project in it vs Rust. Choosing an inferior tool because it's the only one you understand might often be the correct choice, but it's not a choice you want to have to make.
Neither C nor C++ could be considered new languages, and this seems to contribute to this estimation of embedded engineering as a "lost art." C and C++ give a "here be dragons feeling," that only the best engineers can hope to avoid pointer pitfalls and memory leaks. I wonder if Rust's advances in programming language theory could alleviate this problem. The new generation of programmers I feel I belong to are comfortable with functional programming, advanced types, and facile tooling like NPM.
I have personally found embedded engineering underrated in American industry, both for fun and profit. If adopting modern practices leads to further embedded engineering adoption, that would be a worthwhile pursuit for individuals and our community. Perhaps this takes the form of Rust.
[a] Top 300 in global ranking, with a standard but not cutting edge computer science program unlike Stanford or CMU. Having gone to only one university I admit this confusion could simply be a failing of my own education.
Embedded programming in C++ is pure fun. The more modern your code is, the less room you leave for bugs: when it compiles, it mostly works. Where it doesn't, it shows up in your logic, not in random memory corruption.
Constexpr methods seem perfect for embedded in a lot of ways too. Yes, I won't be touching real memory or ports, but I can ensure that the method isn't doing silly things either. Having a memory address class that filters on the proper operations and only allows them is awesome. Saw a good video on the topic recently too https://www.youtube.com/watch?v=fsMmh8F8uV0
C++ code bases may have less buffer overflows and off-by-one errors but I don’t trust them unless they come with an extensive safety-net in the form of unit-tests with good coverage.
I think the cultural shift is partly just people voting with their feet and going where the money is.
It refers to an approach that doesn’t worry much about how things were done in C and instead thinks about how to represent things cleanly and efficiently with the aim of faster development and fewer bugs.
I was an embedded developer for years and still write a lot of code in C++ because it results in fast code that is easier to write than if I tried in C.
One of mantras of the c++ committee is that you should pay (have overhead) for the stuff you don’t use. So I don’t try to write code that looks like C.
Not really. I only use header-only libraries and dependency management is a breeze for me. I check each library out as a git submodule into a third-party subdirectory in my project directory, point the includes path at it and off I go. When I want to upgrade, I pull the git tag/branch/commit I want and recompile. Its pretty simple.
How so?
> Also this works nicely for self contained dependencies, and much less nicely for not self contained dependencies.
Doesn't matter. You said: "You can speak for everyone." which is simply not true, as I have outlined. You didn't say anything about not self contained dependencies or whatnot. The person you replied to said "I spent an unconscionable amount of time managing dependencies and libraries in C++" and I... well, don't. So clearly not everybody does.
Rust catches data races, use of non-thread-safe functions, and use-after-free problems across the entire codebase, including (mis)use of 3rd party libraries, at compile time. I can add `.par_iter()` to a loop, and if it compiles, I know it doesn't mangle any data. If it doesn't compile, the compiler points me to the exact struct that needs a refcount, or a mutex, or atomic. That saves me weeks of chasing heisenbugs.
In debug builds it checks all integer arithmetic for overflow (no need to wrap types in custom class, works for dependencies too). This has saved my ass a few times.
There's a pretty decent standard library, and a good number of quality dependencies that can be installed with a 1-liner. If I need to (de)serialize a struct from JSON, it's a couple of lines. I want to switch that to msgpack instead, 2-line change. I need that compressed? 2 lines again, plugs in easily, and supports serialize-and-compress without an intermediate buffer.
Build system uses convention over configuration, so there's no artisanal "build script" to manage, or even an argument which build system sucks less. Dependency management and workspaces work well enough that it's practical to modularize projects into smaller libraries, and actually reuse them. Unit testing is built-in. Doxygen-like generator is also built-in, no config needed. Of course any language can do the same, but having zero friction removes excuses and really helps making people actually use these things.
Qt and C++ it is then.