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
Feature request: Bring back newtypes instead of type aliases #1393
Comments
It's not just clarity either. The following code compiles with v0.29: unsafe fn foo() {
let dc = GetDC(0);
let _ = GetDC(dc); // Should take an HWND, not an HDC
} Likewise, you can pass a After moving to v0.29 some of my code got less verbose (mostly around conversions between concrete GDI object handles and the generic |
With the tuple struct versions it would be easy enough to add impl std::ops::BitAnd<HWND> for HWND {
type Output = HWND;
fn bitand(self, rhs: HWND) -> Self::Output {
HWND(self.0 & rhs.0)
}
} |
I figured consistency with |
Just to throw my opinion into the mix, I prefer the type aliases from experience with using the
On a side note, I find the duplication between the Is there a future plan to consume Note: This could boil down to that I prefer what I'll also add that I greatly appreciate the amount of effort you've put into this project @kennykerr. You have a very intense workflow and I hope you are getting some rest over these holidays! |
@avitex raises a valid question: What is the scope of Prior to the split of With the
As a user I'd absolutely hope for |
Regarding #4, I actually started writing a documentation parser that made a pretty good effort to figure out what type a function returns, which |
Briefly regarding |
I like the type aliases better than newtypes, largely because they are less verbose. Another reason is that there are some functions that take different types than the parameter. For example, And I don't remember having a bug due to passing the wrong type to a function, but I don't have a whole lot of code using the Windows API. Regarding |
Seems like |
Hey all, this thread asks some good questions. Specifically about the change to the handles, but also more generally about the relationship between TL;DR: We're planning to bring back newtypes for the What is the relationship between
|
Crate name | Win32 support |
WinRT and COM support |
Focus | Best for |
---|---|---|---|---|
windows |
✅ | ✅ | Good ergonomics | Applications |
windows-sys |
✅ | ❌ | Fast compile times | Libraries |
We wish the windows
would both provide both good ergonomics and compile-times, but the unfortunate reality is that we're limited by the performance of both cargo 1 and the compiler. Which is not surprising, because with over over 230.000 unique (!) types Windows is definitely pushing the boundaries of what the compiler expects to handle in a library 2.
We hope the situation will improve over time, and we can eventually recommend windows
for both applications and libraries, but unfortunately we're not there yet.
WinRT
and COM
for libraries
As shown in the table above, windows-sys
doesn't support WinRT
and COM
APIs. This means that for now if you want to use those APIs in a library you have to use the windows
crate for now.
We're still thinking through a solution to improve on this. Bare WinRT
and COM
bindings are incredibly hard to use. And adding ergonomic bindings to windows-sys
would drastically increase compile times. Right now we're thinking of bringing windows-bindgen
to a good enough spot so library authors can generate their own types where needed, but that doesn't seem like a great long-term solution either 3.
What shape should handles have?
First off: what are handles? Unlike what some might expect, handles are not necessarily pointers: they tend to be opaque values representing a resource. windows-sys
uses the semantics exposed by the platform's underlying types, so in most cases pointer semantics won't apply. 4
With that out of the way, we can attempt to answer the question in this thread: how should we expose the handles? After talking about it yesterday with @kennykerr, we're thinking of doing different things for the different crates:
windows
: focus on ergonomics by exposing a new-type, enabling things likeType::default()
to work again.windows-sys
: focus on performance by exposing a type-alias, which provides fewer guarantees but compiles faster.
We hope that this will satisfy the varying needs folks have, as right now we unfortunately can't reconcile them in a single crate.
Closing notes
We'd love to hear what you think of this! We hope to provide better documentation on the differences between windows
and windows-sys
, and this is a first attempt at that. Also are there any uses we missed? Would this change be problematic for certain folks? Let us know!
Footnotes
-
Download sizes are a real concern too. ↩
-
Not all types add the same cost. For the
windows
crate we've observed that in particular generating function bodies is expensive. ↩ -
windows-rs
used to only expose codegen functionality. We moved away from that because it made it difficult to align types between crates, and reuse generated code by the compiler. Whilewindows-bindgen
has its place, we are aware of the tradeoffs that come with it. ↩ -
Some work in Rust has gone in to model OS resource handles using borrow semantics: RFC 3128: IO Safety. But it's an open question how much of this we may be able to leverage for handles
windows
/windows-sys
, and whether we can make them fit their intended goals. ↩
Another, perhaps more actionable, way to phrase the "for libraries" or "for performance" vs "for applications" distinction is that The primary reason the This goal does tend to overlap with faster compile times, but it's also about flexibility, and a clean separation between what is provided by the foreign API and what is specific to Rust. So in that sense, type aliases are the right choice for a |
Motivation
Before
0.29
,Foundation::HWND
and friends were defined as wrappers around ausize
/isize
or something else. It made code a little verbose but it was very easy to differentiate values and to see exactly what was what.This is now impossible and can easily lead to confusion when passing defaults/values defined far away.
For example, I liked to use
Type::default()
orHWND(0)
because it made the type very clear, even in code reviews where type hint are hover docs are missing.Drawbacks
Verbose, probably worse compile times.
Rationale and alternatives
Keep current format.
Additional context
One thing that was missing was Binary operations, like Or/And/Xor for such types. Since those are now type aliases, that makes them available by default, which is nice. Maybe find a way to have both ?
The text was updated successfully, but these errors were encountered: