Description
�If traits no longer implicitly passed-by-reference, then rustc should reject passing traits by value.
My understanding from #3635 is that traits were once implicitly boxed with @
, but now you must explicitly include an pointer-type annotation when you use a trait as an object type.
I illustrate some of the cases that arise in the code sample below; the comments indicate how I think each case should be handled.
The heart of this ticket is that I am suggesting that rustc
be changed so that fromV
below would be rejected, as it does not make sense to pass ByVal
by-value, since e.g. it is a trait and therefore we do not know what the underlying object-size is. (Alternatively, rustc could treat it as an implicitly polymorphic function, analogous to fromT
in the example. But I think that would be a mistake -- if the user wants polymorphism, they should the syntax for it.)
trait ByRef { fn ref_to_int(&self) -> int; }
trait ByVal { fn val_to_int(self) -> int; }
// Ideally this would carry a default implementation that DELegates,
// but default methods are experimental and signal error from rustc.
trait ByDel : ByRef { fn del_to_int(self) -> int; }
impl ByRef for int { fn ref_to_int(&self) -> int { 2 } }
impl ByVal for int { fn val_to_int( self) -> int { 3 } }
impl ByDel for int { fn del_to_int(self) -> int { self.ref_to_int() } }
// One can do this (passing trait-by-reference == object type). Good.
fn fromH(_a:@ByRef) -> int {
if false { _a.ref_to_int() } else { 5 };
5
}
// Probably should *not* be able even to declare this function
// (passing trait by value is senseless). It does compile currently;
// presumably this is compiling into implicit reference.):
fn fromV(_a:ByVal) -> int {
// if false { _a.val_to_int() } else { 6 }; // (leave in comment, senseless)
6
}
// But one *should* be able to do this (passing concrete T by value is sane):
fn fromT<T:ByVal>(_a: T) -> int {
// Unfortunately, if you uncomment this, you hit ICE #4406.
// if false { _a.val_to_int() } else { 7 };
7
}
// This is similar to fromT above; it is just meant to add a check of
// pass-self-by-value traits that extend object-compatible traits.
// Unfortunately, like fromT above, it hits same ICE, so cannot test.
fn fromD<T:ByDel>(_a: T) -> int {
// Unfortunately, if you uncomment this, you hit ICE #4406.
// if false { _a.del_to_int() } else { 8 };
8
}
fn main() {
io::println(fmt!("%?", fromH(@10 as @ByRef)));
io::println(fmt!("%?", fromV(10 as ByVal)));
io::println(fmt!("%?", fromT(10)));
io::println(fmt!("%?", fromD(10)));
}
The ByDel
example is my attempt to implement a suggestion that Niko gave me, where he was suggesting dividing a trait carrying both object-compatible and object-incompatible methods (see #5086) into two traits, where the object-incompatible trait would inherit from the object-compatible one. I see now that #5086 is closed; I do not yet know what that implies for the state of Niko's suggestion.