Is there a concrete reason for not allowing generi...
# language-evolution
e
Is there a concrete reason for not allowing generic types on enum classes, or is it just lack of use cases?
l
How does that even work? 😳
Copy code
enum class Type<T> {
    INT<Int>,
    LONG<Long>,
    FLOAT<Float>,
    DOUBLE<Double>
}
This is cursed.
e
I do have a use case for it though 😅 I'm looking to work around the lack of a non reflection based way to enumerate sealed hierarchy subclasses. One idea I had was to delegate the behavior to an enum since they can be enumerated. So there's the sealed hierarchy called
A
, a
Delegate
interface that describes the actions that need to be taken for each subclass in
A
, and a
Delegates
enum that provides the actual implementation of the actions for each subclass of
A
. The original issue is that
provide
is "static", almost like an A factory. This pattern works fine for that. But once I started doing that, I enjoyed moving the logic from companion objects in A subclasses (or from the subclass itself if it was an
object
) to
Delegates
because it made A much more clean. I wanted to do the same for
toUri
but that works by creating a
Uri
to represent the
A
subclass, i.e. it operates on an instance of
A
. So I need
Delegate
to be typed to specific subclasses of `A`:
Copy code
interface Delegate<T> {
  fun Uri.provide(): T?
  fun toUri(t: T): String
}

sealed interface A {
  fun toUri(): String

  object B : A {
    override fun toUri() = ADelegates.B.toUri(this)
  }

  object C : A {
    override fun toUri() = ADelegates.C.toUri(this)
  }
}

enum class ADelegates<T : A> : Delegate<T> {
  B<A.B> {
    override fun Uri.provide() = ...
    override fun toUri(t: A.B) = "..."
  },
  
  C<A.C> {
    override fun Uri.provide() = ...
    override fun toUri(t: A.C) = "..."
  }
}
y
You can always use a sealed class instead of enums to model the same pattern
e
Then I can't enumerate them
s
Afaik you can (
.sealedSubclasses
) but unfortunately not in a way to provide exhaustive checks. Its a shame enums are still superior in this regard.
e
sealedSubclasses
uses reflection which I don't want to use
y
You should have a look at https://github.com/livefront/sealed-enum It uses KSP to add
.values
and other nice extensions for your sealed class (as long as all its non-sealed inheritors are objects). It can even generate an enum based on your sealed class. You can absolutely with sealed classes get exhaustive checks btw.
e
https://github.com/livefront/sealed-enum
Looks cool, I'll check it out
you can absolutely with sealed classes get exhaustive checks
I never claimed otherwise; by enumerate I meant there's no way to iterate over then like enum values
https://youtrack.jetbrains.com/issue/KT-25871/Provide-ability-to-enumerate-all-direct-subclasses-of-a-sealed-class-at-compile-time-without-reflection
Linked above 😁
reflekt
I looked at that originally but the README says that it supports Kotlin 1.7 and I'm on 1.8
h
The suggestion is legit, but in your example, any reason why you don't go for removing the toUri method from the sealed interface and create it as extension? You could then use exhaustive when over subclasses, call your enum implementstions and you are done, arent you? You don't want to bloat the A interface, which you don't that way. You could even implement it in A interface and have a private impl on top level that gets called, which would again be the when over subclasses. Holefully i am not missing the point. I always try to make functions on sealed hierarchies extensions because sealed types allow for exactly that :)
e
It was just nice to have it localized in the same place. Your suggestion would work.
h
I mean it IS in the Same place, two declarations right next to each other in the file xD
e
True, it would just be nice to have them "namespaced" together