Project

General

Profile

Actions

Bug #19448

closed

[Hash] Using Set as default value

Added by bobanj (Boban Jovanoski) almost 2 years ago. Updated almost 2 years ago.

Status:
Rejected
Assignee:
-
Target version:
-
ruby -v:
ruby 3.1.3p185 (2022-11-24 revision 1a6b16756e) [x86_64-darwin22]
[ruby-core:112477]

Description

When using a hash and set is used as a default value, the keys method for the hash does not return expected values.
A workaround for this is provided in the attachment.


Files

bug.rb (382 Bytes) bug.rb Also contains a workaround bobanj (Boban Jovanoski), 02/17/2023 03:39 PM

Updated by byroot (Jean Boussier) almost 2 years ago

  • Status changed from Open to Rejected

This isn't a bug and is documented in Hash.new https://docs.ruby-lang.org/en/3.2/Hash.html#class-Hash-label-Default+Values

Note that the default value is used without being duplicated. It is not advised to set the default value to a mutable object:

synonyms = Hash.new([])
synonyms[:hello] # => []
synonyms[:hello] << :hi # => [:hi], but this mutates the default!
synonyms.default # => [:hi]
synonyms[:world] << :universe
synonyms[:world] # => [:hi, :universe], oops
synonyms.keys # => [], oops

To use a mutable object as default, it is recommended to use a default proc

Updated by Hanmac (Hans Mackowiak) almost 2 years ago

That's is known limitation when using Hash default value

Also your problem is that << would alter the same object you put into as default object

meaning:

h = Hash.new(Set.new)
h[:a] << 1
h[:b] << 2
p h[:c] #=> Set[1,2]

Updated by sawa (Tsuyoshi Sawada) almost 2 years ago

@byroot (Jean Boussier) (Jean Boussier), I think your comment is misleading if not irrelevant.

The issue's point is that, a key-value pair is not stored in the hash just by calling it. The relevant part in the example you cited is:

synonyms.keys # => [], oops

which is indeed not a bug.

To use a mutable object as default, it is recommended to use a default proc

is irrelevant/incomplete as a response to this issue because:

h = Hash.new{Set.new}

will not help. You have to explicitly store the key-value pair as in:

h = Hash.new{|hash, key| hash[key] = Set.new}

Updated by byroot (Jean Boussier) almost 2 years ago

@sawa (Tsuyoshi Sawada) I wasn't planning to answer the question myself, only to point the author to the detailed documentation of how Hash defaults works, so they can answer their own question.

Actions

Also available in: Atom PDF

Like0
Like1Like1Like0Like0