2

I'd like to try using Ruby in a more functional style, in which common operators are replaced with methods. I saw an example of this in Volt Framework where Object#or is used in place of ||, e.g.

x.or(y) == x || y

... which is implemented as

class Object
  def or(other)
    if self && !self.nil?
      self
    else
      other
    end
  end
end

Volt also implements Object#and. It would be nice to extend the same idea to other operators, like

x.eq(y)    == (x == y)
x.lt(y)    == x < y
x.times(y) == x * y
x.exp(y)   == x ** y

Arel::Predications are a nice collection of these for ActiveRecord attributes, but not for generic objects.

Are there any libraries or other examples available for this approach?

The only objection to it that I can think of is that it pollutes the Object namespace, risking collisions down the inheritance chain. (This could be minimized with a naming strategy, like Object#_or.) Are there other problems with it?

Mori
  • 27,279
  • 10
  • 68
  • 73
  • 4
    The main problem here `or` it is ruby `keyword` and i think it is bad practice use ruby `keyword` as method name. – Roman Kiselenko Jan 25 '15 at 08:31
  • 2
    Replacing method names is not a functional style. Those boolean operators (||, &&, !) and equality/inequality operators are themselves methods. Remember, that everything in Ruby is an object. If you want something resembling functional style, try to think about passing around small pieces of unevaluated code. Checkout blocks, procs and lambdas. – Simon Polak Jan 25 '15 at 10:54
  • 1
    For comparing objects, I would include Comparable mixin into my custom objects http://www.ruby-doc.org/core-2.2.0/Comparable.html – Simon Polak Jan 25 '15 at 11:02
  • 2
    @blushrt: No, `||`, `&&`, `and`, and `or` are *not* methods. That is very unfortunate, because it breaks Ruby's object-orientation in many ways. For example, one of the basic tenets of OO is simulation (in fact, OO was born out of simulation, the very first OO language was the simulation language Simula). You can always make an object which simulates another object. But that is not true in Ruby: you cannot make an object that simulates `false`, because `&&`, `||`, `and`, `or`, `if`, `while`, etc. are hardcoded for `false` (and `nil`). – Jörg W Mittag Jan 25 '15 at 11:16
  • @JörgWMittag, ahhh I see, I mixed boolean operators with bitwise operators, which are methods. I see I can not even instantiate FalseClass in ruby... Oh well, I think OO programming is a big misconception about the world and how programs should be written. Putting data and operations on that data in the same place is the root of the problem in OO. – Simon Polak Jan 25 '15 at 12:31

2 Answers2

2

You have some of these in Ruby already.

There's a.eql?(b) and a.equal?(b) for equality, and you can even redefine the == and === methods. There's some nuance to what "equality" means exactly – see What's the difference between equal?, eql?, ===, and ==?.

The mathematical operators are methods: you can do 1.*(2) and you can redefine it:

class Fixnum
  def *(other)
    self + other
  end
end

2 * 5  # => 7
Community
  • 1
  • 1
Henrik N
  • 15,786
  • 5
  • 82
  • 131
2

The problem with or and and is that they're guaranteed to be short circuited. Due to Ruby's evaluation strategy it's impossible to implement these methods as a part of a library.

Other methods are, of course, possible, but I don't think it's a good idea. First of all, declaring, say, the method + on the class Object forces all the subclasses to implement the method, even if it doesn't make sense. What's User.find(1) + User.find(2)? Interface segregation principle warns you agains it. And secondly, you wouldn't have the syntactic sugar of the + method, you'd need to call it using the dot notation. Well, it's not really true for +, but I think you got the idea. Symbolic functions, like a >>= b aren't possible.

shock_one
  • 5,845
  • 3
  • 28
  • 39