At first glance, these features look quite general to me and not particularly tied to the kernel, they are important utilities for doing this kind of programming in the real world.
These new features are all about making things that the kernel devs need possible in safe Rust. This often requires support for some quite fancy abstractions, some of which cannot be expressed in current stable Rust.
Only if you primarily work with `cargo` and want to interact with C from Rust. The other way around has far less support and `rustc` does not standardize the object generation. This is actively preventing projects like `systemd` to adopt Rust into their project as an example.
In what way(s) does Rust's C interop depend on cargo?
> The other way around has far less support and `rustc` does not standardize the object generation.
I believe in this context the understanding is that you're going to be using `extern "C"` and/or `#[repr(C)]` in your Rust code, which gives you a plain C interface. I think attempting to use "raw" Rust code from other languages is a rare phenomenon, if it's even attempted at all.
> This is actively preventing projects like `systemd` to adopt Rust into their project as an example.
Could you point out specific instances from that thread? From a quick glance I didn't see any obvious instances of someone saying that using Rust from C is problematic.
Do rust and cargo allow for multiple interpretations of the same C header file across different objects in the same program? That's how C libraries are often implemented in practice due to preprocessor tricks, though I wish it wasn't normal to do this sort of thing.
If the header files are consumed by C code that is then consumed by Rust then you'll have full support for what C supports because it will be compiled by a C compiler.
However, some people use cargo's build scripts to build c programs, which then you can link into your Rust program. Support would then depend on whatever the person wrote with the script, which in my experience usually delegates to whatever build system that project uses. So it should work fine.
I guess looking at that pedantically that's "just" a tooling issue, rather than an issue with the Rust language itself. That's not really a useful distinction from an end user's perspective, though; it's friction either way, and worth addressing.
I am currently working on a fairly involved C & Rust embedded systems project and getting the inter-language interface stable and memory-leak free took a good amount of effort. It probably didn't help that I don't have access to valgrind or gdb on this platform.
There is some C++/rust interop in the past that I've worked on that would have enjoyed the arbitrary self types feature, but not particularly because of the C++ part of the equation. In fact I think if it had been a pure rust project it would also have enjoyed that feature just as much so... eh... take it for what little it's worth I guess.
Writing Rust code to be called from C (but within the same application)? Doable but somewhat painful.
Writing Rust code to act like a C shared library? Quite painful and some pretty important features are missing (proper symbol versioning support being the most obvious one). Theoretically doable if you're willing to compromise.
There's also some aspects of FFI-safety that are very subtle and easy to mess up:
* #[repr(C)] enums still have the same requirements as Rust enums and so C callers can easily trigger UB, so you need to use something like open_enum. Thankfully cbindgen is too dumb to know that #[open_enum] is a proc macro and produces a non-enum type.
* Before io_safety in Rust 1.63, dealing with file descriptors from C without accidentally closing them was horrific (though this was a wider problem in Rust). BorrowedFd is quite nice -- though Rustix will panic if you use negative fds and so you need to add validation and your own type in practice. However, #[repr(transparent)] is very nice for this.
* Lots of reading about unsafe Rust is necessary when doing most non-trivial things with C FFI.
* You need to make use of a lot of compiler internals, build scripts, and other magic to get the output you want.
* Tools like cargo-c and cbindgen are nice and probably work great for 80% of projects, but the 20% really suffer from no useful tooling. I haven't tried to use rustc directly to work around some of the remaining issues, but I suspect it'd be even more painful.
I would say that the C interop with Rust is pretty good but it has lots of room for improvement and it feels like very few resources have been spent on it after they got the core stuff working.Source: I've been writing a Rust library intended to be used primarily via C FFI and run into a lot of issues...
Philopp has been a particular force for change in this area.
As someone who's written a number of userspace applications in many languages as well as embedded firmwares running on bare metal, Rust is a rare gem that excels at both.
I'm particularly fond of how easy it was to make all the controls live in the editor, and editable with changes appearing immediately. imgui would probably provide a similar experience, but I find C++ much more of a pain to work with than Rust.
Beyond that, Dart / Futter are truly an absolute pleasure to use for that use case.
"There ain't no such thing as a free lunch" as the saying goes.
That too requires a substantial investment of time and resources.
I think in a more pragmatic sense too that you can form a very good understanding on if you’re going to have weird special requirements just from looking at what others have done with the same tools in similar situations before you.
> That too requires a substantial investment of time and resources.
The discussion has gotten to be pretty abstract at this point. To get back to concrete examples, the egui RAD builder I've been hacking on worked on day 1, first commit. It's been a joy to put together, and no more difficult than building GUI apps with any other toolkit I've worked with. Which causes me to question your statements about additional complexity. You can dig deep and do dark magic with Rust if you want, but you can also treat it like any high level language and get things done quickly. That's part of what makes it a rare gem to me.
Some folks don't like dealing with strict types, or with the borrow checker, but I find that the errors they illuminate for me would have been similarly serious in other languages which lacked the tooling to highlight them. Which adds to my appreciation of Rust.
(Disclaimer: I'm one of the Slint developers.)
I actually wrote a blog post about this exact topic, since it's a common question: https://slint.dev/blog/domain-specific-language-vs-imperativ...
That said, great work! There's plenty of room in the language for more than one solution!
Like the person you’re replying to, I am generally averse to DSLs where the domain is a single project because I associate them with previous bad experiences where I spent time learning only to find it totally misses the mark. There’s also the issue of software where I’m the sole maintainer and look at it rarely. If it’s the only place I use Slint, then I’m going to be worried that I need to relearn the DSL in three months when I want to tweak the UI. Although you can probably say the same about any non-trivial framework’s API whether or not it uses a DSL.
All that said, I’ll be a bit more open to DSLs after reading your post, and if I ever need to write a GUI in Rust I’ll give Slint a shot (although that seems unlikely since I don’t typically write Rust or GUIs).
In your article, you mention that an imperative code in Rust looks more complicated, but this can be fixed by adding an "object tree" syntax to Rust, that allows creating trees of objects and link them like this:
VBox margin=10:
Label text=label_text
Button label="OK" onclick=on_ok_clicked
This syntax could be used not only for UI, but for describing configuration, database tables and many other things. I think it would be better solution than a proprietary language.Also I think it would be better if GUI could be drawn in the editor, it would allow to use lower paid developers without expensive computer science education for making UI.
https://github.com/slint-ui/slint?tab=License-1-ov-file#read...
Immediate mode has it's detractors, but in practice I've found it remarkably flexible, the resulting code relatively clean, and egui gets out of the way when I want to do something like blit fast graphics to a memory mapped area of the screen. Responses have been positive.
Immediate mode was certainly a different paradigm to wrap my head around, but so far I haven't found anything I couldn't accomplish with egui, including some fairly complex applications like https://timschmidt.github.io/alumina-interface/
GUIs are incredibly hard and most languages never get high quality GUI libraries. Rust is still pretty young and a ton of people are working on the problem so that will definitely change.
I strongly agree with this. In particular the Rust GUI libraries I've looked at have text layout / rendering that is nowhere near what should be considered adequate today (imo).
For example egui:
- It doesn't do any bidi reordering.
- It also doesn't do any font fallback so even if you didn't need bidi you can't render many languages without first acquiring an appropriate font somehow.
- Complex shaping is nowhere to be seen either.
- egui's italics look really terrible and I'm not sure why since I can't believe even synthesized ones have to look that bad.
CSS has been doing this for years and it's been doing it very well. So I am kind of disappointed that we don't have equally powerful tools in the general Rust ecosystem. Even just considering text layout / rendering libraries, only `cosmic-text` has an API that is somewhat in the right direction[1], but even it fails simply because I don't see a way to insert a button (block element) in-between the text[2].
Note that I'm not just hating on egui here, egui is amazing. Afaict it is the most complete GUI library for Rust and it's great to be able to make GUIs this easily. However I can't just not point out that it is, in fact, not perfect and doesn't truly "excel" at GUIs.
Also I have no idea how inline layout looks in other established GUI libraries like GTK and Qt so maybe I'm complaining about something that is not available most places outside a browser. If anyone knows, it would be interesting to learn how well they compare here.
[1] CSS inline layout is so complex that even this is a decent achievement, since it is not reasonable to expect most CSS features out of new Rust libraries with a significant time disadvantage.
[2] This is non-trivial because bidi reordering should happen on the whole paragraph not only on both sides of the button, so the inline layout API must handle non-text blocks in text.
However, it seems like most of the other UI toolkits discussed here, even in other languages, suffer similar issues. Which points to the difficulty of the problems. Consequently, I don't have any problem praising egui and Rust alongside. They're great! And even great can always get better! :)
BTW, this happens to almost all languages. Which ACTUAL good GUIs toolkits exist? And which ACTUAL languages HAVE good integration or implementation of them?
A good GUI kit AND integration is a bigger task than do a Os or a RDBMS. (And neither are many good languages for RDBMS)
I think Swift (and even ObjC) is perfect for AppKit & UIKit. I think those frameworks are pretty good and I like using them. Languages have great integration, Swift literally made around them. Those toolkits have great integrations with the macOS.
I find C# a pretty nice language for GUI, I assume it has good (maybe not great) integration with at least one of MS GUI toolkits.
I find Rust good for GUI, but right now story is meh. Wrapper style frameworks always suffer from Rust not being whatever it wraps. Pure Rust framework miss a lot of features compared to wrapper frameworks.
All of the above also have great ORM libraries and RDBMS standard driver APIs, as doing data entry applications is a common enterprise GUI workflow.
A truly good one? FoxPro. Is very hard to know if you don't have exposure to what should be.
There is a full-fledged DE written in Rust that uses Iced: https://en.wikipedia.org/wiki/COSMIC_(desktop_environment)
This can be true but it can still be the case that a managed language is even better at one of them.
Except for thread safety.
In memory resources shared among threads.
Turns out threads also may share resources like out-of-process files, memory mapped regions, shared memory, databases, distributed transactions,.... where the Send and Sync traits is of no help.
Also you happen to forget Haskell has a Software Transactional Memory, and Swift also has similar protocols since version 6, and effects are a thing in OCaml, Scala, Koka, while languages like Dafny, Koka and Idris also provide similar capabilities via proofs.
That might be true if you're developing a pure application [1], but not if you're writing a library. Have fun integrating a C# library in a Java program, a Java library in a C# program, or either of those in a Python, Node, C, C++, or Rust program. There's something to be said for not requiring a runtime.
[1] Unless you care about easy parallelization with statically guaranteed thread-safety. But hey, who needs this in the age of multicore CPUs?
Message-passing IPC is much, much slower and less efficient than shared-memory communication, and inter-process IPC (both message-passing and shared-memory) is much less convenient than intra-process multi-threading. Rust is the only mainstream language, managed or otherwise, which enables safe and efficient multi-threading.
> Turns out threads also may share resources like out-of-process files, memory mapped regions, shared memory, databases, distributed transactions
For multi-threaded parallelization,
- out-of-process files
- databases
- distributed transactions
aren't really relevant, and Rust directly helps with the other two aspects: - memory mapped regions
- shared memory
In practice, your "very specific" aspect is the most important one, and the hardest to get right without Rust's Send and Sync traits and their automatic enforcement.> aren't really relevant, and Rust directly helps with the other two aspects:
Not at all, because Rust code has nothing to say about what other processes do to those resources, the only thing you can do is wrap accesses in a unsafe code block and hope for the best, that nothing was corrupted.
Rust plucks the fruit it can reach and it mostly stays in its lane and it's trying to expand it here and there (like Rust in Linux and embedded). I too want one ultimate language and one ultimate kernel but I don't think you and I will live to see it. Maybe our grandchildren will not as well.