Pop Quiz: aliasing versus wrapping

Below are two files that differ only in the 2nd line of code in each.
Can you guess what difference they will reveal? I must admit I was
surprised when I ran into this.

$ cat alias.rb
class Object
alias_method :to_js, :inspect
end

class Array
def to_js; “[#{map{|o|o.to_js}.join(’,’)}]”; end
end

class Hash
def to_js
“{#{map{|k,v| “#{k.to_s.to_js}:#{v.to_js}” }.join(’,’)}}”
end
end

[ 1, [true], {a:“foo”} ].each{ |o| puts o.to_js }

$ cat wrapped.rb
class Object
def to_js; inspect; end
end

class Array
def to_js; “[#{map{|o|o.to_js}.join(’,’)}]”; end
end

class Hash
def to_js
“{#{map{|k,v| “#{k.to_s.to_js}:#{v.to_js}” }.join(’,’)}}”
end
end

[ 1, [true], {a:“foo”} ].each{ |o| puts o.to_js }

2010/3/31 Phrogz [email protected]:

Below are two files that differ only in the 2nd line of code in each.
Can you guess what difference they will reveal? I must admit I was
surprised when I ran into this.

$ cat alias.rb
class Object
alias_method :to_js, :inspect
end

This one always invokes Object#inspect - unless you override #to_js
explicitly.

$ cat wrapped.rb
class Object
def to_js; inspect; end
end

This is the one you really want IMHO: #to_js delegates to whatever
#inspect is present in the class.

Pretty straightforward inheritance behavior - although I’d concede
that it’s subtle.

Kind regards

robert

On Wed, Mar 31, 2010 at 10:01 AM, Phrogz [email protected] wrote:

Below are two files that differ only in the 2nd line of code in each.
Can you guess what difference they will reveal? I must admit I was
surprised when I ran into this.

It’s pretty clear if you think of it in terms of message handlers and
method objects

class Object
alias_method :to_js, :inspect
end

This binds the message handler Object#to_js to the method object
Object#inspect. This should be illustrative:

$ cat test.rb
class Object
alias_method :to_js, :inspect
alias_method :inspect, :hash
end

a = Object.new
puts a.inspect
p a
puts a.to_js

$ ruby test.rb
67266180
67266180
#Object:0x804cd08

$ cat wrapped.rb
class Object
def to_js; inspect; end
end

This creates a new method object, which contains a thunk that sends
the message “inspect” to self when it is invoked, and binds the
Object#to_js message handler to that method object.

martin

On Mar 31, 3:19 am, Robert K. [email protected] wrote:

This one always invokes Object#inspect - unless you override #to_js explicitly.

Yes; specifically, in this case, Object#inspect on a String calls
#to_s (because it’s defined), so:
puts “foo”.to_js
#=> foo
instead of the desired “foo” (with quotes).