Skip to content
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

Implemented HashMap::try_insert #74

Merged
merged 24 commits into from
Mar 24, 2020
Merged

Implemented HashMap::try_insert #74

merged 24 commits into from
Mar 24, 2020

Conversation

GarkGarcia
Copy link
Contributor

@GarkGarcia GarkGarcia commented Mar 22, 2020

Follow up on #58.


This change is Reviewable

@GarkGarcia GarkGarcia changed the title Implemented HashMap::try_insert. Implemented HashMap::try_insert Mar 22, 2020
Copy link
Collaborator

@domenicquirl domenicquirl left a comment

Choose a reason for hiding this comment

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

Thanks, this looks good! Especially the effort you put into the documentation 😊

I've left some comments, mainly I think we should do the change to a Result return value. This None on success thing still confuses me 😅

src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map_ref.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map_ref.rs Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map_ref.rs Outdated Show resolved Hide resolved
@jonhoo
Copy link
Owner

jonhoo commented Mar 23, 2020

Ah, I saw just now that the existing insert method has docs similar to the ones I just had you rewrite :p Maybe we should update the insert docs to match the style of the new try_insert docs while we're at it?

@GarkGarcia
Copy link
Contributor Author

Ah, I saw just now that the existing insert method has docs similar to the ones I just had you rewrite :p Maybe we should update the insert docs to match the style of the new try_insert docs while we're at it?

Exactly! Gonna work on this.

@jonhoo
Copy link
Owner

jonhoo commented Mar 23, 2020

#76 has now landed!

@GarkGarcia
Copy link
Contributor Author

All done I think.

src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
@jonhoo
Copy link
Owner

jonhoo commented Mar 23, 2020

I still think we should use the TryInsertError struct I proposed earlier, since currently the user has no way to recover the value (or key) they provided in the case of a failed insert.

@jonhoo
Copy link
Owner

jonhoo commented Mar 23, 2020

See #77 for a way to recover the value.

@GarkGarcia
Copy link
Contributor Author

I still think we should use the TryInsertError struct I proposed earlier, since currently the user has no way to recover the value (or key) they provided in the case of a failed insert.

I'm not quite sold on this proposal. Although it does provide some useful functionality which is not provided in our current public API, I seems a bit cumbersome and unergonomic.

Also, since this is a public API, we'd probably have to implement the ? operator for it, besides some traits for useful conversions.

@domenicquirl
Copy link
Collaborator

Can/did you run cargo fmt --all -- --check exactly? That's what the CI task checks against.

Regarding the fields, I don't actually know; can you destructure a struct if it's fields are private? I would like the user to be able to do

match map.try_insert(&i, value, &guard) {
	Ok(new) => {...},
	Err(TryInsertError { old, not_inserted } ) => {...}
}

@GarkGarcia
Copy link
Contributor Author

Regarding the fields, I don't actually know; can you destructure a struct if it's fields are private? I would like the user to be able to do

match map.try_insert(&i, value, &guard) {
	Ok(new) => {...},
	Err(TryInsertError { old, not_inserted } ) => {...}
}

Nope, you can't. I think you can deconstruct them inside the matches! macro, but I'm not sure and that's pretty limited anyway.

@GarkGarcia
Copy link
Contributor Author

Can/did you run cargo fmt --all -- --check exactly? That's what the CI task checks against.

Just did it:

$ cargo fmt --all -- --check
Diff in ~/Documents/flurry/src/map.rs at line 135:

 #[derive(Eq, PartialEq, Clone, Debug)]
 enum PutResult<'a, T> {
-    Inserted {
-        new: &'a T,
-    },
-    Replaced {
-        old: &'a T,
-        new: &'a T,
-    },
-    Exists {
-        old: &'a T,
-        not_inserted: Box<T>,
-    },
+    Inserted { new: &'a T },
+    Replaced { old: &'a T, new: &'a T },
+    Exists { old: &'a T, not_inserted: Box<T> },
 }

 impl<'a, T> PutResult<'a, T> {

Dunno why cargo fmt hasn't fixed it by itself. Anyway, on my way to fixing it.

@domenicquirl
Copy link
Collaborator

Nope, you can't. I think you can deconstruct them inside the matches! macro, but I'm not sure and that's pretty limited anyway.

Then I'm against making them private. I think it's not worth for them to be private if we lose the destructuring

@GarkGarcia
Copy link
Contributor Author

GarkGarcia commented Mar 23, 2020

Nope, you can't. I think you can deconstruct them inside the matches! macro, but I'm not sure and that's pretty limited anyway.

Then I'm against making them private. I think it's not worth for them to be private if we lose the destructuring

Makes sense. @jonhoo what do you think?

src/map.rs Outdated Show resolved Hide resolved
@jonhoo
Copy link
Owner

jonhoo commented Mar 23, 2020

I am strongly in favor of both fields being public. We could mark it #[non_exhaustive], but I don't think even that's necessary.

@GarkGarcia
Copy link
Contributor Author

I am strongly in favor of both fields being public. We could mark it #[non_exhaustive], but I don't think even that's necessary.

Alright, public it is. Marking things as #[non_exhaustive] is good practice.

I guess the only things left to do are:

  • Polishing the documentation of TryInsertError and TryInsertResult.
  • Implementing Display and Error for TryInsertError.

src/map.rs Outdated Show resolved Hide resolved
@jonhoo
Copy link
Owner

jonhoo commented Mar 23, 2020

The biggest downside of #[non_exhaustive] is that people now must match on TryInsertError with , .., which is a bit of an ergonomic penalty. I guess the question is how likely we think it is that we'll want to change it later. I think it's fairly unlikely..?

@GarkGarcia
Copy link
Contributor Author

The biggest downside of #[non_exhaustive] is that people now must match on TryInsertError with , .., which is a bit of an ergonomic penalty. I guess the question is how likely we think it is that we'll want to change it later. I think it's fairly unlikely..?

Fair enough. Seems unlikely indeed.

src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
src/map.rs Outdated Show resolved Hide resolved
@jonhoo jonhoo merged commit f6d4eb6 into jonhoo:master Mar 24, 2020
jonhoo pushed a commit that referenced this pull request Mar 24, 2020
If an entry already exists in the map for a given key, the existing
`HashMap::insert` replaces it. That is not always what you want. This
patch adds `HashMap::try_insert`, which returns an error if the key is
already present in the map.
@GarkGarcia
Copy link
Contributor Author

GarkGarcia commented Mar 24, 2020

Thanks @jonhoo and @domenicquirl for the help! 😁️

@jonhoo
Copy link
Owner

jonhoo commented Mar 24, 2020

Thanks for taking the time to implement it, and to follow up on all our nitpicking 😅

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.

3 participants