News for hackers. Stuff that matters.
Re:Linux Rust Support by skor on Tuesday July 06, 2021 @08:16AM (#27747426)
What is really good about Rust that you cannot get in C?
Re:Linux Rust Support by garrinm on Tuesday July 06, 2021 @08:39AM (#27747665)
It'd be very hard to make a statement like "Rust can do X that C can't" without there being a statement "You can do Y, then Z in C and that is like X" because clearly they are both Turing complete languages at the end of the day.

So I'll instead just give reasons why people might prefer to program in Rust:

- Memory management / safety (no GC, variable lifetimes are tracked by the compiler, no dangling, no null pointer ...)

- Ergonomics (built-in unit tests, feature-full std lib, unicode strings, modern dependency manager, more formalized macros ...)

- Functional-lite (you must explicitly discard unused enum variants, the "null" value is an enum variant ...)

Long story short: Rust makes it really easy to write sound software. I think you see that on crates.io where Rust packages are hosted. Lots of packages quickly reach maintenance mode and receive very few updates, but remain extremely useful. Once you've written (compiled) something in Rust, you feel much more confident that is is free of latent runtime bugs.

Without commenting on whether or not this is necessary or good for the Linux kernel, I'll say that there are probably many devs out there that feel like working other non GC languages feels like pulling teeth after having worked with Rust. And that might be part of the pressure.

Re:Linux Rust Support by ozarkerD on Tuesday July 06, 2021 @08:52AM (#27747811)
I love cargo. That alone almost makes it worth it to me after years of wrestling cmake and dependency compilation.
Re:Linux Rust Support by gpm on Tuesday July 06, 2021 @09:22AM (#27748151)
Note that the kernel won't use cargo to build most (or all) of the rust code.

Though dealing with rust dependencies by hand is usually nicer than dealing with C dependencies by hand because the build process is more standardized.

Re:Linux Rust Support by whb07 on Tuesday July 06, 2021 @08:24AM (#27747496)
Compile time guarantees that you didn’t access memory you didn’t really “own”.

Dangling pointers are not a thing.

No double free.

Forces you to think up front about what are the possible state something could be in, and so you won’t get runtime or weird UB.

lastly, to be more pedantic for everyone who is at Linus-levels, it’s like all the best static analysis and warnings/errors all rolled up natively into the language. Please don’t bombard me with “but I can just run clang’s X and get the same thing”. No you can’t, and if you did this forces you to run it regardless.

Re:Linux Rust Support by emilfihlman on Tuesday July 06, 2021 @09:06AM (#27747977)
All easily achievable with gcc.

Yes, we can.

Re:Linux Rust Support by bicolao on Tuesday July 06, 2021 @10:09AM (#27748792)
Please show us how. I don't think these can be achieved within current C semantics.
Re:Linux Rust Support by masklinn on Tuesday July 06, 2021 @10:38AM (#27749227)
In full anyway. Limited subsets? Sure, if you assign a null and immediately try to deref' it Clang and GCC will probably notice and yell at you.
Re:Linux Rust Support by whb07 on Tuesday July 06, 2021 @12:43PM (#27750951)
Well, no. You’re talking about using all the flags and tooling like i just mentioned, which 99.99% of people don’t use every time they run a build. Even then the best and strictest of flags + Werror still falls short.

Then you still have to run extensive fuzzing and testing to trigger different paths and whatnot.

Or you could just use Rust.

Re:Linux Rust Support by gpm on Tuesday July 06, 2021 @08:48AM (#27747767)
Apart from all the safety benefits mentioned, a modern language with modern conveniences.

Type inference

Language support for tagged unions (which they call enums for some reason), which among other things results in error handling which is "out of channel" instead of magic return values.

Speaking out error handling - syntax for easily forwarding errors to the calling function.

Generics, and therefore

- Libraries of collections with a rich collection of methods implemented for you.

- Library support for lazy iteration

- ...

Method (postfix call) syntax allowing for readable chaining

Hygenic macros

Compiler supported test harnesses

Compiler supported linting (that is really good)

Compiler supported automatic formatting (that is really good)

Compiler supported vtables

(pointer, length) strings

Proper namespaces

And so on and so forth

Re:Linux Rust Support by cesarb on Tuesday July 06, 2021 @12:02PM (#27750297)
> Language support for tagged unions (which they call enums for some reason)

Probably because the simplest case of Rust enums (without any data other than the tag itself) can act similar to a C enum, to the point that you can "#[repr(C)]" it and use as FFI for the equivalent C enum. One understated advantage of Rust for C programmers (which is on topic given that the Linux kernel is written mostly in C) is that its syntax and keywords have many similarities with C, starting with the use of braces for blocks and semicolons to end statements.

Re:Linux Rust Support by gpm on Tuesday July 06, 2021 @12:19PM (#27750574)
Ya, that was a throwaway comment that I probably should have left out.

> and use as FFI for the equivalent C enum.

Only if you're willing to accept undefined behavior if the foreign code passes you an unknown variant. For actual ffi work I've ended up using a macro that makes a "#[repr(C)] struct EnumName(u32)" with a bunch of constants for the values.

Re:Linux Rust Support by ElderKorihor on Tuesday July 06, 2021 @08:36PM (#27756086)
> Only if you're willing to accept undefined behavior if the foreign code passes you an unknown variant.

Isn't that what `#[non_exhaustive]` is for?

Re:Linux Rust Support by gpm on Tuesday July 06, 2021 @08:43PM (#27756128)
As far as I know that flag doesn't give you permission to create unknown variants or effect backend code generation that will assume there are only the defined variants. I could be wrong, but I don't see anything about this documented in the rfc: https://rust-lang.github.io/rfcs/2008-non-exhaustive.html
Re:Linux Rust Support by kzrdude on Tuesday July 06, 2021 @03:33PM (#27753224)
That wouldn't be ABI-correct for ffi function parameters by value, right? (Since it's a struct, not an enum).
Re:Linux Rust Support by gpm on Tuesday July 06, 2021 @03:49PM (#27753379)
It would be correct, up to the size of the integer. As far as the abi is concerned a C enum is just an integer. As far as the abi is concerned a struct containing a single integer field, is also just an integer.

If there are any values that don't fit in a u32, I would need to use a different int type. C enums automatically use bigger int types if they don't fit in the smaller ones.

If I was on an architecture where int was smaller than 32 bits it would also be incorrect (except by coincidence that 32 bits was the smallest type that could hold all the values). I could "solve" that by using libc::c_int instead, but that only sort of solves the issue because if libc::c_int is 8 bits, and the enum has a value 257, it's just not correct anymore.

I suppose it's possible that some abi treats a struct containing an int differently from an int, I doubt it though. If that's the case, #[repr(transparent)] instead of #[repr(C)] would be slightly more correct.

Re:Linux Rust Support by jlokier on Tuesday July 06, 2021 @07:16PM (#27755546)
> As far as the abi is concerned a C enum is just an integer

In some ABIs this is not true, a C enum is a char if the constants fit. Your code that assumes enums are stored and passed around as 32-bit integers is not entirely portable.

Re:Linux Rust Support by gpm on Tuesday July 06, 2021 @08:33PM (#27756068)
Yes, I agree.

Ultimately, at least at the time, there was no other option that had better compatibility. Now I suppose you could use MaybeUninit<#[repr(C)] enum> or something. Realistically I don't have much confidence in rustc properly matching enum sizes with C implementations that don't follow the typical behaviour here, so I doubt that would be worth it.

I guess the linux kernel is generic enough that it might end up on some such platforms, I guess in that context I'd just bite the bullet and accept undefined behavior if passed an unexpected enum variant, it's not like that should happen in a coherent system like the linux kernel (vs my use case which was wrapping some library that definitely might chose to add enum variants).

Re:Linux Rust Support by tialaramex on Tuesday July 06, 2021 @12:56PM (#27751187)
You can do all sorts of C things in Rust, and they're merely not idiomatic.

For example your Rust function that always returns 42 should probably be:

  const fn fortytwo() -> i32 {
    42
  }
But C programmers might try:

  const fn fortytwo() -> i32 {
    return 42;
  }
And that works fine, the compiler sees that you wanted to return 42 here, and, although the value at the tail of the function is an empty tuple and thus incompatible with your function signature you never reach that tail, so no problem.
Re:Linux Rust Support by Macha on Tuesday July 06, 2021 @08:54AM (#27747843)
1. Modern standard toolchain

2. Ergonomic use of functional idioms like sum types (Rust's enums)

3. Memory safety without GC overhead - Windows, Linux, curl, over and over again 40% of vulnerabilities in larger C projects are found to be preventable if there was a memory safe language

Re:Linux Rust Support by wffurr on Tuesday July 06, 2021 @08:25AM (#27747510)
The main benefit is that in Rust, use-after-free, data races, and bounds overflows are statically checked with zero runtime cost. It eliminates entire classes of common severe memory safety bugs at compile time.
Re:Linux Rust Support by volta83 on Tuesday July 06, 2021 @08:30AM (#27747547)
The ability to refactor large code bases quickly without introducing segmentation faults, memory bugs, UB, etc.
Re:Linux Rust Support by lemmox on Tuesday July 06, 2021 @08:51PM (#27756167)
I came for the memory footprint but I stayed with Rust for this. Rust became my daily-driver for hobby projects because refactoring and tinkering with old projects is a breeze. For me, Rust projects don't seem to require much cognitive burden to load into my human memory. I do not claim that this quality is unique to Rust however it is very much present in Rust.
Re:Linux Rust Support by mvolfik on Tuesday July 06, 2021 @08:23AM (#27747493)
I'd guess guaranteed memory safety (unless you use `unsafe` blocks) without compromising for some garbage collector or ref. counting is a big thing
Re:Linux Rust Support by 0x008 on Tuesday July 06, 2021 @08:27AM (#27747529)
It's not about if you can get there but how fast and at what cost.
Re:Linux Rust Support by goodpoint on Tuesday July 06, 2021 @08:37AM (#27747639)
What is really good about Rust that you cannot get in Nim?
Re:Linux Rust Support by geofft on Tuesday July 06, 2021 @10:31AM (#27749143)
Safe, GC-less memory allocation. Nim requires a GC, at least runtime refcounting, in order to not leak memory: https://nim-lang.org/docs/gc.html

The ownership/lifetime system is basically novel to Rust (well, it's based on Cyclone, which would probably have been an interesting choice for the kernel too because it's based on C, but Cyclone is no longer actively developed), and it allows you to get the performance of manual memory management (no refcounting required) without either leaking memory or hitting use-after-free bugs.

Rust's ownership system also tracks shared/immutable references and unique/mutable references at compile time, avoiding a whole bunch of setups for creating race conditions or otherwise corrupting data.

Re:Linux Rust Support by goodpoint on Tuesday July 06, 2021 @12:43PM (#27750956)
Nim is memory-safe and compiles to C, which is a big plus for integrating an existing C codebase.

> Rust's ownership system also tracks shared/immutable references

See https://nim-lang.org/araq/ownedrefs.html

Re:Linux Rust Support by geofft on Tuesday July 06, 2021 @05:13PM (#27754318)
If I understand correctly, that post describes a proposal to add "owned refs" to Nim, not an actual language feature, and that proposal was abandoned / postponed in favor of the refcounting approach I linked to: see https://github.com/nim-lang/RFCs/issues/144 and https://github.com/nim-lang/RFCs/issues/177 .

But shared/immutable vs. unique/mutable references aren't the same thing, they're something more interesting. Rust has three types of ways you might be able to get at a variable: you could own the variable, you could have a shared/immutable reference to it, or you could have a unique/mutable reference to it. The Nim proposal only distinguishes the ownership case (responsible from freeing the data when it's done - basically RAII or __attribute__((cleanup)) or autorelease) from the unowned case.

Having shared/immutable references gives you a neat feature for achieving correctness, not just memory safety (and I strongly disagree that the idea of "memory safety" in that post really counts, incidentally, because by that definition Heartbleed wasn't a memory-safety bug, but for the sake of argument let's say it does). The compiler prevents you from having more than one mutable reference at a time. It also prevents you from writing data you own while someone holds a reference to it, or even reading data while someone holds a mutable reference. So if you're writing code where you pass a reference to some other routine, and that function ends up holding onto it for future use, you won't be able to modify it. That prevents logical bugs where code doesn't realize that data has changed or conversely doesn't realize that a change hasn't taken effect.

Again, this is not solely about memory safety. This is about easily writing correct code, of which memory safety is one aspect.

You can think of this as basically type-level reader/writer locks. At any given time you can have multiple readers and no writer, or exactly one writer. While runtime memory safety is one thing that reader/writer locks can do (e.g., preventing you from calling realloc() while other people still have a pointer that they intend to read), they're used for a lot more than that.

Furthermore, Rust's approach requires no runtime overhead and preserves correct behavior. Nim's approach requires refcounting, and the post argues that refcounting could be disabled in a release build if you're confident your code is correct.

Re:Linux Rust Support by jlokier on Tuesday July 06, 2021 @07:31PM (#27755672)
The current direction in Nim is towards borrowing and borrow checking, move semantics with type annotations, and using refcounting where needed. Similar to Rust really, which also uses refcounting where needed.

Nim had the concept of borrowing from very early on. It's not a bolt-on, it's part of the design philosophy. But it's had consistency issues. The move semantics in newer Nim improve on it.

I would say one of the major things Rust offers over Nim at the moment is the implementation quality of the Rust compiler, standard library and type systems is generally of higher quality and more consistent. Things are thought-through more completely in Rust's design, and tested more against real world problems.

The multi-threading in Rust is also of much higher quality. It's just buggy in Nim.

Nim however has a much cleaner syntax, and the quality issues could change if the community really wanted that (I don't think it does).

They both have slow compile times for large programs.

Re:Linux Rust Support by swiley on Tuesday July 06, 2021 @08:40AM (#27747673)
NPM style package management :p

But there are some significant improvements WRT memory management/indirection.