“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?
“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?
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 ?
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?
“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.
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
Math.sqrt(2)
result
The problem is that mathn is using the module_function method to
irb(main):042:0> module Math
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.
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
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.
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)
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.