Why should I implement a function type as an interface in Kotlin - kotlin

I came across something and wondered all the time why you should do this.
You implement an interface in Kotlin through a simple function type:
"It is possible for a class to implement a function type as if it were an interface. It must then supply an operator function called invoke with the given signature, and instances of that class may then be assigned to a variable of that function type:"
class Divider : (Int, Int) -> Double {
override fun invoke(numerator: Int, denominator: Int): Double = ...
}
But why should I do this? Why should I add an interface in that way? I think its only possible to add one function and not more.
Or is it an advantage that I can implement a function with a function body and not only the function head like in normal interfaces? I think it is possible in Java to add default methods to interfaces with a function body. So maybe it is something like that?

Function as a class can have state. For example you could store the last invocations and use the history as a cache:
class Divider : (Int, Int) -> Double {
val history = mutableMapOf<Pair<Int, Int>, Double>()
override fun invoke(numerator: Int, denominator: Int): Double {
return history.computeIfAbsent(Pair(numerator, denominator)) {
numerator.toDouble() / denominator.toDouble()
}
}
}
fun main() {
val divider = Divider()
println(divider(1,2))
println(divider(2,3))
println(divider.history)
}

It is probably not very useful to write a class that only implements a function type interface; however, it might be useful to write a class that can among other things be used in place of a function.
An example from the standard library is the KProperty1 interface. You can write code like this:
data class C(val id: Int, val name: String)
val objs = listOf(C(1, "name1"), C(2, "name2"), C(3, "name3"))
val ids = objs.map(C::id)
Here, C::id is a property reference of type KProperty1<C, Int>, and it can be used as an argument to List.map in place of a lambda because KProperty1<C, Int> extends (C) -> Int. However, KProperty1 has a lot of other uses besides being passed as a function.

Related

Kotlin Return function as fun interface

Functional interfaces work well when you want to inject a function as an interface, example:
fun interface MakeCoffee {
operator fun invoke()
}
class CoffeeManager(private val makeCoffee: MakeCoffee) {...}
fun provideCoffeeManager(): CoffeeManager = CoffeeManager { }
However if I try to return a function when the return type is a fun interface like this:
fun provideMakeCoffee(): MakeCoffee = {}
it will fail for a mismatch KFunction0<Unit> vs MakeCoffee.
Is there any workaround?
fun interface enables two features. It does not make your interface fully interchangeable with matching Function type.
When calling a function with that interface as a parameter, you can use any functional reference or lambda, and it will be auto-converted into that interface type. This is the only situation where functions are auto-converted into your interface, which is why the code you show doesn't work.
An implicit constructor is created for your interface, where the parameter is a function matching the signature of the interface's function. This constructor creates an instance of your interface by using that function. You can use lambda syntax with this constructor to create an instance of your interface.
So in your case, you could use
fun provideMakeCoffee(): MakeCoffee = MakeCoffee {}
which calls the implicit MakeCoffee constructor, and is passing a trailing lambda parameter to it.
I’m using the word constructor loosely. It looks like a constructor call but it’s really a factory function since interfaces don’t have constructors.
I found the solution to the problem in the end.
#Tenfour04 answer works but it doesn't answer the question of "how to return a function as fun interface".
The example provided was very simple and maybe that's why the question was a bit misleading, but imagine you have the following case:
fun interface MakeCoffee {
operator fun invoke(sugarAmount: Double, milkAmount: Double, coffeeAmount: Double)
}
//function you already have
fun doCoffee(sugarAmount: Double, milkAmount: Double, coffeeAmount: Double) { ... }
How do you return your doCoffee as MakeCoffee?
Solution
fun provideMakeCoffee(): MakeCoffee = MakeCoffee(::doCoffee)

Custom Class Implement a Function Type

Found this in kotlin documentation about function and lambda
class IntTransformer: (Int) -> Int {
override operator fun invoke(x: Int): Int = TODO()
}
val intFunction: (Int) -> Int = IntTransformer()
In this page, it says that you can implement function type to class like an interface. How does it work? Can you give me some explanation every each part and give me an example how this is done?
From what I understand, IntTransformer expand/implement anonymous function that takes int as argument and output type, but I still didn't know how does it work...
Thanks
You can think of a function type sort of like an interface that has a single function named invoke with the parameters and return type matching its definition.
So
(Int) -> String
is very much like
interface Foo {
operator fun invoke(param: Int): String
}
And so if a class inherits from (Int) -> String, you would do it in exactly the same way as you would to inherit Foo above. You could say the function inheritance is more versatile, because it allows your class to be passed around as a functional argument directly instead of having to get a reference to its invoke function using ::invoke.

Kotlin member and extension at the same time

In an attempt to understand more about Kotlin and play around with it, I'm developing a sample Android app where I can try different things.
However, even after searching on the topic for a while, I haven't been able to find a proper answer for the following issue :
Let's declare a (dummy) extension function on View class :
fun View.isViewVisibility(v: Int): Boolean = visibility == v
Now how can I reference this function from somewhere else to later call invoke() on it?
val f: (Int) -> Boolean = View::isViewVisibility
Currently gives me :
Error:(57, 35) Type mismatch: inferred type is KFunction2 but (Int) -> Boolean was
expectedError:(57, 41) 'isViewVisibility' is a member and an extension
at the same time. References to such elements are not allowed
Is there any workaround?
Thanks !
Extensions are resolved statically, where the first parameter accepts an instance of the receiver type. isViewVisibility actually accept two parameters, View and Int. So, the correct type of it should be (View, Int) -> Boolean, like this:
val f: (View, Int) -> Boolean = View::isViewVisibility
The error message states:
'isViewVisibility' is a member and an extension at the same time. References to such elements are not allowed
It's saying that the method is both an extension function, which is what you're wanting it to be, and a member. You don't show the entire context of your definition, but it probably looks something like this:
// MyClass.kt
class MyClass {
fun String.coolStringExtension() = "Cool $this"
val bar = String::coolStringExtension
}
fun main() {
print(MyClass().bar("foo"))
}
Kotlin Playground
As you can see the coolStringExtension is defined as a member of MyClass. This is what the error is referring to. Kotlin doesn't allow you to refer to extension function that is also a member, hence the error.
You can resolve this by defining the extension function at the top level, rather than as a member. For example:
// MyClass.kt
class MyClass {
val bar = String::coolStringExtension
}
fun String.coolStringExtension() = "Cool $this"
fun main() {
print(MyClass().bar("foo"))
}
Kotlin Playground
A better fit is the extension function type View.(Int) -> Boolean:
val f: View.(Int) -> Boolean = View::isViewVisibility
But actually the extension types are mostly interchangeable (assignment-compatible) with normal function types with the receiver being the first parameter:
View.(Int) -> Boolean ↔ (View, Int) -> Boolean
I faced the same problem when I declared extension function inside another class and try to pass that extension function as parameter.
I found a workaround by passing function with same signature as extension which in turn delegates to actual extension function.
MyUtils.kt:
object MyUtils {
//extension to MyClass, signature: (Int)->Unit
fun MyClass.extend(val:Int) {
}
}
AnyClass.kt:
//importing extension from MyUtils
import MyUtils.extend
// Assume you want to pass your extension function as parameter
fun someMethodWithLambda(func: (Int)->Unit) {}
class AnyClass {
fun someMethod() {
//this line throws error
someMethodWithLambda(MyClass::extend) //member and extension at the same time
//workaround
val myClassInstance = MyClass()
// you pass a proxy lambda which will call your extension function
someMethodWithLambda { someIntegerValue ->
myClassInstance.extend(someIntegerValue)
}
}
}
As a workaround you can create a separate normal function and invoke it from an inline extension method:
inline fun View.isVisibility(v: Int): Boolean = isViewVisibility(this, v)
fun isViewVisibility(v: View, k: Int): Boolean = (v.visibility == k)
You can't call directly the extension method because you don't have the implicit this object available.
Using either a type with two parameters (the first for the implicit receiver, as #Bakawaii has already mentioned) or an extension type should both work without any warnings at all.
Let's take this function as an example:
fun String.foo(f: Int) = true
You can use assign this to a property that has a two parameter function type like this:
val prop: (String, Int) -> Boolean = String::foo
fun bar() {
prop("bar", 123)
}
Or, you can use an extension function type, that you can then call with either of these two syntaxes:
val prop2: String.(Int) -> Boolean = String::foo
fun bar2() {
prop2("bar2", 123)
"bar2".prop2(123)
}
Again, the above should all run without any errors or warnings.

Can we achieve compile-time type safety for a union of types we can't control?

Let's say I have a function:
fun doSomething(vararg pairs: Pair<String, *>) {
// Do things with the pairs
}
The problem with this approach is that it allows any type for the second half of Pair (e.g. Pair<String, CustomType1>).
What if I only want to allow a finite number of types, how would I achieve that?
If the function had a simpler signature, I could achieve the restriction via overload, like so:
fun doSomethingSimpler(param: Boolean) {
// Boolean implementation
}
fun doSomethingSimpler(param: Int) {
// Int implementation
}
// etc.
If the restricted type "set" was in my control, I could use an interface or a sealed class to achieve this. E.g.
sealed class Root
class Child1 : Root()
class Child2 : Root()
fun doSomethingICanControl(param: Root) {
// Root implementation
}
Yet what if I don't have control over the types or they are primitive, how do I prevent * from allowing everything through?
I know I could use smart-casts to get run-time safety, but can this be done at compile time?
Or does the language disallow it?
Edit 1
I know I could create my own box types (e.g. MyBoolean) and use a common interface or sealed class, but that would be boilerplate that everyone would have to write every time they needed to.
Edit 2
To be clear, I'd like to be able to make an invocation like so:
doSomething(
"key1" to false,
"key2" to "value2",
"key3" to 86
)
... I.e. Have a mixed set of "second" (of Pair) types.
So to sum it quickly up:
You want to call methods from a library that expects Pair<String, *>,
but limit the possible values that * can be.
TL;DR: What you are trying to accomplish is not possible without some kind of wrapper, because
We have no Sum-Types in Kotlin, so no way to tell the compiler that you expect an Int or a Double or a Float and nothing else
If a library-method expects something to be Pair<String, *>, there is no way for us to tell the compiler, that we just want to be able to give it a String instead of *
One way to get that behaviour is to create a Decorator (Decorator Pattern), e.g. create your own extension methods that allow only a subset
class Foo {
//Allows everything
fun doSomething(param: Pair<String, *>)
}
//Now lets create our own extension methods
fun Foo.doSomethingWithInt(param: Pair<String, Int>)
fun Foo.doSomethingWithBoolean(param: Pair<String, Boolean>)
fun Foo.doSomethingWithString(param: Pair<String, String>)
Or if you dont want to be able to call Foo.doSomething() you
can create a Decoractor-Class:
class FooDecorator {
val foo = Foo()
fun doSomething(param: Pair<String, Int>) { }
}
And the following example is not possible without some kind of Wrapper, because there are no Sum-Types in Kotlin:
doSomething(
"key1" to false,
"key2" to "value2",
"key3" to 86
)
What you could do is something like:
At first, create your own JSONItem type and add Extension-Methods to Types that can be used as one
class JSONItem<T> private constructor (item: T)
fun Int.asJSONItem() = JSONItem(this)
fun String.asJSONItem() = JSONItem(this)
fun Boolean.asJSONItem() = JSONItem(this)
Then you are able to do something like that:
//Your own personal doSomething
fun doSomething(varargs: param: Pair<String, JSONItem>) {
//Call the real doSomething()
doSomething(param.map { Pair(it.first, it.second.item) }}
}
doSomething(
"key1" to false.asJSONItem(),
"key2" to "value2".asJSONItem(),
"key3" to 86.asJSONItem()
)
Denotable union and intersection types are not currently supported in Kotlin (as of 1.1.x).
This is the relevant issue.

How can I assign a value to KMutableProperty parameter?

In a method I would like to receive KMutableProperty as parameter and assign a value to it.
Another question is what is the correct way of passing a parameter into such a method.
Basically I would like to have something like that:
class MyBinder {
...
fun bind(property: KMutableProperty<Int>): Unit {
property.set(internalIntValue)
}
}
And then call it in another class
myBinder.bind(this::intProperty)
Kotlin 1.0 does not allow the this::intProperty syntax, but this is being worked currently and will be available soon as a part of the early access preview of 1.1 (issue, KEEP proposal).
With this in mind, I'd consider doing what you're describing in another way, for example making bind accept a lambda which sets the property:
class MyBinder {
fun bind(setProperty: (Int) -> Unit) {
setProperty(internalIntValue)
}
}
...
myBinder.bind { intProperty = it }
Anyway, to answer your question about setting the value of KMutableProperty: to set the value of some property or, technically speaking, to invoke the property setter, you should know its arity, or the number of parameters that property (and its getter/setter) accepts. Properties declared in a file do not accept any parameters, member properties and extension properties require one parameter (the receiver instance), while member properties which are also extensions take two parameters. These kinds of properties are represented by the following subtypes of KMutableProperty respectively: KMutableProperty0, KMutableProperty1, KMutableProperty2 -- the number means the arity and their generic type parameters mean the types of receivers. Each of these property types has a set method with the corresponding parameters. Some examples:
fun setValue(property: KMutableProperty0<Int>, value: Int) {
property.set(value)
}
fun setValue(property: KMutableProperty1<SomeType, Int>, instance: SomeType, value: Int) {
property.set(instance, value)
}
Note that there's no set (or get) method in the abstract KMutableProperty interface precisely because it's impossible to declare it, not knowing the number of required receiver parameters.
Additionally to Alexander's answer, you can try something like this:
import kotlin.reflect.KMutableProperty
class Binder {
val internalIntValue = 10
fun bind(self: Any, aProperty: KMutableProperty<Int>) {
aProperty.setter.call(self, internalIntValue)
}
}
class Foo {
var bar = 1
fun changeBar() {
Binder().bind(this, Foo::bar)
}
}
fun main(args: Array<String>) {
val foo = Foo()
assert(1 == foo.bar)
foo.changeBar()
assert(10 == foo.bar)
}
A more robust/safe way to do the same thing:
fun <T> bind(self: T, aProperty: KMutableProperty1<T, Int>) {
aProperty.set(self, internalIntValue)
}
My thanks to Alexander. His answer gave me the previous idea.