-
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
Make function pointer types look like borrowed pointer types for forwards compatability #883
Conversation
# Summary | ||
|
||
It is likely that Rust will want to someday have a notion of an unboxed function type to be used | ||
with custom pointer types[1]. Ideally then today's function pointers would become `&'static`s of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broken link, should be e.g.: [custom pointer types][1]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case I wanted an actual footnote. But maybe there is a way I can make that clearer / look better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right. There's usually a way to do superscripts but I think it's nonstandard, foo^1
on reddit and foo<sup>1</sup>
on GH. (let'ssee... yup.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! How awful is it that allow tags in their markdown....
What is the benefit of this over simply using the |
@scialex the The best hack in the existing language is to create a new type of a function pointer with a phantom lifetime for borrowed pointers, and a newtype with a drop instance for owned pointers. |
Then how do we handle extern-functions? And can we remove that optional argument name? #838 I'll try making a PoC soon. |
I like this RFC, but I think it should be adjusted to require |
+1 to the RFC with @P1start's amendment
Unfortunately, IIRC, a similar idea was already discussed and rejected. |
+1 to this with amendment. @P1start, do you mean @petrochenkov, was that discussion before the implementation of DST? |
Particularly with the amendment, I really like this. It could alleviate the fallout from the recent-ish change that each function has its own type. I.e. where we now need: fn f(x: Ty) { ... }
let f: fn(Ty) = f; // coerce to fn pointer
foo.map(f) we could probably do: fn f(x: Ty) { ... }
foo.map(&f) |
Some thoughts about the proposal.
Edit: |
@bombless If you are wondering whether @P1start Are you saying we should get rid of the secret_unboxed_function -> function pointer conversion and replace it with @petrochenkov @Florob if you don't mind, I think both your examples would look great in the RFC to explain the coercion changes. @petrochenkov To be clear these semantic decisions would be left for the future, but I'm happy to speculate on how thing might turn out in the long run:
|
@Ericson2314 Yeah. In other words, a slight change in coercion rules that means that @CloudiDust @Florob Why do you need to coerce to a function pointer anyway? Assuming that @petrochenkov The anonymous function item types should already be zero-sized, but unfortunately aren’t yet (cc rust-lang/rust#19925). Regarding the |
@P1start Indeed you may disregard that comment. It's a mixture of outdated information and lack of coherent thinking at the time. That said I am still generally in favour of this proposal. It adds a nice explicitness to things. |
9afe31f
to
c712323
Compare
Ok, added the coercion rules. The response seems pretty positive here, any team member want to comment? |
This can be seen as an amendment to RFC 401, the Function type polymorphism section.
No need to change.
No need to change.
All function pointers are implicitly coercible to a
No need to change, but we will not be passing
No need to change. Examples: fn foo() { ... } // `foo` has a fresh and non-denotable type. (`fn() {foo}`)
fn main() {
let x: fn() = foo; // error (currently valid)
let x: &fn() = &foo; // ok, `&foo` is coerced to `&fn()`. (currently invalid)
let y: &Fn() = x; // ok, `x` is coerced to `&Fn` (a closure object),
// legal because `x` is a `&fn()` here, and `fn()` implements `Fn()`.
let z: &Fn() = foo; // error.
let z: &Fn() = &foo; // ok, `&foo` is coerced to `&Fn()`,
} I think one of the reasons that we want functions have unique types that implement closure traits directly, is to avoid virtual calls. Is this correct? EDIT: some corrections. |
@petrochenkov, after reading RFC 401, I think one of the reasons that "function values" (that have unique types) exist now, is because virtual calls can be avoided when function values are used as closures, while the same cannot be said about function pointers. If my understanding is correct, then it makes sense to pass function values around, and the lack of fn f() {}
// f has type fn(){f}, zero sized (ideally) and unnameable
// &f has type &fn(){f}, pointer to the zero sized and unnameable type
// fn() is the unsized and generalized function type.
// &fn() is the pointer type to the unsized and generalized function type
fn main() {
let g = f; // OK, copying a "function value".
let g = &f; // OK, g is a `&fn(){f}`
let g: &fn() = f; // ERROR: can't coerce fn(){f} to &fn()
let g: fn() = &f; // ERROR: can't create object of unsized type on stack
let g: &fn() = &f; // OK; pointers to concrete functions coerce to pointers to generalized function
} |
On Wed, Mar 04, 2015 at 03:04:47AM -0800, Huon Wilson wrote:
Thanks huon, I was going to ask for the same. At this point, I can I think my preferred proposal is as follows:
I believe this is more-or-less what @huonw presented as "option 2", |
I was thinking about this in the shower and I realized that what I wrote doesn't actually work. In particular, the use of an unsize coercion doesn't make sense -- it only makes sense if we assume that the only pointers of type
This is basically exactly what we have today except that the type of a fn pointer is I think that going through this exercise leaves me more-or-less where I was before, but perhaps mildly more negative. The use case being addressed here feels marginal -- we're making the implementations of a dynamic linking utility library or jit a smidgen more safe. (Am I missing some other advantage?) I guess it ultimately depends on whether you prefer to see |
@nikomatsakis I think "pointers should look like pointers" outweighs the disadvantage, especially when there can be function pointers that have non-static lifetimes in the future. I notice that you assumed the I'd prefer (I expect |
@nikomatsakis One issue that I see with the "custom type implementing a In other words, its not actually possible right now to define a custom function pointer type that can be used as By having function types actually just describe the actual code, unrelated to having a pointer to it, it would be possible to off-load all that complexity to the primitve, compiler-provided function types: |
@nikomatsakis, I realized that I might have missed a point of your posts. Were you implying that even if we wouldn't do If this is the case, then I'd settle with simply doing |
Sorry everybody, I've been busy with school. I'll try to fix this up this weekend---and go with the proxy approach. @Kimundi Excellent point @nikomatsakis In case you missed it, I mentioned that (using your identifiers)
|
@Ericson2314, I suspect dereferencing to unsized types need special-casing anyway, so if That said, @nikomatsakis, I wonder why |
On Thu, Mar 05, 2015 at 06:24:58PM -0800, Richard Zhang wrote:
I was implying that, but I think I was wrong. I thought about it some |
On Thu, Mar 05, 2015 at 11:35:36PM -0800, Richard Zhang wrote:
To be clear, any instance of type |
Even though I wrote "to be clear", I think I was anything but. |
@nikomatsakis, thanks, so actually you were to mean: Currently, as (So, And most importantly |
On Fri, Mar 06, 2015 at 04:57:41PM -0800, Richard Zhang wrote:
Yes.
Yes. |
So here is a summary of what we may want to do (assuming that we are going the "functions are almost statics" route):
Note:
There seems to be some asymmetry. @nikomatsakis, will |
They should work. Although, it may require the planned changes that ensure that |
Here is a summery of what I am thinking (based off of @nikomatsakis and @CloudiDust's:
|
For |
@CloudiDust I think I see what you mean. While impls on the unsized functions are better for trait objects, impls on the pointers are better for calling polymorphic functions. Frankly though, I see the problem not specific to the closure traits, but more broadly part of a trade off between supporting in polymorphic code non-Copy types (or values that could be coppied but should be mutated in place) and cutting down on extraneous indirection. The controversy of whether iterators should be Copy, and the ByRef adapter iterator I'd wager stems in part from this. An associated type defined to a borrowed pointer for non-copy types and a the type itself non copy ones would help in many places in Rust. The counter-argument is optimization should do most of that work, and it would make a whole lot of a code much less readable. And of course, negative bounds are needed to implement this. Probably the best lower-impact solution is to make some blanket impls. This would also make "reusing" sugar-made closures more ergonomic, to give an example of a different benefit. |
I think you mean:
Right? I'm thinking, generally, for non-
I think "blanket impls" would do nothing? The impls would delegate to the underlying functions. Also, would you please update the RFC? If you are still busy I'd like to help. |
Most of what I see here looks good, but there's a certain detail I've been pondering on - the use of "unsized" terminology. All our (current) DSTs keep around enough information to query size and alignment, so we could have a Then "unsizing" can be defined as One might also wonder what semantics would manual implementations of trait Array<T> { const LEN: usize; }
// "Just" needs generics over values.
impl<T, const N: usize> Array<T> for [T; N] { const LEN = N; }
impl<T> Sizeable for Array<T> {
fn size_of(&self) -> usize { self.LEN * size_of::<T>() }
fn min_align_of(&self) -> usize { min_align_of::<T>() }
}
// This is the tricky part, that might require backwards incompatible
// changes to Drop.
impl<T: Drop> Drop for Array<T> {
fn drop(&move self) {
for _ in self.into_iter() {}
}
} I didn't mean to post that in its entirety, but there you go. More creative usecases left as an exercise for the reader. |
@CloudiDust Yeah that sounds good. A simpler way to look at the problem than my ranty post above is that in many cases we consume of an abstract type bounded on a trait that only borrows self. (e.g. consuming a FnMut in Also, size isn't important because it it trivial to always compile pass-by-value to pass-by-reference (we already do that) for specific, while the converse breaks code that depends on the pointer value itself (e.g. pointer equality). @eddyb Yeah I want that for HAMTs, where traditionally nodes has a sparse array of a dynamically sized array with a bitmap to show which elements are present to save space. The size is thus the hamming weight of the bitmap. When @nikomatsakis said "... with an "auxiliary data" type of |
There is no mechanism in place and such a type is not valid today, as all types are required to allow their size and alignment to be queried, dynamically in the case of DSTs. |
@Ericson2314, would you please update the RFC soon? If you are still busy, I'd like to post an alternative RFC tomorrow (local time) to describe what we have come up in the discussions. The beta is approaching fast, so I think we should move forward now. |
@CloudiDust Yeah sorry. I've been busy, and for the upcoming week I won't have internet access, so I think you better do that. Thanks for taking the initiative! |
@Ericson2314, no problem and thanks for this RFC. The new RFC is #996. |
Should we close this RFC in favor of #996? |
Rendered