Storing KClass<T> where T is an interface or abstract class

Hello I was wondering if there is a way to store KClass objects where the class inherits from an interface. In my case I want to store the class in an enum. I was also wondering if there is a way to do something like an anonymous class, where i can just write the class definition in the enum instance.

enum class Pose(val poseClass: KClass<PluginPose>) {
    // Todo: how to store anonymous classes in enum
    // STANDING(class {
    //
    // }),
    // SITTING,
    // LAYING,
    CRAWLING(CrawlingClass::class)
}

class CrawlingClass : PluginPose {
    override fun init() { }
    override fun play(target: McPlayer) { }
    override fun stop() { }
}

interface PluginPose {
    fun init()
    fun play(target: McPlayer)
    fun stop()
}

I don’t want to store instances of the interface PluginPose, because AFAIK that’s not possible (or if it is it wouldn’t be very useful to me). Instead I want to store classes that inherit from PluginPose. When I try this code Intellij tells me that I can’t store CrawlingClass in the enum, even though it inherits from PluginPose. Is there something else that I need to type in the generic of KClass to get it to accept inherited classes?

The other thing is if there is a way to create anonymous classes (something like in Pose.STANDING) and write them directly in the enum, instead of having to write the class and then store it in the enum with Class::class. I know of object keyword, but that gives me instances, not the class itself.

Also I would be interested to know if this method is the best to do, it if it is possible at all. Is there a better way to store Classes (not instances) in a collection like this other than using an enum? I want to be able to do things like this:

fun something(pose: Pose) {
    if (pose == Pose.CRAWLING)
        pose.play()
}

Edit: To be more detailed on the purpose of storing the class in an enum, I want to do things like in the if statement above, but also anything else you can do with a class like call the constructor to make new instances and such (like Pose.CRAWLING.poseClass(...))

Make PluginPose a sealed interface, and make CrawlingClass an object. Then, instead of using an enum, just pass PluginPose around, and you can do all your checks on it as per usual (i.e. you’ll be able to do:

when(pose) {
    StandingClass -> { }
    CrawlingClass -> { }
    SittingClass -> { }
    LayingClass -> { }
}

and not need an else branch)

I don’t really get what you are saying. What do you mean make Crawling class an object? wouldnt that mean that its an instance of a class and not a class itself? Also what do you mean pass PosePlugin around?

Also i think i needed to be more detailed in what i wanted with this. I wanted to do that if statement thing, but also call the constructor for the class and do anything i would be able to do with a class

To answer the question about generics:
Although a dog is an animal, a list of dogs is not a list of animals - because the list of dogs can’t hold any other animals than a dog – but a list of animals has to be able to hold any animal. Similarly, the class of CrawlingClass is not a class of PluginPose.
But one can use KClass<out PluginPose> in your example.

Please see the terms “variance” and “type projections” here: Generics: in, out, where | Kotlin
It’s very informative and helpful.

The given use case with “if” then looks like this:

fun something(pose: Pose) {
    if (Pose.Crawling.poseClass.isInstance(pose)) {
        pose.play()
    }
    // but simpler version:
    if (pose is Crawling) {
        pose.play()
    }
}

As you can see from the given use case, just doing it without the enum and KClasses would be easier. It depends on the exact use cases you need, but I tend to agree with @kyay10 that a different design could probably make your work much easier.

You mentioned that you also want to create instances from the KClass objects. That is possible, but a safer way to do it would most likely be factory methods (a Creator interface with a method that has the exact correct parameters instead of reflection, where there are a lot of possibilities to give wrong arguments which the compiler can’t prevent).
Then again, even if you still want to use KClass/reflection to create the instances, there is the question whether you need the enum. Right now, it means that you basically have to do work twice: defining the class and then defining an enum case for it. If the interface defines all necessary functions, creating implementing classes will be sufficient. So what is the use case here that requires the additional enum?

Well, that is such a unique use case (create a KClass from an anonymous class without the object) that it would be most surprising if there was a special syntax for it. It becomes especially interesting in combination with your wish to later create instances from it. Anonymous objects in Kotlin don’t allow any constructor. Java’s anonymous classes will have an internally created constructor, but I am not sure whether this is part of the specification or just technical implementation – the concept of an anonymous class/object does not require any reusable constructor, since it only promises us one object/instance of that class. You want the opposite: having a class without actually creating an instance at that time, but with a constructor for later usage. So, I think you will just have to create a class and give it sufficiently restrictive scope.

kyay10 already mentioned a sealed interface.
Personally, I actually tend to try to prevent source code with type-checking-cascades and instead use a function call (with the function documented in interface):

pose.descriptiveOperationName()

instead of

when(pose) {
    StandingClass -> { }
    CrawlingClass -> { }
    SittingClass -> { }
    LayingClass -> { }
}

That way, when adding another type, I just have to write source code in this new type and not hopping around and adding cases in multiple classes where “when” is used (or even with “if”-cascades that additionally bear the risk of being overlooked when a new type is added).

But obviously, it depends on personal taste and the use-case at hand.

2 Likes

Something like KClass<out PluginPose> is what i was looking for, but also I see your point tlin. The reason why i was trying to do this in the first place is because I’m rewriting an api that was originally written in java but does’t work anymore, and they were doing this thing with storing the classes in the enum. I think going with the if (pose is CrawlingClass) is a more polished solution than using an enum with classes (i did not know that could be done). I might just go with the sealed interface like kyay said and use when because I believe I only need to use it in 2 places (though i could be wrong). Thanks for the help

Technically speaking it is possible to get a KClass of anonymous object and we do this as usual:

object : PluginPose { ... }::class)

Of course, that creates an instance which we just throw away and I fully agree with @tlin47 - we probably should not do this. Anonymous objects were designed to be… well, anonymous objects, not represented as a specific class.

BTW, while using JVM we can instantiate such “anonymous class” with another hack:

class_.java.getDeclaredConstructor().newInstance()

But see above.

2 Likes