34

I am feeling that following solution

class Fixnum
  def +(x)
    self + x + 1
  end
end

should not work, since + will be called recursively.

Stefan
  • 109,145
  • 14
  • 143
  • 218
Huang Minghe
  • 441
  • 1
  • 6
  • 12
  • 34
    Why do you want to do that? I laughed after reading the question. – Sharvy Ahmed Mar 12 '15 at 07:21
  • You've defined an instance method on `Object`: `self.class.instance_method(:+).owner #=> Object`, so you need to invoke it like this (for example): `Object.new + 3`. That's probably not what you want and it's obviously not going to work. If you write `1+2`, you are using `Fixnum#+`, because `1.class #=> Fixnum`. – Cary Swoveland Mar 12 '15 at 08:09
  • 12
    Whatever the reason, don't go down this path, man! There's still time to turn back. – rr- Mar 12 '15 at 12:01
  • 4
    @SharvyAhmed Maybe his subconscious wants to have a baby? – fredoverflow Mar 12 '15 at 12:34
  • @FredOverflow well that's a way a true programmer would go about it ;) – Konrad Morawski Mar 12 '15 at 14:52
  • The important part to take away from this question is that we can write methods using symbols, they aren't reserved for Ruby: https://gist.github.com/8f4837a817f9be36f812 – justinpage Mar 12 '15 at 19:42
  • See also http://codegolf.stackexchange.com/questions/28786/write-a-program-that-makes-2-2-5 – Digital Trauma Mar 12 '15 at 22:27
  • Yes, it's a duplicate, but I think I'm beginning to understand why--as here-- it's so common for non-Rubiest to mark a Ruby question a duplicate. None of the five duplicate-markers above seem to have answered any Ruby questions. However, one, in his profile, boasts, "Top 5 Close Voters of All Time". I had no idea there was competition for closing questions at SO. – Cary Swoveland Mar 16 '15 at 09:10

2 Answers2

28

Using alias to store the original + like this works:

class Fixnum
  alias old_plus +
  def +(x)
    old_plus(x).succ
  end
end
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 5
    using old_plus(x).old_plus(1) works too. – Huang Minghe Mar 12 '15 at 07:30
  • 3
    I don't think it is right to break all the `+` functionality, only `1 + 1 = 3` should be affected. So I suggest the new `+(x)` should be `(x == 1 && self == 1) ? 3 : old_plus(x)` – xlembouras Mar 12 '15 at 07:35
  • 2
    @xlembouras I'm sure it's only for fun, no one would use it in practice :) – Yu Hao Mar 12 '15 at 07:42
  • 20
    @YuHao at my coworker's prior workplace, someone overloaded assignment operator `=` and made it do some business logic. Then he did another hack: he added `a=a;` whose purpose was to trigger this logic. Shortly after, someone removed that obviously meaningless `a=a;` statement... boom. Magnitude of tests suddenly failed. Needless to say, it took very long time to discover the reason. – rr- Mar 12 '15 at 11:57
  • 16
    @rr-: At least you had tests. – Ilmari Karonen Mar 12 '15 at 14:34
26

Another way is to prepend a module:

module PlusOne
  def +(x)
    super.succ
  end
end

Fixnum.prepend(PlusOne)

1 + 1 #=> 3
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • 1
    you are a genius. You always have a different solution! :) – Sharvy Ahmed Mar 12 '15 at 12:37
  • Ever since prepend became a thing, I've always prefered it over overriding methods directly. Not only is it easier to do it this way, but it's also clearer and results in an inheritance chain which documents your modifications quite nicely. (E.g. `Fixnum.ancestors.first #=> PlusOne`) – Ajedi32 Mar 12 '15 at 13:36
  • One minor issue though: `prepend` is private. So either do `Fixnum.send(:prepend, PlusOne)`, or `class Fixnum; prepend PlusOne; end` – Ajedi32 Mar 12 '15 at 13:37
  • 1
    @Ajedi32 `Module#include` and `Module#prepend` are public in Ruby 2.1 and later. – Stefan Mar 12 '15 at 14:30