Skip to content

Give users direct access to bitflags and enumeration constants#554

Closed
MarijnS95 wants to merge 1 commit intomasterfrom
bitflags-enum-pub
Closed

Give users direct access to bitflags and enumeration constants#554
MarijnS95 wants to merge 1 commit intomasterfrom
bitflags-enum-pub

Conversation

@MarijnS95
Copy link
Copy Markdown
Collaborator

@MarijnS95 MarijnS95 commented Jan 11, 2022

Nothing special happens when converting to and from these constants, and its API is found to be more concise yet ever so slightly (0.1s) faster to compile than having separate to_raw and from_raw functions for each 1, that it makes sense to drop these entirely. Ash is still on a nonbreaking contribution streak so these functions are marked deprecated for now and will be removed at the next breaking crate release.

MarijnS95 added a commit that referenced this pull request Jan 11, 2022


And drop the deprecated =/- markdown syntax from our readme: this is
analogous to #/## for a h1/h2 header, instead of defining a title and
(usually smaller font) subtitle or description.
@aloucks
Copy link
Copy Markdown
Contributor

aloucks commented Jan 12, 2022

Making the inner type public seems fine, but please don't deprecate as_raw/from_raw.

@MarijnS95
Copy link
Copy Markdown
Collaborator Author

@aloucks just like my PR description above you will have to justify your comment otherwise there's no way for me to even consider honouring your request.

In other words: why?

@MarijnS95 MarijnS95 requested a review from Ralith January 13, 2022 19:01
@aloucks
Copy link
Copy Markdown
Contributor

aloucks commented Jan 13, 2022

The newtype `.0` member is now directly available and preferred

What makes this preferred? It wouldn't be my preference. I guess this is subjective, but requiring newtype syntax in a public API is unappealing to me. as_raw hints at what you're getting and is more descriptive than simply .0.

Removing the methods and making the inner component public is a step in the direction towards making them a simple typedef. I think we can all agree is not the right choice. Why do we want to move in this direction?

Furthermore, with this change, the way you construct a bitflag type and a handle type from a raw value now uses different API, where as without this PR both use a common from_raw/as_raw API. It's also possible to break a bunch of code for no real gain.

@Ralith
Copy link
Copy Markdown
Collaborator

Ralith commented Jan 14, 2022

My feeling is that it's a pretty minor cosmetic difference to be spending buildtime on, but I also don't feel too strongly either way.

Do you actually have a bunch of code calling these methods? I'd have thought conversions to/from raw form would tend to be isolated.

@MarijnS95
Copy link
Copy Markdown
Collaborator Author

The newtype `.0` member is now directly available and preferred

What makes this preferred? It wouldn't be my preference. I guess this is subjective, but requiring newtype syntax in a public API is unappealing to me. as_raw hints at what you're getting and is more descriptive than simply .0.

I am preferring it because it looks more natural to write pub const RGBA: Self = Self(Self::R.0 | Self::G.0 | Self::B.0 | Self::A.0); than doing the same with from/as_raw: #549 (comment). We can re-evaluate if public newtypes are discouraged globally across crates.

By the way I can't help but notice that I've been writing it "wrongly" as to_raw instead of Ash's as_raw all along. The Rust naming conventions are pretty clear that Ash's as_ prefix should only be used for reference->reference conversion, whereas these enums and bitflags are actually owned copy types. They should use to_ which is probably something we should fix regardless as yet another breaking change.

Removing the methods and making the inner component public is a step in the direction towards making them a simple typedef. I think we can all agree is not the right choice. Why do we want to move in this direction?

Not at all. A newtype is still fundamentally different from a typedef no matter the inner value being pub. With typedefs you can easily and accidentally pass any enum or bitflag constant into any other, whereas the newtype still requires explicit construction of said newtype. We can only protect against users accidentally passing the wrong type, not against explicitly constructing the right type from the wrong constant value.

Agreed though, dropping the raw here in favour of direct newtype construction and unwrapping does make that less explicit.

Furthermore, with this change, the way you construct a bitflag type and a handle type from a raw value now uses different API, where as without this PR both use a common from_raw/as_raw API. It's also possible to break a bunch of code for no real gain.

Bitflags are still different from handles, especially the dispatchable one that performs a cast between a raw u64 and holding a *mut u8 internally.

Either way this PR was really only sparked as a means to accommodate the const case from #549: as @Ralith mentioned uses of from/as_raw should be far if nonexistent in most programs, the newtype can be retained everywhere in the API thanks to all the ops:: implementations.
Together with an almost negligible compile-time improvement of 0.1s this is perhaps the wrong decision to make? (Again: I'm willing to break as_raw and name it to_raw properly.) Do we instead prefer the const construction functions originally found in #549 to cater to trivial ops:: not being const and having no alternative?

@aloucks
Copy link
Copy Markdown
Contributor

aloucks commented Jan 14, 2022

They should use to_ which is probably something we should fix regardless as yet another breaking change.

That's not entirely correct either. The to_ convention is to convey that it is an expensive operation, where as the as_ convection is to in indicate that it is free. The most correct convention in this case would be into_ .

Conversions prefixed as_ and into_ typically decrease abstraction, either exposing a view into the underlying representation (as) or deconstructing data into its underlying representation (into). Conversions prefixed to_, on the other hand, typically stay at the same level of abstraction but do some work to change from one representation to another.

https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv

Prefix Cost Ownership
as_ Free borrowed -> borrowed
to_ Expensive borrowed -> borrowed, borrowed -> owned (non-Copy types), owned -> owned (Copy types)
into_ Variable owned -> owned (non-Copy types)

@Ralith
Copy link
Copy Markdown
Collaborator

Ralith commented Jan 14, 2022

These are very much Copy types, though. Unfortunately the guidelines don't seem to cover this case.

MarijnS95 added a commit that referenced this pull request Jan 17, 2022


And drop the deprecated =/- markdown syntax from our readme: this is
analogous to #/## for a h1/h2 header, instead of defining a title and
(usually smaller font) subtitle or description.
MarijnS95 added a commit that referenced this pull request Jan 17, 2022


And drop the deprecated =/- markdown syntax from our readme: this is
analogous to #/## for a h1/h2 header, instead of defining a title and
(usually smaller font) subtitle or description.
Nothing special happens when converting to and from these constants, and
its API is found to be more concise yet ever so slightly (0.1s) faster
to compile than having separate `to_raw` and `from_raw` functions for
each, that it makes sense to drop these entirely.  Ash is still on a
nonbreaking contribution streak so these functions are marked
`deprecated` for now and will be removed at the next breaking crate
release.

[1]: #549 (comment)
@MarijnS95
Copy link
Copy Markdown
Collaborator Author

@aloucks Fair enough, I didn't read my own link 🤦

Not sure what else it should be then though, if everything in that table is wrong... For the bitflags we could/should definitely match bitflags! fn bits() and fn from_bits_unchecked() (can't do fn from_bits_truncate() unless we introduce the machinery to produce a proper fn all() this time). It seems some suggest to use the name of the field as if it were a getter (without the get_ prefix of course) but there's no such name in newtypes.

Anyway, should we leave this for a future discussion/PR and solely focus on whether to keep these functions in the first place / make the inner type public, per the initial intent of the PR? At this point I'm feeling more and more indifferent to it all.

@Ralith
Copy link
Copy Markdown
Collaborator

Ralith commented Jan 17, 2022

Works for me. Decisions are always easier one at a time.

@MaikKlein
Copy link
Copy Markdown
Member

Honestly I have no strong preference here. I'd keep the as_raw functions though, and I think as_ is the correct pattern here because it is a free conversion.

Having both as_raw and the inner field public is a bit weird though.

@MarijnS95
Copy link
Copy Markdown
Collaborator Author

Honestly I have no strong preference here. I'd keep the as_raw functions though, and I think as_ is the correct pattern here because it is a free conversion.

as_ seems to match best, it's not fully correct but with no better alternative it's not worth the API churn to change to anything else.

Having both as_raw and the inner field public is a bit weird though.

Of course they're marked deprecated now, but we can also remove them immediately as the next breaking release is imminent anyway.

On that note, is this still something we want in? Repeating what I said before: this PR is mainly to smoothen the const side of things since Ash itself has all the Ops implemented for non-const and regular API usage doesn't require these functions anyway.

@Ralith
Copy link
Copy Markdown
Collaborator

Ralith commented Feb 19, 2022

Given that IMO const use is niche and already possible, and the compile time impact is very marginal, I don't feel like this is a big win.

@MarijnS95
Copy link
Copy Markdown
Collaborator Author

Closing this as being unclear and not worth the trouble.

I don't think we should reopen #549 then either. While using type-safe functions is preferred this is probably not worth the trouble for a few const cases. If anything Rust should find a solution for const ops upstream.

@MarijnS95 MarijnS95 closed this Feb 22, 2022
@MarijnS95 MarijnS95 deleted the bitflags-enum-pub branch February 22, 2022 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants