Question

I have my own class

class Mutnum
    attr_reader :value
    def initialize(number)
        raise TypeError, "Mutnum created on a non-numeric value" unless number.is_a? Numeric
        @value = number
    end
    def ==(other)
        if other.is_a? Mutnum
            other.value == @value
        else
            @value == other
        end
    end
    def set(newval)
        @value = newval
    end
    def to_i
        @value
    end
    def to_s
        @value.to_s
    end
    def +(other)
        if other.is_a? Numeric
            @value + other
        elsif other.is_a? Mutnum
            Mutnum.new(@value + other.value)
        end
    end
    def coerce(other)
        if other.is_a? Numeric
            [other, @value]
        else
            super
        end
    end
end

which functions essentially as a mutable number (as in, I can pass one to a function, change it in that function, and read the result from the location it was called). I'm using this to make using wxRuby and gosu in the same application less irritating.

I want to be able to say Array#[Mutnum] as in, [1,2,3,4][Mutnum.new(3)] should result in 4.

What other functions should I add to Mutnum edit so that I can use Mutnums as array indices \edit? I suppose I can say [1,2,3,4][Mutnum.new(3).to_i], but then I have to do more debugging.

Was it helpful?

Solution

There is no such thing as mutable numbers. But there are data structures that can contain a number. MutableNumber is not generally a good name for them. The way to use such container classes is:

class Container
  attr_accessor :value

  def initialize value
    @value = value
  end
end

A, B = Container.new( 42 ), Container.new( 43 )

For what you want to do, you will have to say

[1, 2, 3, 4][ Container.new( 3 ).value ]

Get over it. It is possible to delegate many methods to @value assuming that this is of one of the Numeric subclasses. But with Array#[] method, it wont work, as its principles are different. The main point to get is, containers are actually not numbers.

You would have to define

class EasyArray < Array
  def [] arg
    index = arg.value rescue arg
    super index
  end
end

EasyArray[ 1, 2, 3, 4 ][ Container.new( 3 ) ] #=> 4

All in all, your best bet is not to define your own conntainer classes at all, but go with Petri nets from my YNelson gem; gem install y_nelson. After you install it, use Petri net places as containers:

require 'y_nelson' and include YNelson
P, Q = Place( m: 2 ), Place( m: 3 )
[ P, Q ].map &:value #=> 2, 3

Remember, when computer scientists want mutable numbers, they use Petri net places.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top