-
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
Add a newtype
keyword that creates a non-coercible, castable alias.
#949
Conversation
An interesting consequence of this definition is that the wrapping types, newtype w8 = u8; and then the operations |
This is pretty minor but the keyword |
I believe this RFC is not actually proposing adding a new The problem with renaming
trait Foo { type Bar = DefaultBar; } // repurposed `type` is supposed to create a newtype, but no newtype is created here.
trait Foo { alias Bar = DefaultBar; } // why are we creating "an alias" here? It's not clear `Bar` is an associated type. So I think we should either:
|
There is also another alternative that is: Use But I don't think we need two new keywords and a large scale breaking change. |
|
||
### Casting | ||
|
||
Let `R1` be the binary, transitive, symmetric, irreflexive relation generated by |
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 don't understand what relations are being generated here if they are not reflexive.
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.
And I assume by "generated by newtype
" you mean that if newtype T = U;
then R1
contains (T, U)
?
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.
Let X
be the set of types. Let A
be set of tuples in X^2
such that (T, U) \in A
iff newtype T = U
or alias T = U
or T != U
are numeric types. R1
is the smallest transitive, symmetric superset of A
in X^2
.
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.
Maybe a more intuitive definition is in order:
The newtype
and alias
keywords create an undirected graph such that the edge T <-> U
exists if alias T = U
or newtype T = U
. To this graph we add the numeric casts u8 <-> f64
and so on.
(T, U)
is in R1
if there is a path between T
and U
in this graph and T != U
.
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.
Does that mean that this is legal?
newtype Foo = Bar;
newtype Bar = f64;
newtype Baz = Qux;
newtype Qux = u8;
let x = 1 as Baz;
x as Foo
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.
Yes, what you've just written is basically the cast c_uchar -> c_double
which has to be legal.
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.
You use consistently 'has' for a lot of things that are not obviously compulsory to me (and others); maybe you could expand?
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.
The motivation of this RFC is to create a system that, in the case of the numeric typedefs in liblibc, is not harder to use than the current system. If casts between typedefs of different built-in numeric rust types are not allowed, then the RFC has failed.
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.
If casts between types newtype T = U
and built-in types W != U
(both numeric) are not possible, then the system becomes completely useless because you can only cast between c_long
and i32
on Windows and only between c_long
and i64
on 64 bit unix.
cc #186 |
Yes, this is useful. Another example is casting an I think it would be also nice to have a version that allows casting only from the newtype to the type, to represent types with added or removed constraints (the other direction would only be allowed for code that has "private" access to the newtype). For example, F32NotNaN could be a newtype where F32NotNaN -> f32 conversion is allowed, but not viceversa. This could perhaps be done by allowing these coercions for newtype structs. |
Are there any places this is required in |
|
||
The same rules as for `Fn` apply to `FnOnce`. | ||
|
||
#### Default impls |
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 rule now covers Send
and Sync
(afaik), no need to mention them above.
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 rule is also implied by the OIBIT rules, i.e. could be written as "Traits with default impls behave as if newtype T = U;
is the same as struct T(U);
."
I've uploaded a significant revision of the RFC that should hopefully address most of the points raised here. Changelog:
These new rules also allow the cast mentioned by @bill-myers above:
|
Please refrain from commenting in the now collapsed comment threads. Instead open a new one.
Some libc types are exposed in the public interface. Apart from that, the implementation makes heavy use of libc types. |
I think I've come up with a somewhat simpler and more powerful way to make |
After thinking about it some more, the current version is as good as it gets for now. |
Why not rename |
Thanks for the detailed RFC. No question that generalized newtype deriving could be useful, but it doesn't fit into the current priorities. Therefore we're going to postpone this RFC using the existing issue #261. |
Shouldn't something like this be a 1.0 blocker? It seems like you don't want people rolling their own solutions to get around a pain point in something as fundamental as newtype. For example, it would be nice to be able to do checked addition, max_value(), etc... on a newtyped int without a bunch of boilerplane: Credit: this came from help I got during an IRC discussion with flan3002. Thanks! |
Rust 1.0 is the point that backwards incompatible changes won't be allowed. It doesn't mean every wanted feature will be in it. This feature is wanted, but can be added without a compatibility hazard, so there's no reason to block 1.0. With a six week release cycle, it'll be in as soon as somebody prioritizes it. |
@Havvy, I get that. It seemed to me like newtype is more of a fundamental part of how the typesystem works, and doesn't really count as a "feature." If it can be added later in backwards compatible way on top of the existing types (i.e. without resorting to another flavor of struct), that will be awesome and surprising to me, but it won't be the first time the rust devs have pulled off such a feat :) |
reopened rfc in #2242 |
Add a
newtype
keyword that creates a non-coercible, castable alias.Rename
type
toalias
.Rendered