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

adds some inline docs to hash constructors #6923

Merged
merged 5 commits into from
Nov 9, 2018

Conversation

KCErb
Copy link
Contributor

@KCErb KCErb commented Oct 10, 2018

As described in #6918, here's a little documentation for hash construction.

I decided to nix the initialize docs since the other two self.new methods are wrappers to it. Let me know if that's misguided.

I'm open to adding in docs for other initialization methods (JSON, YAML), I would just need to actually learn about them (haven't used them myself) so it would slow this down a little.

@wooster0
Copy link
Contributor

Run crystal tool format to format your code and fix CircleCI.

@jkthorne
Copy link
Contributor

@KCErb Thank you for more docs it is great to have these filled out.
I think integers could be confusing because it looks like array indexing. Using something like Strings might implicitly show that these are different then Arrays.

@KCErb
Copy link
Contributor Author

KCErb commented Oct 10, 2018

@r00ster91 Thanks for the pointer, forgot that that runs on doc comments too!
@wontruefree Good point, I changed the examples a bit to address it.

@jkthorne
Copy link
Contributor

@KCErb looks good thanks for the docs :)

src/hash.cr Outdated
@@ -23,10 +24,36 @@ class Hash(K, V)
@block = block
end

# Creates a new empty `Hash` of *initial_capacity* with a *block* that handles missing keys.
Copy link
Member

Choose a reason for hiding this comment

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

I'd remove of *initial_capacity* from this sentence. It's explained in the next.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

src/hash.cr Outdated
@@ -13,6 +13,7 @@ class Hash(K, V)
@last : Entry(K, V)?
@block : (self, K -> V)?

# :nodoc:
Copy link
Member

Choose a reason for hiding this comment

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

Why is this nodoc?

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 decided to nix the initialize docs since the other two self.new methods are wrappers to it. Let me know if that's misguided.

Copy link
Member

Choose a reason for hiding this comment

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

No, this overload should also be publicly documented.

Copy link
Contributor

Choose a reason for hiding this comment

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

@KCErb ping

src/hash.cr Outdated
# of the maximum number of elements a hash will hold, the hash should
# be initialized with that capacity for improved performance.
#
# NOTE: *initial_capacity* defaults to 11 and an input of < 11 is ignored.
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this should be a NOTE. Just write that the default and minimal number is 11.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

src/hash.cr Outdated
# Creates a new empty `Hash` of *initial_capacity* with a *block* that handles missing keys.
#
# The *initial_capacity* is useful to avoid unnecessary reallocations
# of the internal buffer in case of growth. If you have an estimate
Copy link
Member

Choose a reason for hiding this comment

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

API docs usually don't address the reader directly.

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 just copied and pasted this from the Array docs. Not totally sure it's entirely accurate here since I know that bucket size also is used for determining when to rehash. Should I mostly keep it as is but change the voice to avoid "I, me, you" stuff? Should I update the Array docs while I'm at it?

src/hash.cr Outdated
# be initialized with that capacity for improved performance.
#
# NOTE: *initial_capacity* defaults to 11 and an input of < 11 is ignored.
# NOTE: `#size` does not reflect capacity as in `Array`.
Copy link
Member

Choose a reason for hiding this comment

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

Is this comment really useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe? It surprised me for just a second before I realized that this makes sense / is obvious, so I decided to make a note in the docs. Happy to remove it.

src/hash.cr Outdated
# NOTE: `#size` does not reflect capacity as in `Array`.
#
# ```
# new_hash = Hash(String, Int32).new(50) do |hash, key|
Copy link
Member

Choose a reason for hiding this comment

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

I would leave the initial capacity out of this example, as it doesn't make sense here.

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 would like to include it since it's one of the args to the method I'm trying to demo. I like the example to show exactly how and where to use the argument. But I agree, it's a pretty pointless example. Is there a way to demo with a meaningful example?

src/hash.cr Outdated
# end
# new_hash.size # => 0
# new_hash["zero"] = 0
# new_hash["two"] = 2
Copy link
Member

Choose a reason for hiding this comment

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

These two lines don't really help illustrate the purpose. I think this would be a better example:

hash = Hash(String, Int32).new do |hash, key|
  hash[key] = key.size
end

hash.size        # => 0
hash["foo"]      # => 3
hash.size        # => 1
hash["bar"] = 10
hash["bar"]      # => 10

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good to me. I was also thinking of borrowing the "go fish" example used in the Ruby docs. Does anyone want to comment on the value of that example as opposed to this one?

They also had one where you used the block feature to essentially use the hash as a cache for some kind of calculation that can be done using the key alone. But I wondered if that was too abstract.

src/hash.cr Show resolved Hide resolved
@KCErb
Copy link
Contributor Author

KCErb commented Oct 22, 2018

Is this one waiting on something from me? I think I've responded to all of the comments. :)

@KCErb
Copy link
Contributor Author

KCErb commented Oct 26, 2018

@straight-shoota most recent commit addresses the issues you brought up, thanks for the thorough review.

These initializers overlap in interesting ways, so I was a little conflicted on how best to describe the main purpose of each without being repetitive. Ultimately I decided to move the initialize definition beneath the two new overrides which is probably unorthodox. But I think the result pushes this in the right direction.

@RX14
Copy link
Contributor

RX14 commented Oct 26, 2018

@KCErb please don't reorder here - being repetitive and copy/pasting is fine.

@KCErb
Copy link
Contributor Author

KCErb commented Nov 6, 2018

Sorry for the slow cycle on this one, I've been much busier than I expected. I restored the order of the initializers and decided to add an example for the first one since it will be the first that a person sees.

src/hash.cr Outdated
# Creates a new empty `Hash` with a *block* for handling missing keys.
#
# ```
# def foo(&block : (Hash(String, Int32), String -> Int32))
Copy link
Member

Choose a reason for hiding this comment

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

This example is too complicated. You don't need a method to demonstrate it. Use the same code as in the next example, but with a proc literal.

src/hash.cr Outdated
# ```
#
# The *initial_capacity* is useful to avoid unnecessary reallocations
# of the internal buffer in case of growth. If the maximum number of elements
Copy link
Member

Choose a reason for hiding this comment

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

initial_capacity should rather be set to the minimum or some number that is very likely to be reached. If you assign the maximum, it could easily lead to regular allocations way beyond the required capacity, hence wasting memory.

Copy link
Member

Choose a reason for hiding this comment

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

Ditto below. And this paragraph should also be added to the third overload.

@KCErb
Copy link
Contributor Author

KCErb commented Nov 6, 2018

@straight-shoota thanks for your patience and feedback! I changed the first example to a proc literal as suggested and reworded the note about initial capacity to simply say that if the number of elements is known then this is helpful.

@bcardiff bcardiff merged commit c7181be into crystal-lang:master Nov 9, 2018
@bcardiff
Copy link
Member

bcardiff commented Nov 9, 2018

Thanks @KCErb for improving adding docs here.

Welcome to the contributors list 🎉

@bcardiff bcardiff added this to the 0.27.1 milestone Nov 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants