T
Thomas
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.
Cheers,
Thomas.
class Vector < Array
def []=(pos, val)
check_values([val])
super
end
def +(values)
check_values(values)
Vector.new(super)
end
def <<(*values)
check_values(values)
super
end
def unshift(*values)
check_values(values)
super
end
def check_values(values)
unless defined?(@protoclass)
prototype = self[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
v << 1
v[2] = 2
p v + [1,2,3]
v += [1,2,3]
v.unshift(3)
# but this should throw an error (that's what this is all about)
v << "a"
end
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.
Cheers,
Thomas.
class Vector < Array
def []=(pos, val)
check_values([val])
super
end
def +(values)
check_values(values)
Vector.new(super)
end
def <<(*values)
check_values(values)
super
end
def unshift(*values)
check_values(values)
super
end
def check_values(values)
unless defined?(@protoclass)
prototype = self[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
v << 1
v[2] = 2
p v + [1,2,3]
v += [1,2,3]
v.unshift(3)
# but this should throw an error (that's what this is all about)
v << "a"
end