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.