On 22/05/05, Thomas <sanobast-2005a / yahoo.de> wrote:
> Hi folks,
> 
> I recently tried to implement a uniform vector class being defined as a
> vector the elements of which all comply to some kind of common interface
> or are a subclass of some prototype class.
> 
> My first naive approach was to inherit from Array and to overwrite some
> methods to make sure that new elements are ok. This works fine for
> methods like []=, <<, or unshift but when implementing + I ran into the
> following problem: Array#+ returns an Array and not a Vector which is
> why I have to create a new Vector from the result of Array#+. As Array#+
> already creates a new Array, this probably isn't very efficient and I
> don't like the idea of having to do this for all possible methods that
> return an Array. I was hoping to be able to somehow limit my
> modifications of Array to a few essential methods.
> 
> So, the question is: Does somebody know a way to make sure that methods
> returning an Array (+, &, -, * etc.) always return a Vector without
> having to redefine each of them?
> 
> Please find my current toy implementation down below.
> 

Hello Thomas,

I'm quite shure you don't need to do what you are doing, because this
violates duck typing, but if you really want to you can use something
like the below.

Here I don't inherit from an array, but forward to an array, which
often is the simpler approach.

Please rethink your design. If you really want to do this for speed,
you could implement a simple C extension that includes a numeric
array, or use the narray class. Otherwise just don't put anything
wrong into the array, and everything will work out fine. And if
someone wants to put something into the array that quacks like a duck
but is no duck, also everything will continue to work.

best regards,

Brian

class Vector
  def initialize(*args)
    @numbers = args
    check_values(args)
  end

  def method_missing(method, *args, &block)
    result = @numbers.send(method, *args, &block)
    if result.is_a?Array
      Vector.new(*result)    
    else
      result
    end
  end

  private
  def check_values(values)
    return true if @numbers.empty? and values.empty?
    unless defined?(@protoclass)
      prototype = @numbers[0] || values[0]
      @protoclass = prototype.class
    end
    values.each do |e|
      unless e.kind_of?(@protoclass)
	raise TypeError, "Expected #{@protoclass} but got #{e.class}", caller[2..-1]
      end
    end
  end
end

if __FILE__ == $0
  v = Vector.new
  # these are okay
  p v
  v << 1
  p v
  v[1] = 2
  p v
  p (v + [1,2,3])
  v += [1,2,3]
  p v
  v.unshift(3)
  p v

  # but this should throw an error (that's what this is all about)
  v << "a"
  p v
end


-- 
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/