2

Consider

class Container

  def initialize(value = 0)
    @value = value
  end

  def + (other)
    return @value + other
  end

  def - (other)
    return @value - other
  end

  def * (other)
    return @value * other
  end

  def / (other)
    return @value / other
  end

  def get
    return @value
  end

end

I would like to use += to increase the value in the container, like this:

c = Container.new(100)
c += 100
print c.get   # Expecting  200

The above won't work, as 100 will overwrite c.

I know I could use something like an attr_accessor to generate a getter and setter for the value, but I'm curious if I could do this in a prettier way such as using +=.

Saturn
  • 17,888
  • 49
  • 145
  • 271

3 Answers3

10

Since c += 100 is just a sugar for c = c + 100, you can't escape overwriting c. BUT you can overwrite it with a similar object (and not with fixnum, as in your question).

class Container
  def initialize(value = 0)
    @value = value
  end

  def + (other)
    Container.new(@value + other)
  end

  def get
    @value
  end
end

c = Container.new(100)
c += 100
c.get # => 200
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 3
    It's an incredibly bad idea to make `+` mutate the object. `+` should return a new object with the increased value. The way you implemented it, writing `d = c + 100` would change `c` as well as `d`. – sepp2k Sep 06 '13 at 18:58
  • 1
    right, my bad. Amending – Sergio Tulentsev Sep 06 '13 at 18:58
3

x += y is just syntactic sugar for x = x + y. So you only have to implement + in your class and you get += for free.

Mori
  • 27,279
  • 10
  • 68
  • 73
  • 4
    Correct, however in this case the `+` method returns the result of the added value, and not the instance that implements the method. Which means `c += 100` would change `c` to a totally different type of object, from a `Container` to a number. I'm guessing this isn't what @Omega wants. – Alex Wayne Sep 06 '13 at 18:50
1

No, you can't overload +=. See list of ruby operators that can be overridden/implemented for the full list of overloadable operators.

In Ruby x += y always means x = x + y. The only way to change the meaning of += for a given x is overriding + in x.class. However, + has a different semantics, and the user most probably expects that + returns a new object. If you make + return the original x, that may confuse some of your users. If you make + return a different object, then x would point to that other object in your example, and as far as I understand your question you don't want that.

Community
  • 1
  • 1
pts
  • 80,836
  • 20
  • 110
  • 183
  • It wouldn't hurt to say *why not*. – Borodin Sep 06 '13 at 18:56
  • @Borodin: I don't know any deeper explanation, maybe the authors know. The Ruby language was designed and implemented this way. – pts Sep 06 '13 at 18:58
  • 1
    As others have noted, it is simply that `a += b` is simply `a = a + b`, so `+=` isn't a "real" operator at all. It may not be in the list of *operators that can be overloaded*, but neither is it in the list of *operators*. `=` cannot be overloaded, because then the dark arts would reign, but `+` *can*. – Borodin Sep 06 '13 at 19:09