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

Add entry for No Mutable Defaults #955

Merged
Merged
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
39 changes: 39 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4294,6 +4294,45 @@ hash = { one: 1, two: 2, three: 3 }

Avoid the use of mutable objects as hash keys.

=== No Mutable Defaults [[no-mutable-defaults]]

Avoid the use of shared mutable objects as hash default values.

Creating a Hash in such a way will share the default value
across all keys, causing unexpected behavior when modifying it.

For example, when the Hash was created with an Array as the argument,
calling `hash[:foo] << 'bar'` will also change the value of all
other keys that have not been explicitly assigned to.

[source,ruby]
----
# bad
Hash.new([])
Hash.new({})
Hash.new(Array.new)
Hash.new(Hash.new)

# okay -- beware this will silently discard mutations and only remember assignments
Copy link
Contributor

@andyw8 andyw8 Nov 30, 2024

Choose a reason for hiding this comment

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

Are there any legitimate uses for this? Can we say 'probably bad' instead of 'okay'?

This can be discussed in rubocop/rubocop#13463 instead.

Hash.new { Array.new }
Hash.new { Hash.new }
Hash.new { {} }
Hash.new { [] }

# good - frozen solution will raise an error when mutation is attempted
Hash.new([].freeze)
Hash.new({}.freeze)

# good - using a proc will create a new object for each key
h = Hash.new
h.default_proc = ->(h, k) { [] }
h.default_proc = ->(h, k) { {} }

# good - using a block will create a new object for each key
Hash.new { |h, k| h[k] = [] }
Hash.new { |h, k| h[k] = {} }
----

=== Hash Literals [[hash-literals]]

Use the Ruby 1.9 hash literal syntax when your hash keys are symbols.
Expand Down