Ruby: overload operator behaviour for some cases only - ruby

My question is: how do I overload an operator on a builtin class (such as Integer.new.+) but only for some cases, depending on the class of the second operand
This is the behaviour I'm looking for:
myObject = myClass.new
1 + myObject #=> special behaviour
1 + 2 #=> default behaviour (3)
For example, in Python I would define a __radd__ method on myClass to override case 1.
I've tried using super but apparently Numeric doesn't have operator methods.
Ideally, what I'm looking for is a way to extract the + method and rename it.
Like this:
class Integer
self.plus = self.+ # you know what i mean, I don't know how else to express this.
# I also know that methods don't work like this, this is just to
# illustrate a point.
def + other
other.class == myClass ? special behaviour : self.plus other
end
end
Thanks for your help

Both approaches posted here so far are a legacy Rails way, which is plain wrong. It relies on the fact that the class has no method called plus and nobody will reopen the class to create a method called plus. Otherwise things will go mad.
The correct solution is Module#prepend:
Integer.prepend(Module.new do
def + other
case other
when Fixnum then special_behaviour
else super(other)
end
end
end)

Yes, you can override the behavior of almost anything in the standard library to achieve an outcome, but that's going to hurt understanding of the code and come back to bite you sometime in the future.
In this particular case, Fixnum#+ is designed to take a numeric value and return a numeric result. If we want to define our own classes to interact with Fixnum#+, we need to understand the design contract and adhere to it.
The general convention in Ruby is to use duck typing. We don't care about the class of the object, we just care whether it behaves like / can be converted to the object we want. Eg:
class StringifiedNumber
def initialize(number)
#number = number
end
# String#+ calls to_str on any object passed to it
def to_str
# replace with number to string parsing logic
"one hundred"
end
end
> "total: " + StringifiedNumber.new(100)
=> "total: one hundred"
Things are a bit more complex with numbers since you may mix integers, floats, complex numbers, etc. The convention to handle this is to define a coerce method which returns two elements of the same type which are then used to perform the requested operation.
class NumberfiedString
def initialize(string)
#string = string
end
def to_i
# replace with complicated natural language parsing logic
100
end
def +(other_numberfied_string)
NumberfiedString.new(self.to_i + other_numberfied_string.to_i)
end
# For types which are not directly supported,
# Fixnum#+(target) will call the equivalent of
# target.coerce[0] + target.coerce[1]
def coerce(other)
[NumberfiedString.new(other.to_s), self]
end
end
> NumberfiedString.new("one hundred") + NumberfiedString.new("one hundred")
=> #<NumberfiedString:0x007fadbc036d28 #string=200>
> 100 + NumberfiedString.new("one hundred")
=> #<NumberfiedString:0x007fadbc824c88 #string="200">
To answer OP's follow up question:
Is there no equivalent to Python's radd and related methods? (Where,
if the first operand doesn't support the operation or the types, the
second operand takes over)
class MyClass
def +(other)
puts "called +"
end
def coerce(other)
[self, other]
end
end
> 1 + MyClass.new
called +
=> nil

Related

Template methods in ruby

Simple question:
In java you can define :
void myFunction<T>(T value) { //do stuff }
Is there an equivalent in ruby, and if not, how can I achieve a similar result (passing class types?)
You can pass a class to a method just like passing normal objects. For example
def create_object(klass, *args)
klass.new(*args)
end
create_object(String) #=> ""
create_object(Hash) #=> {}
create_object(Array, 3, :hello) #=> [:hello, :hello, :hello]
First a few definitions
Generics is an abstraction over types
Polymorphism is a sum-type pattern
Composition is a product-type pattern
Most OO languages lean towards polymorphism
Ruby is an OO language. Polymorphism is at the core of its design. The type system in Ruby is only getting strong in Ruby 3. So we may see more interesting generics at that point; but until now, I haven't heard that to be a feature.
To achieve this, we technically need to figure out a way of applying a method on separate types without knowing the type. It's a lot of code duplication is possible.
Your Java example…
void myFunction<T>(T value) { //do stuff }
…can be translated into Ruby as
def myFunction(value)
raise "Only works with T types" unless value.is_a? T
# do stuff
end
Where the magic now has to happen is in defining the possible set of T. I'm thinking something like…
class T
def _required_for_MyFunction()
raise "T is abstract!"
end
end
class Something < T
def _required_for_MyFunction()
# does something
end
end
class Nothing < T
def _required_for_MyFunction()
# does nothing
end
end
The painful part of polymorphism is that you have to define your type space from the get-go. The good parts of this is you have total control of the domain space.
Ruby follows duck typing. You can pass arguments of any class to any method (which is the original reason why you might need generics). If you want to get the class of said argument, you can still use #class
def foo(bar)
bar.class
end
foo 'baz' # => String
foo 42 # => Fixnum

What is Replace Conditional with Polymorphism Refactoring? How is it implemented in Ruby?

I recently came across the Replace Conditional with Polymorphism Refactoring while asking for elimination of if..else conditional in ruby.the link
Can anybody explain to me how can i implement the same in ruby?(A simple sweet code would do)
The Replace Conditional with Polymorphism Refactoring is rather simple and it is pretty much exactly what it sounds like. You have a method with a conditional like this:
def speed
case #type
when :european then base_speed
when :african then base_speed - load_factor * #number_of_coconuts
when :norwegian_blue then if nailed? then 0 else base_speed(#voltage) end
end
and you replace it with polymorphism like this:
class European
def speed
base_speed
end
end
class African
def speed
base_speed - load_factor * #number_coconuts
end
end
class NorwegianBlue
def speed
if nailed? then 0 else base_speed(#voltage)
end
end
You can apply the Refactoring again to NorwegianBlue#speed by creating a subclass of NorwegianBlue:
class NorwegianBlue
def speed
base_speed(#voltage)
end
end
class NailedNorwegianBlue < NorwegianBlue
def speed
0
end
end
Voilà, all your conditionals are gone.
You might ask yourself: does this always work? Can I always replace an if with message dispatch? And the answer is: yes, you can! In fact, if you didn't have if, you can implement it yourself using nothing but message dispatch. (This is, in fact, how Smalltalk does it, there are no conditionals in Smalltalk.)
class TrueClass
def iff(thn:, els: ->{})
thn.()
end
def &
yield
end
def |
self
end
def !
false
end
end
class FalseClass
def iff(thn:, els: ->{})
els.()
end
def &
self
end
def |
yield
end
def !
true
end
end
(3 > 4).iff(thn: ->{ 'three is bigger than four' }, els: ->{ 'four is bigger than three' } )
# => 'four is bigger than three'
true.& { puts 'Hello' }
# Hello
true.| { puts 'Hello' }
# => true
Also relevant: the Anti-IF Campaign
I think I would format the bolded phrase a little differently, i.e.: Refactor your code to replace the conditional with polymorphism.
If that is indeed what the comment is supposed to mean, then Yehuda Katz has a great post giving an example in ruby:
http://yehudakatz.com/2009/10/04/emulating-smalltalks-conditionals-in-ruby/
Basically, the argument is that an if/else statement exists to execute different code based on the value of a boolean. It requires special syntax, and is limited to only the types TrueClass/FalseClass (or Object/NilClass if you're being lax about truthiness). Dynamic dispatch on the other hand performs the same operation of selecting branches of code to execute based on the value of an object, but it does not rely on specialized syntax, nor is it limited to any specific group of types.

Why can't I override the * method in Ruby?

I'm working on a Ruby Gem for creating presentations, and I would like to create a syntax for defining slides that is simple and intuitive. I'm making use of instance_eval so I can call methods on self. Here's what I originally planned to do:
slide {
title 'What is Ruby?'
* 'a programming language'
* 'with lots of interpreters'
* 'lots of fun!'
}
Even though I've defined a * method, I get the error:
in `instance_eval': ... syntax error, unexpected '\n', expecting :: or '[' or '.' (SyntaxError)
I have compromised by creating a short method called b for creating bullets, but it's not as nice:
slide {
title 'What is Ruby?'
b 'a programming language'
b 'with lots of interpreters'
b 'lots of fun!'
}
Is this just a limitation of the interpreter? Or is there a way to get around it?
Update: If you want, you can dig into the full source code, but here is a small example of how it is implemented:
class Slide
attr_accessor :title, :bullets
end
class SlidesDSL
attr_accessor :slides
def slide
#slides ||= []
s = SlideDSL.new
s.instance_eval(&block)
#slides << s.slide
end
class SlideDSL
def slide
#slide ||= Slide.new
end
def title(text)
slide.title
end
def *(text)
bullet(text)
end
def b(text)
slide.bullets ||= []
slide.bullets << text
end
end
end
# load_slides_from_file
source = File.read(filename)
dsl = SlidesDSL.new
dsl.instance_eval(source, filename, 0)
#slides = dsl.slides
It seems that you are relying on syntactic sugar that is given to the
* method for many things.
That's not the case. You can do this:
class Dog
private
def do_stuff(arg)
puts 2 + arg
end
end
d = Dog.new
d.instance_eval do
do_stuff(3)
end
--output:--
5
instance_eval() changes self to its receiver, d in this case.
In Ruby, private only means you cannot call the method with an explicit receiver.
A method call without an explicit receiver implicitly uses self as the receiver.
Now if you change the method's name from do_stuff to *:
class Dog
private
def *(arg)
puts 2 + arg
end
end
d = Dog.new
d.instance_eval do
*(3)
end
--output:--
1.rb:13: syntax error, unexpected '\n', expecting tCOLON2 or '[' or '.'
So the op is relying on normal method operation, not any syntactic sugar attributed to *. Inside the instance_eval block, you would expect Ruby to implicitly execute:
self.*(3)
which is equivalent to:
d.*(3)
Yes, this is a limitation of the Ruby grammar. Specifically, you cannot, as sawa points out, use it with an implicit receiver (nor turn into a unary operator): it expects something on the left hand side.
All operators are simply methods called on the object referenced before it, but some operators are more equal than others. Most methods accept an implicit receiver, but the one named * doesn't.
I opted for o in a similar situation.
-- Added later (as I originally commented on 7stud's post):
The problem is that the Ruby parser (Yacc grammar + a bunch of methods) simply does not allow a line starting with a * to be parsed such that the * denotes a method call. If a line starts with a *, the only possible parsing is one where the * is the 'splat' operator. This limitation is unique to the * character used as a method name.
If instead of using *, you are willing to use - (or +), you can achieve a very similar result by overloading the unary minus (or plus) operators on String. The following code automatically defines, and undefines unary - on string, so it works during the block but doesn't change any definition when the block is finished. Note that if a method is called inside the block, the - will still use the custom behaviour. This isn't much of an issue though, as there isn't a default definition for unary - for Strings. It could also be useful for extracting common code.
class Slide
attr_accessor :title, :bullets
end
class SlidesDSL
attr_accessor :slides
def slide(&block)
#slides ||= []
s = SlideDSL.new
old_unary_minus = String.instance_method(:-#) rescue nil
begin
String.send(:define_method, :-#) do
s.b(self)
end
s.instance_eval(&block)
ensure
String.send(:remove_method, :-#)
if old_unary_minus
String.send(:define_method, :-#) do
old_unary_minus.bind(self).call
end
end
end
#slides << s.slide
end
class SlideDSL
def slide
#slide ||= Slide.new
end
def title(text)
slide.title = text
end
def *(text)
bullet(text)
end
def b(text)
slide.bullets ||= []
slide.bullets << text
end
end
end
Example usage:
SlidesDSL.new.slide do
title "Some title"
- "one value"
- "another value"
4.times do |i|
- "repeated value #{i}"
end
end
Returns:
[#<Slide:0x007f99a194d0f8 #bullets=["one value", "another value", "repeated value 0", "repeated value 1", "repeated value 2", "repeated value 3"], #title="Some title">]
It looks like the * method has to be "anti-private". With the predefined method * on numerals, you can observe this.
3.instance_eval{*} # => syntax error, unexpected '}', expecting '='
3.instance_eval{*()} # => syntax error, unexpected '}', expecting :: or '[' or '.'
3.instance_eval{self.*} # => wrong number of arguments (0 for 1)
It looks like * is hard-wired to require an explicit receiver.
It seems that you are relying on syntactic sugar that is given to the * method for many things.
If you write your * method and use it with the implicit . to indicate it is a message to the receiver, you may have better luck.
For instance, when I do this with Fixnum
class Fixnum
def *
"This is the modified star"
end
end
When I try this in IRB
>> 1 * 1
ArgumentError: wrong number of arguments (1 for 0)
I would also get the normal problem of having it recognize the * if I were to simply press enter... it would expect more input on the next line...
However, if I do this:
>> 1.*
=> ""This is the modified star"
So it isn't that it is impossible to do, you may just be fighting with syntactic sugar that evolves around this particular symbol.
Consider the private method, which you can do, but you would have difficulties using the 'eval' family of calls. You could instead do this:
some_instance.send(:*)
If, of course, there is an argument needed, we can do some_instance.send(:*, argument)

Trying to create a method that chooses a random method from that same class

Maybe this is a stupid idea... I am new to Ruby (and to OOP, so I still dont really know what I am doing most of the time), and I thought of a small, fun project to build, and I am struggling with some concepts.
What I am building is basically a string manipulator. I am building a module with extra methods, and then including that on the String class.
My module has several methods that manipulate the strings in different ways, mostly replacing words, and then return the modified string.
What I want to do in order to make the string manipulation more 'spontaneous' and natural, is to create a "main" method (the one I will be calling from the strings), that randomly selects one of the string manipulation methods, and then returns the string (and then can be called again to apply several manipulations in one go)
How can I do this, or something similar? Hope I explained myself
Thanks
O.
Here's the random manipulation module, as you described it. something_random is the main method:
module RandomStringManipulation
def something_random
methods = RandomStringManipulation.instance_methods
methods -= [:something_random]
send methods.sample # Ruby >= 1.9 required. See below for Ruby 1.8.
end
def foo
self + "foo"
end
def bar
self + "bar"
end
end
Mix it into String:
class String
include RandomStringManipulation
end
Now we can create an empty string, and then do something random to it a few times, printing it out each time:
s = ""
4.times do
s = s.something_random
p s
end
# => "foo"
# => "foobar"
# => "foobarbar"
# => "foobarbarfoo"
There are two bits that are interesting. The first is this:
methods -= [:something_random]
That removes :something_random from the array methods, preventing the *something_random* method from calling itself. The second interesting bit is this:
send methods.sample
Array.sample (Ruby >= 1.9) selects a random method. send then dispatches that method. In Ruby 1.8, do this instead:
send methods[rand(methods.size)]
If all the code that will be using your functionality is your code, I would make a new class instead of monkey-patching String. Monkey-patching leads to code that is harder to understand and share.
Anyway, given a list of mutator methods, you can easily pick one at random and use Object#send to call it:
module StringMutator
def fold() ... end
def spindle() ... end
def mutilate() ... end
end
class NiftyString
include StringMutator
def random_change()
im = StringMutator.instance_methods
self.send im[rand im.length]
end
end

Optimal Design of a Ruby Data Structures Library

I am working with data structures fundamentals in Ruby for learning at the CS sophomore/junior level.
My question: Given the following code, does anyone see any design issues with this approach to a data structures library in Ruby? Especially the Module#abstract_method. Is it okay to do this in terms of duck typing philosophy? Does this make the code clearer for people from static languages and give some semblance of an interface?
class Module
def abstract_method(symbol)
module_eval <<-"end_eval"
def #{symbol.id2name}(*args)
raise MethodNotImplementedError
end
end_eval
end
end
class AbstractObject < Object
abstract_method :compare_to
protected :compare_to
class MethodNotImplementedError < StandardError; end
def initialize
super
end
include Comparable
def <=>(other)
if is_a?(other.class)
return compare_to(other)
elsif other.is_a?(self.class)
return -other.compare_to(self)
else
return self.class <=> other.class
end
end
end
# methods for insertion/deletion should be provided by concrete implementations as this behavior
# is unique to the type of data structure. Also, concrete classes should override purge to discard
# all the contents of the container
class Container < AbstractObject
include Enumerable
def initialize
super
#count = 0
end
attr_reader :count
alias :size :count
# should return an iterator
abstract_method :iter
# depends on iterator object returned from iter method
# layer of abstraction for how to iterate a structure
def each
i = iter
while i.more?
yield i.succ
end
end
# a visitor provides another layer of abstraction for additional
# extensible and re-usable traversal operations
def accept(visitor)
raise ArgumentError, "Argument must be a visitor" unless visitor.is_a?(Visitor)
each do |obj|
break if visitor.done?
visitor.visit(obj)
end
end
# expected to over-ride this in derived classes to clear container
def purge
#count = 0
end
def empty?
count == 0
end
def full?
false
end
def to_s
s = ""
each do |obj|
s << ", " if not s.empty?
s << obj.to_s
end
self.class + "{" + s + "}"
end
end
class List < Container
def initialize
super
end
def compare_to(obj)
"fix me"
end
end
A few remarks:
Defining a method that only raises a NotImplemented error is somewhat redundant, since Ruby will do that anyway if the method does not exist. The code you wrote there is just as useful as simply putting a comment to say "You must implement a method called compare_to". In fact that is what the Enumerable module in Ruby's standard library does - in the documentation it specifically says that in order to use the functionality in Enumerable you must define an each() method.
a compare_to method is also redundant, since that is precisely what the <=> operator is for.
Using an actual iterator object is a bit overkill in Ruby, since blocks tend to have a much more elegant and simple approach. Same goes for your visitor pattern - you don't need to use a visitor for "extensible and re-usable traversal operations" when you can just pass a block to a traverse method. For example you have many of them in Enumerable: each, each_with_index, map, inject, select, delete_if, partition, etc. All of these use a block in a different way to provide a different type of functionality, and other functionality can be added on in a fairly simple and consistent way (especially when you have open classes).
Regarding interfaces, in Ruby (and pretty much any other dynamic language, like Python) people usually use interfaces that are implicit, which means that you don't actually define the interface in code. Instead you typically rely on documentation and proper testing suites to ensure that code works well together.
I think that your code may be more coherent to someone coming from a Java world because it sticks to the "Java way" of doing things. However to other Ruby programmers your code would be confusing and difficult to work with since it doesn't really stick to the "Ruby way" of doing things. For example, an implementation of a select function using an iterator object:
it = my_list.iter
results = []
while it.has_next?
obj = it.next
results << obj if some_condition?
end
is much less clear to a Ruby programmer than:
results = my_list.select do |obj|
some_condition?
end
If you would like to see an example of a data structures library in Ruby, you can see the algorithms gem here: http://rubydoc.info/gems/algorithms/0.3.0/frames
Also take a look at what is provided by default in the Enumerable module: http://www.ruby-doc.org/core/classes/Enumerable.html. When you include Enumerable you receive all of these functions for free.
I hope this helps!

Resources