-
-
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 missing documentation to Hash.merge!(other : Hash, &block) #8380
Conversation
src/hash.cr
Outdated
@@ -1343,6 +1343,15 @@ class Hash(K, V) | |||
self | |||
end | |||
|
|||
# Adds the contents of *other* to this hash. | |||
# The value of each duplicate key is determined by calling the block with the key, its value in this hash and its value in *other*. |
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 little bit more verbose description, but help understanding:
# The value of each duplicate key is determined by calling the block with the key, its value in this hash and its value in *other*. | |
# If a key exists in both hashes, the given block is called to determine the value to be used. The block arguments are the key, the value in `self` and the value in *other*. |
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're right i chaged it.
src/hash.cr
Outdated
# other = { "b" => 254, "c" => 300 } | ||
# hash.merge!(other) { |key, v1, v2| v1 } | ||
# hash # => {"a" => 100, "b" => 200, "c" => 300} | ||
#``` | ||
def merge!(other : Hash, &block) |
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 can also add documentation for the block types:
def merge!(other : Hash, &block) | |
def merge!(other : Hash, & : (K, V, V) -> V) : self |
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.
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.
Wow, amazing that you digged up that old issue.
But anyway, even without recursive aliases, the type restriction is incorrect, because the generic arguments of other
don't need to equal those of self
, they can also be smaller.
For example you can merge Hash(String, Bool)
into Hash(String | Int32, Bool | Nil)
. This can't be expressed currently, but is tracked in #3803. So, yeah let's leave it for now.
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.
At least the new syntax for non-captured blocks can be used.
6d095e0
to
df48642
Compare
And now i found that i forgot non bang version with block, def merge(other : Hash(L, W), &block : K, V, W -> V | W) forall L, W. But when i try it, i found maybe a bug, at least it's very confusing. It's documented to accept other hash with any types of keys and values, but block is defined to receive type of key K as in self, but if you look at implementation, it iterates second one so it can't compile at all.
which leads to: |
@jan-zajic how about def merge(other : Hash(K2, V2), & : (K | K2, V, V2) -> V | V2) forall K2, V2 ? |
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.
Thank you! This is already a strict improvement to the documentation.
@@ -1343,7 +1343,17 @@ class Hash(K, V) | |||
self | |||
end | |||
|
|||
def merge!(other : Hash, &block) | |||
# Adds the contents of *other* to this hash. |
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.
# Adds the contents of *other* to this hash. | |
# Adds the contents of *other* to `self`. |
That would work, but I think it's to complicated. The type restriction is not necessary for technical reasons, but mainly for documentation. For improving the documentation, this looks too complex IMO. And it's confusing because it's not really for all Only benefit would be more precise error messages when using this method with non-matching types. Btw. the key in the block argument is not |
Ah, I didn't look at the implementation.... class Hash(K, V)
def merge2(other : Hash(K2, V2), & : (K2, V, V2) -> V | V2) : Hash(K | K2, V | V2) forall K2, V2
hash = Hash(K | K2, V | V2).new
hash.merge! self
other.each do |k2, v2|
if self.has_key?(k2)
hash[k2] = yield k2, self[k2], v2
else
hash[k2] = v2
end
end
hash
end
end This allows for the full type signature. That's for another PR though... That being said, I'd very much like the full type signature in the docs. That type signature encodes a lot of information, for example it's clear to see that the block is encoding a choice when you see Plus it's actually |
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.
Shall we merge?
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.
Great, thank you!
@RX14 Your code looks good. But that's actually |
@straight-shoota We were talking about the non-bang version the whole time! I was responding to @jan-zajic's comment about the non-bang version. Also, my implementation is different to the current implementation in that it uses |
@straight-shoota @RX14 yes that #8380 (comment) comment ;). Well that this is already merged. We can continue that discussion in some issue or in the forum ... |
Yeah, I was planning to make this another PR. |
Ooops, I think I got lost somewehere. |
Completely missing description in api docs for Hash.merge! method, version with block. Without description, one cannot known which arguments are passed to given block (Except Ruby programmers, of course, because it behave same).
Related to #8377.