Enum var field

Hello folks.

I got an idea of "enum var field" feature. Which is something like this.

enum Foo {
    var bar: Int
    case qux(String)
    case kaz(fred: UInt8)
    var waldo: Double
}

Which is just a shorten form of;

enum Foo {
    case qux(bar: Int, String, waldo: Double)
    case kaz(bar: Int, fred: UInt8, waldo: Double)
}

Or,

struct Foo {
    var bar: Int
    var _middle: _Middle
    enum _Middle {
        case qux(String)
        case kaz(fred: UInt8)
    }
    var waldo: Double
}

Please note that all fields are positioned in order they appeared.

As the field exists for all cases, it can directly be accessed using property access syntax.

let a: Foo = ...
print(a.bar) // Okay.
a.bar = 333 // Sets `bar` field regardless of whatever case.

This kind of "fields repeated for all cases" sometimes happen, and repeating them for all cases is really painful if there're many cases. I think this feature would make programming in Swift a bit nicer.

Please point me if this topic has been discussed before. I want to know the conclusion.

When I was discovering Swift I was really confused, why can't I access an enum property if it is presented in each case and had same type so I had to dance around creating computed properties, switching over self to finally get my property.
I would like to have such ability to introduce a variable that will be presented in each case or compiler might synthesize it from the enum.

1 Like

I would suggest using a compound type then instead of just an enum.

enum A {
   case qux(String)
   case kaz(fred: UInt8)
}

struct Foo {
   var bar: Int
   var choice: A
}

Wouldn't this be a better simpler abstraction?
Now any Foo always has a bar property and also the cases of A.

This also doesn't rely on any order of variables or other magic™

5 Likes

That`s the approach I took to meet my needs. But thinking about an enum which has cases with exact same name and type I wondered if I could have some shorthand to get it without switching over.
Still it might be more appropriate to use product types instead of trying to make sum types to behave like them.

It's not really a simpler abstraction.

I hit this problem a while ago and didn't have a good solution for it. I was parsing text, and each "Token" I got out of the string had a Range<String.Index> to indicate where in the string it came from. However, it also wanted to hold the various "kind" information about the token; was it an identifier, an operator, a literal, etc.

I ended up with this composite struct approach, but frankly it was exceptionally tedious to deal with. I wanted to switch over the returned token type, and that was difficult to do, because I would have to implement a custom ~= operator, or just switch on a property within the struct, which felt semantically incorrect. I'm not totally sold on "enums should allow stored properties" being the solution, but the enum-inside-a-struct approach ended up being a boxing nightmare.

FWIW, the code I was doing this on is here: https://github.com/davedelong/DDMathParser. There are several different layers of parsing, and pretty much each one deals with the enum-inside-a-struct approach, and pretty much each one ended up being more work than I felt was necessary.

1 Like

But what would you expect? How is this supposed to work hypothetically?

If I were to rewrite my code, I might do tokens as a protocol type. Lately I've been warming up to the idea that enums are usually the wrong construct to be using, and I've been investigating ways to accomplish the same functionality (but subjectively "better") using protocols and class clusters.

However, a lot of my investigation into this area is impeded by the myriad of problems around protocols with associated types, the lack of decent built-in type erasure, or the utter pain of trying to implement a class cluster in Swift.

3 Likes

This has been discussed and rejected a long time ago:

4 Likes

-1 from me...

I can relate to wanting Enum syntax to be easier, but I think this proposal would be confusing in practice.

At the risk of being a broken record, about a dozen problems with payload Enums would go away if we just did the obvious (well, maybe "obvious" is my frustration speaking) thing and gave them Tuple syntax.

let mycase = MyEnum.foo(123,bar:"hello")

let a = mycase.0 // 123

let b = mycase.bar // "hello"

Life could be that easy.

1 Like

How would the compiler know that bar exists? Would all the cases have the same types in order? The only type information there is the enum type, and every case's associated types would need to be the same to guarantee that bar is there, but it could be done in that scenario. I don't think that syntax would work if the types were different across cases though.

2 Likes

Well, the obvious answer to that is to synthesize var bar: String?, which is nil unless the case has a bar "field". (And hopefully it could be non-optional if all cases had the field.)

But the other problem is, what would be the type of bar (or .0!) if your enum was

enum E {
    case a(String, bar: Int)
    case b(Int, bar: String)
}

?

Perhaps the synthesis would only be provided if there was no conflict like that (like the restrictions on Equatable synthesis).

by optional and, where there is a possible Type conflict, by type annotation

my previous gripe on this was fleshed out a bit better: If case in?

Okay I got it. Thanks.

@davedelong Your point is my point. My intention was all about showing intentions.

I agree that there can be some syntactic ambiguity and subtle semantic issues. For now I have no good solution for that issues.

1 Like
Terms of Service

Privacy Policy

Cookie Policy