Can extension functions be called in a "static" way? - kotlin

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:
It has all of the benefits that standard extension functions give.
An instance of the class doesn't need to be created just to access the extra functionality.
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.

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.

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()
}

Related

Dagger Dependency Injection in main function

I am calling a function in a class S3FileOperationsAdapter from the main function in my kotlin code. I am injecting the class S3FileOperationsAdapter in the main function file. So it looks like
class Runner {
#set:Inject
lateinit var s3FileOperationsAdapter: S3FileOperationsAdapter
fun main(args: Array<String>) {
s3FileOperationsAdapter.readFunction()
}
}
Now the issue is:
When I try to run the above code, I get the error Error: Main method is not static in class com.amazon.bram.sim.BatchJobRunner, please define the main method as:. This is understandable.
And we can only make a static function within an object in kotlin. So upon doing that, I cannot Inject the dependency, because Dagger does not support injection into Kotlin objects. So it feels like a deadlock.
My question is, I want to inject the dependency in this file anyhow so that I can call the respective function. And I am calling this function from the "fun main()" in kotlin. How can I achieve this? Has anyone ever faced this before?
In order to inject anything in Dagger, you must first create an instance of your component. Since no code at all will run before fun main(), this needs to be done during main itself (or in a field initializer).
After creating an instance of the component, you can ask it for an instance of S3FileOperationsAdapter directly.
fun main(args: Array<String>) {
// Create the component.
val component = DaggerMyComponent.create()
// or use the Component.Builder or Component.Factory you defined for MyComponent.
// Get an object from the component.
// This method should be defined in your component interface.
val adapter = component.s3FileOperationsAdapter()
// Use the object.
adapter.readFunction()
}
If your actual code is more complicated, with multiple injected objects and a longer main() function, this may be a bit unwieldy. In that case, you can extract your current main() into its own class and let Dagger provide that class in main().

What is the benefit of having a private constructor and a use a method inside companion object to instantiate a class?

I've bumped into this code and I'm not sure why would anyone do this. Basically the author decided for making the class constructor private so that it cannot be instantiated outside the file, and added a public method to a companion object in the class that creates a new instance of this class. What is the benefit of this approach?
This is what I found:
class Foo private constructor(private val arg1: Any) {
//more code here..
companion object {
fun newFoo(arg1: Any) = Foo(arg1 = arg1)
}
}
Why is it better than this?
class Foo(private val arg1: Any) {
//more code here..
}
There are several benefits to providing a factory method instead of a public constructor, including:
It can do lots of processing before calling the construstor. (This can be important if the superclass constructor takes parameters that need to be calculated.)
It can return cached values instead of new instances where appropriate.
It can return a subclass. (This allows you to make the top class an interface, as noted in another answer.) The exact class can differ between calls, and can even be an anonymous type.
It can have a name (as noted in another answer). This is especially important if you need multiple methods taking the same parameters. (E.g. a Point object which could be constructed from rectangular or polar co-ordinates.) However, a factory method doesn't need a specific name; if you implement the invoke() method in the companion object, you can call it in exactly the same way as a constructor.
It makes it easier to change the implementation of the class without affecting its public interface.
It also has an important drawback:
It can't be used by subclass constructors.
Factory methods seem to be less used in Kotlin than Java, perhaps due to Kotlin's simpler syntax for primary constructors and properties. But they're still worth considering — especially as Kotlin companion objects can inherit.
For much deeper info, see this article, which looks at the recommendation in Effective Java and how it applies to Kotlin.
If you want to change Foo into an interface in the future the code based on the method will keep working, since you can return a concrete class which still implements Foo, unlike the constructor which no longer exists.
An example specific to android is, that Fragments should be constructed with an empty constructed, and any data you'd like to pass through to them should be put in a bundle.
We can create a static/companion function, which takes in the arguments we need for that fragment, and this method would construct the fragment using the empty constructor and pass in the data using a bundle.
There are many useful cases, for example what Kiskae described. Another good one would be to be able to "give your constructors names":
class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
//more code here...
companion object {
fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
fun createForPurposeY() = Foo(a = 1, b = 2)
}
}
Call site:
Foo.createForPurposeX("Hey")
Foo.createForPurposeY()
Note: You should use generic types instead of Any.

KClass::memberExtensionFunctions always be empty

Code
import kotlin.reflect.full.*
class FooBar(val bar: String)
fun FooBar.baz(): Unit {println(this.bar)}
fun main(args: Array<String>) {
FooBar::class.declaredMemberExtensionFunctions.forEach {
println(it)
}
FooBar::class.memberExtensionFunctions.forEach {
println(it)
}
}
Output is empty
This is because declaredMemberExtensionFunctions only returns extension functions that are declared inside a class (as seen in the docs) and FooBar.baz() is a top level declaration (So it is not declared inside FooBar.
class FooBar(val bar: String) {
fun FooBar.baz(): Unit {
println(this.bar)
}
}
While I imagine this is not what you want, structuring the extension function like this would make your main method output lines.
TLDR: You aren't going to be able to do this. Because extension functions can be declared everywhere, you are limited in what the reflection system can do for you.
There is a thread on kotlinlang.org that covers this exact question and why it is not possible.
Essentially, Kotlin's declaredMemberExtensionFunctions function is able to list extension functions which are declared as part of the class, not externally. The docs state:
Returns extension functions declared in this class.
And of course, memberExtensionFunctions behaves similarly:
Returns extension functions declared in this class and all of its superclasses.
Here's what #Yole says in that thread as to why this is not possible:
The task of finding all extension functions for Foo is equivalent to finding all methods which have Foo as the first parameter. Neither of these is possible without accessing every single class in your application through reflection.
#Yole is on here, he might be able to provide a more authoritative answer for you.

Kotlin default arguments in interface bug?

kotlin file
interface Test {
fun test(message: String, delay: Int =100)
}
class A: Test
{
override fun test(message: String, delay: Int) {
}
}
I find i can't use #JvmOverloads in interface nor class.
if i add a #JvmOverloads in interface,the error is #JvmOverloads annotation cannot be used on interface method,if i add #JvmOverloads in class,the error is platform declaration clash....
However, I seem able to use defaults paramters in kotlin files,like this.
var a=A()
a.test("1234")
But when I use it in a java file, it seems that the method is not overloaded。
A a=new A();
a.test("123");//Compile error
The following version without interface can work
class A
{
#JvmOverloads
fun test(message: String, delay: Int=100) {
}
}
Then I can use it normally in java file
A a=new A();
a.test("123");
But how to maintain the same functionality after add the interface?
This is not a bug. #JvmOverloads annotation simply does not work with abstract methods.
From Kotlin docs:
Normally, if you write a Kotlin function with default parameter values, it will be visible in Java only as a full signature, with all parameters present. If you wish to expose multiple overloads to Java callers, you can use the #JvmOverloads annotation.
The annotation also works for constructors, static methods etc. It can't be used on abstract methods, including methods defined in interfaces.
source: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#overloads-generation
Why?
Because as You can learn from the doc I mentioned, #JvmOverloads instructs compiler to generate bunch of Java overloaded methods, omitting each of the parameters one by one, starting from the last one.
As far as I understand, each overloaded method calls internally method with one more parameter, and this additional parameter has default value. Edit: see comment by #hotkey here
This won't work with abstract methods, because they don't have any body.
Also new Java interface would have more methods, and its implementations would have to implement all of them. Kotlin interface had only one method.
To get to the same result you can make a LegacySupport class in Kotlin that will actually call the function with the default parameter and then you can expose only the return of the function to the java class from this class.

How can one add static methods to Java classes in Kotlin

Is it possible to add a new static method to the java.lang.Math class in Kotlin? Usually, such things are possible in Kotlin thanks to Kotlin Extensions.
I already tried doing the following in a file I made called Extensions.kt:
fun Math.Companion.clamp(value:Double,minValue:Double,maxValue:Double):Double
{
return Math.max(Math.min(value,maxValue),minValue)
}
but Math.Companion could not be resolved...
As of Kotlin 1.3, this is not possible. However, it's being considered for a future release!
To help this feature get implemented, go vote on this issue: https://youtrack.jetbrains.com/issue/KT-11968
Because all proposals are basically in limbo right now, I wouldn't hold my breath that this will get in any time soon
I think this is not possible. Documentation says the following:
If a class has a companion object defined, you can also define extension functions and properties for the companion object.
The Math class is a Java class, not a Kotlin one and does not have a companion object in it. You can add a clamp method to the Double class instead.
As of Kotlin 1.2 it is still not possible.
As a workaround, to statically "extend" Environment class I am currently using:
Class EnvironmentExtensions {
companion object {
#JvmStatic
fun getSomething(): File {
...
return Environment.something()
}
}
}
It is not an ideal solution but IntelliJ/Android Studio code completion helps with the usage:
val something = EnvironmentExtensions.getSomething()