What is the difference between Hash.new([]) and Hash.new()

class School
	def initialize
		@db = Hash.new([])
	end
	def db
		@db
	end

	def add(student_name,student_grade)

      @db[student_grade] = @db[student_grade] || Array.new
      puts @db
      @db[student_grade] << student_name
      puts @db
	end
end

This piece of code is giving me strange results. If there isn’t the key defined on the hash @db then a new array is not being allocated to the hash key instead it is picking the value of the array from previous array.

I think in Hash.new() case, each key shares the same value of the array with my piece of code.

If I use Hash.new() and the key is not present then how can I append a value to it?

From the docs:

When you pass an argument to Hash.new(argument) it will make that object the default value when trying to access any key that doesn’t exist

h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"]           #=> 100
h["c"]           #=> "Go Fish"
# The following alters the single default object
h["c"].upcase!   #=> "GO FISH"
h["d"]           #=> "GO FISH"
h.keys           #=> ["a", "b"]

# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"]           #=> "Go Fish: c"
h["c"].upcase!   #=> "GO FISH: C"
h["d"]           #=> "Go Fish: d"
h.keys           #=> ["c", "d"]

When you initialize you are creating a new hash and setting it’s default value to a new array. In your def add you trying to set @db[student_grade] to itself or a new array. However you defined the default value so @db[student_grade] will be set to the default object. I think this is what you want:

class School
  attr_reader :db # This is a lovely shortcut for def db

  def initialize
    @db = Hash.new()
  end

  def add(student_name,student_grade)
    @db[student_grade] ||= []
    # Here we are setting the key to [] unless it already exists.
    b[student_grade] << student_name
  end
end

This will give you:

> s = School.new
# => #<School:0x007ffba125ce58 @db={}> 
> s.add("Matt", "A")
# => ["Matt"] 
> s.add("Ben", "B")
# => ["Ben"] 
> s.db
# => {"A"=>["Matt"], "B"=>["Ben"]} 
> s.add("Tim", "A")
# => ["Matt", "Tim"] 
> s.db
# => {"A"=>["Matt", "Tim"], "B"=>["Ben"]} 

@DeviousDuck I understood your answer but in your h = Hash.new(“Go Fish”) example why do h.keys give only [“a”,b"] and not [“a”,“b”,“c”,“d”] ? Also in that example are h[“c”] and h[“d”] referencing the same default object?

So in the “go fish!” example h.keys is only returning the keys that have had values set to them. We never set a value for c or d, we only tried to access their values. Since we set a default value it knew what to return.

Your correct about them referencing the same default object. This is why if we try to change the object i.e. h[“c”].upcase! we end up with it being changed for everything.

Awesome. Thanks for clearing this to me.

No worries. Glad it makes sense =D