-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Permit fn(self)
methods to be invoked on object types
#10672
Comments
I am of two minds on this issue. One part of me likes simple rules of thumb like: "eschew fn foo(~self); do foo(self) instead." (as noted on niko's Thoughts on DST part I). So that part of me would like such methods to actually be supported on object types. Another part of me likes to have a simplified compilation model in my mind, with as little magic as possible (or at least the potential for ALMAP ... I am after all still a GC guy...). And that part of me figures we should keep things the way that they are; if you want a method to be invokable on the objects of a trait, then the type for the self pointer needs to be reflected in the method's type, including which kind of pointer it is. Having said that, I haven't thought of a concrete reason to disallow the generalization suggested here, beyond mental complexity when trying to understand the control flow from the invocation point to the entry to the method itself. For which pointer-variants would we generate these shim functions? Will it only work for Or is this something that we can infer on a impl by impl basis, choosing the most general option that is sound? |
On Mon, Dec 02, 2013 at 08:43:47AM -0800, Felix S Klock II wrote:
In general I agree, but, if we don't wind up with a DST-based system,
As magic goes, what I proposed is pretty minimal. Basically a variant
That said, this interacts with the smart pointers. I outlined some |
I have closed #9893 in favor of this bug, but if this bug is rejected then that bug should be re-opened (because the error message today isn't exactly ideal). |
As part of another discussion, I realized that this is a special case of a more general sort of pointer. For want of a better name, I'll call it a "my" pointer: So the "adapter" methods I described for |
Is this the same mythical pointer type that's needed to make once stack closures as DSTs work? (Maybe that's what the I think it makes sense to view this as a natural progression on I think it also makes sense to think about the converse: a pointer to potentially-unitialized memory which you have the obligation to initialize, corresponding to C#'s concept of an |
Yes, i've spent some time thinking about "obliation to initialize" -- that is much harder. In particular, that would have to be a linear value -- meaning it could not be 'dropped' (except possibly by failure -- but even there we have to be careful). Currently, though, we assume all values can be dropped, and hence permit generic functions like the following:
and I invoke with a The natural implication is that either (1) dropping a type parameter must become an explicit operation:
(Incidentally this only works if |
I guess that the natural pointer type for |
You're right, I was sloppy in my thinking about the out-pointer. I was thinking it would error if you reached the end of the function without initializing through it, but that obviously didn't take generic functions into account. I wonder how many generic functions would actually wind up needing a |
Not a backcompat risk; so accepting at P-low. (If one finds more evidence to up its priority, then renominate.) |
I couldn't fall asleep last night because I was thinking about pointer types; how's that for fun? As you alluded to, the problem of (I also don't see any reason why making As before, after assigning through an
I think this is fine, because if someone lends you an
These two effectively reify the cycling of data between initialized and uninitialized states as a first class abstraction for the programmer. Using the above we can implement
I suspect this means that arbitrary permutations could also be expressed using only safe code.
where it allocates an element and returns the obligation to initialize it. Smart pointers:
where it initializes the pointer, allocates the box, and returns the obligation to initialize its contents. (I also suspect it could be used to tie the knot, though I haven't figured out a way to do it without Anyway, I used to think |
@nikomatsakis I'm starting to have second thoughts, not about
I suppose, if it stays part of the language, we could hardcode this for |
I envisioned a distinct method being called for shallow drop, in this case. Clearly the pointer type would have to opt-in. It's actually already an issue of sorts, in that we would like to be able to move out of smart pointer types. |
cc @pcwalton |
Nominating, P-backcompat-lang—needed for unboxed closures to replace |
Already marked P-backcompat-lang; adding to the 1.0 milestone. |
referenced by boxes. This is done by creating a shim function that handles the cleanup of the box properly. Closes rust-lang#10672.
…chton I can't believe this worked! I believe that the way the ABI and immediates work mean that this Just Works. Closes #10672. r? @alexcrichton
…endoo Add `excessive_nesting` lint changelog: new lint [`excessive_nesting`]
Currently, methods declared as
self
cannot be invoked on object types. The reason for this is that, without knowing the type of the receiver, we can't know whetherself
is to be passed with indirection or as an immediate value.For example:
So now if I have a
~int
casted to~Consume
, and I were to invoketake()
, I would want to load from the~int
, pass the loaded value, and then free the~int
after the call returns (or maybe in a different order; I don't want to think too hard about weird failure cases since that's not really the point of this issue). If I have a~MyBigStruct
, I would want to pass the pointer itself totake
(sincetake
expects aMyBigStruct*
, essentially). After the call returns,take()
will have freed theMyBigStruct
but not the~
pointer itself, so I can shallow free the pointer. But of course all I know at codegen time is that I have a~Consume
and thus I can't distinguish these two cases.This is however rather inconvenient, as the above example shows. It is particularly inconvenient since using a
~self
method isn't really a good alternative, particularly if you try to implement the trait for the object type:Now I need a
~~Message
! Silly. This would work fine ifsend()
were aself
method, though.The thing is, if we were a bit more clever, we could permit by-value calls on object types. We can just say that for virtual calls
self
is always passed indirectly, and then generate a shim function to use in the vtable that does a load for immediate receivers.Nominating although I think this is something that can possibly wait till post 1.0, since it's not a backwards compat question. I'd still call it high priority (presuming others agree with my reasoning).
The text was updated successfully, but these errors were encountered: