Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for `arbitrary_self_types` #44874
Comments
arielb1
added
the
E-needs-mentor
label
Sep 26, 2017
arielb1
changed the title
Allow methods with arbitrary self-types
Allow trait methods with arbitrary self-types
Sep 26, 2017
arielb1
added
the
WG-compiler-middle
label
Sep 26, 2017
aidanhs
added
the
C-feature-request
label
Sep 28, 2017
This comment has been minimized.
This comment has been minimized.
porky11
commented
Sep 28, 2017
|
Why would you need this?
I'd rather define the trait different. Maybe like this:
In this case, Rc would be a trait type. If every generic type implemented a specific trait (this could be implemented automatically for generic types) this seems more understandable to me. |
This comment has been minimized.
This comment has been minimized.
|
This could only be allowed for For inherent methods, I can't |
This comment has been minimized.
This comment has been minimized.
|
This is still pending lang team decisions (I hope there will be at least 1 RFC) but I think it will only be allowed for trait method impls. |
This comment has been minimized.
This comment has been minimized.
|
You can't implement anything for |
This comment has been minimized.
This comment has been minimized.
|
So changes needed:
|
arielb1
added
E-mentor
and removed
E-needs-mentor
labels
Oct 2, 2017
This comment has been minimized.
This comment has been minimized.
|
I’ll look into this. |
This comment has been minimized.
This comment has been minimized.
|
Note that this is only supported to work with trait methods (and trait impl methods), aka trait Foo {
fn foo(self: Rc<Self>);
}
impl Foo for () {
fn foo(self: Rc<Self>) {}
}and is NOT supposed to work for inherent impl methods: struct Foo;
impl Foo {
fn foo(self: Rc<Self>) {}
} |
This comment has been minimized.
This comment has been minimized.
|
I got caught in some more Stylo work that's gonna take a while, so if someone else wants to work on this in the meantime feel free. |
This comment has been minimized.
This comment has been minimized.
|
Is this supposed to allow any type as long as it involves trait MyStuff {
fn a(self: Option<Self>);
fn b(self: Result<Self, Self>);
fn c(self: (Self, Self, Self));
fn d(self: Box<Box<Self>>);
}
impl MyStuff for i32 {
...
}
Some(1).a(); // ok?
Ok(2).b(); // ok?
(3, 4, 5).c(); // ok?
(box box 6).d(); // ok? |
mikeyhew
referenced this issue
Oct 8, 2017
Merged
Update comments referring to old check_method_self_type #45099
kennytm
added a commit
to kennytm/rust
that referenced
this issue
Oct 10, 2017
kennytm
added a commit
to kennytm/rust
that referenced
this issue
Oct 10, 2017
This comment has been minimized.
This comment has been minimized.
|
I've started working on this issue. You can see my progress on this branch |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 You seem adamant that this should only be allowed for traits and not structs. Aside from method shadowing, are there other concerns? |
This comment has been minimized.
This comment has been minimized.
|
inherent impl methods are loaded based on the type. You shouldn't be able to add a method to |
This comment has been minimized.
This comment has been minimized.
|
That's it, if you write something like trait Foo {
fn bar(self: Rc<Self>);
}Then it can only be used if the trait If you write an inherent impl, then it can be called without having the trait in-scope, which means we have to be more careful to not allow these sorts of things. |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 Can you give an example of what we want to avoid? I'm afraid I don't really see what the issue is. A method you define to take |
This comment has been minimized.
This comment has been minimized.
|
I've been trying to figure out how we can support dynamic dispatch with arbitrary self types. Basically we need a way to take a (1) is pretty straightforward: call The tough question is, how do we get the type @arielb1 @nikomatsakis any thoughts? |
This comment has been minimized.
This comment has been minimized.
Wait, why do you not want it work for inherent impl methods? Because of scoping? I'm confused. =) |
This comment has been minimized.
This comment has been minimized.
I do want to support that, but I expected it to be out of scope for this first cut. That is, I expected that if a trait uses anything other than |
This comment has been minimized.
This comment has been minimized.
I know, but I couldn't help looking into it, it's all very interesting to me :) |
This comment has been minimized.
This comment has been minimized.
We need some sort of "orphan rule" to at least prevent people from doing things like this: struct Foo;
impl Foo {
fn frobnicate<T>(self: Vec<T>, x: Self) { /* ... */ }
}Because then every crate in the world can call Maybe the best way to solve this would be to require I think that if we have the deref-back requirement, there's no problem with allowing inherent methods - we just need to change inherent method search a bit to also look at defids of derefs. So that's probably a better idea than restricting to trait methods only. Note that the struct Foo;
impl Tr for Foo {
fn frobnicate<A: Allocator+?Sized>(self: RcWithAllocator<Self, A>) { /* ... */ }
}Where an |
This comment has been minimized.
This comment has been minimized.
Are saying is that there would be a "conflicting symbols for architechture x86_64..." linker error?
I'm confused, are you still talking about |
This comment has been minimized.
This comment has been minimized.
The deref-back requirement is supposed to be for everything, not only object-safety. It prevents the problem when one person does struct MyType;
impl MyType {
fn foo<T>(self: Vec<(MyType, T)>) { /* ... */ }
} While another person does struct OurType;
impl OurType {
fn foo<T>(self: Vec<(T, OurType)>) {/* ... */ }
} And now you have a conflict on |
This comment has been minimized.
This comment has been minimized.
raphaelcohn
commented
Jan 23, 2019
•
|
Just played around with this a bit and found that whilst a receiver of
To my mind, where I know the receiver is a non-null pointer, but not necessarily initialized properly, this is a useful way of writing code as documentation; particularly for a trait, where the implementor can be certain he hasn't been given null. It might also be worth considering |
This comment has been minimized.
This comment has been minimized.
Because
|
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
Sure, but that was a specific addition (See also #46664):
Raw pointers are definitely special-cased in the compiler, while |
This comment has been minimized.
This comment has been minimized.
Indeed. |
This comment has been minimized.
This comment has been minimized.
raphaelcohn
commented
Jan 24, 2019
•
|
@mikeyhew Another RFC? That's disappointing to learn. I haven't got the desire to go down that route. At least the thought's there. @shepmaster I the code I am now commonly writing when dealing with low-level pointer stuff, |
This comment has been minimized.
This comment has been minimized.
|
This is the trait that I was thinking of. Both trait DerefRaw {
type Target;
fn deref_raw(&self) -> *const Self::Target;
} |
This comment has been minimized.
This comment has been minimized.
|
I’m really not sure about doing this for |
This comment has been minimized.
This comment has been minimized.
raphaelcohn
commented
Jan 25, 2019
|
|
This comment has been minimized.
This comment has been minimized.
|
Sorry, I should have clarified. Using |
This comment has been minimized.
This comment has been minimized.
|
the big question around raw pointers is the requirements as to the validity
of vtables for invalid pointers. I’m not sure what we should do, but if we
made Option<NonNull<T>> impl DerefRaw we’d be assuming the vtable could be
invalid; calling a dynamic method on None would just always be UB, I
believe.
…On Friday, January 25, 2019, Simon Sapin ***@***.***> wrote:
Sorry, I should have clarified. Using Option<NonNull<T>> in general
sounds good. What I’m not sure about is implementing DerefRaw as proposed
above for Option<NonNull<T>>. Sure, it has an obvious implementation, but
converting to a nullable *const T seems to defeat the point of using
Option<NonNull<T>> in the first place.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#44874 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AIpL0Jj1TskgEDDbOJ_vjVIk9U258spjks5vGwougaJpZM4Pk3fK>
.
|
This comment was marked as outdated.
This comment was marked as outdated.
|
Unless we have decided a representation of a dynamic-sized |
This comment has been minimized.
This comment has been minimized.
|
@withoutboats Ohh, good point, I forgot about that. That means there's potentially a real difference between @kennytm I think you're confusing |
This comment has been minimized.
This comment has been minimized.
|
@mikeyhew Oh right, sorry. |
This comment has been minimized.
This comment has been minimized.
|
Are you talking about |
This comment has been minimized.
This comment has been minimized.
|
BTW, from an API design standpoint, one thing that would work would be to have a special trait ArbitrarySelfTypePtr {
type Next: ?Sized;
}
impl<T: Deref + ?Sized> ArbitrarySelfTypePtr for T {
type Next = T::Target;
}
impl<T: ?Sized> ArbitrarySelfTypePtr for *mut T {
type Next = T;
}
impl<T: ?Sized> ArbitrarySelfTypePtr for *const T {
type Next = T;
}
impl<T: ?Sized> ArbitrarySelfTypePtr for NonNull<T> {
type Next = T;
}
// Maybe, if we really want that?
impl<T: ?Sized> ArbitrarySelfTypePtr for Option<T> {
type Next = T;
} |
This comment has been minimized.
This comment has been minimized.
|
The "ArbitrarySelfTypePtr" exists solely so we can have a "sane" deref chain for inherent methods etc. |
This comment has been minimized.
This comment has been minimized.
raphaelcohn
commented
Jan 27, 2019
|
@arielb1 I like your suggested BTW, for the avoidance of doubt, I'm not absolutely wedded to the |
Centril
added
T-lang
and removed
T-compiler
labels
Feb 18, 2019
Centril
referenced this issue
Feb 18, 2019
Closed
Changing the type of self in methods doesn't work #27941
OddCoincidence
referenced this issue
Feb 28, 2019
Merged
Derive types, arity, conversions and more from rust fns #572
kevinmehall
referenced this issue
Mar 29, 2019
Open
Run through rustfmt, update to Rust 2018, rework to use Arc instead of lifetimes. #30
This comment has been minimized.
This comment has been minimized.
|
Did anyone consider |
This comment has been minimized.
This comment has been minimized.
|
That seems unsafe since the self pointer could then be dropped while yhe method is executing, leaving |
This comment has been minimized.
This comment has been minimized.
Hmm? Am I missing something? (probably) |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
Thank you for the clarification! Any chance Maybe another reason for an |
This comment has been minimized.
This comment has been minimized.
|
Yeah, I think using a separate trait from
Of the above list, all but Also, here is a potential name for the trait: |
arielb1 commentedSep 26, 2017
•
edited
Tracking issue for
#![feature(arbitrary_self_types)].This needs an RFC before stabilization, and also requires the following issues to be handled:
Object Safety
See #27941 (comment)
Handling of inference variables
Calling a method on
*const _could now pick impls of the formBecause method dispatch wants to be "limited", this won't really work, and as with the existing situation on
&_we should be emitting an "the type of this value must be known in this context" error.This feels like fairly standard inference breakage, but we need to check the impact of this before proceeding.
Safe virtual raw pointer methods
e.g. this is UB, so we might want to force the call
<dyn Foo as Foo>::barto be unsafe somehow - e.g. by not allowingdyn Footo be object safe unlessbarwas anunsafe fnHowever, even today you could UB in safe code with
mem::size_of_val(foo)on the above code, so this might not be actually a problem.More information
There's no reason the
selfsyntax has to be restricted to&T,&mut TandBox<T>, we should allow for more types there, e.g.This doesn't have an RFC, but we want to experiment on this without one.
See #27941.