You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current rules for when traits can be used as object types are a bit complex and hard to explain and understand. I propose the following:
A trait is said to be "object-compatible" if it meets the following requirements:
No method uses the Self type more than once, including the receiver and return type positions.
No use of by-value Self
For every object type @T, &T, or ~T, the trait T must be an object-compatible trait
No "static" functions (see extension below)
I am not sure what's the best place to report errors. We can enforce this in various possible ways:
Report an error for every object type with an incompatible trait T.
Report an error whenever an object is created with an incompatible trait T.
Report an error when a method is called on an incompatible trait T.
Enforcing the rule at point (1) may result in a lot of errors but is probably the clearest thing. No matter what, I think we should definitely enforce the rule at point (2). It guarantees that no instances of illegal traits actually exist at runtime. We'll have to be careful around point (3) anyhow because users may try to call illegal methods; I think right now we ICE (see #5085).
Justifications
Why these rules? We need to prevent objects from being used in scenarios like this:
trait Eq {
fn eq(&self, b: &Self) -> bool;
}
since we can't enforce this rule if we don't know what the Self type is.
Note that it's not enough to say "don't call eq()" because of generic code:
fn foo<A: Eq>(a: &A, b: &A) -> bool { a.eq(b) }
Unless we're careful, one could call foo() on an instance of @Eq since @Eq implements Eq.
What we do today
Today we do not permit eq() to be called and we say that if a trait is non-object-like, then @Eq does not implement Eq, thus preventing a generic method like foo() from being invoked. This is maximally flexible and sound but (I think) overly complex and hard to explain.
Possible Extensions
We could in principle allow return types of Self and "auto-box" them. This is an extension.
In some cases, we could also allow static functions, but we would need (a) auto-boxing for return values and (b) auto-unboxing on call. We then have to make sure that Self does not appear in a by-value position or as part of another type, like here:
trait Foo {
fn foo(v: &Self) { ... } // OK, we can "auto-unwrap" in monomorphization
fn foo(v: Self) { ... } // Not so good
fn foo(v: Option<Self>) { ... } // Uh-oh
}
The text was updated successfully, but these errors were encountered:
The current rules for when traits can be used as object types are a bit complex and hard to explain and understand. I propose the following:
Self
type more than once, including the receiver and return type positions.@T
,&T
, or~T
, the traitT
must be an object-compatible traitI am not sure what's the best place to report errors. We can enforce this in various possible ways:
T
.T
.T
.Enforcing the rule at point (1) may result in a lot of errors but is probably the clearest thing. No matter what, I think we should definitely enforce the rule at point (2). It guarantees that no instances of illegal traits actually exist at runtime. We'll have to be careful around point (3) anyhow because users may try to call illegal methods; I think right now we ICE (see #5085).
Justifications
Why these rules? We need to prevent objects from being used in scenarios like this:
since we can't enforce this rule if we don't know what the
Self
type is.Note that it's not enough to say "don't call eq()" because of generic code:
Unless we're careful, one could call
foo()
on an instance of@Eq
since@Eq
implementsEq
.What we do today
Today we do not permit
eq()
to be called and we say that if a trait is non-object-like, then@Eq
does not implementEq
, thus preventing a generic method likefoo()
from being invoked. This is maximally flexible and sound but (I think) overly complex and hard to explain.Possible Extensions
We could in principle allow return types of
Self
and "auto-box" them. This is an extension.In some cases, we could also allow static functions, but we would need (a) auto-boxing for return values and (b) auto-unboxing on call. We then have to make sure that Self does not appear in a by-value position or as part of another type, like here:
The text was updated successfully, but these errors were encountered: