3 ms·
> The complexity of Rust's ownership model is not added to an otherwise simple program, it is merely the compiler being extremely pedantic about your code obeyi
by robalni 5y ago
> The complexity of Rust's ownership model is not added to an otherwise simple program, it is merely the compiler being extremely pedantic about your code obeying rules it had to obey anyway.
Not exactly.
I remember when I learned Rust a few years ago (so maybe things are different today), sometimes the compiler didn't let me do things that should have been perfectly fine things to do.
This forced me to write the code in a more complicated way than what should have been necessary.
I think this often happens beacuse the compiler's rules don't always match reality.
Like if I have a struct S that contains members X and Y, the compiler doesn't let me have two mutable references to that struct even if one of them only changes X and the other one Y.
In reality there is no problem but compiler thinks there is a problem so it forces me to write more complicated code.
I have had this almost exact problem in a program I was writing.
The reason I could not just pass X to one function and Y to the other is that one of those functions I had to call was from a library that could only take an S.
The solution was that I had to write a macro that extracted Y from S and call that macro every time I wanted to pass Y to a function.
- zozbot234 5y ago> the compiler doesn't let me have two mutable references to that struct even if one of them only changes X and the other one Y. The semantics of mutable references and other interface constructs must be independent from actual implementation, to allow for changes in the latter. So Rust is behaving as expected here. If the changes to X and Y are truly independent, you can have a function that returns separate mutable references to both ("splits" the struct). But if your library function takes an S, it might rely on the whole struct and then the changes are no longer truly independent.
- cowl 5y ago> then the changes are no longer truly independent. But the author of the code is telling you that they are independent. The author may be proved wrong if some future change accidentally triggers dependence but we as humans can have knowledge that the compiler can not have. The compiler sees a possibility of conflict and wants to protect you from yourself. That is a usability issue.
- zozbot234 5y agoRust is exploring techniques to allow "the author of the code" to provide finer "separation" semantics without resorting to unsafe - this is what GhostCell, QCell, LCell etc. are all about though their "usability" is still low. There's plenty of ongoing research in this space, so feel free to stay tuned for more!
- garethrowlands 5y agoFun computer science fact: any type system will disallow some otherwise valid programs and also allow some invalid programs. The trick for type system designers is to find a sweet spot.
- aix1 5y agoI'm curious if this is a provable result or an empirical observation? (Come to think of it, I'm not even sure what's meant by program validity in this context.)
- astrange 5y agoPrograms are proofs and so this follows from Godel's incompleteness theorem. But "invalid program" needs defining.
- duped 5y ago> The solution was that I had to write a macro that extracted Y from S and call that macro every time I wanted to pass Y to a function. Why does that require a macro? ``` struct S { x:X, y:Y } fn do_with_y (y:&mut Y) {} fn do_with_s (y:&mut S) {} fn main_program (mut s: S) { do_with_s(&mut s); do_with_y(&s.y); /* ... */ } ``` I prefer seeing code like this rather than wrapping it in abstractions and macros/helpers because it's not particularly verbose and very clear where the borrowing happens ; you'd see the same in C++ or C, to be honest.
- robalni 5y agoI made a macro because it was more complicated than just S.Y. It was more like `Something.get_stuff().unwrap().things`