S
Stefan Haflidason
My languages lecturer is a fan of a feature called 'variant' in a model
language he defined. The variant declaration is used to specify that a
variable may be of one or another type.
When he stated that no languages we are taught have this functionality,
I asked him whether using an abstract class which is subclassed for
each variant type would be enough. He said that this would work, but is
a form of encoding the declaration and as such is not as good as such a
declaration provided as part of the language.
I had a go at implementing 'variant' in Ruby. I'm going to show it to
him tomorrow and see what he thinks. Comments welcome.
Variant takes the name of the property, and one or more types. I
haven't seen him use this for more than two types however.
Can anyone see a way to do away with the instance variables? I could
have made them methods, but this does not seem to offer additional
encapsulation.
Code:
class Class
def variant(name, *classes)
instance_variable_set("@#{name}_value", nil)
instance_variable_set("@#{name}_classes", classes)
classes = instance_variable_get("@#{name}_classes")
define_method("#{name}=") do |value|
if classes.include? value.class
instance_variable_set("@#{name}_value", value)
else
raise "TypeException for '#{value}'. May be one of
[#{classes.join(', ')}]"
end
end
define_method(name) do
instance_variable_get("@#{name}_value")
end
end
end
class ListItem
def initialize(value)
self.value = value
end
attr_accessor :value
variant :next, ListItem, NilClass
end
item = ListItem.new('1')
item.next = ListItem.new('2')
item.next.next = ListItem.new('3')
# Try assigning a value which would not make sense
# in the context of a list.
begin
item.next.next = 2.2
rescue => ex
puts ex
end
while item != nil
puts item.value
item = item.next
end
# Output:
# TypeException for '2.2'. May be one of [ListItem, NilClass]
# 1
# 2
# 3
Stefan.
language he defined. The variant declaration is used to specify that a
variable may be of one or another type.
When he stated that no languages we are taught have this functionality,
I asked him whether using an abstract class which is subclassed for
each variant type would be enough. He said that this would work, but is
a form of encoding the declaration and as such is not as good as such a
declaration provided as part of the language.
I had a go at implementing 'variant' in Ruby. I'm going to show it to
him tomorrow and see what he thinks. Comments welcome.
Variant takes the name of the property, and one or more types. I
haven't seen him use this for more than two types however.
Can anyone see a way to do away with the instance variables? I could
have made them methods, but this does not seem to offer additional
encapsulation.
Code:
class Class
def variant(name, *classes)
instance_variable_set("@#{name}_value", nil)
instance_variable_set("@#{name}_classes", classes)
classes = instance_variable_get("@#{name}_classes")
define_method("#{name}=") do |value|
if classes.include? value.class
instance_variable_set("@#{name}_value", value)
else
raise "TypeException for '#{value}'. May be one of
[#{classes.join(', ')}]"
end
end
define_method(name) do
instance_variable_get("@#{name}_value")
end
end
end
class ListItem
def initialize(value)
self.value = value
end
attr_accessor :value
variant :next, ListItem, NilClass
end
item = ListItem.new('1')
item.next = ListItem.new('2')
item.next.next = ListItem.new('3')
# Try assigning a value which would not make sense
# in the context of a list.
begin
item.next.next = 2.2
rescue => ex
puts ex
end
while item != nil
puts item.value
item = item.next
end
# Output:
# TypeException for '2.2'. May be one of [ListItem, NilClass]
# 1
# 2
# 3
Stefan.