How to use a Kotlin extension function on a class?
Asked Answered
G

1

5

I have a pretty short question about an extension function that would help clear some of my code. Basically I have some transformations on the hashCode of a class name and I want an extension function to do the transformations.

Example:

Getting the name hashCode: StateA::class.java.name.hashCode() where StateA is a simple class.

I want to the extension function like:

    fun Class<*>.transformName(): String {
       var hashString = this.javaClass.name.hashCode()

       //Do my stuff on that hashString

       return hashString
    }

But this doesn't seem to work. When I apply the extension function with StateA.transformName(), the function gives me an error with Unresolved Reference.

I tried various things like applying the function to StateA::class or having the hashString equal to this::class.java.name.hashCode() but nothing works. Any tips?

Gilletta answered 10/10, 2019 at 7:31 Comment(3)
You've created extension on Class type and StateA is not a type of Class. StateA::class.java is a valid Class type object.Andersonandert
StateA::class.java.transformName() would workAttestation
I see now. Yes it does work. And the string in the function will be like this.name.hashCode()Race
F
9

You can't really achieve the StateA.transformName() syntax, as StateA just on its own refers to the companion object inside that class. So to get that syntax, you'd need to have a companion object inside every class that you want to use this extension on.

What you can do in a very general way is get the KClass that describes your class first. This gives you an object (the KClass instance) that you can then call an extension on:

fun KClass<*>.transformName() {
    val clazz: Class<*> = this.java
    clazz.name.hashCode()
}

StateA::class.transformName()

Another approach, which is less verbose on the call site could be a generic function like this, where the reified keyword allows you to access the concrete class that was used as the generic type parameter inside the function:

inline fun <reified T> transformName() {
    val clazz: Class<*> = T::class.java
    clazz.name.hashCode()
}

transformName<StateA>()
Files answered 10/10, 2019 at 7:40 Comment(3)
Now I see. Thanks. I think all three solutions are good. I think I will come down to creating a companion object (like you said) in every class and use it the simple way like StateA.transformName(). I'll log some things to make sure it doesn't cause any problems but the other two solutions are also great in terms of code practice. Thank you a lot, sir!Race
Or maybe not. If I think more about it, the cleaner solution is your last one with the reified. I don't think it's actually a good practice to add some useless companion objects just for some function.Race
It's not a bad practice to add a companion object in a class to put extensions on it like that (it's why kotlin.Boolean has a companion, for example), but yes, it might be tedious to do it for several classes, only to let them be used with this one extension.Files

© 2022 - 2024 — McMap. All rights reserved.