-
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
Newtype deriving #508
Closed
Closed
Newtype deriving #508
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
- Start Date: 2014-12-09 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
|
||
Introduce a `#[newtype_deriving(...)]` syntax extension that allows a newtype | ||
to derive traits of the wrapped type. | ||
|
||
# Motivation | ||
|
||
Newtypes are very useful to avoid mixing similar types with different | ||
semantics. The typical example is a `struct Centimeters(f64)` and a | ||
`struct Inches(f64)`. | ||
|
||
A big problem with the usage of newtypes is that you need to manually implement | ||
the traits of the wrapped type in order to use them. In the previous example, | ||
you cannot add two `Centimeters` unless you implement the `Add` trait for the | ||
struct (which is trivial, but verbose). This causes a lot of unnecessary | ||
boilerplate which discourages using newtypes and makes it very painful when you | ||
have no alternative. | ||
|
||
# Detailed design | ||
|
||
Introduce a new syntax extension similar to `#[deriving(...)]` but for | ||
newtypes. A possible name is `#[newtype_deriving(...)]`. | ||
|
||
Example: | ||
|
||
```rust | ||
#[newtype_deriving(Add, Sub, Mul, Div)] | ||
struct Centimeters(f64); | ||
|
||
fn do_something(cm: Centimeters) -> Centimeters { | ||
cm + cm * cm / cm - cm | ||
} | ||
``` | ||
|
||
Deriving a trait is trivial once you know the required functions and their | ||
signatures. A first approach would be to hardcode this information like it | ||
is done in the `#[deriving(...)]` syntax extension. However, if the first | ||
unresolved question is solved (see below), we could derive any trait including | ||
user-defined ones. | ||
|
||
In case the first approach is chosen, the traits available to be derived would be: | ||
* All traits in `std::ops` | ||
* Show | ||
|
||
Note that the comparison operators, serialization, Clone, Hash, Rand, Default | ||
and FromPrimitive don't need to be included since they can be derived using | ||
`#[deriving(...)]`. | ||
|
||
# Drawbacks | ||
|
||
It adds complexity to the language. | ||
|
||
If a trait is modified, this syntax extension would need to be updated as well. | ||
In case we can implement *arbitrary trait deriving* this would not be an issue, | ||
since the syntax extension could look at the trait definition (see unresolved | ||
questions). | ||
|
||
# Alternatives | ||
|
||
We could extend the current `#[deriving(...)]` syntax extension to handle the | ||
case of newtypes. This could cause ambiguity (e.g. `#[deriving(Show)`] | ||
could produce a `"Centimeter(5.0)"` as output or just `"5.0"`). | ||
|
||
Do nothing and let future IDEs generate the boilerplate for us. | ||
|
||
# Unresolved questions | ||
|
||
1. According to [this comment] | ||
(https://github.com/rust-lang/rust/issues/19597#issuecomment-65909118), | ||
a syntax extension has no access to the function signatures of a trait. If | ||
this changes, we could derive any trait (also user-defined ones) for a newtype. | ||
Is it possible to allow syntax extensions to see the (required) function | ||
signatures of a trait? How difficult would it be? | ||
|
||
2. In case 1 cannot be solved, which traits should be available to be derived? |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Show
can be derived via#[deriving(Show)]
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.
While this is true, maybe you are only be interested in the wrapped value (e.g. showing
"2.0"
instead of"Centimeters(2.0)"
). In that case it is useful to be able to deriveShow
.