How do I import/use a generic overloaded operator function? - kotlin

I have a Kotlin class which is the base for other classes, and want to define an operator times to be used with its derived classes.
In Base.kt
abstract class Base<Q : Base<Q>> internal constructor(open protected val rawValue: Long)
: Comparable<Q> {
// allows Q * Double
operator fun times(factor: Double) = selfFactory(rawValue * factor)
// selfFactory instantiates an object of derived type Q
}
// Supposed to allow Double * Q
internal operator fun <Q : Base<Q>> Double.times(factor: Q) = factor * this
In Derived.kt
data class Derived internal constructor(override val rawValue: Long)
: Base<Derived>(rawValue) {
}
In some other file
import com.mycompany.Derived
fun foo(d: Derived): Derived = 5.0 * d; // doesn't find the operator
How can I import this generic operator to allow Double * Q?

The operator is defined in Base.kt file.
So, assuming the base.kt file in located in the package com.mycompany you just need to import the operator times : com.mycompany.times

Make sure the operator function returns Q, not Base<Q>. Otherwise, at your use site in foo(), it will be trying to return Base<Derived> instead of Derived, which is not necessarily the same thing.
Maybe it already does, but I don't know what selfFactory() looks like.
It's good practice to be explicit about declaring return types of public functions, even if you're using the = notation.
If your use site is not in the same package you defined the extension function in, you need to import it. You can hover the cursor over the * inside foo() if you want the IDE to offer to add the import for you.
You marked it internal so it will not be visible in other modules.

Related

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.

How to refer to an outer function from a lambda?

The question is in the comment. I want to refer to the outer function append, and not the one that's defined in the StringBuilder, how do I do this?
fun append(c: Char) {
println("TEST")
}
fun sbTest() = with(StringBuilder()) {
for(c in 'A'..'Z') {
append(c) // how do I refer to the append function declared above?
}
toString()
}
I know I can introduce a function reference variable, like this:
val f = ::append
and call f instead of append, but is there another way?
The problem is that anything called within with shadows the outer functions, because this is introduced. The same problem appears if you have a class and a top-level function with a function with the same signature.
The obvious option would just be re-naming it. Also, the function you have there isn't really descriptive compared to what it actually does. But if you for some reason can't rename, there are still other options.
Top-level methods can be referenced by package in Kotlin, for an instance like com.some.package.method. It can also be imported as such, which is the most common way to do it. There are very few methods that are called as com.some.package.method().
Kotlin, like Python, allows as in imports. Which means, you can do this:
package com.example;
// This is the important line; it declares the import with a custom name.
import com.example.append as appendChar; // Just an example name; this could be anything ***except append***. If it's append, it defeats the purpose
fun append(c: Char) {
println("TEST")
}
fun sbTest() = with(StringBuilder()) {
for(c in 'A'..'Z') {
appendChar(c)
}
toString()
}
Alternatively, as I mentioned, you can add the package:
for(c in 'A'..'Z') {
com.example.append(c)
}
val f = ::append is of course an option too, either way, it is still easier to rename the function than create imports with as or constants, assuming you have access to the function (and that it doesn't belong to a dependency).
If your file is outside a package, which I do not recommend you do, you can just declare the import as:
import append as appendChar
You could also use an extension function instead of with(), such as .let{...}.
This will send StringBuilder as an argument to the extension function as it (You can rename it to whatever you want btw):
fun sbTest() = StringBuilder().let{ it ->
for(c in 'A'..'Z') {
// using string builder
it.append(c)
// using your function
append(c)
}
it.toString()
}
The .let{...} function returns your last statement, aka the String from toString(), so your original function would still return it properly. Other functions can return this instead, such as .also{...}
I tend to use extension functions rather than with() as they're more flexible.
See this post to master extension functions: https://medium.com/#elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84
EDIT: Got also{} and let{} mixed up. I switched them

Import class and extension functions for the class simultaneously

When you are writing a class (here it will be a simple Integer class, so it will be easy to follow) and you are overloading operators, I already had a problem on how to overload the operator for a stranger class, which takes your object as a parameter. Look at this example:
package com.example
class Integer(var value: Int) {
operator fun plus(x: Integer) = Integer(value + x.value)
operator fun plus(x: Int) = Integer(value + x)
operator fun minus(x: Integer) = Integer(value - x.value)
operator fun minus(x: Int) = Integer(value - x)
override fun toString(): String {
return value.toString()
}
}
I simply overload simple operators so maybe another programmer can use these overloads to avoid creating functions on his own. Now I got following problem: When overloading operators for classes you don't own, you can create simple extension functions like this:
operator fun Int.plus(x: Integer) = Integer(x.value + this) // This is referencing to the actual `Int` object
operator fun Int.minus(x: Integer) = Integer(x.value - this)
...
but where do I got to place these extension functions to be imported automatically when the Integer class is being used?
// Main.kt
import com.example.Integer
fun main(args: Array<String>) {
val int1: Integer(2) + 3 // Compiles
val int2: 3 + Integer(2) // Doesn't compile unleast you add the extensions functions in `Integer` before the class declaration
// (between the package declaration and the class) and import them explicity
// like `import com.example.plus`
I could workaround this by import com.example.*, but then every single class in the package gets imported even if they remain unused. So how do I do this correctly?
Unless you want to place these extension functions into their own package and use a * import on that package, I don't see how you could make this any better. You just have to import the extension functions one by one, that's how the compiler knows where they come from. Otherwise you could have the same extension functions defined in multiple packages and files all over your project and there would be no way to choose between them.

What is a typealias in Kotlin and how is it being used in this implementation?

I see there is a typealias keyword being used and then the invoke method is being called on that "type"
Can someone please provide insight into what this is and how it is being used?
typealias NewKittiesReceived = (Kitty) -> Unit
class KittyRepository {
private val timer = Timer()
private val random = Random()
private val period = TimeUnit.SECONDS.toMillis(1)
internal fun receiveNewKitties(newKittiesReceived: NewKittiesReceived) {
timer.schedule(object : TimerTask() {
override fun run() {
val nameRandom = random.nextInt(KittyNames.values().size)
val ageRandom = random.nextInt(5)
newKittiesReceived.invoke(Kitty(KittyNames.values()[nameRandom].name, ageRandom))
}
}, period, period)
}
}
It’s often more readable to have dedicated names for function types, such as (Kitty) -> Unit. In the end, a typealias simply gives us a way to define an alias for such a (e.g.) function type which can then be used throughout the code instead of that explicit type as a 1:1 replacement.
In your example the function type (Kitty) -> Unit is being aliased with NewKittiesReceived, which is an argument to the shown function receiveNewKitties. Every variable holding a function (newKittiesReceived in the example) can be invoked with function.invoke(arguments...) or simpler with function(arguments).
There’s only a single situation in which the typealias is used actually: the definition of newKittiesReceived: NewKittiesReceived will be translated to newKittiesReceived: (Kitty) -> Unit.
The docs are found here.
This is what the documentation says:
Type aliases provide alternative names for existing types. If the type
name is too long you can introduce a different shorter name and use
the new one instead.
So, as you can see, typealises improve readability and shorten names that are to long.

Difference between function receiver and extension function

I was reading about Kotlin and did not quite get the idea
from What I understood extension function gives ability to a class with new functionality without having to inherit from the class
and what is receiver the same except it can be assigned to variable
Is there anything else about it?
Can someone give some examples on it
Extension functions:
Like Swift and C#, Kotlin provides the ability to extend a class with new functionality without having to modify the class or inherit from the class.
You might wonder why? Because we cannot edit and add functions to the language or SDK classes. So we end up creating Util classes in Java. I believe all the projects have a bunch of *Utils classes to put the helper methods that are used at multiple places in the code base. Extensions functions help to fix this Util problem.
How do we write a helper method in Java to find whether the given long value refers to today?
public class DateUtils {
public static boolean isToday(long when) {
// logic ...
}
}
And we call that method by passing the long value as an argument:
void someFunc(long when) {
boolean isToday = DateUtils.isToday(when);
}
In Kotlin, we can extend the Long class to include the isToday() function in it. And we can call the isToday() function on the Long value itself like any other member functions in the class.
// Extension function
fun Long.isToday(): Boolean {
// logic ...
}
fun someFunc(time: Long) {
val isToday = time.isToday()
}
Compared to the Util methods, Kotlin provides a much richer syntax using the Extension functions.
This improves the readability of the code which in turns improves its maintainability. And we get a little help from the code completion of the IDE. So we don't have to remember which Util class to use for the desired function.
Under the hood, Kotlin compiler generates the static helper methods as though we had written them as Java static Util methods. So we get this nice and richer syntax in Kotlin without sacrificing any performance.
Similar to functions, Kotlin also supports extension properties where we can add a property to an existing class.
Higher order functions:
A higher-order function is a function that takes functions as parameters, or returns a function.
Lets look at how a higher order function is written.
fun execute(x: Int, y: Int, op: (Int, Int) -> Int): Int {
return op(x, y)
}
Here the third parameter ( op ) is a function and so it makes this function a higher order function. The type of the parameter op is a function that takes 2 Ints as parameter and returns a Int.
To invoke this Higher order function, we can pass a function or a lambda expression:
execute(5, 5) { a, b -> a + b }
Receiver (or Function literal with Receiver or Lambda with Recevier):
A Higher order function that takes an extension function as its parameter is called Lambda with Receiver.
Let's look at the implementation of the apply function which is available in the Kotlin standard library.
inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
The function we pass to this apply function is actually an extension function to the type T. So in the lambda function, we can access the properties and the functions of the type T as though we are writing this function inside class T itself.
Here the generic type T is the receiver and we are passing a lambda function, hence the name Lambda with Receiver.
Another Example:
inline fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
beginTransaction()
try {
func()
setTransactionSuccessful()
} finally {
endTransaction()
}
}
Here, the inTransaction() is an Extension function to the SQLiteDatabase class and the parameter of the inTransaction() function is also an extension function to the SQLiteDatabase class. Here SQLiteDatabase is the receiver, for the lambda that is passed as the argument.
To invoke that function:
db.inTransaction {
delete( ... )
}
Here the delete() is the function of the SQLiteDatabase class and since the lambda we pass is an Extension function to the receiver SQLiteDatabase we can access the delete function without any additional qualifiers with it, as though we are calling the function from inside the SQLiteDatabase class itself.
While #Bob's answer is far more informative on Kotlin than could I hope to be, including extension functions, it doesn't directly refer to the comparison between "function literals with receiver" as described in https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver and extension functions (https://kotlinlang.org/docs/reference/extensions.html). I.e. the difference between:
val isEven: Int.() -> Boolean = { this % 2 == 0 }
and
fun Int.isEven(): Boolean = this % 2 == 0
The receiver part of the name refers to both of these syntaxes receiving the base Int argument as this.
As I understand it, the difference between the two is simply between one being an expression confirming to a function type and the other a declaration. Functionally they are equivalent and can both be called as:
when { myNumber.isEven() -> doSomething(myNumber) }
but one is intended for use in extension libraries, while the other is typically intended for use as an argument for a function with a function-type parameter, particularly the Kotlin builder DSLs.