-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
object-safety and static methods #428
Comments
I don't think having a default implementation in a constructor would be too common. At least, I have 2 use cases in hyper. Here's one: I had to break up // ideally in the future
trait NetworkStream {
// 'constructor'
fn connect(host, port, scheme) -> Self;
// instance methods
fn peer_name(&self) -> SocketAddr;
fn set_timeout(&self);
} |
@seanmonstar why do you have |
Not sure if it's of as much interest to you guys, but I also have a use-case currently within my procedural music engine. /// Generate a fill for the rhythm and append it to the end.
fn gen_fill(&mut self,
attr: &SongAttributes,
part_dur: &Duration,
phrase: &Phrase,
generated: &Vec<Vec<&Rhythm>>,
r: RhythmPack) {
let mut temp: Self = Rhythm::empty(TimePack::from_attr(attr));
let fill_duration = self.gen_fill_duration(attr);
temp.gen_section(attr, part_dur, fill_duration, phrase, generated, r);
let perc = (self.get_ticks() - temp.get_ticks()) as f32 / self.get_ticks() as f32;
self.truncate(perc);
self.append(&temp);
} In saying this, I think I've managed to work out a way of moving the Rhythm trait into an enum instead, however it'll be a lot of work. |
@mitchmindtree could you link to the traits and function definitions please? And explain how this fits with the static method issue? I don't understand what is going on, sorry. |
@nick29581 my apologies, maybe I have the wrong idea of what's going on! I thought we were discussing use cases of static trait methods (that are constructor-like) in regards to your first option for dealing with object safety by disallowing them? Sorry if I've totally missed the mark here :) edit: To clarify, I wouldn't be opposed to the decision, as I feel it would simply encourage me to use algebraic data types more often instead. |
@nick29581 because each implementation of a impl Request {
fn new(method: Method, url: Url) -> Request {
Request::with_stream::<HttpStream>(method, url)
}
fn with_stream<N: NetworkStream>(method: Method, url: Url) -> Request {
let stream: N = NetworkStream::connect(...);
Request { body: box stream as Box<NetworkStream>, ... }
}
} This gave me a few things:
Essentially |
I think that if we stick with object safety (which at the moment I still prefer, though it's a fine line), then we should be consistent and hence consider "static fns" as making a trait not "object safe". |
Closes rust-lang#19949 and rust-lang/rfcs#428 [breaking change] If you have traits used with objects with static methods, you'll need to move the static methods to a different trait.
I see no other way than to forbid static methods and it turned out not to have much fallout, so we'll give it a go. Closing - tracking issue is rust-lang/rust#19949. |
Closes rust-lang#19949 and rust-lang/rfcs#428 [breaking change] If you have traits used with objects with static methods, you'll need to move the static methods to a different trait. r? @cmr
RFC #255 glossed over the issue of static methods. With the current implementation (plus rust-lang/rust#18527) we ignore static methods when deciding on object-safety (pre rust-lang/rust#18527, we ICE'ed). However, this does not allow us to use object-safety to guide the use of trait objects with traits (the 'auto-impl's for trait objects). E.g.,
Here, the call to
bar
should be disallowed because the callX::foo()
cannot be resolved becausefoo
is static.I see three options:
We could also relax the check on static methods where the method is provided rather than required, since there is then an implementation for a method when making a static method call. However, this would lose the usual, expected overriding behaviour (the provided method would always be called, even if the dynamic concrete type overrides it).
I think my favoured solution is option 1 with the provided method relaxation. I believe (though might be wrong here) that there is only benefit to having static constructor methods in a trait, rather than a concrete type, if there is a provided default method. So, the only cases which become inconvenient are where there is a provided constructor and this is overridden in a concrete type which is used to make an object.
See also discussion in rust-lang/rust#18527
cc @aturon @nikomatsakis
The text was updated successfully, but these errors were encountered: