Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re-opening an existing module and changing a method

0 views
Skip to first unread message

Aldric Giacomoni

unread,
Nov 19, 2009, 12:27:40 PM11/19/09
to
"I hear and I forget; I see and I remember; I do and I understand."
Wouldn't it be nice if it were that simple - clearly they did not know
about the subtle art of debugging.

So, I'm trying to hack at the math module.
Expected:
>> Math.sqrt(2)
=> sqrt(2)
Actual result, mileage does not vary:
>> Math.sqrt(2)
=> 1.4142135623731

require 'mathn'
module Math
alias :old_sqrt :sqrt
def sqrt x
result = old_sqrt x
if result.is_a? Float
"sqrt(#{x})"
else
result
end
end
end

puts Math.sqrt(2)

I had originally not attempted an alias, I just did "result = super x"
but it didn't really amount to much, either.
Where am I thinking about this wrong?
--
Posted via http://www.ruby-forum.com/.

Marnen Laibow-Koser

unread,
Nov 19, 2009, 12:48:42 PM11/19/09
to

Looks fine to me. Does old_sqrt actually return a Float or some other
numeric type?

Actually, why use type checking at all? Why not change the condition to
use kind_of or simply test result.to_i - result == 0 ?


Best,
--
Marnen Laibow-Koser
http://www.marnen.org
mar...@marnen.org

Jesús Gabriel y Galán

unread,
Nov 19, 2009, 1:17:03 PM11/19/09
to

The problem is that mathn is using the module_function method to
convert sqrt into an method of the Math module.
According to http://ruby-doc.org/core/classes/Module.src/M001642.html:

"Module functions are copies of the original, and so may be changed
independently"

So I think you are not redefining the module function, but the
original, which doesn't have any effect when you call Math.sqrt (this
is calling the version created by module_function). Doing this:

irb(main):042:0> module Math
irb(main):043:1> def sqrt x
irb(main):044:2> result = super x
irb(main):045:2> p [result, result.class]
irb(main):046:2> result
irb(main):047:2> end
irb(main):048:1> module_function :sqrt
irb(main):049:1> end
=> Math
irb(main):050:0> Math.sqrt 2
NoMethodError: super: no superclass method `sqrt'
from (irb):44:in `sqr

allows you to actually override the version created by
module_function, but I don't know how to then call the original, since
neither the original alias you had nor super are working. But maybe
this points you in the right direction.

Jesus.

Jesús Gabriel y Galán

unread,
Nov 19, 2009, 1:20:20 PM11/19/09
to
2009/11/19 Jesús Gabriel y Galán <jgabrie...@gmail.com>:

Got it:

irb(main):001:0> require 'mathn'
=> true
irb(main):002:0> module Math
irb(main):003:1> class << self
irb(main):004:2> alias :old_sqrt :sqrt
irb(main):005:2> end
irb(main):006:1> def sqrt x
irb(main):007:2> result = old_sqrt x
irb(main):008:2> p [result, result.class]
irb(main):009:2> result
irb(main):010:2> end
irb(main):011:1> module_function :sqrt
irb(main):012:1> end
=> Math
irb(main):013:0> Math.sqrt 2
[1.4142135623731, Float]
=> 1.4142135623731

Jesus.

Aldric Giacomoni

unread,
Nov 19, 2009, 1:35:11 PM11/19/09
to
Marnen Laibow-Koser wrote:
>
> Looks fine to me. Does old_sqrt actually return a Float or some other
> numeric type?
>
> Actually, why use type checking at all? Why not change the condition to
> use kind_of or simply test result.to_i - result == 0 ?
>
Well.. Not that it's particularly meaningful, but here's my benchmark
for that question:

require 'benchamrk'
num = 5.5
n = 5_000_000
Benchmark.bmbm do |x|
x.report("kind_of?") { n.times do ; n.kind_of? Float ; end }
x.report("is_a?") { n.times do ; n.is_a? Float ; end }
x.report("to_i") { n.times do ; n.to_i - n == 0 ; end }
end

Rehearsal --------------------------------------------
kind_of? 1.719000 0.000000 1.719000 ( 1.720000)
is_a? 1.641000 0.000000 1.641000 ( 1.642000)
to_i 2.750000 0.000000 2.750000 ( 2.751000)
----------------------------------- total: 6.110000sec

user system total real
kind_of? 1.734000 0.000000 1.734000 ( 1.735000)
is_a? 1.703000 0.000000 1.703000 ( 1.720000)
to_i 2.688000 0.000000 2.688000 ( 2.689000)

__________________

You know how metaprogramming is all about the self, according to Yehuda
Katz's latest blog post? :) I, er, forgot to do self.sqrt ...

module Math
alias_method :old_sqrt, :sqrt
def self.sqrt x
result = 5.5 #self.old_sqrt(x)


if result.is_a? Float
"sqrt(#{x})"
else
result
end
end
end


>> puts Math.sqrt(2)
=> sqrt(2)
>> puts Math.methods.find { |i| i[0..0] == "o"}
=> object_id

.. So I'm not sure how to do an alias_method on a method that's got a
"self." in front of it, I guess..
puts Math.methods.find { |i| i[0..0] == "o"}

Aldric Giacomoni

unread,
Nov 19, 2009, 1:45:06 PM11/19/09
to
Jesús Gabriel y Galán wrote:

> irb(main):003:1> class << self
> irb(main):004:2> alias :old_sqrt :sqrt
> irb(main):005:2> end

Ah-ha! My version is underneath. So, what the bit of code I quoted does
is.. It reopens "the class of the module" to make a change in the alias?

module Math

class << self
alias :old_sqrt :sqrt
end

def self.sqrt x
result = old_sqrt(x)


if result.is_a? Float
"sqrt(#{x})"
else
result
end
end
end


>> puts Math.sqrt(2)
=> sqrt(2)

Jesús Gabriel y Galán

unread,
Nov 19, 2009, 2:54:05 PM11/19/09
to
On Thu, Nov 19, 2009 at 7:45 PM, Aldric Giacomoni <ald...@trevoke.net> wrote:
> Jesús Gabriel y Galán wrote:
>
>> irb(main):003:1> class << self
>> irb(main):004:2> alias :old_sqrt :sqrt
>> irb(main):005:2> end
>
> Ah-ha! My version is underneath. So, what the bit of code I quoted does
> is.. It reopens "the class of the module" to make a change in the alias?

Yes, module_function creates a method in the singleton class of the module.
So you need to enter that singleton class via class << self to be in a
place where self is that singleton class, in order to be able to alias
that method correctly.


>
> module Math
>
>  class << self
>    alias :old_sqrt :sqrt
>  end
>
>  def self.sqrt x
>    result = old_sqrt(x)
>    if result.is_a? Float
>      "sqrt(#{x})"
>    else
>      result
>    end
>  end
> end
>
>
>>> puts Math.sqrt(2)
> => sqrt(2)

Jesus.

Julian Leviston

unread,
Nov 19, 2009, 4:07:37 PM11/19/09
to
You're doing instance methods when you really want class methods.

Good time to google the difference if you don't already know.

Julian

Blog: http://random8.zenunit.com/
Twitter: http://twitter.com/random8r
Learn: http://sensei.zenunit.com/
New video up now at http://sensei.zenunit.com/ real fastcgi rails
deploy process! Check it out now!

Aldric Giacomoni

unread,
Nov 20, 2009, 7:47:32 AM11/20/09
to
Julian Leviston wrote:
> You're doing instance methods when you really want class methods.
>
> Good time to google the difference if you don't already know.
>

Is this a new insight, or is this just putting words to what Jesus
already helped me discover (and hack) ?
Instance method : Customer.new.phone # (probably yields an error : phone
number not set)
Class method : Customer.find(:first) # (Rails-style)

Right ?

Jesús Gabriel y Galán

unread,
Nov 20, 2009, 1:33:25 PM11/20/09
to
On Fri, Nov 20, 2009 at 1:47 PM, Aldric Giacomoni <ald...@trevoke.net> wrote:
> Julian Leviston wrote:
>> You're doing instance methods when you really want class methods.
>>
>> Good time to google the difference if you don't already know.
>>
>
> Is this a new insight, or is this just putting words to what Jesus
> already helped me discover (and hack) ?

Well, people usually call class methods to methods that are defined in
the singleton class of a class.
In this case it could be a bit confusing, since we are not talking
about a class but a Module.
So I would call it a module method (or module function).

> Instance method : Customer.new.phone # (probably yields an error : phone
> number not set)
> Class method : Customer.find(:first) # (Rails-style)
>
> Right ?

Right, but it would be more clear to say module method, in my opinion.

Jesus.

Aldric Giacomoni

unread,
Nov 20, 2009, 3:07:34 PM11/20/09
to
Jesús Gabriel y Galán wrote:
>
>> Instance method : Customer.new.phone # (probably yields an error : phone
>> number not set)
>> Class method : Customer.find(:first) # (Rails-style)
>>
>> Right ?
>
> Right, but it would be more clear to say module method, in my opinion.
>
Well --

Math.sqrt(5) : Module method, because it's defined in a module
Customer.find(:first) : Class method, because it's defined in the class

Right? :)

0 new messages