33 ms·
How to make your C codebase Rusty: rewriting keyboard firmware keymap
- wyldfire 7y agoHah, interesting. A new spin on RIIR: RIIRFTSOETC ("rewrite it in rust for the sake of exporting it to C").
- matheusmoreira 7y agoWhat's commonly known as the C ABI is actually the System V ABI: http://wiki.osdev.org/System_V_ABI http://wiki.osdev.org/System_V_ABI Projects that are meant to be widely reused should export their functionality through that simple ABI. Otherwise people will rewrite it in C.
- gpm 7y agoIt's known as the System V ABI on Linux. Not on Windows (Microsoft X64 Calling Convention for x64 windows). https://stackoverflow.com/a/44893431 https://stackoverflow.com/a/44893431
- umanwizard 7y agoThose are not actually the same. There are several differences, but the most obvious one is that the standard ABI on x86-64 Linux passes integer parameters in the following order: rdi, rsi, rdx, rcx, r8, r9. I noticed this immediately the first time I tried reading some Windows disassembly, as “rdi rsi rdx” is very thoroughly burned into my brain...
- gpm 7y agoDidn't mean to imply that they are the same ABI, sorry. Just that they're both "What's commonly known as the C ABI".
- umanwizard 7y agoMy bad for misunderstanding you!
- shepmaster 7y agoSee also “Rust out your C” by Carol Nichols: https://github.com/carols10cents/rust-out-your-c-talk https://github.com/carols10cents/rust-out-your-c-talk
- discardable_dan 7y agoAt this point, I'm not so much against Rust because it's a difficult or hard thing to use, but because there's such a learning curve I can't, in good conscious, move team projects to it. "To continue to work on this with me, you must first learn Rust" is a hard sell.
- wwright 7y agoIMO, this even applies when replacing most C/C++: a lot of that code doesn’t need most of the benefits or C++ or Rust. Often, it’s better to replace it with simpler programs doing less work in Go or JavaScript or Python. I love Rust, but most use cases just don’t need it. The language needs a pretty substantial amount of experience to use, though, so you don’t want just a few Rust programs lying around; no one will have a reason to learn, so they will be even harder to support. Between these, it becomes pretty difficult to find a critical mass of problems that need Rust enough to both justify the cost and to get a decent amount of traction in the company.
- umanwizard 7y agoDespite being a Rust fan, I do believe that it is in fact harder to use than nearly all languages, despite the valiant effort of the community to make it as easy to use as possible. Things shouldn’t be ported to Rust willy-nilly, but in its niche (basically: a better C++, because the compiler enforces many of the things you need to keep track of in your head in C++, and also because as many productivity features as are possible without violating “pay-for-what-you-use” too fragrantly are baked in), it can be worth the cost. I am sure some others will disagree with this, but I think using Rust in domains that Python or Java or Awk or Bash is well-suited to is quite silly. For me, Rust competes with C and C++, and little else.
- clktmr 7y agoI don't know, to me the C version is more readable. I know for sure that in the end the C macros will only do text replacement, whereas the Rust macros could do anything. And emojiis in code, really?
- Analemma_ 7y ago> I know for sure that in the end the C macros will only do text replacement, whereas the Rust macros could do anything. My impression is exactly the opposite: Rust macros are guaranteed to expand to syntactically valid code that still obeys the memory/type/lifetime-safety constraints, whereas C macros can expand to something that won't even compile, never mind have any guarantees about soundness. Not to mention all the hoops you have to jump through with extra parens and whatnot to avoid the footguns of C macro operator precedence.
- F-0X 7y agoRust macros can do worse things than C macros can. They can execute arbitrary code at compile time.
- cdirkx 7y agoThat is only with procedural macros. Normal macros operate just by token substitutions. Procedural macros are also special in that they are the only macros that can be 'unhygenic': creating new identifiers in the current scope that were not passed as an argument to the macro. (Although knowing if something is a procedural macro or not is not obvious when using one in code)
- juped 7y agoNot compiling is a great outcome when you've introduced an error.
- Lev1a 7y agoThat's the same for Rust macros though. If the expanded code does not pass all the checks along with the other/normal code the program/lib won't compile.
- zabzonk 7y agoAs far as I can see the major difference is that the C code uses longer macro names.
- xvilka 7y agoMuch or this can be automated with c2rust[1][2]. They recently published an overview[3] of lessons learned and future directions for Rust and C integration. [1] https://c2rust.com https://c2rust.com [2] https://github.com/immunant/c2rust https://github.com/immunant/c2rust [3] https://immunant.com/blog/2019/11/rust2020/ https://immunant.com/blog/2019/11/rust2020/
- sansnomme 7y agoA lot of established C codebases are really preprocessor heavy. E.g. https://github.com/remacs/remacs https://github.com/remacs/remacs
- nerpderp82 7y agoCompile C to Wasm and run in a Rust hosted Wasm sandbox.
- pjmlp 7y agoIncluding the Heartbleed version of OpenSSL if one so desires.
- Animats 7y agoThat doesn't really translate C to Rust, it compiles it to unsafe Rust with all the weaknesses of the C code. It doesn't even use Rust arrays. You would not want to maintain what comes out. It turns p[j] = p[j-1]; into *p.offset(j as isize) = *p.offset((j - 1 as libc::c_int) as isize); which is unmaintainable. If you put in void insertion_sort(int const n, int const p[]) you get pub unsafe extern "C" fn insertion_sort(n: libc::c_int, mut p: *const libc::c_int) C has no way to say how big p is. (Biggest flaw in the design of C). That info is essential to translating this properly. The translator needs either a hint from the user, or inference from examining the calls to the function. Now, if you could stick something like ASSERT(LENGTHOF(p) == n); which would be ignored by C if ASSERT was defined to ignore it, and the Rust translator understood that, it could use a Rust array, which has a size. Now the output Rust code could use subscripts properly. Generating constraints like that is a hard problem, but providing an interactive tool which prompts the user on where to insert them is not.
- unlinked_dll 7y agoI'd argue it'd make more sense for the keymap macro to load a json/toml/yaml config file and then generate the code but that's just me. Would be a little more straightforward too using serde, just type out your schema in normal rust, automatically derive the deserializer via serde, load a file with a function like macro, and synthesize the C compatible code from there.
- jeffdavis 7y agoTrue, but there's some difficulty using codegen. If macros can do it, it's often nicer. But not always, and it's subjective.
- unlinked_dll 7y agoProcedural macros in Rust are essentially code generators.
- hotz 7y agoAll these Rust posts are starting to become quite tiring.
- viraptor 7y agoIn what way? They've got Rust in the title... you can just ignore them mostly.
- 0xdead 7y agoI'd pay for something that filters out front-page titles with specific words in them.
- AmericanChopper 7y agoHN has an RSS feed, so this is quite simple. Here you go: https://hn.algolia.com/?dateRange=last24h&page=0&prefix=false&query=-rust&sort=byPopularity&type=all https://hn.algolia.com/?dateRange=last24h&page=0&prefix=fals...
- jay_kyburz 7y agoOff Topic, but I really like this trend towards very simple blog themes.
- alxmdev 7y agoReading the comments here it seems like I'm not the only one who thinks some Rust code is pretty syntax-heavy even compared to older systems languages like C and C++. I wonder if this is in part to further separate application development from system development (slowly paving the way for more verbose but formally verifiable code in core components), and to push more people to write higher level code instead. I can imagine many reasons for why things would be steered this way. Edit: Bad code example, sorry; thanks for the informative reply! I didn't mean to be unnecessarily negative, just a thought that ran through my head.
- steveklabnik 7y agoI can assure you that Rust's syntax is not designed to further separate application development from system development, if anything, we encourage a way broader audience to learn Rust than just pure systems programmer folks. In general, Rust's syntax is intended to be vaguely similar to C/C++/Java, but with some influence from functional languages where appropriate, and with syntactic forms that work better with type inference. There is very few syntactic forms that are truly novel in Rust (even lifetimes are taken from OCaml's generic syntax, because lifetimes are generics!) That said, fn my_panic(_info: &core::panic::PanicInfo) -> ! { would be something like [[ noreturn ]] void my_panic(&core::panic::PanicInfo _info) { in C++, which is very similar, syntactically speaking. The main differences are: * fn for function declarations * Rust has the return type after parameter list, and adds -> * ! is [[ noreturn ]], less punctuation actually! * no need for the superflous void return type * "name: type" not "type name", which adds a single : I am admittedly very biased, but it seems much more similar than different.
- gpm 7y agoIn addition to this excellent reply, if you were using the type core::panic::PanicInfo commonly (i.e. "twice") you would import PanicInfo at the top of the file use core::panic::PanicInfo and the function would become the much shorter fn my_panic(_info: PanicInfo) -> ! {
- steveklabnik 7y ago
- andrepd 7y agoThe `keymaps!` macro does indeed look somewhat cleaner, but I wonder how many hours it took to develop for such marginal benefit :p
- z3t4 7y agoThe Rust example made me feel anxious. I never got macro systems. What's so hard to read about a basic multi dimensional array? It's like the most basic of data structures. Am I the only one that can easily picture this in my head ?
- squiggleblaz 7y agoIsn't the advantage of the macro in the Rust example not the fact that it's a more convenient multi-dimensional array (is it even that? like you say...) but that we're using literals not for their literal value, but for some local symbolic value. For instance, `1` doesn't mean 1, it means whatever `KC_1` means (perhaps that 63). I surely find the Rust macro example easier to read in isolation. Macro systems that are effectively simple find-and-replace are terrible. Modern macro systems that give you access to the actual syntax tree to manipulate directly - well, I feel more comfortable writing a little more code than using them, but at some point the differences mount up. I suspect the tradeoff here is better in the demonstration than the actual use, but other cases are valuable.