Scoping Java static methods in Kotlin - kotlin

There's have a Java library's class which has aVeryLongNameThatIDontWantToTypeEveryTime. This class has a few static methods with generic names: get(), abs() etc.
Now I need to construct complicated calls with them in my kotlin code like this one:
aVeryLongNameThatIDontWantToTypeEveryTime.get(aVeryLongNameThatIDontWantToTypeEveryTime.abs(aVeryLongNameThatIDontWantToTypeEveryTime.get(...), aVeryLongNameThatIDontWantToTypeEveryTime.get(...)))
Now, I would like to use a local scoping function in order to not repeat myself so often. However, simply using
with(aVeryLongNameThatIDontWantToTypeEveryTime) {
get(abs(get(...), get(...)))
}
does not work: It complains that aVeryLongNameThatIDontWantToTypeEveryTime does not have a companion object. (Of course it doesn't, it's a Java class.)
The only "solution" is to globally import aVeryLongNameThatIDontWantToTypeEveryTime.* in the file which isn't great since the method names are so generic and could collide.

You can use import alias to give it locally a more convenient name:
import com.example.aVeryLongNameThatIDontWantToTypeEveryTime as MyShortName
If you prefer your scoped solution then I think the only way right now is to specify your own "scope":
object aVeryLongNameThatIDontWantToTypeEveryTimeScope {
inline fun get() = aVeryLongNameThatIDontWantToTypeEveryTime.get()
inline fun set() = aVeryLongNameThatIDontWantToTypeEveryTime.set()
inline fun abs() = aVeryLongNameThatIDontWantToTypeEveryTime.abs()
}
with (aVeryLongNameThatIDontWantToTypeEveryTimeScope) {
get()
set()
abs()
}
Unfortunately, that requires rewriting all functions, including their parameters.
In the future it could be possible to use Java static members similarly to companion objects. There are similar tasks in Kotlin's YouTrack.

Related

Extension function from a generic interface

Consider the following interface
interface EntityConverter<in A, out B> {
fun A.convert(): B
fun List<A>.convert(): List<B> = this.map { it.convert() }
}
I want to use it in a spring boot application where specific implementations get injected so that the extension function becomes usable on the type.
However this doesn't work. The compiler does not resolve the extension function.
Note that you're defining extension functions that are also member functions of the EntityConverter type. You should take a look at this part of the doc for information about how this works.
Essentially, in order to use them, you need 2 instances in scope:
the dispatch receiver (an instance of EntityConverter<A, B>)
the extension receiver (an instance of A or List<A>, where A matches the first type parameter of the EntityConverter in scope)
You can use with() to bring the EntityConverter in scope so you can use convert on your other instances using the usual . syntax:
val converter = object : EntityConverter<Int, String> {
override fun Int.convert() = "#$this"
}
val list = listOf(1, 2, 3)
val convertedList = with(converter) {
list.convert()
}
println(convertedList) // prints [#1, #2, #3]
Now you have to decide whether this kind of usage pattern is what makes most sense for your use case. If you'd prefer more "classic" calls without extensions (converter.convert(a) returning a B), you can declare your functions as regular methods taking an argument instead of a receiver.
Bonus: functional interface
As a side note, if you add the fun keyword in front of your EntityConverter interface, you can create instances of it very easily like this:
val converter = EntityConverter<Int, String> { "#$this" }
This is because your converter interface only has a single abstract method, making it easy to implement with a single lambda. See the docs about functional interfaces.
I'm not sure if you can mention extension functions as a part of interface, because it's like static functions.
I'd recommend to put "common" function in interface with A typed parameter. Then just put extension method for list nearby.
interface EntityConverter<in A, out B> {
fun convert(a: A): B
}
fun <A, B> EntityConverter<A, B>.convert(list: List<A>): List<B> = list.map { convert(it) }
Update
I wasn't aware about possibility of inheritance of extension methods in Kotlin. And about its overriding as well. So my answer could be just an alternative of using extension methods.

How do I specify an ActionListener in Kotlin?

I want to add an ActionListener to a JButton in Kotlin. In Java, I would just write this:
JPanel makeButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
JButton dirButton = new JButton("Change directory");
dirButton.addActionListener(e -> chooseDirectory());
panel.add(dirButton)
return panel;
}
But it's not so simple in Kotlin. I first tried this:
private fun makeButtonPanel() : JPanel {
val panel = JPanel(FlowLayout())
val dirButton = JButton("Choose")
dirButton.addActionListener(e -> chooseDirectory()) // error message here
// ...
}
private fun chooseDirectory() { ... }
But I'm getting this error message:
Type Mismatch
Required: ((ActionEvent!) -> Unit)!
Found: KFunction1<ActionEvent, Unit>
I understand that the ! means that this is a java method with uncertain nullability, but that doesn't help me understand how to write it. All I want it to do is call the chooseDirectory() method. There must be a clean, simple way to do this, but I don't see it.
As you've discovered, you need to use braces ({ }).
This is because braces are a necessary part of defining a lambda in Kotlin.  (That differs from languages like Java and Scala, where the necessary part is the -> or => arrow.  That's because in Kotlin the arrow is optional if there are one or no parameters; if one, the it keyword is used.)
Without the braces, the code would call your chooseDirectory() function, and try to pass its result to addActionListener() — which obviously wouldn't work.
Braces are also sufficient: they're taken as defining a lambda unless you're giving the body of a function or method or an if/when branch.  (Again, this differs from most C/Java-like languages.  In Kotlin, if you just want a block scope, you have to use a construct such as run.)
As for the parentheses, they're optional here.  You could include them if you wanted:
dirButton.addActionListener({ chooseDirectory() })
But Kotlin has a convention that if a function's last parameter is a function, you can pass it after the parens:
dirButton.addActionListener(){ chooseDirectory() }
And if that would make the parens empty, then you can omit them entirely:
dirButton.addActionListener{ chooseDirectory() }
That's to allow functions that look like new language syntax.  For example, you may have met the with function:
with(someObject) {
itsProperty = someValue
}
That's just a perfectly ordinary function, defined in the standard library, and taking a function as its last parameter.  Similarly, repeat:
repeat(10) {
// Some code to be run 10 times…
}
There's one further thing worth mentioning here.  In Kotlin, lambdas are one way to define functions, which are first-class types and can be defined, passed around, and used just like other types.  This differs from Java, which has traditionally used interfaces for those purposes — often interfaces with a Single Abstract Method (‘SAM interfaces’) — and in which lambdas are little more than syntactic sugar for defining an anonymous implementation of such an interface.
As a special case, for interoperability, Kotlin allows a lambda to define an implementation of a Java SAM interface (or, since Kotlin 1.4, of a Kotlin fun interface), instead of a function.
ActionListener is a Java SAM interface, which is why you can use a lambda here.
Okay, I figured it out, and it was pretty simple. I just have to dispense with the parentheses and say
dirButton.addActionListener { chooseDirectory() }
I'm still not clear on when I should use braces instead of parentheses.

Companion object with extension function in kotlin?

I would like to have extension function and use logger from kotlin-logging and have constants inside companion object.
My function:
fun String.toFoo(): Foo {
logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
...
}
Question is where I should put val logger = KotlinLogging.logger {} and MY_CONST since I cannot use companion object with an extension function?
If you just want you logger to be a singleton you can make an object that contains and instance of the logger and reach it from there.
Object LoggerSingleton( val logger = KotlinLogging.logger{})
Then in your extension function
fun String.toFoo(): Foo {
LoggerSingleton.logger.debug { "Mapping [$this] to Foo" }
if(MY_CONST.equals(this) {
}
Since an Object in Kotlin is guaranteed to have only one instance you won't have a different logger for each use of toFoo.
EDIT
To keep the desired class name
Use this signature
Like so:
Object StringLoggerSingleton( val logger = KotlinLogging.logger("String"))
I do not know what you want to accomplish with your logger, but I show you what I did already ;-)
Usually I put extension functions in its own file named similar to what the function is actually extending (e.g. either StringExtensionFunction or if is more related to its purpose and maybe only available if certain dependencies are available, I also did something like, e.g. JsoupExtensionFunctions (where there was a String.toJsoupHtml(), File.toJsoupXml(), etc.)).
If I then need constants I just place them within that file, e.g. by just writing something like:
private const val MY_CONST = "my_const_value"
No surrounding class, no surrounding object.
Regarding the logger... as loggers are usually tied to a certain name/class, I usually put a logger inside every (important) class or associate some logger to specific names... So I am not completely sure what your intent is here... If it's ok for you that the logger is returning the container of your extension function (maybe StringExtensionFunction.kt), then you can also put a logger-val inside that file similar to what I showed with MY_CONST.
If your intention was rather to reuse the callers logger, that might not work so easily... (the easiest would then probably be to pass it to the function, but usually you do not want that)... and other mechanisms may not really be worth it ;-)

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.

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

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