-
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
Introduce Pointee and DynSized #2984
base: master
Are you sure you want to change the base?
Conversation
Those two new language traits are at the intersection of rust-lang#1861, rust-lang#2580, rust-lang#2594, and this RFC's raison d'être is solely to try to get some progress for those 3 RFCs all at once by specifying their common core part.
Thanks for the pointer, I missed this one and will now look into it. |
I probably missed a lot of small concerns, but here is a first stream of thought with some direct pointers to past comments. So the first concern mentioned in #2255 is that opt-out bounds such as My own framing on that is that going from @mikeyhew then adds in #2255 (comment) that they would rather allow the user to write normal bounds of supertraits of I agree with @mikeyhew that this is something that could be done, but my understanding is that it is mechanically equivalent to allowing In April 2018, @nikomatsakis writes in rust-lang/rust#43467 (comment) that he doesn't think that In my opinion, extern types still didn't land exactly because we still don't have a Finally in September 2019, @Ixrec in #2255 (comment) follows-up that In my opinion, we can confidently say that an additional The second concern is raised by @eddyb in #2255 (comment) and is about whether we should plan for @kennytm in #2255 also mentions that introducing I don't think extending the language to support some kinds of non-dynamically-sized types should be blocked on downstream crates not supporting them from the get-go. To conclude, reading through the comments of #2255 reaffirms my belief that this RFC defines the most viable core that we should go for as a first step for extern types and pointer metadata APIs, given that the gist of the concerns from the language team is the ergonomic cost of |
This isn't the case. People suggest additional question mark types with regularity. Some people want to revisit Move, some people want a ?Trait to add linear types, its even been proposed (though I think only offline) to add a ?Trait governing whether a type exists in 1 memory space or more, to better support wasm reference types. I think all of these would be a poor choice, for many of the same reasons as ?DynSized. People want to use the ?Trait feature to add new exceptions to the requirements that Rust currently assumes every type adheres to. I don't think we should ever do this, because going from one ?Trait to more than one is, in my opinion, remarkably expensive in terms of onboarding new users and headaches for existing users, concerns you mention but dismiss.
This isn't why we haven't made progress on extern types. We haven't made progress because no one is driving the feature. I think within the lang team there is (weak) consensus that making size_of_val/align_of_val panic when passed an extern type would be an adequate solution, and I don't think the feature is blocked on having a compile-time solution. |
Ack, I meant that I don't see people from any Rust team pushing for those, but maybe I'm just not seeing those discussions.
I didn't dismiss anything, I literally started my comment by saying that I probably missed some concerns. Given there was never more than one
Ack. I shouldn't have mentioned |
I'll amend the RFC to include more unresolved questions based on this discussion. I don't care if the PR ends up closed, I just feel like it would be a good thing to have a document that centralise them anyway. |
I doubt this works but.. Is there any value in distinguishing between raw pointers and borrowed references here? In other words, could |
I don't understand why that would be useful, extern types definitely let you get a |
Apologies for the derail. I'm asking if |
Oh I see. My own use case for extern types is to improve bindings for things such as the Carbon APIs on macOS, which are all defined as |
Safe C-style string wrappers would also benefit from |
Cc @retep998 who makes winapi and who also expressed interest for a proper support of unsized types at the type-level. |
From my perspective, both extern types and DST metadata manipulation are not blocked so much as they are just not being driven anywhere. I don't think these need to intersect. I'm fully in favor of stabilizing extern types with |
@withoutboats Could you expand on why you are ok with Pointee but not DynSized to reject size_of_val from being used with extern types? Is it just because of the additional opt-out bound?
Edit: "from being used", not "from being rejected"
|
From my own perspective, there are quite a few community actors that maintain FFI crates that want something like |
@nox Yes, I think the costs of adding a ?Trait are very high, as I said, and I don't think converting a panic in As an alternative design for the pointee type, I would make the |
If there is no such additional |
I'll try to reiterate the objection to DynSized. I realize that users who are deeply invested in writing FFI bindings would like their bindings to be as typesafe as possible, and would like the compiler to check that users do not pass extern types to APIs which cannot rationally accept them, but this has to be balanced against the cost to all other users. This cost is twofold: the burden added to writing and maintaining correct Rust libraries, and the burden added to learning Rust. By adding I also think adding a ?Trait may not be backward compatible because of the assumptions made about which types implement Sized or don't today. DynSized may be excepted from this issue because of its relationship with Sized, but I'm not sure. Similarly, the I just don't think compile time checking that no one tries to get the layout of an extern type is valuable enough to justify these burdens.
The syntax to define the |
Thanks for that.
Are you completely closed to the idea that maybe having more than one opt-out bound would actually help understand how opt-out bounds work?
I don't see this as an argument against To me that's like arguing against
Fair, I personally don't think 1 or 2 of those change the complexity of the system but that's a matter of opinion anyway.
Also fair, but I really feel like
To me, that seems like way more of a burden than |
I think these comments represent a disagreement that I often have with contributors about what it is to learn how to use Rust. Users approaching Rust have a very fuzzy, informal understanding of the type system, based on limited and incomplete information filled in with assumptions or inferences which in may cases, if investigated thoroughly, would reveal themselves as contradictory and false. As they learn Rust, they slowly correct these misunderstandings based on the response of the compiler and the supporting documentation they read as they introduce errors into their code. Often, user perspective on what change would be clear, helpful, confusing, etc is based on a perspective that makes a lot of sense if you already understand the entire system formally, but in my opinion is not at all the case if you do not understand what's going on. Adding more exceptions to the rules, more points of decision making presented to the user early on, more distinct ways that errors can be surfaced - these all are examples of things that are very confusing for learning users. On the other hand, making the one exceptional case more exceptional is usually not a problem, because learning users have been signalled to ignore it as exceptional when trying to understand things and users with a formal understanding can just enumerate the exceptions. |
Thanks for expanding. Apart from |
Auto traits cannot have supertraits so I encoded things that way, but that was my first idea too. |
Ah ok, but could it work if it is not an auto trait? I don't think it would really need to, especially because currently, there are only roughly three or four cases: trait PointeeMeta: 'static + Copy + Eq + Ord + Send + Sync + Unpin + … {}
trait Pointee {
type Meta: PointeeMeta;
}
/// no metadata at all
impl PointeeMeta for () {}
/// metadata for slices
impl PointeeMeta for usize {}
/// metadata for & dyn trait's
/// Basic Variant
impl PointeeMeta for VTable {}
/// or maybe multiple VTables (e.g. &dyn A + B, where neither A nor B are auto traits)
/// X=number of VTables, would need const generics (https://github.com/rust-lang/rust/issues/44580)
/// but could also be compiler- or macro-generated
impl<X: usize> PointeeMeta for VTable<X> {} |
Yea, I think pushing on the space that this and 2580 are in would be interesting and valuable. The big problem then would be bandwidth. |
Good to know! Totally understand for bandwidth, especially with pandemic. But anyway… sorry if I missed this concern in one of the dozen related RFCs and threads, but I just realised something: if we implement what I just proposed, extern types end up not even |
If |
Sorry if I missed someone bringing this up already. But note that For example, to support the common case of null-terminated strings, I think you'd need some kind of As @withoutboats points out, to fully support such types things like |
@petertodd I am not sure how that relates to this RFC, whether or not it is decided to adopt something similar to the |
Ah! I see what you mean: |
The current behavior as I recall is for extern types to return |
Returning 0 would be a-ok I think and I didn't know it was the current default, I guess I should have tried it at some point. Then all the rest that I mentioned to later introduce an opt-out |
I recently read https://matklad.github.io/2020/09/20/why-not-rust.html which was great, and give me a new argument for One quote was this
But do do that safely, we need to ensure that in demoting the type, any still-allowed program as unchanged semantics. That means that changing |
I'd think |
How so? It's just a type that is not sized, but otherwise is just the same as any other type. It's not weirder than having methods on |
I read pimpl as invoking There are at least two approaches to pimpl trait objects, either |
@burdges pimpl is sub-par because not only does it require boxing, it chooses the type of boxing for you. This is more like |
Extern types (or any type that wouldn't implement |
I just want to note also that I'm skeptical of this working also, because all crates across all editions need to be coherent with one another. We need the answer to the question This is the take away that I would really want to impart on the thread: Rust has allowed users to make certain assumptions about the properties of all types, and of all |
type Meta: 'static + Copy + Eq + Ord + Send + Sync + Unpin + …; | ||
} | ||
|
||
/// Types with a dynamic size. |
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.
It took me forever to understand the reasoning behind the existence of this when it has no items of its own, until I read more closely and noticed that extern types are the only things that are excluded. Would recommend making that clear in the summary for this so that it's more immediately apparent.
Is there a reason |
In the context of Is custom allocators the right abstraction?, where I proposed defining "storages" instead, the need to, generically, slice a pointer into meta-data + data-pointer and then later stitch them back together has come again. I've been thinking quite a bit about the API I would need, and in terms of this RFC it would be something such as:
Where
(With The functions Custom DST would require the user to create their own struct implementing I also think it is better to encapsulate (and hide) the exact implementation of the meta-data, and not make any guarantee on the representation, so as to keep our options open going forward. |
@matthieu-m This is almost exactly #2580 except it proposes a |
I want to bring rust-lang/rust#79409 to attention here; I'm not sure how that could be resolved without something like |
To repeat what I wrote in rust-lang/rust#43467 (comment), we now have a good argument from @SimonSapin for Don't fight the math; hiding the essential complexity only makes more for accidental complexity. |
You’re putting words in my mouth. That the trait resolver should be able to deduce |
Yes, all I mean to say you support is To me, having |
Since #2580 was merged, does that mean this RFC is redundant? |
@clarfonthey No, I think they are actually quite complementary, though by no means does the other one require this one. |
Possibly of interest to folks subscribed to this issue: I've proposed an RFC to add RFC 3536: Trait for !Sized thin pointers I think this would be broadly compatible with |
Those two new language traits are at the intersection of #1861, #2580, #2594, and this RFC's raison d'être is solely to try to get some progress for those 3 RFCs all at once by specifying their common core part.
Rendered