Can extension functions be called in a "static" way?
Asked Answered
Y

2

7

Is it possible to create an extension function and call it as if it were static?

For Example...

fun System.sayByeAndExit() {
    println("Goodbye!")
    System.exit()
}

fun main(args: Array<String>) {
    System.sayByeAndExit() // I'd like to be able to call this
}

I know that the code sample doesn't work...

  • I understand that kotlin's extension functions are resolved statically, as mentioned in the Kotlin Reference (Extension Functions), but this does not mean they can be called as if they were static functions within a class (in a Java sense).

  • I also understand that this code will not work because there is no instance of System to pass into the method that the compiler will generate; therefore it won't compile.

Why would I want this?

Some of you might be wondering why this behaviour is desirable. I can understand why you would think that is isn't, so here are some reasons:

  1. It has all of the benefits that standard extension functions give.
  2. An instance of the class doesn't need to be created just to access the extra functionality.
  3. The functions can be accessed from an application-wide context (provided the class is visible).

To summarise...

Does Kotlin have a way to "hook" a static function onto a class? I'd love to know.

Yuyuan answered 3/9, 2016 at 18:30 Comment(1)
Possible duplicate of How can one add static methods to Java classes in KotlinCatholicism
C
12

You are really asking for "extension functions for a Class reference" or "adding static methods to existing classes" which was covered by another question here: How can one add static methods to Java classes in Kotlin which is covered by a feature request KT-11968

Extension functions cannot be added to anything that does not have an instance. A reference to a Class is not an instance and therefore you cannot extend something like java.lang.System. You can however extend a companion object of an existing class. For example:

class LibraryThing {
    companion object { /* ... */ }
}

Allows you to extend LibraryThing.Companion and therefore calling some new myExtension() method would look like you are extending the Class reference itself, when really you are extending the singleton instance of the companion object:

fun LibraryThing.Companion.myExtension() = "foo"

LibraryThing.Companion.myExtension() // results in "foo"
LibraryThing.myExtension() // results in "foo"

Therefore you might find some Kotlin libraries add empty companion objects just for this case. Others do not, and for those you are "out of luck." Since Java does not have companion objects, you cannot do the same for Java either.

The other commonly requested feature is to take an existing Java static method that accepts an instance of a class as the first parameter, and make it behave as an extension function. This is tracked by issues KT-5261, KT-2844, KT-732, KT-3487 and probably other feature requests.

Catholicism answered 3/9, 2016 at 18:30 Comment(0)
P
2

You can define extension function for an object and use it from system-wide context. An object will be created only once.

object MyClz

fun MyClz.exit() = System.exit(0)

fun main(args: Array<String>) {
    MyClz.exit()
}

Or

class MyClz {
    companion object
}

fun MyClz.Companion.exit() = System.exit(0)

fun main(args: Array<String>) {
    MyClz.exit()
}
Parlay answered 3/9, 2016 at 18:41 Comment(3)
While this is a good idea, creating an object called System will shadow existing classes like java.lang.System. I tested it out and that was my result. Although I could have been doing it wrong.Yuyuan
It is not a good idea to mimic java.lang.System (the same package and the same name). It can lead you to problems with classloading, compilation and ide support. AFAIK, it is not possible to create a companion object for java class.Parlay
Okay, you should add this info into your answer. It's quite useful. My question is more about adding static methods to existing classes, rather than just creating "static" methods using objects.Yuyuan

© 2022 - 2024 — McMap. All rights reserved.