Skip to content
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

[RFC accepted] add wrapper for discriminant_value intrinsic #34785

Closed
wants to merge 1 commit into from

Conversation

Projects
None yet
@durka
Copy link
Contributor

durka commented Jul 12, 2016

add wrapper for discriminant_value intrinsic

Wraps the discriminant_value intrinsic under the name std::mem::discriminant. In order to avoid prematurely leaking information about the implementation of enums, the return value is an opaque type, generic over the enum type, which implements Copy, Clone, PartialEq, Eq, Hash, and Debug (notably not PartialOrd). There is currently no way to get the value out excepting printing the debug representation.

The wrapper is safe and can be stabilized soon as per discussion in #24263.

r? @brson

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Jul 12, 2016

I just realized the wrapper should be safe. Another commit incoming...

pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}

/// Returns the value of the discriminant for the enum variant in `v`.

This comment has been minimized.

@sfackler

sfackler Jul 12, 2016

Member

It is probably worth adding a warning that discriminants may not compare in the correct order if the enum is #[repr(i64)] due to overflow.

This comment has been minimized.

@durka

durka Jul 12, 2016

Author Contributor

Will do.

On Tue, Jul 12, 2016 at 1:43 PM, Steven Fackler notifications@github.com
wrote:

In src/libcore/raw.rs
#34785 (comment):

pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
+
+/// Returns the value of the discriminant for the enum variant in v.

It is probably worth adding a warning that discriminants may not compare
in the correct order if the enum is #[repr(u64)] due to overflow.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/rust-lang/rust/pull/34785/files/609c17e8d0ceac437261df2c6b4231225f1faf08#r70485187,
or mute the thread
https://github.com/notifications/unsubscribe/AAC3n4IaNbDuCLcSiYjaKILI3yho7yvLks5qU9IrgaJpZM4JKnnt
.

This comment has been minimized.

@durka

durka Jul 12, 2016

Author Contributor

Wait, I don't understand. You mean if the enum is not #[repr(u64)]?

On Tue, Jul 12, 2016 at 1:46 PM, Alex Burka durka42@gmail.com wrote:

Will do.

On Tue, Jul 12, 2016 at 1:43 PM, Steven Fackler notifications@github.com
wrote:

In src/libcore/raw.rs
#34785 (comment):

pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
+
+/// Returns the value of the discriminant for the enum variant in v.

It is probably worth adding a warning that discriminants may not compare
in the correct order if the enum is #[repr(u64)] due to overflow.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/rust-lang/rust/pull/34785/files/609c17e8d0ceac437261df2c6b4231225f1faf08#r70485187,
or mute the thread
https://github.com/notifications/unsubscribe/AAC3n4IaNbDuCLcSiYjaKILI3yho7yvLks5qU9IrgaJpZM4JKnnt
.

This comment has been minimized.

@sfackler

sfackler Jul 12, 2016

Member

Er, yeah. Your doc change is what I was thinking of.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jul 12, 2016

I might personally prefer this being located in the std::mem module as opposed to std::raw. We've almost deleted the entire std::raw module and I'd personally like to see it go out all the way!

Also, could the actual stabilization be deferred to a later date? The libs team tends to not apply stabilizations mid-cycle but instead places issues into final comment period at the end of which we decide on the stabilization outcome (as a result of the discussion, if any, that happened).

cc @rust-lang/libs, any objections on moving this to FCP though? Seems good to me!

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Jul 12, 2016

OK, I had previously asked at the tracking issue if this should be insta-stable (since it is basically stabilizing the intrinsic, even though it doesn't actually do that) and @brson said yes. But I'm happy to mark it unstable for now. I'll move it to std::mem as well (though it doesn't have much if anything to do with memory).

@durka durka force-pushed the durka:discriminant_value branch 2 times, most recently from 29e3b0d to 1001205 Jul 12, 2016

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Jul 12, 2016

@sfackler's comment was hidden, but I added a note about comparisons.

@durka durka force-pushed the durka:discriminant_value branch 2 times, most recently from eb26969 to 3a88d88 Jul 12, 2016

/// enum Foo { A(String), B(i32) }
///
/// # fn main() {
/// assert!(mem::discriminant(Foo::A("bar")) != mem::discriminant(Foo::A("baz")));

This comment has been minimized.

@alexcrichton

alexcrichton Jul 12, 2016

Member

I think these examples may not compile, the discriminants should be the same here, right? Additionally, shouldn't a shared reference be passed in?

This comment has been minimized.

@durka

durka Jul 12, 2016

Author Contributor

Yeah, I just noticed that and fixed it.

On Tue, Jul 12, 2016 at 2:19 PM, Alex Crichton notifications@github.com
wrote:

In src/libcore/mem.rs
#34785 (comment):

+/// same order as actual enum variants would under #[derive(PartialOrd)].
+///
+/// If T is not an enum, the return value is unspecified.
+///
+/// # Example
+///
+/// This can be used to compare enums that carry data, while disregarding
+/// the actual data:
+///
+/// ```
+/// use std::mem;
+///
+/// enum Foo { A(String), B(i32) }
+///
+/// # fn main() {
+/// assert!(mem::discriminant(Foo::A("bar")) != mem::discriminant(Foo::A("baz")));

I think these examples may not compile, the discriminants should be the
same here, right? Additionally, shouldn't a shared reference be passed in?


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/rust-lang/rust/pull/34785/files/3a88d8811ae23af836e8ed4349e4a96656303878#r70492383,
or mute the thread
https://github.com/notifications/unsubscribe/AAC3n1nIqX5ydVTZ2ue3rNp94IPEA-khks5qU9qggaJpZM4JKnnt
.

/// the discriminant values returned by this function will not compare in the
/// same order as actual enum variants would under `#[derive(PartialOrd)]`.
///
/// If `T` is not an enum, the return value is unspecified.

This comment has been minimized.

@alexcrichton

alexcrichton Jul 12, 2016

Member

Could this clarify though that it's not like undefined behavior will happen, it's just that the actual value returned cannot be relied on?

This comment has been minimized.

@alexcrichton

alexcrichton Jul 12, 2016

Member

It may also be worth explaining that the returned value only really makes sense to compare with other discriminants generated from values of the same type? That is, comparing the discriminants of types A and B won't result in anything meaningful

This comment has been minimized.

@durka

durka Jul 12, 2016

Author Contributor

Could this clarify though that it's not like undefined behavior will happen, it's just that the actual value returned cannot be relied on?

Done.

It may also be worth explaining that the returned value only really makes sense to compare with other discriminants generated from values of the same type? That is, comparing the discriminants of types A and B won't result in anything meaningful

Not sure about this one. You can choose discriminants by hand (in the enum definition I mean), so you could for example set up certain error enums to have known discriminants corresponding to the errors produced by a -sys crate or something.

@durka durka force-pushed the durka:discriminant_value branch 3 times, most recently from 987979d to c35ec62 Jul 12, 2016

@sfackler

This comment has been minimized.

Copy link
Member

sfackler commented Jul 12, 2016

@alexcrichton I want to stabilize type_name or something like it, so we might want to keep std::raw around for things like that.

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Jul 12, 2016

Is it the case that a discriminant can never be larger than u64? (I think there is an RFC to add u128 and whatnot...)

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Jul 12, 2016

For the record (on the theme of my previous comment) I still think it would be better to use the type system to make this function's return type better. But I also understand we want to stabilize something.

@durka durka changed the title add stable wrapper for discriminant_value intrinsic add soon-to-be-stable wrapper for discriminant_value intrinsic Jul 12, 2016

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jul 12, 2016

@sfackler hm that's a good point about type_name, but I figure we can probably figure out a better way to do that than putting it in std::raw

@brson brson added the relnotes label Jul 12, 2016

@durka durka force-pushed the durka:discriminant_value branch from c35ec62 to 90e4530 Jul 13, 2016

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Jul 13, 2016

I wasn't initially a fan of std::mem for this, but I can sort of see it now. E.g. this is not so different from things like size_of, which are type-generic functions giving repr details. I could see type_name living here eventually, too.

assert_eq!(mem::discriminant(&NullablePointer::Something(&CONST)), 0);

// unlike the test for the intrinsic, there are no tests with non-enums here
// because the result is documented to be unspecified

This comment has been minimized.

@tbu-

tbu- Jul 13, 2016

Contributor

You could still call it on a struct, just to check that it doesn't panic.

This comment has been minimized.

@durka

durka Jul 13, 2016

Author Contributor

Done.


/// Returns the value of the discriminant for the enum variant in `v`.
///
/// The returned discriminant is cast to `u64`, no matter what the actual

This comment has been minimized.

@ollie27

ollie27 Jul 13, 2016

Contributor

I would like to see more explanation about where the value comes from, along with examples if possible.

Also what stability guarantees do the returned values have. For example is discriminant_value(&Some(123)) == 1 guaranteed to always be true?

This comment has been minimized.

@durka

durka Jul 13, 2016

Author Contributor

Added an example.

Also what stability guarantees do the returned values have.

Hmm... this is a tough one. Since the discriminant depends on the order of enum variants, stability would imply that libraries following semver may not shuffle the order of variants, or add new ones except at the end, in minor versions (actually, they already can't add new variants, unless they have a hack like std::io::ErrorKind::__Nonexhaustive). This seems OK to me (needs to be documented of course), but others might have thoughts?

This comment has been minimized.

@sfackler

sfackler Jul 13, 2016

Member

I think we should say that consumers shouldn't depend on discriminants being stable across versions of a dependency unless otherwise documented on the enum.

I think it's probably reasonable to state that discriminants will be stable for a given enum definition though across compilations. Maybe compiler versions as well?

This comment has been minimized.

@durka

durka Jul 13, 2016

Author Contributor

Quoth the reference:

If a discriminant isn't specified, they start at zero, and add one for each variant, in order.

So I think they must be stable across compiler minor versions.

This comment has been minimized.

@nagisa

nagisa Jul 14, 2016

Contributor

If a discriminant isn't specified, they start at zero, and add one for each variant, in order.

This is for C-like (i.e. numeric/data-less) enums only. We do not specify anything for sum-types. I would like to not guarantee anything other than discriminant(Enum::Variant) == discriminant(Enum::Variant) within the crates compiled by the same version of rustc, except for C-like enums, where the usual increment-by-one rules apply.

This comment has been minimized.

@nagisa

nagisa Jul 14, 2016

Contributor

Seems problematic with #[repr(i/u128)] potentially happening once we get i/u128 primitives. Are we gonna forbid such attribute?

This comment has been minimized.

@durka

durka Jul 14, 2016

Author Contributor

I agree. How likely are we to add those primitives?

This comment has been minimized.

@durka

durka Jul 14, 2016

Author Contributor

This is for C-like (i.e. numeric/data-less) enums only.

The reference does not restrict or qualify this statement in any way. It is in a section called "Enumerations". If you want to remove this as a guarantee for all enums, then change the reference. I do understand the reluctance to make guarantees, but this is a bit ridiculous. What would the motivation be for changing discriminants according to the phase of the moon?

@durka durka referenced this pull request Aug 1, 2016

Merged

mem::discriminant() #1696

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Aug 1, 2016

RFC posted at rust-lang/rfcs#1696.

@bors

This comment has been minimized.

Copy link
Contributor

bors commented Aug 26, 2016

☔️ The latest upstream changes (presumably #35906) made this pull request unmergeable. Please resolve the merge conflicts.

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Aug 26, 2016

Waiting to rebase until the RFC process concludes.

@durka durka changed the title [WIP] add wrapper for discriminant_value intrinsic [RFC accepted] add wrapper for discriminant_value intrinsic Sep 16, 2016

@durka durka force-pushed the durka:discriminant_value branch from a7de3ad to a8c3cf6 Sep 16, 2016

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Sep 16, 2016

Rebased and updated.

I removed the Reflect bound as per the RFC (nobody opined on it during FCP). I'm assuming that trait's FCP will end in deprecation; if not, we could revisit.

I updated the stability section of the documentation to say (again, nobody opined during FCP):

Discriminants can change if enum variants are reordered, if a new variant is addedin the middle, or (in the case of a C-like enum) if explicitly set discriminants are changed. Therefore, relying on the discriminants of enums outside of your crate may be a poor decision. However, discriminants of an identical enum should not change between subsequent compilations with the same compiler.

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Sep 27, 2016

@nagisa Can you take over this review, given that you've already looked at the PR?

///
/// # Stability
///
/// Discriminants can change if enum variants are reordered, if a new variant is added

This comment has been minimized.

@nagisa

nagisa Sep 27, 2016

Contributor

As the return value of this wrapper is a opaque value Discriminant<T>, this section reads weird. Namely it changing makes little sense because you aren’t supposed to be able to inspect it directly. Rather the stability and behaviour should be described in terms of PartialEq and Hash.

This comment has been minimized.

@durka

durka Sep 27, 2016

Author Contributor

That's a good point.

#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
impl<T> fmt::Debug for Discriminant<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(fmt)

This comment has been minimized.

@nagisa

nagisa Sep 27, 2016

Contributor

This probably wants to use a debug builder and output something along the lines of Discriminant(<number>), rather than outputting a plain number.

This comment has been minimized.

@durka

durka Sep 27, 2016

Author Contributor

OK.

pub struct Discriminant<T>(u64, PhantomData<*const T>);

#[unstable(feature = "discriminant_value", reason = "recently added, follows RFC", issue = "24263")]
impl<T> Copy for Discriminant<T> {}

This comment has been minimized.

@nagisa

nagisa Sep 27, 2016

Contributor

Why not derive all these implementations?

This comment has been minimized.

@durka

durka Sep 27, 2016

Author Contributor

You'd get nonsense bounds on T.

This comment has been minimized.

@durka

durka Sep 27, 2016

Author Contributor

I thought I'd included a comment to this effect. I'll add one.

@durka durka force-pushed the durka:discriminant_value branch from a8c3cf6 to e447d42 Sep 27, 2016

@durka durka force-pushed the durka:discriminant_value branch from e447d42 to a84b550 Sep 27, 2016

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Sep 27, 2016

I think it's ready, just waiting for tests.

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Sep 27, 2016

@durka OK, just give a ping once it's ready for bors and i'll send it along.

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Sep 28, 2016

Tests and tidy pass locally.

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Sep 28, 2016

Huzzah!

@bors: r=nagisa

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Sep 28, 2016

@bors? you there?

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Sep 28, 2016

@bors: r+

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Sep 28, 2016

@bors r=nagisa

@aturon aturon closed this Sep 28, 2016

@aturon aturon reopened this Sep 28, 2016

@aturon

This comment has been minimized.

Copy link
Member

aturon commented Sep 28, 2016

@bors: r=nagisa

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Sep 29, 2016

Should I try reopening as a new PR?

@durka

This comment has been minimized.

Copy link
Contributor Author

durka commented Sep 29, 2016

Moved to #36823.

bors added a commit that referenced this pull request Sep 30, 2016

Auto merge of #36823 - durka:discriminant_value, r=nagisa
add wrapper for discriminant_value, take 2

[This is #34785 reopened, since @bors apparently gave up on that thread.]

add wrapper for discriminant_value intrinsic

Implementation of [RFC 1696](https://github.com/rust-lang/rfcs/blob/master/text/1696-discriminant.md).

Wraps the `discriminant_value` intrinsic under the name `std::mem::discriminant`. In order to avoid prematurely leaking information about the implementation of enums, the return value is an opaque type, generic over the enum type, which implements Copy, Clone, PartialEq, Eq, Hash, and Debug (notably not PartialOrd). There is currently no way to get the value out excepting printing the debug representation.

The wrapper is safe and can be stabilized soon as per discussion in #24263.

cc @aturon
r? @nagisa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.