Is it possible to overload function with receiver operator in Kotlin? - kotlin

I can define invoke inside a class
class A {
fun invoke(x: Double): Double {
...
}
}
and then use class instance as a functiion
val a: A()
val b = a(2.3)
right?
But can I define class instance to simulate function with receiver?
val o: MyClass()
val a: A()
val b = o.a(2.3)
Is it possible?

and then use class instance as a functiion
The invoke operator is just a way to define what happens when using the syntax () on some instance. Just like you can overload what + means, you can overload what () means. It's not exactly making an instance of A "usable as a function", but rather defining the operator () on instances of A. This is why I think it cannot really translate to "making it usable as a function with receiver".
The obvious easy way to declare an extension function would be the following:
fun MyClass.a(input: Double): Double = TODO(...)
But this doesn't seem to suit your needs. If what you really want is to add such functions as "capabilities" to some instances dynamically "on the spot" as in your example, I guess you could do so by defining such extension in a class that you provide as scope:
class A {
fun MyClass.a(x: Double): Double {
...
}
}
fun main() {
val o = MyClass()
val b = with(A()) { // brings this instance of A in scope to add the extension
o.a(2.3)
}
}

Related

How can generics in functions be used to avoid duplicate code?

I have a specific question about the usage of generics in Kotlin.
I want to create a function which takes a generic T as an argument.
It uses that to assign name from one of the classes: Class1 or Class2 to the local variable testString.
Unfortunately this is only possible when I check the type of the argument with the if conditions.
This leads to duplicate code. If I try to avoid that and use Line 12 I get this error during compile time: Unresolved reference: name
Is it possible in Kotlin to avoid the if conditions and use the testString assignment only once when the classes you are going to use have the same property with the same name?
Code:
fun main() {
val class1 = Class1("Foo1")
val class2 = Class2("Foo2")
}
class Class1(val name: String)
class Class2(val name: String)
fun <T> doStuff(classOneOrTwo: T) {
var testString: String
testString = classOneOrTwo.name //not working: Unresolved reference: name
if (classOneOrTwo is Class1) {
testString = classOneOrTwo.name
}
if (classOneOrTwo is Class2) {
testString = classOneOrTwo.name
}
}
You don't need generics here.
You can just write an interface that requires its implementers to have a name property.
interface HasName {
val name: String
}
Class1 and Class2 should implement the interface:
class Class1(override val name: String): HasName
class Class2(override val name: String): HasName
Then doStuff can be written as:
fun doStuff(classOneOrTwo: HasName) {
var testString = classOneOrTwo.name
// ...
}
You can make doStuff generic:
fun <T: HasName> doStuff(classOneOrTwo: T) {
var testString = classOneOrTwo.name
// ...
}
But you don't gain anything in particular by doing so.
Non-reified* generics are the most helpful when you want to establish some kind of "link", whether it be between parameters, or between parameters and the return type. For example, if your method is supposed to return the same type of thing as it takes:
fun <T> doStuff(foo: T): T { ... }
Or your method takes two parameters, and the second parameter must be the element type of the first parameter, which is a mutable list:
fun <T> doStuff(list: MutableList<T>, t: T) { ... }
* This paragraph doesn't quite apply to reified generics, which could be useful on their own.
Class1 and Class2 have nothing in common for the doStuff function to resolve the property name even though they were written exactly the same way, if you expect that just because you have a generic parameter T everything will be automatically be resolved, unfortunately the compiler doesn't know what T is here, aside from it being implcitly Any? type, (i.e <T: Any?>).
You're having a compile error here becase name is not a property of Any?
classOneOrTwo.name //not working: Unresolved reference: name
However, calling the doStuff function compiles fine because everything in Kotlin is a direct or indirect child of Any?
fun main() {
val class1 = Class1("Foo1")
val class2 = Class2("Foo2")
doStuff(class1)
doStuff(class2)
}
and if you try to invoke some function using classOneOrTwo param and pressed cltr+click on it, youll see its a function of the type Any?
fun <T> doStuff(classOneOrTwo: T) {
...
...
classOneOrTwo.toString() // <-- ctrl + click this you'll see its a function of Any?,
You should create a hierarchy (Inheritance) where Class1 and Class2 can inherit something from, in your case name
open class ParentClass(open val name: String)
class Class1(override val name: String) : ParentClass(name)
class Class2(override val name: String) : ParentClass(name)
fun <T: ParentClass> doStuff(classOneOrTwo: T) {
Log.e("DoStuff", classOneOrTwo.name) // now this works find because
}
Now it works because you explicitly tell the compiler that T is a type of ParentClass where the name property exists, and is inherited by your Class1 and Class2.
Back to your main function
doStuff(class1)
doStuff(class2)
prints,
Foo1
Foo2

Make class extend multiple function type interfaces with the same signature in Kotlin

I want to make a class extend multiple function type interfaces.
This works since the function types have different signatures, () -> Unit and (String) - Unit
typealias A = () -> Unit
typealias B = (something: String) -> Unit
class Test : A, B {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: String) {
TODO("Not yet implemented")
}
}
Now if I add a third function type, the compiler complains about Conflicting Overloads or A supertype appears twice
typealias A = () -> Unit
typealias B = (something: String) -> Unit
typealias C = (somethingElse: String) -> Unit
class Test : A, B, C {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: String) {
TODO("Not yet implemented")
}
override fun invoke(somethingElse: String) {
TODO("Not yet implemented")
}
}
I can obviously go and add garbage params to C to make it work, but this seems more like a hack
typealias C = (somethingElse: String, garbage: Unit?) -> Unit
but now if I define type D with the same signature,
typealias D = (somethingElseElse: String, garbage: Unit?) -> Unit
I would run into the same issue.
I thought that maybe value classes could help here:
#JvmInline
value class BString(val value: String)
#JvmInline
value class CString(val value: String)
typealias A = () -> Unit
typealias B = (something: BString) -> Unit
typealias C = (somethingElse: CString) -> Unit
class Test : A, B, C {
override fun invoke() {
TODO("Not yet implemented")
}
override fun invoke(something: BString) {
TODO("Not yet implemented")
}
override fun invoke(somethingElse: CString) {
TODO("Not yet implemented")
}
}
... but since value classes are compiled out of existence, that too is not a solution
Platform declaration clash: The following declarations have the same
JVM signature (invoke(Ljava/lang/Object;)Ljava/lang/Object;):
I'm assuming Kotlin KEEP 302, Binary Signature Name (https://github.com/Kotlin/KEEP/blob/binary-signature/proposals/multiplatform/binary-signature.md), would solve this issue in the future, but what is the correct way in the meantime to implement multiple function interfaces with the same signatures?
Practical use-case that I can think of: let's say you want to have a class that can handle Clickable and DoubleClickable, both would have something like (Event) -> Unit
EDIT: based on #mateusz's answer, this works, but only when using value classes, not if interface B and C are using normal Strings:
#JvmInline
value class BString(val value: String)
#JvmInline
value class CString(val value: String)
interface A {
operator fun invoke()
}
interface B {
operator fun invoke(something: BString)
}
interface C {
operator fun invoke(somethingElse: CString)
}
class Test : A, B, C {
override operator fun invoke() {
println("invoke A")
}
override operator fun invoke(something: BString) {
println("invoke B - something = $something")
}
override operator fun invoke(somethingElse: CString) {
println("invoke C - somethingElse = $somethingElse")
}
}
fun main(args: Array<String>) {
val handlerA = A::invoke
val handlerB = B::invoke
val handlerC = C::invoke
val t = Test()
handlerA(t)
handlerB(t, BString("hello B"))
handlerC(t, CString("hello C"))
}
outputs:
invoke A
invoke B - something = BString(value=hello B)
invoke C -somethingElse = CString(value=hello C)
The completer does not care about parameter's names.
The fun test(a: String): String and fun test(b: String): String are the same functions. When you will call test("some") then which function should be called?
You can create dedicated interfaces:
interface Clickable {
fun click(param: String)
}
interface DoubleClickable {
fun fastDoubleClick(param: String)
fun slowDoubleClick(param: String)
}
Then you can use function references if you want val handleClickFun: String -> Unit = Clickable::click
This will never work. At the fundamental JVM level, you can't implement the same interface twice with different generics. I would not expect this to ever work, even with the KEEP you mention.
Why do you want to extend function interfaces at all? If you just want the nice call syntax, you can have separate operator fun invoke overloads, without overriding anything. But even better would be using functions with actual names. If you need to pass it to methods accepting lambdas, use method references, e.g. Test::handleClick and Test::handleDoubleClick.
A typealias is just a way to give a convenient label to a specific type - it's not a type in itself, anywhere you specify that typealias, you can can just pass in a variable defined as the real type, or any other typealias you've derived from it.
So B and C are the same thing. You can have two different aliases for the same thing if that makes sense in different parts of your code (that's kinda the whole point of them! Relabel types to make them more readable or understandable) but that's just ways to refer to a type.
But when it comes to defining your class, it makes no sense. B and C are the same type, you're repeating yourself (and the compiler will give you a supertype appears twice error). And to implement that one type, you need one function - and only one, because if you have two identical functions then which one would get called?
So you can do this if you want:
typealias A = () -> Unit
typealias B = (something: String) -> Unit
typealias C = (somethingElse: String) -> Unit
class Test : A, B {
override fun invoke() {
println("invoke")
}
override fun invoke(something: String) {
println("invoke: $something")
}
}
fun doAThing(thing: C) {
thing("wow")
}
fun main() {
doAThing(Test())
}
doAThing takes a C, so we can pass it a B, because B is C.
I'm guessing that's not very useful to you, but that's the limitation of typealiases, and bare function types in general. If you want two separate functions with the exact same signature in the same scope, you need to be able to refer to them explicitly - and that usually means giving them different names.
How is your click-handler class going to handle your Event if you can't tell it whether it's a single or double-click? And even if you could (e.g. through something like (handlerFunction as B).invoke(event)) then which of your identical overridden functions in the class is which?
Like Mateusz says, you need to use interfaces, and then you can pass references to the functions, because you have a name for each one you can refer to. The things you're passing those functions into can define the types using typealiases if they want. And if you want a type that can handle both kinds of clicks, create another interface that implements both types.
If you want to be able to pass a single object that has multiple functions with the same signature, that's what you need. If you want to use function types instead, you'll have to pass the individual function references in - but something somewhere has to be able to distinguish between them in the first place, and that's usually where they're defined

How do I run code before calling the primary constructor?

I am writing a class that contains two immutable values, which are set in the primary constructor. I would like to add a secondary constructor that takes a string and parses it to get those two values. However, I can't figure out a way to implement this in Kotlin, as the secondary constructor calls the primary constructor immediately, before parsing the string.
In java, I would call this(a,b) in one of the other constructors, but Java doesn't have primary constructors. How do I add this functionality?
class Object (a: double, b:double)
{
val a = a
val b = b
constructor(str: String) //Parsing constructor
{
//Do parsing
a = parsed_a
b = parsed_b
}
}
You can either replace your parsing constructor with a factory method:
class Object(val a: Double, val b: Double) {
companion object {
// this method invocation looks like constructor invocation
operator fun invoke(str: String): Object {
// do parsing
return Object(parsed_a, parsed_b)
}
}
}
Or make both constructors secondary:
class Object {
val a: Double
val b: Double
constructor(a: Double, b: Double) {
this.a = a
this.b = b
}
// parsing constructor
constructor(str: String) {
// do parsing
a = parsed_a
b = parsed_b
}
}
Secondary constructors are disfavored in Kotlin. Your best solution is to use a factory method. See, e.g.:
class A(val a: Int, val b: Int) {
companion object {
fun fromString(str: String): A {
val (foo, bar) = Pair(1, 2) // sub with your parsing stuff
return A(foo, bar)
}
}
}
This will lead to more readable code. Imagine a class with ten different constructors identified no way other than MyClass as opposed to many more obvious ones enabled by the factory approach: MyClass.fromString(str: String) and MyClass.fromCoordinates(coordinates: Pair<Int, Int>) and so forth.
Secondary constructors weren't even allowed in Kotlin until relatively recently.

How to define functional interface with generics in Kotlin?

I'm learning Kotlin and I have some trouble with functions.
I'm trying to create something like a functional interface with a generic parameter.
In Java I would create something like this:
#FunctionalInterface
public interface Foo<T extends Bar> {
String something(T arg);
}
Then I can use this somewhere else like this (given that Person extends Bar:
Foo<Person> f = p -> p.toString();
How do you write this with Kotlin?
The first thing I tried was to use type-aliases like this:
typealias Foo<T> = (T) -> String
However, it stopped working when I added the bound to the type parameter:
typealias Foo<T: Bar> = (T) -> String // Error: Bounds are not allowed on type alias parameters
The second approach was to write an interface that extends the function type:
interface Foo<T: Bar> : (T) -> String
However, now I don't know how to instantiate a lambda function from with this. It works when I create class from it like this:
class Something: Foo<Person> {
override fun invoke(p: Person): String {
return p.toString()
}
}
val f = Something()
But this is a big overhead and I'm sure there has to be a better solution.
So how can I define a function signature that can be reused by many functions that supports generic parameters with bounds in kotlin?
Most of the time (always?) it is sufficient to define the type of the lambda in the parameter of the function that receives it.
For example:
open class Bar
class Person: Bar()
var f = { p: Person -> p.toString() }
fun <T : Bar> withFoo(block: (T) -> String) { }
fun <T : Bar> otherFoo(block: (T) -> String) { }
fun main() {
withFoo(f)
otherFoo(f)
}
The same way the Kotlin documentation states:
"since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported."
See https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions

How to specify "own type" as return type in Kotlin

Is there a way to specify the return type of a function to be the type of the called object?
e.g.
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
In effect, this would be roughly equivalent to instancetype in Objective-C or Self in Swift.
There's no language feature supporting this, but you can always use recursive generics (which is the pattern many libraries use):
// Define a recursive generic parameter Me
trait Foo<Me: Foo<Me>> {
fun bar(): Me {
// Here we have to cast, because the compiler does not know that Me is the same as this class
return this as Me
}
}
// In subclasses, pass itself to the superclass as an argument:
class FooClassA : Foo<FooClassA> {
fun a() {}
}
class FooClassB : Foo<FooClassB> {
fun b() {}
}
You can return something's own type with extension functions.
interface ExampleInterface
// Everything that implements ExampleInterface will have this method.
fun <T : ExampleInterface> T.doSomething(): T {
return this
}
class ClassA : ExampleInterface {
fun classASpecificMethod() {}
}
class ClassB : ExampleInterface {
fun classBSpecificMethod() {}
}
fun example() {
// doSomething() returns ClassA!
ClassA().doSomething().classASpecificMethod()
// doSomething() returns ClassB!
ClassB().doSomething().classBSpecificMethod()
}
You can use an extension method to achieve the "returns same type" effect. Here's a quick example that shows a base type with multiple type parameters and an extension method that takes a function which operates on an instance of said type:
public abstract class BuilderBase<A, B> {}
public fun <B : BuilderBase<*, *>> B.doIt(): B {
// Do something
return this
}
public class MyBuilder : BuilderBase<Int,String>() {}
public fun demo() {
val b : MyBuilder = MyBuilder().doIt()
}
Since extension methods are resolved statically (at least as of M12), you may need to have the extension delegate the actual implementation to its this should you need type-specific behaviors.
Recursive Type Bound
The pattern you have shown in the question is known as recursive type bound in the JVM world. A recursive type is one that includes a function that uses that type itself as a type for its parameter or its return value. In your example, you are using the same type for the return value by saying return this.
Example
Let's understand this with a simple and real example. We'll replace trait from your example with interface because trait is now deprecated in Kotlin. In this example, the interface VitaminSource returns different implementations of the sources of different vitamins.
In the following interface, you can see that its type parameter has itself as an upper bound. This is why it's known as recursive type bound:
VitaminSource.kt
interface VitaminSource<T: VitaminSource<T>> {
fun getSource(): T {
#Suppress("UNCHECKED_CAST")
return this as T
}
}
We suppress the UNCHECKED_CAST warning because the compiler can't possibly know whether we passed the same class name as a type argument.
Then we extend the interface with concrete implementations:
Carrot.kt
class Carrot : VitaminSource<Carrot> {
fun getVitaminA() = println("Vitamin A")
}
Banana.kt
class Banana : VitaminSource<Banana> {
fun getVitaminB() = println("Vitamin B")
}
While extending the classes, you must make sure to pass the same class to the interface otherwise you'll get ClassCastException at runtime:
class Banana : VitaminSource<Banana> // OK
class Banana : VitaminSource<Carrot> // No compiler error but exception at runtime
Test.kt
fun main() {
val carrot = Carrot().getSource()
carrot.getVitaminA()
val banana = Banana().getSource()
banana.getVitaminB()
}
That's it! Hope that helps.
Depending on the exact use case, scope functions can be a good alternative. For the builder pattern apply seems to be most useful because the context object is this and the result of the scope function is this as well.
Consider this example for a builder of List with a specialized builder subclass:
open class ListBuilder<E> {
// Return type does not matter, could also use Unit and not return anything
// But might be good to avoid that to not force users to use scope functions
fun add(element: E): ListBuilder<E> {
...
return this
}
fun buildList(): List<E> {
...
}
}
class EnhancedListBuilder<E>: ListBuilder<E>() {
fun addTwice(element: E): EnhancedListBuilder<E> {
addNTimes(element, 2)
return this
}
fun addNTimes(element: E, times: Int): EnhancedListBuilder<E> {
repeat(times) {
add(element)
}
return this
}
}
// Usage of builder:
val list = EnhancedListBuilder<String>().apply {
add("a") // Note: This would return only ListBuilder
addTwice("b")
addNTimes("c", 3)
}.buildList()
However, this only works if all methods have this as result. If one of the methods actually creates a new instance, then that instance would be discarded.
This is based on this answer to a similar question.
You can do it also via extension functions.
class Foo
fun <T: Foo>T.someFun(): T {
return this
}
Foo().someFun().someFun()