Reputation: 45
Why is the output of the program:
require 'set'
class Set
alias :old_add :add
def add(arg)
arg = 5
old_add arg
end
end
s = Set.new ([1,2])
s.add(3)
puts s.inspect
being
#<Set: {5}>
as opposed to
#<Set: {1,2,5}>
The method add
is redefined to run with argument 5
.
Upvotes: 0
Views: 66
Reputation: 118271
Looking at the source of Set::new
:
# File set.rb, line 80
def initialize(enum = nil, &block) # :yields: o
@hash ||= Hash.new
enum.nil? and return
if block
do_with_enum(enum) { |o| add(block[o]) }
else
# you did not supply any block, when you called `new`
# thus else part will be executed here
merge(enum)
end
end
it seems that Set.new
calls method #add
internally. In the OP's example, block
is nil
, thus #merge
is called:
# File set.rb, line 351
def merge(enum)
if enum.instance_of?(self.class)
@hash.update(enum.instance_variable_get(:@hash))
else
# in your case this else part will be executed.
do_with_enum(enum) { |o| add(o) }
end
self
end
Hence add
is called for each element of enum
([1,2]
). Here, you overrode the original #add
method, and within that method, you are calling the old #add
method with the argument 5
.
Set implements a collection of unordered values with no duplicates. Thus even if you added 5
twice, you are getting only one 5
. This is the reason you are not getting #<Set: {1,2}>
, but #<Set: {5}>
. As below, when you call Set.new
, the object #<Set: {5}>
is created just as I explained above:
require 'set'
class Set
alias :old_add :add
def add(arg)
arg = 5
old_add arg
end
end
s = Set.new ([1,2])
s # => #<Set: {5}>
When you called s.add(3)
, your overridden add
method was called, and it again passed the 5
to the old add
method. As I said earlier, Set
doesn't contain duplicate values, thus the object will still be the same as the earlier #<Set: {5}>
.
Upvotes: 2
Reputation: 20125
When you instantiate a new set with given members, the members are added using the add
method. This can be shown by investigating the set after creating it:
Set.new([1,2])
# => #<Set: {5}>
Thus, when you do s.add(3)
you basically add 5
again, which has already been added twice to the set and therefore the method doesn't actually change the set.
Upvotes: 0