Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions examples/generics/phantom/testcase_units/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,17 @@ A useful method of unit conversions can be examined by implementing `Add`
for a phantom type. The `Add` `trait` is examined below:

```rust
// This construction would impose: `Self + RHS = Output`.
// This construction would impose: `Self + RHS = Output`
// where RHS defaults to Self if not specified in the implementation.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the period to the end of the sentence. I'm not sure if you wanted it removed completely, but I thought that would be inconsistent with line 13.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, we may have inconsistencies. Rust by Example was donated to the Rust organization, and I haven't had the chance to go over the entire thing yet. So, when adding new stuff, I tend to apply our already-existing conventions, even though the project as a whole may not have totally adopted them yet. Make sense?

pub trait Add<RHS = Self> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't quite right. Add<RHS = Self> seems to force RHS to default to Self. So:

impl Add<f64> for T {} // T + f64 (override default)
impl Add for T // T + T (RHS is Self because of the default)

There is no defaults section though probably because I couldn't figure them out when I was working on the associated types sections.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this isn't your mistake. It just wasn't written correctly before.

It's mainly an issue because it uses <X = Y> but the actual example doesn't require that part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I missed that comment yesterday... Well I didn't know about that defaulting mechanism indeed, it's nice.
I updated the comment to mention that. I would have removed that line but since it's not explained anywhere else, it does get confusing. Let me know if there's anything else.

type Output;

fn add(self, rhs: RHS) -> Self::Output;
}

// So, `Output` must be `T` and therefore, `T + T = T`.
impl<T> Add<T, Output = T> for T {}

// Similarly, this imposes: `S<T> + S<T> = S<T>` can be
// added only when `T + T = T`.
impl<S<T>> Add<S<T> for S<T> where
T: Add<T, Output = T> {
type Output = S<T>;
// `Output` must be `T<U>` so that `T<U> + T<U> = T<U>`.
impl<U> Add for T<U> {
type Output = T<U>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be inclined to drop one of these 2 blocks because that super heavyweight bounds section isn't there anymore however you as the reader have better insight than I do on whether these are helpful. Therefore deferring to your judgement seems the most proper thing to do.

...
}
```
Expand Down
42 changes: 24 additions & 18 deletions examples/generics/phantom/testcase_units/units.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
use std::ops::Add;
use std::marker::PhantomData;

/// Null enumerations to define unit types
/// Null enumerations define unit types.
#[derive(Debug, Clone, Copy)]
struct Inch;
#[derive(Debug, Clone, Copy)]
struct Mm;

/// Length is phantom type with hidden parameter `Unit`
/// `Length` is phantom type with hidden parameter `Unit`.
///
/// `f64` already implements the `Clone` and `Copy` traits.
#[derive(Debug, Clone, Copy)]
struct Length<Unit, T>(T,PhantomData<Unit>);
struct Length<Unit>(f64,PhantomData<Unit>);

// This is similar to the header except `T` must also
// implement `Clone` and `Copy.
impl<Unit, T> Add<Length<Unit, T>> for Length<Unit, T> where
T: Add<T, Output=T> + Clone + Copy {
type Output = Length<Unit, T>;
/// The `Add` trait defines the behavior of the `+` operator.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you wanted a period added here and at line 20, since the rest of the website never uses periods in the playpens.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The official policy is that comments should be punctuated. Generally that's fairly easy to check in small patches but rbe has had many many sweeping changes in the past year where it's hard to notice little things like that.

Ideally rbe would start conforming more to the standard. The situation should get better with time and stability.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdinger yes, thanks you beat me to it, and i just mentioned it #583 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I should terminate the rest of the comments too ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you'd like, yes. Thanks :)

impl<Unit> Add for Length<Unit> {
type Output = Length<Unit>;

fn add(self, r: Length<Unit, T>) -> Length<Unit, T> {
Length(self.0 + r.0, PhantomData)
// add() returns a new `Length` struct containing the sum.
fn add(self, rhs: Length<Unit>) -> Length<Unit> {
// `+` calls the `Add` implementation for `f64`.
Length(self.0 + rhs.0, PhantomData)
}
}

fn main() {
// Specialize one_foot to have hidden parameter `Inch`
let one_foot: Length<Inch, f32> = Length(12.0, PhantomData);
// one_meter has hidden parameter `Mm`
let one_meter: Length<Mm, f32> = Length(1000.0, PhantomData);

// Specializes `one_foot` to have hidden parameter `Inch`.
let one_foot: Length<Inch> = Length(12.0, PhantomData);
// `one_meter` has hidden parameter `Mm`.
let one_meter: Length<Mm> = Length(1000.0, PhantomData);

// `+` calls the `add()` method we implemented for `Length<Unit>`.
//
// Since `Length` implements `Clone` + `Copy`, `add()` does not consume
// `one_foot` and `one_meter` but makes a copy of them in `self` and `rhs`.
let two_feet = one_foot + one_foot;
let two_meters = one_meter + one_meter;

// Addition works
// Addition works.
println!("one foot + one_foot = {:?}", two_feet);
println!("one meter + one_meter = {:?}", two_meters);

// Nonsensical operations fail as they should
// Error: type mismatch
// Nonsensical operations fail as they should:
// Error: type mismatch.
//let one_feter = one_foot + one_meter;
}