Function interface in Kotlin 1.4 - kotlin

This feature will be coming Kotlin 1.4. Here is an excerpt from KotlinConf'19.
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
runAction{
println("Hello")
}
It looks nice, but I still don't know what it does.
What is the function interface? What is its practical value? What specific scenarios can it be used for?

This is about functional interfaces — interfaces with a Single Abstract Method (also called SAM interfaces).
To understand the point, I'll need to cover a little history…  In Java, lambdas were added relatively recently.  Before that, you implemented callbacks and similar by implementing a suitable interface.  For example, if you wanted to be informed when an AWT component was actioned, you'd create an object which implemented the ActionListener interface.  That has a single method (called actionPerformed()); you'd put your code inside that method:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Do something
}
});
When they added lambdas, they wanted to blend in with all the existing code, and change as little as possible, so they did it exactly the same way: the compiler infers which interface you're implementing, and creates an object implementing that interface.  You could write:
myButton.addActionListener(e -> {
// Do something
});
which is shorter — but it compiles down to pretty much the same as the first example.
So in Java, functions are not first-class objects; lambdas are simply a more concise way to implement functional interfaces.
In Kotlin, however, functions are first-class objects: you can write a lambda (or an anonymous function) on its own, assign it, pass it to functions, return it from functions, and so on — so there's no need for SAM interfaces at all!
For easier interoperability with Java, Kotlin lets you easily implement Java SAM interfaces, in the same way you do from Java:
myButton.addActionListener {
// Do something
}
But Kotlin <= 1.3 doesn't let you implement Kotlin interfaces that way; you need to implement those explicitly.  (I suspect this was partly to encourage developers to use proper functions, with all their other advantages, and not rely on the Java-style workaround.)
Your example illustrates this.  It has an interface (Action) with one abstract method (run()).  It has a function (runAction()) which takes an instance of that interface.  And it has some code which wants to call that function, passing just the code for the run() method.
In Kotlin <= 1.3, you'd have to do the latter explicitly, e.g.:
runAction(object : Action {
override fun run() {
println("Hello")
}
})
But from Kotlin 1.4, you can mark the interface as fun interface, and use the Java-style shortcut, as in your example.
(You may or may not think this is a good thing…)

Related

Kotlin static factory method with generics

Found something similar with what I want to achieve for java - java generics and static methods also implementing factory pattern with generics in java from baeldung.
In my case, I also want to have the factory as a static method, but not sure how to achieve it in Kotlin, or maybe the whole concept is wrong.
Shortly, there are certain types of Notifiers, each should handle a certain NotificationInput type. Basically they are also some kind of builders as they build up the Notification object from the input.
Considering the setup below, I get Type mismatch. Required: Notifier<T> Found: DebugNotifier (same for the other Notifier implementations).
interface Notifier<T> {
fun issue(p: NotificationInput<T>): Notification
companion object {
fun <T> getNotifier(p: NotifierParameter): Notifier<T> = when(p.type){
"0" -> DebugNotifier()
"1" -> InfoNotifier()
"2" -> ErrorNotifier()
}
}
class DebugNotifier: Notifier<Debug>{
override fun issue(p: NotificationInput<Debug>): Notification{
return Notification(
somField = p.someDebugFieldValue
)
}
}
data class NotificationInput<T>(
val data: T
)
This is how I plan to call it: Notifier.getNotifier<Debug>(notifierParameter).issue(notificationInput)
How can this be achieved, or what would be a better configuration?
As #broot already explained, the caller has control over 2 things here: the type argument T and the NotifierParameter argument, so the API is kinda broken because the caller could do:
Notifier.getNotifier<Debug>(NotifierParameter("2"))
What would you expect to happen here?
There are too many degrees of freedom in the inputs of getNotifier(), so the compiler cannot allow you to return ErrorNotifier() when you receive "2", because someone could pass <Debug> as type argument.
You cannot compare this kind of API with Java, because Java's generics are broken and allow things that don't make sense.

How do I create a lambda expression from a Kotlin interface?

I have a simple Kotlin interface:
#FunctionalInterface
interface ServiceMethod<T> {
fun doService(): T
}
This, in spite of the name, is essentially identical to Java's Supplier functional interface. The only difference is that I can implement the Supplier, and I can't implement my own.
val supplier = Supplier<String> {
"Hello"
}
val serviceMethod = ServiceMethod<String> {
"Hello"
}
The ServiceMethod implementation gives me a compiler error saying "Interface ServiceMethod does not have constructors." Huh? Of course it doesn't! It's a functional interface.
I know that I can write it as an anonymous inner class:
val serviceMethod = object : ServiceMethod<String> {
override fun doService(): String {
return "Hello"
}
}
But this is much more verbose. In this case I could just use the Supplier interface, but that won't work for other interfaces. I shouldn't have to write an interface in Java, just to be able to a lambda in Kotlin. I'd rather use a lambda for all my Kotlin interfaces, especially since I'll be writing a lot of these. Am I missing something obvious?
Use the fun interface modifier since Kotlin 1.4
In Kotlin 1.3 and earlier, SAM (single abstract method) conversions, where you can instantiate an interface like Supplier using a lambda function, were only supported for Java interfaces.
The language designers originally thought SAM conversions wouldn't be useful for Kotlin interfaces, because a Kotlin function already has a type. For example, the type of your doService function can be written as () -> T. Instead of creating an object that implements an interface, you could simply write:
val serviceMethod: () -> String = { "Hello" }
Kotlin 1.4 adds SAM conversions for Kotlin interfaces, but it doesn't work out of the box for every interface. Instead, you have to apply the special fun modifier to a Kotlin interface to make it eligible for SAM conversion.
In your example, it would simply look like this:
fun interface ServiceMethod<T> {
fun doService(): T
}
With the modifier added, you can create an instance using a lambda exactly as you were hoping in your question.
val serviceMethod = ServiceMethod<String> { "Hello" }
You can learn more in the Kotlin documentation for functional interfaces.

Is there a way to dynamically implement API interface classes in kotlin with bytebuddy? (Mixins pattern)

Let me summerize what I am trying to achieve. Basically I want a way to have a set of interfaces which server an an api that external plugins use to interact with the engine.
Here is how I currently have things setup.
class Engine : ApiEngine {
override fun start() {
println("Starting Engine")
}
override fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
fun start()
fun stop()
}
This is cumbersome and I have seen some other solutions using ASM and injecting the interface dynamically into the "Engine" class. I have seen something like this in another source but never could fully figure out how to do.
#Implements("ApiEngine")
class Engine {
#Export("start")
fun start() {
println("Starting Engine")
}
#Export("stop")
fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
#Import("start")
fun start()
#Import("stop")
fun stop()
}
My question is, in ByteBuddy, is it possible to effively make Engine implement ApiEngine so that it an instance of Engine() can be cast to ApiEngine for API usage?
This is very much possible. You can for example integrate Byte Buddy as a build tool where you generate interfaces upon discovery. Simply implement the Plugin interface and match types based on your annotation being present.
As a next step, you would need to instrument those types to implement an additional interface using the DynamicType.Builder DSL that Byte Buddy provides you. If your methods always match their signature, there is nothing more to be done since Byte Buddy automatically detects those overrides. If the method signatures can vary, you would need to implement the interface methods using MethodCall to implement a delegation to the actual implementation.

override and implement fn from class in interface

I want to override toString() in an interface and have objects that implement that interface to default to using that method (eg: not shadowed)
interface SingletonObjectTrait {
fun toString(): String = this.javaClass.simpleName
}
Is there a straightforward way to define such an interface, preferably with minimal configuration at implementation
object MyEvent: SomeEventLogic(), SomeEventType, SingletonObjectTrait
class SomeEventLogic {}
interface SomeEventType {}
That's not possible, I'm afraid.
Method implementations in interfaces work much like default methods in Java: they're used only if the implementing class doesn't have an implementation already.  But every class already inherits toString() from Any, so the default would never be used.
In fact, the compiler has a specific error for this — if you try to implement toString() in an interface, it says:
An interface may not implement a method of 'Any'
I can't see a good way around this.
As Erik says, one option is to change the interface to an abstract class; but of course that's not viable if any implementations already extend another class.
Another option might be to implement a different method in the interface, and in the comments instruct implementing classes to override toString() and call that method.  Not automatic, but less work for implementers, and less repetition.
There isn't a great way to do this other than using maybe an annotation processor to add the missing override at compile time (by adding an annotation to the interface that you detect and you generate the overrides in the implementation class). This would work, but may be biting off more than you want to, and is likely out of scope of an answer here on Stack Overflow (seek "how to write an annotation processor for Java or Kotlin" and "KAPT" for the one engine that supports Kotlin processors).
Back to your code and why it will not work as-is:
An interface cannot have a method with a signature that matches any of the methods in Any class. And if you try to override one of them you will get a compilation error.
An interface may not implement a method of 'Any'
The minimal code to do something like you want is:
interface SingletonObjectTrait {
fun asString(): String = this.javaClass.simpleName
}
open class SomeEventLogic {}
interface SomeEventType {}
object MyEvent: SomeEventLogic(), SomeEventType, SingletonObjectTrait {
override fun toString(): String = asString() // hope they don't forget to call this!
}
There is no guarantee the implementer will call the trait asString() function but at least you can share the functionality with a one-liner in the implementing class.

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