>> The problem with this is that it requires that the *owner* of a type >> have a *mutable slot*, and you cannot prevent owners from declaring >> their slots as mutable. In the example you gave, you could write "let >> mut var2 = Box { x: 2 }" and it would compile, there's nothing >> preventing usage of the "mut" at the owner. > > Are you saying (if I may lapse into C++ vocab for a moment) that I can't > hide the copy constructor? Anyone can copy my non-mut struct into a > mut struct at any time and I don't have any say in the matter?
I'm not very familiar with what exactly a C++ copy constructor is, but rust-wise it mostly has to do with ownerships and moves. Let's say you have one type, Box. This type has &mut and & methods (dictating when they're call-able). The problem is that &mut is dictated by the *owner* of the box. So if your clone() method hands out another Box, then if whomever owns the box decides to declare it as mutable "let mut box = orig_blox.clone()", then they'll be able to call the '&mut' methods. You need to provide some method of forbidding calling &mut methods, which would probably involve leveraging the type system in one way or another. One way is to have two types. The other I know of is to have the shadow type parameters below. You basically need to forbid "&mut self" from ever being possible. Something like Arc can accomplish this because the Arc *owns* the data. The arc then decides to never hand out &mut pointers, only & pointers. This is along the same lines as a second type for you though, which I think you're right in trying to avoid. Using a shadow type parameter is kinda like having the ancient rust idea of "type state", although I don't know how that worked or how equivalent it is to shadow type parameters. >> With something like this you can write code that works over generic >> boxes (immutable or mutable), but you have a clear separation of what >> a mutable box can do and what a frozen box can do. > > Hmm, this looks promising. Not as nice as mut/non but not as bad as > two unrelated types. What does the declaration/use of these types > look like syntactically? Does the user write out Mutable and Frozen? Using this implementation, it's not super-elegant, but it's perhaps better than having two types: let mut x = Box::new(); x.set_x(100); let x = x.freeze(); let y = x.clone(); do spawn { use(&y) } use(&x); The difficult comes up whenever you have to name the type fn foo(t: Box<Frozen>) {} // only works on frozen boxes fn bar(t: Box<Mutable>) {} // only works on mutable boxes fn baz<T>(t: Box<T>) {} // works on any flavor of box I would probably say that the shadow type parameter route is the direction that you'd want to go in, but maybe I'm missing something! _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev