4 ms·
I've recently wondered if it's possible to extract a subset of Rust without references and borrow checking by using macros (and a custom stdlib). In principle,
by int_19h 1y ago
I've recently wondered if it's possible to extract a subset of Rust without references and borrow checking by using macros (and a custom stdlib).
In principle, the language already has raw pointers with the same expressive power as in C, and unlike references they don't have aliasing restrictions. That is, so long as you only use pointers to access data, this should be fine (in the sense of, it's as safe as doing the same thing in C or Zig).
Note that this last point is not the same as "so long as you don't use references" though! The problem is that aliasing rules apply to variables themselves - e.g. in safe rust taking a mutable reference to, say, local variable and then writing directly to that variable is forbidden, so doing the same with raw pointers is UB. So if you want to be on the safe side, you must never work with variables directly - you must always take a pointer first and then do all reads and writes through it, which guarantees that it can be aliased.
However, this seems something that could be done in an easy mechanical transform. Basically a macro that would treat all & as &raw, and any `let mut x = ...` as something like `let mut x_storage = ...; let x = &raw mut x_storage` and then patch up all references to `x` in scope to `*x`.
The other problem is that stdlib assumes references, but in principle it should be possible to mechanically translate the whole thing as well...
And if you make it into a macro instead of patching the compiler directly, you can still use all the tooling, Cargo, LSP(?) etc.
- dejawu 1y agoI've similarly thought about building a language that compiles to Rust, but handles everything around references and borrowing and abstracts that away from the user. Then you get a language where you don't have to think about memory at all, but the resulting code "should" still be fairly fast because Rust is fast (kind of ending up in the same place as Go). I haven't written a ton of Rust so maybe my assumptions of what's possible are wrong, but it is an idea I've come back to a few times.
- vlovich123 1y agoWhy compile to Rust for this? Many people that build transpilation languages target C directly.
- nine_k 1y agoA C compiler won't complain if your generated code does certain horrible things.
- lblume 1y agoThink of Rust as a kind of kernel guaranteeing correctness of your program, the rules of which your transpiler should not have to reimplement. This may be compared to how proof assistants are able to implement all sorts of complicated simplification and resolution techniques while not endangering correctness of the generated proofs at all due to them having a small kernel that implements all of verification, and as long as that kernel is satisfied with your chain of reasoning, the processes behind its generation can be entirely disregarded.
- nine_k 1y agoWhy, macros that put Arc<Box<T>> everywhere might just be it.
- lblume 1y agoArc<Box<T>> is redundant, for the contents of the Arc are already stored on the heap. You may be thinking of Arc<Mutex<T>> for multithreaded access or Rc<RefCell<T>> for singlethreaded access. Both enable the same "feature" of moving the compile-time borrow checking to runtime (Mutex/RefCell) and using reference-counting instead of direct ownership (Arc/Rc).
- norskeld 1y agoVery tangential, but I couldn't help but remember Crust [1]. This tsoding madlad even wrote a B compiler [2] using these... rules. Or lack thereof? [1]: https://github.com/tsoding/Crust https://github.com/tsoding/Crust [2]: https://github.com/tsoding/b https://github.com/tsoding/b
- int_19h 1y agoCrust is exactly what I had in mind, but enforced on language level basically.
- ameliaquining 1y agoIf you don't want memory safety, it seems like it'd be easier to use C++ with a static analyzer to disallow the parts you don't like. I suppose the lack of a good package manager would still be a problem.
- int_19h 1y agoThe whole point of TFA (with which I fully agree) is that Rust is just generally a much nicer language than C++, once borrow checker is out of the picture. Discriminated unions (enums) with pattern matching alone are worth their weight in gold.
- zozbot234 1y agoYou can freely alias &Cell<T>, and this would give you memory safety compared to raw pointers. AIUI, &Cell<T> is effectively the moral equivalent (but safe) to T* in C/C++.
- int_19h 1y agoIt works if you only ever need to reference the outer value, but it doesn't allow you to e.g. get a working mutable reference to a field inside a struct - even if you declare the field as another Cell<T>, when you read the value from the outer cell, you get a copy, not a reference to original. And the same thing goes for arrays, which is especially inconvenient. So no, not quite equivalent.