Enum variants in Rune?

5 views
Skip to first unread message

Bill Cox

unread,
Apr 19, 2023, 6:30:58 PM4/19/23
to Rune language discussion
A TODO is to support DataDraw-like typed unions, but C++ and Rust have enumerated types that can hold data, which is similar and cool.  I'd go ahead and add Rust-like enum variants to Rune, but I have one concern:

With DataDraw typed unions, I can use the same enum type on different unions.  The common use cases is different classes use the same enum to hold different data.  For example, the C Rune compiler has class Datatype and class Value.  Datatype uses the DatatypeType enum to have a union that holds datatype specific values.  If the datatype is a Class, then the union holds a reference to the class object.  If it is a Function, it holds a reference to the function.  The Value class is meant to hold data, so a Value class of type DE_TYPE_UINT holds a Bigint, and if the type is DE_TYPE_STRING, it holds a string.

What is the right way to hold enum-selected blobs of data?  I found the old DataDraw way pretty useful, but I don't see how the syntax would work in Rune.

You can see the example I am talking about in database/Rune.dd.

Bill

Aiden Hall

unread,
Apr 20, 2023, 10:27:46 AM4/20/23
to Bill Cox, Rune language discussion
How does this work in Rust? I looked at https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html but didn't see anything about putting data inside an enum.

I feel like when I've used Enums effectively in the past it's been mostly for convenience when I specifically don't need to marry any data or functionality to the Enum values themselves. Whereas the use case described above that involves associating data seems more like something that could be done exclusively with Unions, right? I wanna make sure I understand the Rust part first, but that's my gut reaction. Not sure about syntax, needs more thought/context.

--
You received this message because you are subscribed to the Google Groups "Rune language discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rune-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rune-discuss/CAH9QtQE46WWCJQHE_kWGww6%3D4bcW-tM-tdQOBgN2qGN9-4cyEQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Andrew Wilson

unread,
Apr 20, 2023, 11:59:39 AM4/20/23
to Aiden Hall, Bill Cox, Rune language discussion
Sounds like a tagged union to me?


For more options, visit https://groups.google.com/d/optout.


--
Andrew Wilson
Software Engineer, Android TV Eng Prod

Bill Cox

unread,
Apr 20, 2023, 2:53:10 PM4/20/23
to Andrew Wilson, Aiden Hall, Rune language discussion
}Yeah, tagged unions.  Here's a Rust example from that page Aiden linked:

enum IpAddr { V4(String), V6(String), } let home = IpAddr::V4(String::from("127.0.0.1")); let loopback = IpAddr::V6(String::from("::1"));

Rust simplifies the language a bit by not having tagged unions, but it loses some expressive power. If we did a tagged union, it might look like:

enum DatatypeType {
    String
    Uint
    Int
    Tclass
}

union ValueData(DatatypeType) {
    case String {
        stringVal: string
    }
    case Uint, Int {
        bigint: Bigint
    }
}

union DatatypeData(DatatypeType) {
    Tclass {
        tclasss: Tclass
    }
}

We'd also need some way to get the data in and out safely.  Here's what I do in C:

if (datatype.type == TYPE_UINT) {
    doSomethingWithUint(datatype.union1.uintVal)
}

This is unsafe, and we can't allow it in Rune.  We need syntax to let us safely read/write the union data.  What should it look like?

Bill

Andrew Wilson

unread,
Apr 20, 2023, 3:34:35 PM4/20/23
to Bill Cox, Aiden Hall, Rune language discussion
By analogy, here's what Standard ML does with 'tagged unions'

datatype Value = INT of int | STRING of string | UINT of uint | TCLASS of tclass;

and uses pattern matching on the tag ("constructor" in SML parlance) to actually do something

case (thing) 
     of  INT i => ...
      | UINT u => ...
      | STRING s => ...
      | TCLASS t => ...


Bill Cox

unread,
Apr 20, 2023, 7:11:08 PM4/20/23
to Andrew Wilson, Aiden Hall, Rune language discussion
That looks pretty good.  I read through https://en.wikipedia.org/wiki/Tagged_union.  I didn't see what I was looking for until Nim's implementation.  Nim is a very cool language, IMO, with some common motivations with Rune.  Here's tagged unions in Nim:

enum Shape {
    skSquare, skRectangle, skCircle
  Shape = object
    centerX, centerY: int
    case kind: ShapeKind
    of skSquare:
      side: int
    of skRectangle:
      length, height: int
    of skCircle:
      radius: int
I like that Nim puts the tagged union in the struct/object/class rather than in the enum itself. This allows different classes/structs to assign different data using the same enum. For example, consider Color. Some use cases for this enoum might assign RGB values, but there are any number of values we might associate with color, like price, or whether a color is a given person's favorite.

I'm tempted to say we should integrate tagged unions into structs and possibly also tuples, but not classes. A class can always have a struct or tuple as a data member.

For example, maybe syntax like:

enum ShapeType { Square
    Rectangle
    Circle
}
struct Shape {
    centerX: i32
    centerY:i32
    type: ShapeType
    switch type {
        case Square
          side: u32
        }
        case Rectangle {
            length: u32
            width: u32
        }
        case Circle {
            radius: u32
        }
}

Read/write could be done normally, and an error could be thrown if accessing the wrong field for the type.  Structs in Rune are already template types.  For example, if we wanted to implement a Rust-like Option struct:

enum OptionType {
    Some
    None
}

struct Option {
    type: OptionType,
    switch type {
        case Some {
            value  // Note there is no type constraint, making it a template.
        }
        case None {
        {
    }
}

This type could be used to avoid dealing with null values.  If we did that, I think we'd want a more concise syntax than our current switch syntax.  Rust uses something like:

match retVal {
    Some(val) => return val;
    None => panic!("retVal is None")
}

I've sent a CL out for review that lets us use => for one-statement cases, and also deletes the case keyword in front, so it looks more like this.

Andrew Wilson

unread,
Apr 20, 2023, 7:19:29 PM4/20/23
to Bill Cox, Aiden Hall, Rune language discussion
why not use the new syntax in the struct definition too?

switch type {
        Some => <value or sub-block>;
        None => <value or sub-block-or-just;>
}

Bill Cox

unread,
Apr 20, 2023, 7:19:52 PM4/20/23
to Andrew Wilson, Aiden Hall, Rune language discussion
With the simplified syntax, the example above looks like:

For example, maybe syntax like:

enum ShapeType {
    Square
    Rectangle
    Circle
}
struct Shape {
    type: ShapeType
    centerX: i32
    centerY:i32
    switch type {
        Square => side: u32

        Rectangle {
            length: u32
            width: u32
        }
         Circle => radius: u32
}

Using such structs would look like:

square
rectangle
circle = Shape(ShapeType.Circle, 0, 0, 100)
for shape in [square, rectangle, circle] {
    switch shape.type {
        ShapeType.Square => println "Square side = ", shape.side
        ShapeType.Rectangle => println "Rectangle width = ", shape.width, ", length = ", length
        ShapeType.Circle => println "Circle radius = ", shape.radius
    }
}

Bill Cox

unread,
Apr 20, 2023, 7:20:51 PM4/20/23
to Andrew Wilson, Aiden Hall, Rune language discussion
On Thu, Apr 20, 2023 at 4:19 PM 'Andrew Wilson' via Rune language discussion <rune-d...@googlegroups.com> wrote:
why not use the new syntax in the struct definition too?

switch type {
        Some => <value or sub-block>;
        None => <value or sub-block-or-just;>
}


Agreed. 

Aiden Hall

unread,
Apr 21, 2023, 9:24:36 AM4/21/23
to Bill Cox, Andrew Wilson, Rune language discussion
that looks nice

Bill Cox

unread,
Apr 21, 2023, 11:52:54 AM4/21/23
to Aiden Hall, Andrew Wilson, Rune language discussion
I think we need this feature, but I think we can build the bootstrap compiler without it, add the feature later, and rework the compiler to use it.  Same think with struct methods.

I think we're in good shape for moving forward with the bootstrap.  We can add these features to the TODO, or maybe document them but list them as not yet implemented.
Reply all
Reply to author
Forward
0 new messages