Enum types


#1

I have a proposal stemming from a newly-reported issue: https://luceeserver.atlassian.net/browse/LDEV-554

I want to make an enumerated type. For instance, in Java:

// NamedColor.java
enum NamedColor {
    RED(255,0,0),
    BLUE(0,255,0),
    GREEN(0,0,255);
    
    private int r;
    private int g;
    private int b;

    NamedColor(int r,int g,int b) {
        this.r = r;
        this.g = g;
        this.b = b;
    }
}

The above results in a construct so that NamedColor.RED instanceof NamedColor == true.

I tried to replicate the above using public final static members and creating the new instances, but that lead to the above bug report.

I would like to see a true enumerated type in the Lucee dialect. Not sure it would fit in the CFML dialect though.

// NamedColor.lucee
enum {
    
    RED(255,0,0),
    GREEN(0,255,0),
    BLUE(0,0,255);

    private r;
    private g;
    private b;

    private function init(r, g, b) {
        this.r = r;
        this.g = g;
        this.b = b;
    }
}

This might just be some syntatic sugar that accomplishes the same thing as I tried to do in the above bug report.

More Examples:

// DayOfTheWeek.lucee
enum {
    SUNDAY,
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY;
}
// Planet.lucee
enum {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7);

    static {
        // universal gravitational constant  (m3 kg-1 s-2)
        private final G = 6.67300E-11;
    }

    private final mass;   // in kilograms
    private final radius; // in meters

    private function init(numeric mass, numeric radius) {
        this.mass = mass;
        this.radius = radius;
    }

    public numeric function mass() {
        return this.mass;
    }
    
    public numeric function radius() {
        return this.radius;
    }


    public numeric function surfaceGravity() {
        return static.G * mass / (radius * radius);
    }
    
    public numeric function surfaceWeight(numeric otherMass) {
        return otherMass * surfaceGravity();
    }
}

Example Usage

// index.lucee
<:script>
today = DayOfTheWeek::MONDAY;

var i=1;
for (day in DayOfTheWeek::values()) {
    echo(day.name() & (i++%2==0) ? ', happy days. ' : ', ');
}
echo('what a day, groovin all week with you!');

day = DayOfTheWeek::valueOf(form.day);
if (!(day instanceof DayOfTheWeek)) { // get either a day or null
    throw("Invalid day - #form.day#");
}

echo('If you weigh 81kg Earth, you would weigh #Planet::MARS.surfaceWeight(81)#kg on Mars.');
</:script>

#2

Sounds like a good idea @dajester2013. Could you edit your proposal to include example usages of the Enum to make it clear?


#3

I am not sure if creating true Enum types makes sense in Lucee if you would be able to leverage the static constructs. Not sure what Michael would say if that’s possible. But if that’s possible, then that’s all you would need to create static constant constructs with attached behavior. I find that enum’s in Java are mostly used for case evaluations that must be typed and compiled.


#4

The main question for me, how is this better than use a component (expect performance)?

i could also do:

// DayOfWeek
component {
    static.MONDAY = new Day("Monday",1);
    ....
}
// index.cfm
dump(DayOfWeek::MONDAY);

#5

A couple things - first off, less typing. I get that what I’m asking is syntactic sugar. The functionality can be accomplished with just using static members - having an enum construct would be just an easier way to define the same thing.

Second, enum types I would imagine (haven’t tried on the Java side) are static-access only, you shouldn’t be able to create new instances at runtime. As such the constructor is private.

Third, enum types would have default behaviors built in. I have constructed a basic base class (See Enum.cfc in the gist below) that provides the essentials of an enum type - the main drawback is that there is some redundancy in defining a value on an enum class.


#6

Leaving the technical feasibility aside, I really like the concept – and yes, it’s totally syntactic sugar.

I’d be very happy to see this moving forward into a full language proposal and then taken to a TAG meeting.