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.
Activity
pnkfelix commentedon Feb 22, 2013
see also #4406
pnkfelix commentedon Feb 22, 2013
I guess we also need to reject polymorphic-instantiations like
fromT::<ByDel>
, since we cannot passByDel
by-value any more than we can passByVal
by-value. That scenario was not explicitly explored above.nikomatsakis commentedon Feb 22, 2013
I'm not quite sure what you were going for here... it's not quite what I meant to suggest, anyhow. I meant to suggest that if you have:
Then under the rules I proposed (and later retracted) in #5086, it would be illegal to have an object type
@Both
, because we can't compile handle the by-valuebar()
method since we don't know the type of the receiver. Under today's rules, it would be legal to have the trait type@Both
but@Both
is not considered to implement the traitBoth
.Now, in either scenario, suppose I wanted to have a function like
Here the point is that it only calls
foo()
and notbar()
, so in principle it should be fine to use an object type forB
.In that case, I can refactor my trait
Both
as follows:and I can rewrite
do_something()
as:This will work fine.
Of course, as I proposed in #5087, I'd like to say that no object-type
@T
implements the traitT
by default. But this kind of refactoring may still be relevant. After all, it is possible to write:but it is not legal to write
pnkfelix commentedon Feb 22, 2013
Just to clarify my motivation to Niko:
ByRef
in my code is meant to be analogous to yourFoo
, andByDel
is analogous to yourBoth
; that is, the traitByDel
is an extension of theByRef
trait.(The rest of the code surrounding this was either
ByDel
would use the implementation provided byByRef
, by invoking it. But I could not test whether this works, due to the aformentioned ICE.)catamorphism commentedon Apr 25, 2013
Seems non-critical for 0.7. Nominating for milestone 2 (well-defined).
graydon commentedon May 2, 2013
trait-as-type with no sigil is an error; this should be fixed. declining nomination as we think it's fixed.
Auto merge of rust-lang#5088 - rust-lang:gha, r=Manishearth,flip1995
Auto merge of rust-lang#5190 - flip1995:nuke_traveyor, r=phansch,Mani…