-
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
Opaque Data structs for FFI #1993
Conversation
Reading the RFC makes me think, could
|
|
||
Finally, many trait parmaeters would be updated in the standard library to relax | ||
their trait bounds from `?Sized` to `?DynSized` which should be a | ||
backwards-compatible change. |
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.
(nit: parmaeters ↦ parameters)
size_of_val
is used indirectly whenever the type needs to manage allocation itself, so types like Box
and Rc
need to remain T: ?Sized
.
Traits like Borrow
and AsRef
should be loosened to ?DynSized
. UnsafeCell
should also be relaxed to ?DynSized
provided that it is safe to transmute an &mut Opaque
to &UnsafeCell<Opaque>
.
It may not be an easy change.
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.
This could fairly easily be implemented, and then trait bounds relaxed on various places where it is safe in a follow up. I agree that types like Rc
shouldn't have their bound relaxed from T: ?Sized
to T: ?DynSized
.
I can look through the standard library and determine which bounds should be relaxed, adding that to the RFC if we want. Actually relaxing the bounds shouldn't be too hard.
What does it mean to create a trait object of an opaque type? Perhaps Strictly speaking, we cannot say that the type can be figured out at runtime, right? What about using Also, I generally don't know how I feel about this... it is definitely an important problem, and I like this solution's concept, but it seems to touch rather a lot of stuff across the language. That makes me nervous. I feel like there are possibly a lot of places where bounds would change and unexpected behavior might happen, like the point that @kennytm makes here. |
A reference to a trait, or a trait object // A trait like `Trait` with a method:
trait Trait {
fn method(&self);
}
// Is represented something like this (I haven't actually looked
// into Rust's exact VTable layout, so this might be wrong...)
struct TraitVTable {
size: usize,
align: usize,
methods: TraitVTableMethods,
}
struct TraitVTableMethods {
method: fn(this_ptr: *const u8),
}
struct &Trait {
data: *const u8,
vtable: *const TraitVTable,
} If you have an opaque type: struct Mine(Opaque);
impl Trait for Mine {
fn method(&self) { println!("Hello!"); }
} Would then be cast to a trait object by taking the pointer to the struct &Trait + ?DynSized {
data: *const u8,
vtable: *const TraitVTableMethods,
} That way it doesn't need a
We do know the type, and if we have a trait object of the opaque type it can be figured out at runtime, we just cannot know the layout of the type. That's what
That type is not safe to put behind a If we do land this type, it would be awesome to change the definition of
I agree that this is an unfortunately large change to the language, which is why I try to also mention the other, much smaller, options which don't involve introducing the This was designed such that no bounds would change without them being explicitly annotated, so no unexpected behavior should happen. If some behavior would change anywhere, that's a bug in the RFC's design. This RFC should be 100% backwards-compatible. The main reason why |
Nope, I think we would need both |
@kennytm I do mention how this would be implemented under this RFC - It would be done by writing |
Ah, got it. So
Sorry, this is a typo. It should say "we cannot say that the size can be figured out at runtime"... that's why I proposed a name that does not include the word "sized".
Got it 👍
Mostly, I am thinking of weird corner cases that might impact soundness or something... like what is the interaction with
Part of me wonders if there is a more formal way to define Opaqueness in the type system. i.e. is there any type theory exploring this issue which might show us where bugs might show up? (btw, I don't know that much about type theory, so I might be totally wrong). Also, I do want to underscore that I like the RFC in general... I just have vague uneasiness, too... |
So the first thing I want to point out is that Just like in rust today, you cannot have a value of type Another value is "made opaque" by including a field of an "opaque" data type as
You would not be able to implement a trait which requires passing around struct CStr(Opaque);
impl Deref for CStr {
type Target = [u8];
fn deref(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self as *const _ as *const u8, self.len())
}
}
} The reason why I want to support implementing inherit methods and traits on let x: &CStr = ...;
cstr_len(x);
// -- instead of --
x.len();
Values which are
You cannot write this expression, as
It would be a ZST, just like
This is what we're doing here. We're defining Opaqueness as being
My main comfort with this RFC is that it is very similar to code which we IMO the main risk here doesn't really come from its interactions with the type system, so |
|
||
unsafe impl DynSized for MyStruct { | ||
fn size_of_val(&self) -> usize { | ||
somehow_determine_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.
Allowing user to provide these functions means calling size_of_val(&x)
may take unknown run time (e.g. the implementation for CStr would be O(n)), while the size_of_val(&x)
of all existing types are O(1). Is this an acceptable trade-off to make?
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's a matter of taste I've wondered about myself, but since custom DSTs is a very much optional followup project (I do want them but opaque data is quite worthwhile on its own), I'm not inclined to think the resolution of this question blocks this RFC.
I suppose it wouldn't hurt to still mention that though :).
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.
I mostly mention the impl DynSized
construct because it would be required in order to migrate CStr
to using Opaque
, rather than because it is something which I think is essential to the core of this RFC. I'd imagine that we would stabilize impl DynSized
separately from the Opaque
work, and mention as much in the RFC text.
surprised to find that there is no definition of semantic of the |
@liigo what do you think is missing? There is an entire section of the rfc dedicated to describing the dynsized trait, and I tried my best to be thorough. |
@mystor Maybe there lacks a summary line of docs of |
This RFC is an offshoot of (and hopes to supersede) #1861 as mentioned in this comment.
This is a rewrite of the original RFC with a focus on the simpler syntactically
Opaque
unsized struct, and tries to serve as a document exploring both the motivation for implementing this feature in rust today, as well as the different approaches for handling thesize_of_val
andtype_of_val
features.I made the decision to focus the core text of the RFC on the
DynSized
approach to thesize_of_val
andtype_of_val
problem, as it is the solution to the problem which causes the largest change to the language, and needs the most exploration. The other solutions are mentioned in the Alternatives section, and are simpler in concept and implementation, so need less text discussing them. However, I have tried to keep the pieces of the RFC which discuss this separated, so that it is easy to tell which parts of the RFC are related to theDynSized
trait, and which are related to theOpaque
struct.rendered