Skip to content

react: Distinguish cell IDs #499

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

Merged
merged 3 commits into from
Apr 20, 2018
Merged

react: Distinguish cell IDs #499

merged 3 commits into from
Apr 20, 2018

Conversation

petertseng
Copy link
Member

@petertseng petertseng commented Apr 9, 2018

Closes #473

I strongly advise that this should not be merged yet, for at least the following reason:

set_cell_value now can only fail in one way (cell does not exist) since it is no longer possible to designate an input cell to it. Therefore, it no longer needs to return SetValueError. We can just return a boolean, even.

Except for that point, I guess everything else is how I expect it to be.

I'm also happy to hear ideas about being able to move set_value onto input cells directory, in which case I don't see the need for this PR.

@petertseng petertseng changed the title WIP: react: Distinguish cell IDs react: Distinguish cell IDs Apr 17, 2018
@petertseng
Copy link
Member Author

Well, I guess this is it.

@@ -1,12 +1,13 @@
use std::collections::HashMap;

pub type CellID = usize;
pub type InputCellID = usize;
pub type ComputeCellID = usize;
Copy link
Member

Choose a reason for hiding this comment

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

I note that these are typedefs, not newtypes. As such, the compiler treats InputCellID, ComputeCellID, and usize interchangeably. If we want it to enforce real type safety for us, we'll need to use newtypes:

pub struct InputCellID(usize);
pub struct ComputeCellID(usize);
// the above two types _cannot_ be interchanged

pub type CellID = ();
// it will probably be necessary for these three types to be Copy.
pub type InputCellID = ();
pub type ComputeCellID = ();
Copy link
Member

Choose a reason for hiding this comment

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

It might be worth declaring these as

pub struct InputCellID();
pub struct ComputeCellID();

to suggest the newtype pattern instead of the typedef pattern.

Interestingly, I believe that the tests don't care; they should work whether these are type aliases or newtypes. Still, if we're in this for the type safety, we may as well do it right.

@petertseng
Copy link
Member Author

I would like to experiment with adding a compile_fail test (docmented in https://doc.rust-lang.org/stable/rustdoc/documentation-tests.html) to ensure IDs aren't mutually assignable.

This ensures type safety; the types should not be assignable to one
another.
Can no longer error via being given a compute ID, so the only error is a
nonexistent cell.
pub type CallbackID = ();
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ComputeCellID();
#[derive(Clone, Copy, Debug, PartialEq)]
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that the tests are going to need all of these. The reason why Debug and PartialEq should be obvious.

The reason for Copy (and therefore why Clone) is:

error[E0382]: use of moved value: `callback`
   --> tests/react.rs:203:52
    |
201 |     assert!(reactor.remove_callback(output, callback).is_ok());
    |                                             -------- value moved here
202 |     for _ in 1..5 {
203 |         assert_eq!(reactor.remove_callback(output, callback), Err(RemoveCallbackError::NonexistentCallback));
    |                                                    ^^^^^^^^ value used here after move
    |
    = note: move occurs because `callback` has type `react::CallbackID`, which does not implement the `Copy` trait

Copy link
Member

@coriolinus coriolinus left a comment

Choose a reason for hiding this comment

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

Sorry for the delay reviewing this. It looks good!

Exercises such as this form a useful jumping-off point for students into the kind of code they should expect to read and write in the real world, so I am very much in favor of the improved type safety here.

pub struct InputCellID();
/// `ComputeCellID` is a unique identifier for a compute cell.
/// Values of type `InputCellID` and `ComputeCellID` should not be mutually assignable,
/// demonstrated by the following tests:
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if cargo doc flags to the user that the code under test here should fail to compile. If it does, no changes are required. If it does not, it's probably worth mentioning in the text that both of the examples here should fail to compile.

Copy link
Member Author

Choose a reason for hiding this comment

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

I did manage to confirm this. There's a red ⓘ and hovering over it shows "this example deliberately fails to compile"

Given this, I'll be merging it. Just not now, since it is inconvenient to now.

@petertseng petertseng merged commit 08d5197 into exercism:master Apr 20, 2018
@petertseng petertseng deleted the react-cell-ids branch April 20, 2018 06:54
@petertseng
Copy link
Member Author

Thanks for reviewing!

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.

2 participants