Forum: Ruby Strange behaviour

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Javier V. (Guest)
on 2006-03-12 01:28
(Received via mailing list)
Look this:

tigre@enigma tigre $ irb
irb(main):001:0> events = {}
=> {}
irb(main):002:0> events.default = []
=> []
irb(main):003:0> events["trying"] << "hello"
=> ["hello"]
irb(main):004:0> events
=> {}
irb(main):005:0> events.inspect
=> "{}"
irb(main):006:0> events["trying"]
=> ["hello"]
irb(main):007:0> quit
tigre@enigma tigre $


why is happening this behaviour?
Jacob F. (Guest)
on 2006-03-12 02:04
(Received via mailing list)
On 3/11/06, Javier V. <removed_email_address@domain.invalid> wrote:
> => "{}"
> irb(main):006:0> events["trying"]
> => ["hello"]
> irb(main):007:0> quit
> tigre@enigma tigre $
>
>
> why is happening this behaviour?

Take a look at this for some clues:

  $ irb
  irb(main):001:0> events = {}
  => {}
  irb(main):002:0> events.default = []
  => []
  irb(main):003:0> events["trying"] << "hello"
  => ["hello"]
  irb(main):004:0> events.default
  => ["hello"]
  irb(main):005:0> events["test"]
  => ["hello"]

In short, what's happening is that when you call events["trying"] at
statement 3, it returns the default value, which is an array. You then
insert "hello" into that array and *change the default value*. Since
you never assigned to events["trying"], it still doesn't exist. You
were only getting the expected value back on re-access because of the
changed default value.

Try this instead:

  $ irb
  irb(main):001:0> events = Hash.new{ |h,k| h[k] = [] }
  => {}
  irb(main):002:0> events.default
  => []
  irb(main):003:0> events["trying"] << "hello"
  => ["hello"]
  irb(main):004:0> events.default
  => []
  irb(main):005:0> events["trying"]
  => ["hello"]
  irb(main):006:0> events["test"]
  => []
  irb(main):007:0> events
  => {nil=>[], "test"=>[], "trying"=>["hello"]}

This produces the desired behavior, but you have to be careful, since
accessing non-existent keys will pollute the keys of your hash.
Javier V. (Guest)
on 2006-03-12 02:10
(Received via mailing list)
>  => ["hello"]
>Try this instead:
>  irb(main):005:0> events["trying"]
>Jacob F.
>
>
>

Oh thanks, i really had a misunderstood on that point.
Gregory S. (Guest)
on 2006-03-12 02:13
(Received via mailing list)
This stems from a fundamental misunderstanding of how the default
attribute of a hash is used by the hash.

On Sun, Mar 12, 2006 at 08:26:05AM +0900, Javier V. wrote:
} Look this:
}
} tigre@enigma tigre $ irb
} irb(main):001:0> events = {}
} => {}

The events variable has been set to a new instance of a hash.

} irb(main):002:0> events.default = []
} => []

The events.default attribute has been set to a new instance of an array.

} irb(main):003:0> events["trying"] << "hello"
} => ["hello"]

The array in the events.default attribute is retrieved, since "trying"
is
not a key in the hash, and has "hello" appended to it.

} irb(main):004:0> events
} => {}

The events variable continues to hold an empty hash, which has a default
attribute set to ["hello"].

} irb(main):005:0> events.inspect
} => "{}"

Still empty.

} irb(main):006:0> events["trying"]
} => ["hello"]

The events.default attribute is retrieved since "trying" is not a key in
the hash. The attribute is an array which has previously had "hello"
appended to it.

} why is happening this behaviour?

This is correct behavior. The default attribute is not the default
starting
value for any key, it is the value returned when a key is not found. See
the following:

irb(main):001:0> events = {}
=> {}
irb(main):002:0> events.default = []
=> []
irb(main):003:0> events["trying"] << "hello"
=> ["hello"]
irb(main):004:0> events["nosuchkey"]
=> ["hello"]
irb(main):005:0> events.default
=> ["hello"]
irb(main):006:0> events.default.object_id
=> 403034172
irb(main):007:0> events["trying"].object_id
=> 403034172
irb(main):008:0> events["nosuchkey"].object_id
=> 403034172
Timothy H. (Guest)
on 2006-03-12 02:19
(Received via mailing list)
Javier V. wrote:
> => {}
>
The "events.default = []" statement establishes a default object to be
returned when you access a key that is not in the hash. The same object
is always returned. That is, the same array will be returned every time
you access a key that is not in the hash. Further, adding an element to
that array by fetching a non-existent key does not add the key to the
hash. The 'events["trying"] << "hello"' statement sends [] to the hash,
which returns the default array, then adds "hello" to the array. To add
a key to the hash you have to use its []= method*.

Look at this sequence for example:

irb(main):001:0> ary = []
=> []
irb(main):002:0> hsh = {}
=> {}
irb(main):003:0> hsh.default = ary
=> []
irb(main):004:0> hsh[:a] << 1
=> [1]
irb(main):005:0> hsh
=> {}
irb(main):006:0> ary
=> [1]
irb(main):007:0> hsh[:b] = 1
=> 1
irb(main):008:0> hsh
=> {:b=>1}




*Okay, for the picky, there's other ways to add a key to a hash. Work
with me here.
This topic is locked and can not be replied to.