Crell / enum-comparison

A comparison of enumerations and similar features in different languages
82 stars 7 forks source link

Extending enums #20

Closed bwoebi closed 3 years ago

bwoebi commented 4 years ago

Will it be possible to write enum A extends B {} where B is another enum? - Yes, I see no fundamental reason why that should not work out. Can we use traits in enums and cases? - Yes, I would say so.

iluuu1994 commented 4 years ago

Will it be possible to write enum A extends B {} where B is another enum?

I would actually say no.

enum A {
    case Foo;
    case Bar;
}

enum B extends A {
    case Baz;
}

You're now essentially allowing to dynamically add cases to A but the whole point of the enums is that the cases are finite. In other words, you can no longer know if you handle all cases when passing A to a match. I'd suggest making enums final classes.

iluuu1994 commented 4 years ago

Can we use traits in enums and cases? - Yes, I would say so.

I'd say so yes. We'd need to specify that using traits is also allowed in cases.

bwoebi commented 4 years ago

@iluuu1994 yeah, but you cannot pass B::Baz to something expecting A. This would error out at the function boundary already. You could do (with current proposal):

match type ($val) {
  B::Baz => ...,
  A => handleA($val),
}

Essentially this should not be inferior to doing:

enum A {
    case Foo;
    case Bar;
}

enum B {
    case Foo {
        function getA() { return A::Foo; }
    };
    case Bar {
        function getA() { return A::Bar; }
    };
    case Baz;
}

match type ($val) {
   B::Baz => ...,
   B => handleA($val->getA()),
}
bwoebi commented 4 years ago

Alternatively expressed, if you have A|B $val without extending or B $val with B extending A would be defacto equivalent and expose the same problems.

Just that we save boilerplate.

iluuu1994 commented 4 years ago

yeah, but you cannot pass B::Baz to something expecting A

Depends, if we compile A and B down to classes the class hierarchy would essentially look like this:

class A {}
class A::Foo extends A {}
class A::Bar extends A {}

class B extends A {}
class B::Baz extends B {}

Thus B::Baz would be a subtype of A.

bwoebi commented 4 years ago

Ah, right … I was somehow thinking of the following inheritance:

class A {}
class A::Foo extends A, extends B {}
class A::Bar extends A, extends B {}

class B {}
class B::Baz extends B {}

Which would sort of make sense here, but our class model isn't designed for that…

Crell commented 4 years ago

I would be inclined to agree with Iliya. No to extension. Traits... maybe, but that could be a way to sneak in additional properties and other mutable state that IMO we want to avoid.

iluuu1994 commented 4 years ago

Traits... maybe, but that could be a way to sneak in additional properties and other mutable state that IMO we want to avoid.

Yeah... If we disallow consts in enums we'd also need to make sure the trait doesn't include consts.

iluuu1994 commented 3 years ago

No inheritance for now as that would not actually make the classes sealed.