6 ms·
I'd be interested to see the comparison against zig[1], which I am eying up as a quite interesting language for embedded development. I think the comparable fea
by snops 7y ago
I'd be interested to see the comparison against zig[1], which I am eying up as a quite interesting language for embedded development. I think the comparable features would be:
- No automatic magic, anything that looks like a function or memory allocation is, anything that doesn't, isnt.
- Good compile time code generation capabilities including reflection, much nicer than C macros.
- Runtime safety features, such as bounds checking, but not as intrusive as Rust's borrow checker (which makes less sense for single threaded embedded applications). These can be turned off in release builds.
- Very good C interop for use with manufacturer HAL libraries etc, includes a C compiler.
- Better error handling than C, without needing full exceptions, instead the "try" and "defer" macros nicely replace C's "goto" for error handling[2].
- No garbage collection
- Embedded is a first class target, unlike Go/TinyGo
- Working async support on all platforms.
- Sadly not as popular as others, one full time developer currently I think.
[1] https://ziglang.org/ https://ziglang.org/
[2] https://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c https://eli.thegreenplace.net/2009/04/27/using-goto-for-erro...
- bluejekyll 7y agoI’m familiar with Zig. All of those features you list are also Rust’s capabilities. Is there a reason you don’t see Rust as an option in this space?
- pron 7y agoThere are a few. Rust is a very complex language; it's essentially a modern take on C++, and it fully adopts C++'s design philosophy. This has several implications for embedded development. For one, it makes it hard to write custom compilers and direct backends (AFAIK Rust currently only targets LLVM and WASM). For another, it makes certain formal and informal analyses and guarantees hard (this is perhaps ironic given Rust's emphasis on sound safety, but sound static analysis tools are easier to write for C). It appeals to those who already like C++, but embedded developers aren't crazy about C++; C still rules that space. Zig is a very simple language. Its strength is not in the features it has, but in the features it lacks. Also, Zig encourages stricter control over allocation than Rust, and it's C interop is virtually seamless. Zig is very young and may well end up disappointing, but its careful selection of features that provide what seems to me to be a great combination of power and simplicity (a single feature represented by a single keyword does the work of generics, value templates, constexprs and macros, all without the complications macros introduce). Anyway, I find it to be a very interesting take on what modern low-level programming can be.
- bluejekyll 7y ago> Rust is a very complex language; it's essentially a modern take on C++, and it fully adopts C++'s design philosophy. This is a false and inflammatory statement, and unhelpful. It's more complex than C, but has very different set of features and type capabilities from C++ that makes it far simpler. Even for C, I would say it really is a different set of complexity. Rust brings that complexity to the fore-front, whereas C and C++ both have a significant amount of hidden complexity. > It appeals to those who already like C++ Perhaps, but I absolutely abhor C++ (after years of working with it) and completely love Rust, so :shrug: > Zig is a very simple language It is. It also doesn't make many of the same safety guarantees as Rust. So there are trade-offs. > I find it to be a very interesting take on what modern low-level programming can be. As do I! Though, I do think people keep looking for greener fields unnecessarily.
- pron 7y ago> This is a false and inflammatory statement I think it's neither false nor inflammatory, but a neutral, objective observation. I think that if you asked people what languages in more-or-less regular use are about as complex as Rust (or more), they'll give you a very short list (I can think of no more than three: C++, Ada and Scala). That does not make it bad or unsuitable -- in fact, it might well be great for some -- but it does make it less attractive to those who value language simplicity. > It also doesn't make many of the same safety guarantees as Rust. So there are trade-offs. Sure, and if a low-level programmer's primary goal is to write software that's free of certain technical bugs that correspond to C's undefined behavior, then a language that can more-or-less guarantee they don't exist (with some caveats) may be the best way to achieve that. But I don't think that is most people's primary goal. Even for those who value correctness in high-assurance domains, the elimination of undefined behavior, which always comes at a cost, is not necessarily the best way of achieving correctness. Zig, too, puts an emphasis on writing safe code, it just goes about it a different way than ensuring certain guarantees, soundly, in the language itself. Now, let me take this opportunity to also explain why it's uncertain that Rust's approach to correctness is the better one. I saw some report from Microsoft that 70% of their security bugs are due to undefined behavior in C++. Let's assume that all UBs are equally to blame, we'll assume that reducing security bugs is the only thing we care about, and we'll assume that Rust completely eliminates all UB (which isn't necessarily true because of unsafe and because there could be bugs in Rust and/or LLVM, but I'm willing to accept that Rust's approach is the best at eliminating UB). By choosing Rust and developing the software at cost X (it doesn't matter for now whether X is smaller or greater than the cost of developing in C++) we eliminate at 70% of security bugs. Now, there can certainly be a different approach that doesn't eliminate all UB and still reduces security bugs by more than 80%. I'm not saying we know for what that approach is, but what I am saying is that it is not at all certain -- it has neither been justified theoretically nor confirmed empirically -- that soundly eliminating all UB, which comes at some cost, is the best approach of reducing those bugs. I, for one, believe that Zig's approach -- of language simplicity plus some strong safety features -- is a better approach to correctness than Rust's. I don't know that, I just believe that, but those who believe that Rust's approach to safety is better don't have stronger grounds to stand on. So Zig does not trade off correctness; it trades of the sound guarantee for lack of UB, which isn't a goal in an of itself. It's a means to achieving some goal, and some may believe it's the best means, but there is so far little evidence to suggest that it is. Yeah, Rust is better than Zig at eliminating UB, but that doesn't mean it's better at correctness. It could well be worse. > Perhaps, but I absolutely abhor C++ (after years of working with it) and completely love Rust, so :shrug: Rust is an improvement over C++, but C++ isn't a hit in embedded development, either. > I do think people keep looking for greener fields unnecessarily. Why unnecessarily? You don't like C++ but found what you want in Rust; I'm not crazy about C++, either, but Rust doesn't even begin to solve my main problems with C++ (a "better C++" is not what I need), so why is my hope for greener fields less necessary than yours? I would be happy if people gradually shifted from C++ to Rust -- at least we'll have fewer UBs -- but I don't think it will ultimately make a big change in low-level programming; maybe in some sub-niches of it. I think Rust's emphasis on sound safety guarantees came at a cost elsewhere, and that cost is too heavy for some. Some like it, some prefer a different approach. I have no problem with people who like Rust, and they shouldn't have a problem with those who don't. Anyway, you asked why some might not see Rust as the answer to their wishes, and I answered.
- snops 7y agoI don't know Rust very well, but it strikes me as quite, complex, with a lot of language-level features. I think a lot of that complexity isn't needed in embedded, e.g. the borrow checker and "fearless concurrency" makes less sense for single-threaded applications, which is by far the majority of embedded development. The original post lists rust as having a lot of "hidden magic", which zig explicitly states it does not have. I am unsure how much Rust actually has of this tbh. Also, are you sure Rust has "a C compiler built in?[1]" If I look at the official guide, it recommends compiling your C code to a static library[2], though there are crates to add this to the build process. Rust requires bindings to be generated too, which can be automated [3], but in Zig it just requires including the header file[4] and optionally converting the error codes into proper errors, no extra packages. Finally, I don't rule out Rust as an option, especially due to its much higher popularity, mindshare and hence ecosystem. But I think a comparison is interesting when discussing other languages for embedded development. [1] https://ziglang.org/#Zig-is-also-a-C-compiler https://ziglang.org/#Zig-is-also-a-C-compiler [2] https://rust-embedded.github.io/book/interoperability/c-with-rust.html https://rust-embedded.github.io/book/interoperability/c-with... [3] https://rust-embedded.github.io/book/interoperability/c-with-rust.html#automatically-generating-the-interface https://rust-embedded.github.io/book/interoperability/c-with... [4] https://ziglang.org/#Integration-with-C-libraries-without-FFIbindings https://ziglang.org/#Integration-with-C-libraries-without-FF...
- bluejekyll 7y ago> Also, are you sure Rust has "a C compiler built in?[1]" It depends on how you look at it I guess. Rust can represent C FFI directly in the language and has many great tools for incorporating C into the language elegantly, like bindgen, which you allude to. I'm not sure I would call this a gap having worked with incorporating Rust into C projects and also C into Rust projects.
- zozbot234 7y ago> the borrow checker and "fearless concurrency" makes less sense for single-threaded applications Memory safety, safety from reference invalidation, async etc. etc. There are lots of reasons to care about the Rust featureset even in single-threaded code.
- mwcampbell 7y agoAFAIK Zig doesn't have a way to calculate maximum stack usage at build time. But perhaps this could be done in a language-independent way, in LLVM. That would probably be better anyway, since to really do it well, you'd have to do whole-program analysis, including calls between Zig and C.
- snops 7y agoInteresting, GCC has '-fstack-usage' to output the stack usage of each function into .su files, I didn't realise LLVM was lacking this feature. There is a tool in rust[1] I just found that makes LLVM emit this information for rust code, but it stores it within[2] the .stack_sizes section in the emitted .elf instead. Possibly a similar trick could be added to Zig [1] https://github.com/japaric/stack-sizes https://github.com/japaric/stack-sizes [2] https://llvm.org/docs/CodeGenerator.html#emitting-function-stack-size-information https://llvm.org/docs/CodeGenerator.html#emitting-function-s...
- mwcampbell 7y agoI was referring to T1's ability to guarantee a particular stack size for the whole program (if I understand correctly), not individual functions.
- AndyKelley 7y agoit's been planned since the beginning: https://github.com/ziglang/zig/issues/157 https://github.com/ziglang/zig/issues/157 https://github.com/ziglang/zig/issues/1639 https://github.com/ziglang/zig/issues/1639 also I figured out how to have safe recursion, taking advantage of the stackless coroutines: https://github.com/ziglang/zig/issues/1006 https://github.com/ziglang/zig/issues/1006 this is relatively straightforward to solve in a non-llvm backend. The LLVM abstraction gets leaky fast when you try to tackle this problem.