[#1816] Ruby 1.5.3 under Tru64 (Alpha)? — Clemens Hintze <clemens.hintze@...>

Hi all,

17 messages 2000/03/14

[#1989] English Ruby/Gtk Tutorial? — schneik@...

18 messages 2000/03/17

[#2241] setter() for local variables — ts <decoux@...>

18 messages 2000/03/29

[ruby-talk:01924] Re: Enumerations and all that.

From: Dave Thomas <Dave@...>
Date: 2000-03-16 20:02:54 UTC
List: ruby-talk #1924
Well, I've thinking about enumerated types, and was wondering how they 
fit in to a typeless language.

I came to the conclusion that there cannot be such things as free
standing enumerated objects, because the semantics would be all
wrong. If we have

  thing = Enum.new(:red, :green, :blue)

Then how can we use it? We can have

  thing.set(:red)

and

  thing.value  #-> :red

but does that help? Not really, because nothing stops you having

  thing = 'wombat'


To my mind, the benefit of enumerated types comes from ensuring that
the range of values taken by something is predetermined, and we can't
do that with free variables.

However, we probably don't want to do it with free variables. Instead, 
we want to make sure that the parameter to our Door#setState method is 
either :open or :closed. So it seems to make sense to have enumerated
types associated with class attributes.

So, I came up with the following. Here's a class Spigot with two
enumerated type attributes:

     class Spigot

       enum :color, [ :red, :green, :blue ]
       enum :size,  { :small => -1, :medium => 0, :large => 99}

     end

The 'color' attribute has the external values :red, :green, and
:blue. Because there are no associated internal values, they will be
set to 0, 1, and 2.

The 'size' attribute does have internal values associated with the
three external ones.

The external world can set and query the value of either of these
object attributes:

     s = Spigot.new

     s.color = :red
     s.size  = :large

     p s.color
     p s.size

However, if you try to set an attribute using a value that's not
associated with it, a TypeError is raised:

     s.color = :large   #-> TypeError


Finally, within class Spigot, you can get to the internal value of an
attribute using <attribute>_val. If the size is set to :large,
size_val will return 99.

     class Spigot
       def printState
         printf "Internal value of color is #{color_val}\n"
         printf "Internal value of size  is #{size_val}\n"
       end
     end


I implemented 'enum' by extending class Module. It's a fairly ugly
hack right now, but there's scope for it to be tidied...

Anyway, here's all the code. It works under 1.5, but I'm not sure if
the new Symbol stuff means it doesn't work under 1.4.

I'd be interested in comments.


Dave

############################ cut here #############################

class Module

  def enum(nameSym, vals)
    n = nameSym.id2name
    iVar = "_#{n}_var"
    keys = "K_#{n}_keys"
    class_eval "def #{n}() @#{iVar} end"
    class_eval "def #{n}=(val)
                    puts #{keys}.inspect
                    raise TypeError unless #{keys}.has_key?(val)
                    @#{iVar} = val
                end"
    class_eval  "def #{n}_val() #{keys}[@#{iVar}] end"
    class_eval "#{keys} = Hash.new"

    if Hash === vals
      vals.each_pair do |key, val|
        class_eval "#{keys}[#{key}] = #{val}"
      end
    else
      vals.each_index do |i|
        class_eval "#{keys}[#{vals[i]}] = #{i}"
      end
    end
  end

end

###################################################################


class Spigot

  enum :color, [ :red, :green, :blue ]
  enum :size,  { :small => -1, :medium => 0, :large => 99}

  def printState
    printf "Internal value of color is #{color_val}\n"
    printf "Internal value of size  is #{size_val}\n"
  end
end


s = Spigot.new

s.color = :red
s.size  = :large

p s.color
p s.size

s.printState

s.color = :large  # fails

In This Thread