 # Preincrement plays, not about arithmetics actually

One of the first things people often ask for when coming to Ruby is a ++ operator. The standard answer to that has always been that such a thing makes no sense in Ruby, since you don't want

```1++
```

to turn literal ones into twos*1. But one thing one doesn't hear that often is that preincrement/predecrement operators can be simulated pretty straightforwardly with these semantics:

```a = BoxedInteger.new(1)
a += 10
b = a   # => #<BoxedInteger:0xb7ddbd20 @value=11>
a.to_i  # => 11
++a
a.to_i  # => 12
b.to_i  # => 12
```

I'll show an example involving arithmetic with boxed integers, but preincrement/decrement should never be used for that. I can only picture this being of use in some DSL*2.

This takes around 30 lines and it's a pretty interesting exercise, so you might want to try to write it on your own before I give my code. Here are some test cases that will tell you when you're done:

```require 'test/unit'
class Test_Boxed_Integers < Test::Unit::TestCase
def setup
@a = BoxedInteger.new(10)
end

def test_unary
assert_equal(10, (+@a).to_i)
assert_equal(-10, (-@a).to_i)
end

def test_coerce
assert_equal(10, @a.to_i)
assert_equal(10, (0 + @a).to_i)
assert_equal(11, (1 + @a).to_i)
assert_equal(11, (@a + 1).to_i)
end

def test_pre_inc
b = ++@a
assert_equal(11, @a.to_i)
++b
assert_equal(12, b.to_i)
assert_equal(12, @a.to_i)
end

def test_pre_dec
b = --@a
assert_equal(9, @a.to_i)
--b
assert_equal(8, b.to_i)
assert_equal(8, @a.to_i)
++b
assert_equal(9, b.to_i)
assert_equal(9, @a.to_i)
end

def test_binary_ops
b = @a / 10
assert_equal(100, (@a + 100 * b - @a).to_i)
end
end
```

### Some spoilers

```b = BoxedInteger.new(1)
+b      # => #<PreincBoxedInteger:0xb7ddbbcc @value=1, @boxedint=#<BoxedInteger:0xb7ddbbf4 @value=1>>
++b     # => #<BoxedInteger:0xb7ddbbf4 @value=2>
b       # => #<BoxedInteger:0xb7ddbbf4 @value=2>
-b      # => #<PredecBoxedInteger:0xb7ddba8c @value=-2, @boxedint=#<BoxedInteger:0xb7ddbbf4 @value=2>>
b       # => #<BoxedInteger:0xb7ddbbf4 @value=2>
--b     # => #<BoxedInteger:0xb7ddbbf4 @value=1>
b       # => #<BoxedInteger:0xb7ddbbf4 @value=1>
```

... what do you know about unary + and #coerce? ...

### The code

```class BoxedInteger
def initialize(val); @value = val.to_i end
%w[+ - * / << >>].each do |meth|
class_eval <<-EOF, __FILE__, __LINE__ + 1
def #{meth}(o); self.class.new(@value #{meth} o.to_i) end
EOF
end
def +@; PreincBoxedInteger.new(self) end
def -@; PredecBoxedInteger.new(self) end
def coerce(other)
case other
when BoxedInteger
[other, self]
else
[BoxedInteger.new(other), self]
end
end
def to_i; @value end
def replace(value); @value = value; self end
end

class PreincBoxedInteger < BoxedInteger
def initialize(boxedint)
super(boxedint.to_i)
@boxedint = boxedint
end
def +@; @boxedint.replace(@boxedint.to_i + 1) end
end

class PredecBoxedInteger < BoxedInteger
def initialize(boxedint)
super(-boxedint.to_i)
@boxedint = boxedint
end
def -@; @boxedint.replace(@boxedint.to_i - 1) end
end
```

Some hints:

• when you try to do 1 + whatever and Fixnum doesn't know how to handle objects of class whatever.class, it performs whatever.coerce(1) which should return an array with two elements, the first corresponding to '1' and the second to whatever itself. The former receives the #+ message and is given the latter as the argument.
• unary plus is +@

### Dos and donts

Don't use this for actual arithmetics! Only (if at all) in the context of some language where pre-++/-- really makes sense.

### testing - mfp (2006-07-28 (Fri) 15:26:41)

trying to save eigenclass from its imminent death (E_NOSPC)

#### mfp 2006-07-28 (Fri) 15:30:08

and again (seems to be working)

Last modified:2006/07/02 08:56:21
Keyword(s):[blog] [ruby] [frontpage] [preincrement] [predecrement] [++] [--] [coerce] [unary] [operator] [+@] [-@] [technique] [dsl]
References:

*1 another answer would explain that messages are sent to objects, not variables

*2 very much the same way _why made use of unary +/- for filtering rules