Commutativity of '*'

Hi all,

say I have a new class Foo which provides * as a multiplicative method.
Now, given the following lines:

def some_operation_using( lft, rgt )
return "#{lft} times #{rgt}"
end

class Foo

def *( other )
# do something
res = some_operation_using( other, self )
return res
end

def to_s
return "a Foo thingy."
end

end

That given, the following lines will work

f = Foo.new
puts f * 42.0

But this won’t. Instead I get:

…/lm.rb:25:in `*’: Foo can’t be coerced into Float (TypeError)

from …/lm.rb:25

puts 42.0 * f

What would be a (or even the) Ruby Way to get the last line to work?
Some method to coerce a Foo into a Float? Or some hacking of Float
itself? Like adding that, for example:

class Float
alias old_mult *
def *( other )
if other.class == Foo
return other * self
else
return self.old_mult( other )
end
end
end

That doesn’t seem to be terribly elegant, I think.

Any other way?

Happy rubying

Stephan

# But this won't. Instead I get:
# .../lm.rb:25:in `*': Foo can't be coerced into Float (TypeError)

Well, ruby is saying that it can coerce, learn it how to do it

One way to do it

svg% cat b.rb
#!/usr/bin/ruby
def some_operation_using( lft, rgt )
   "#{lft} times #{rgt}"
end

class Foo

   def *(other)
      # do something
      res = some_operation_using( other, self )
      res
   end

   def coerce(other)
      case other
      when Numeric
         [self, other]
      else
         raise TypeError
      end
   end

   def to_s
      "a Foo thingy."
   end

end

f = Foo.new
puts f * 42.0
puts 42.0 * f
svg%

svg% b.rb
42.0 times a Foo thingy.
42.0 times a Foo thingy.
svg%

Guy Decoux

“Stephan Kämper” Stephan.Kaemper@Schleswig-Holstein.de schrieb im
Newsbeitrag news:c72lo9$hi3jp$1@ID-96582.news.uni-berlin.de

Hi all,

say I have a new class Foo which provides * as a multiplicative method.
Now, given the following lines:

def some_operation_using( lft, rgt )
return “#{lft} times #{rgt}”
end

class Foo

def *( other )
# do something
res = some_operation_using( other, self )
return res
end

def to_s
return “a Foo thingy.”
end

end

That given, the following lines will work

f = Foo.new
puts f * 42.0

But this won’t. Instead I get:

…/lm.rb:25:in `*': Foo can’t be coerced into Float (TypeError)

from …/lm.rb:25

puts 42.0 * f

What would be a (or even the) Ruby Way to get the last line to work?
Some method to coerce a Foo into a Float? Or some hacking of Float
itself? Like adding that, for example:

class Float
alias old_mult *
def *( other )
if other.class == Foo
return other * self
else
return self.old_mult( other )
end
end
end

That doesn’t seem to be terribly elegant, I think.

Any other way?

You want coerce. See my posting in thread “coerce(), what protocol to
implement it” from 30 Apr.
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/98791

Kind regards

robert

It is maybe not a good idea to reverse the order in coerce.
It may work with * and +, but you will get a problem when
order matters, like in / (division):

#— including the above code —

class Foo
def /(other)
“divide #{self} by #{other}”
end
end

puts (f / 2)
=> “divide a Foo thingy. by 2”
puts (2 / f)
=> “divide a Foo thingy. by 2”

#— end code —

Note that some classes which use *, and don’t represent a number
just give an error:

“string” * 2
=> “stringstring”
2 * “string”
=> TypeError: String can’t be coerced into Fixnum

That behaviour is probably the best if you are not representing
a number.

Kristof

···

On Sun, 02 May 2004 20:43:20 +0900, ts wrote:

#!/usr/bin/ruby
def some_operation_using( lft, rgt )
“#{lft} times #{rgt}”
end

class Foo

def *(other)
# do something
res = some_operation_using( other, self )
res
end

def coerce(other)
case other
when Numeric
[self, other]
else
raise TypeError
end
end

def to_s
“a Foo thingy.”
end

end

f = Foo.new
puts f * 42.0
puts 42.0 * f
svg%

svg% b.rb
42.0 times a Foo thingy.
42.0 times a Foo thingy.
svg%

Guy Decoux