4 ms·
Ooh, a chance to talk about Rust in the context of fish. I did the initial introduction of pthreads to fish 1.x, when it was thread-oblivious, and it was very
by ridiculous_fish 10y ago
Ooh, a chance to talk about Rust in the context of fish.
I did the initial introduction of pthreads to fish 1.x, when it was thread-oblivious, and it was very difficult because there was a lot of global data (it's a shell, after all). Races and deadlocks were initially very common, and Rust could have helped with at least the first problem. It would have been very valuable.
More generally, the Rust pattern of having a lock own the data it protects is really nice. This can be more-or-less implemented in C++11 via lambdas, which should solve the wrong-lock problem. (I didn't use that technique at the time because I was targeting C++98.)
It's fun to think of a shell in the context of Rust. One place where Rust's guarantees cannot provide much help is signal handling. Signal handlers require global data to do anything, and signals are incompatible with most of Rust's ownership machinery for globals, primarily locks.
Code that runs post-fork is similar: it must not allocate memory, and there's no protection against that in Rust (or in C++).
A second place is the system interface. fish often has to dip below the surface-level APIs. It can't use getenv() or strerror(), and instead has to access `environ` and `sys_errlist` directly. Many of Rust's safe interfaces would not be usable, and we would have to write replacements using unsafe code.
fish also uses shared memory (mmap, shm_open) in a few places. Rust is supposed to protect against data races, but I don't see how it can do so in the context of shared memory.
Last and probably most importantly, shells make use of a lot of the horrible termios stuff, which tends to vary across systems and make heavy use of the C preprocessor. This will be gross anywhere, but especially gross in anything that's not C or C++. I first attempted to write a shell in Go, and this is why I gave up.
Overall IMO Rust could provide a lot of value for a shell, but probably will require a fair amount of unsafe code at the edges and fiddling to support legacy interfaces.
- steveklabnik 10y ago> I don't see how it can do so in the context of shared memory. Basically, it does not let you access shared memory without _some_ kind of synchronization primitive in safe code. That might be an atomic variable, or maybe a mutex, whatever.
- ridiculous_fish 10y agoIf two threads independently mmap the same file, what is the thing that Rust forces them to synchronize on?
- steveklabnik 10y agommap can't be exposed with a safe interface, in my understanding.
- Manishearth 10y agoOf course, you can access `/proc/self/mem` safely so technically it's all possible in safe code. But that's not something Rust can prevent.
- notriddle 10y agoThat's a known bug: https://github.com/rust-lang/rust/issues/32670 https://github.com/rust-lang/rust/issues/32670 This bug was posted on April 1st, being a bit more ha-ha-only-serious than the emoji-based error handling one that the core team put on. AFAIK, it's the only WONTFIX safety bug in Rust's issue tracker.
- burntsushi 10y agoThe de facto memmap crate for Rust makes it unsafe to access the contents of a memory map: https://docs.rs/memmap/0.5.0/memmap/struct.Mmap.html#method.as_slice https://docs.rs/memmap/0.5.0/memmap/struct.Mmap.html#method.... This doesn't actually answer your question, but the presence of `unsafe` will at least warn you that you need to put some thought into what you're doing.
- eridius 10y agoFWIW, you can avoid allocation in Rust by limiting yourself to libcore, which doesn't know about allocation. Stick the #![no_implicit_prelude] attribute on your module and now you can't use anything from liballoc or libstd without an explicit `use` directive.
- mmstick 10y agoWe've not had any issues developing the Ion shell in Rust -- performs as well as Dash. Basically, you can't come at Rust with the mindset of object-oriented programming. Make your shell event-driven and you'll do perfectly well. Queue your signals and act on them at a later time when you can. I've been particularly fond of Rust's Iterator trait which has been quite valuable for efficient parsing in Ion.