TWiki . Dev . EnumImplementation

Nice will get enums soon but first the exact implementation and syntax needs to be discussed.

Specification

A good starting point is the java 1.5 enum proposal: http://www.jcp.org/aboutJava/communityprocess/jsr/tiger/enum.html

An example of the java proposal:

public enum Coin {
  penny(1), nickel(5), dime(10), quarter(25);
 
  Coin(int value) { this.value = value; }

  private final int value;
  public int value() { return value; }
}
In Nice we could make the syntax simpler:
public enum Coin(int value) { penny(1), nickel(5),  dime(10),  quarter(25)}

Implementation

And the compiler would generate in case of this example something like:

abstract class Coin implement Enum {
final Coin penny = new penny();
final Coin nickel = new nickel();
final Coin dime = new dime();
final Coin quarter = new quarter();
}
final class penny extends Coin{}
final class nickel extends Coin{}
final class dime extends Coin{}
final class quarter extends Coin{}

int value(Coin);
value(f@penny) = 1;
value(f@nickel) = 5;
value(f@dime) = 10;
value(f@quarter) = 25;

-- ArjanB - 30 Apr 2003

An alternative is not to declare a class for each value, but make them an instance of the same class. An advantage is that we generate less classes, which should improve runtime efficiency (loading classes takes time to the jvm). If we did that, then we cannot use class dispatch for methods. We could either compare references, or assign a unique small number to each case, and use a switch bytecode to dispatch. This is an implementation detail, and should not make any difference in the specification part. This makes it possible to use the class implementation first since it seems simpler, and to optimize for speed after the implementation works well.

-- DanielBonniot - 30 Apr 2003

We can use dispatch on value for enum by giving each element a final field(named ordinal?). It is only a bit more work.

Another implementation problem is how do we prevent the addition of elements after the enum is made. It should not be possible because it might bypass the coverage tests.

-- ArjanB

An important question is: should enums be extendible? It's tricky because then a inverted inheritance tree for enums is needed. I think it's doable although I haven't figured out the details yet.

Because of the complexity for the users and of the implementation, Java 1.5 will not have extendible enums.

-- ArjanB - 16 May 2003


Even though I am not a fan of enumerations, I had this idea when I was walking home yesterday for a safe switch construct for enumerations. Consider, that for every enumeration, two methods switch and switch_default are automatically generated in the same package like this:

  <Any T> switch(Coin c, void->T penny, void->T nickel, void->T dime, void->T quarter) {
        if      (c == Coin.penny)   return penny();
        else if (c == Coin.nickel)  return nickel();
        else if (c == Coin.dime)    return dime();
        else if (c == Coin.quarter) return quarter();
        else throw new Error("something is seriously wrong");
  }
        
  <Any T> switch_default(Coin c, void->T default,
                                 void->T penny   = default,
                                 void->T nickel  = default,
                                 void->T dime    = default,
                                 void->T quarter = default)
        = switch(c, penny, nickel, dime, quarter);

Also, assume that there is a different anonymous function syntax as Arjan hinted at in BlockCallSyntax, where "() => doSomeThing(); } is equivalent to { doSomeThing(); )". Then, we can write:

let size = switch(c, penny:   { return 2; },
                     nickel:  { return 3; }, 
                     dime:    { return 1; },
                     quarter: { return 4; });

Note that this would be "safe," because if you add another enumeration value (e.g. half_dollar) then the signatures of the switch and default_switch methods change, and all callers of those methods will have to be updated in order to compile properly (like when adding a constructor to an algebraic datatype in ML). Presumably, during code generation these calls could be translated into the same JVM instructions that Java switch statements use.

Anyway, I still am not sure that enumerations are useful, and it seems like this does not have any value over the method dispatch technique below, but I wanted to present this idea before I forgot it:

    int coinSize(Coin c);
    coinSize(penny) = 2;
    coinSize(nickel) = 3;
    coinSize(dime) = 1;
    coinSize(quarter) = 4;

    let size = coinSize(s);

-- BrianSmith - 21 Feb 2004


I saw an implementation like the following a while ago, which I think does it quite nicely. Consider it as a pattern to be generate when ever an enum is specified:

final public class Coin {

    public final static Coin PENNY   = new Coin("Penny");
    public final static Coin NICKEL  = new Coin("Nickel");
    public final static Coin DIME    = new Coin("Dime");
    public final static Coin QUARTER = new Coin("Quarter");

    final String name;

    private Coin(String name) {
        this.name = name;
    }

    public String toString() {
        return name;
    }
}

An example of usage:
Coin aPenny = Coin.PENNY; // ok
Coin aHalfDollar = new Coin("HalfDollar"); // fails due to private constructor

This has some advantages in that one can't add on to a declared enum, code is readable, equals(), hashCode(), and == operator (i.e. identity) work nicely, as does toString(). Of course, it's type-safe too. On the downside, it depends on access modifiers, which don't exist yet in Nice (but will be implemented, of course).

If one wants to associate values with the enum, then this implementation is no good, of course. Though one could probably handle that by changing from what one generates the resulting code to be like in the Java 1.5 spec and then generate the following:

final public class Coin {

    public final static Coin PENNY   = new Coin("Penny", 1);
    public final static Coin NICKEL  = new Coin("Nickel", 5);
    public final static Coin DIME    = new Coin("Dime", 10);
    public final static Coin QUARTER = new Coin("Quarter", 25);

    private final String name;
    private final int value;

    private Coin(String name, int value) {
        this.name = "Coin." + name; // replace "Coin." with fully qualified class name perhaps. or eliminate (?)
        this.value = value;
    }

    public String toString() {
        return name;
    }

    public int value() {
        return value;
    }
}

-- MotiN - 16 Jan 2005

----- Revision r1.8 - 16 Jan 2005 - 15:22 GMT - MotiN
Copyright © 1999-2003 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback.