Kotlin - print function expressions - kotlin

In C# I can represent a function expression like so
Expression<Func<int, int, int>> add = (a, b) => a + b;
The string representation of the function expression looks like this
(a, b) => (a + b)
In Kotlin I can represent a function expression like so
val add = { a: Int, b: Int -> a + b }
The string representation of the function expression looks like this
(kotlin.Int, kotlin.Int) -> kotlin.Int
Is there a way that Kotlin can represent the function expression more aligned to C#, showing the input parameters and the function body?

val add = { a: Int, b: Int -> a + b }
is equivalent to
Func<int, int, int> add = (a, b) => a + b;
not to Expression<...>. And if you print that, you'll see something like System.Func<int, int, int>, like in Kotlin.
I don't think Kotlin has a type like Expression in the standard library, or that you can implement it without language support. Its reflection API is richer than Java's (see KFunction) but doesn't let you access the body. You could do it with byte code manipulation libraries, but it would be a lot of work.

Related

Understanding a lambda construct that contains dot followed by brackets

This is the function declaration for rememberCoilPainter:
#Composable
fun rememberCoilPainter(
request: Any?,
imageLoader: ImageLoader = CoilPainterDefaults.defaultImageLoader(),
shouldRefetchOnSizeChange: ShouldRefetchOnSizeChange = ShouldRefetchOnSizeChange { _, _ -> false },
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null,
fadeIn: Boolean = false,
fadeInDurationMs: Int = LoadPainterDefaults.FadeInTransitionDuration,
#DrawableRes previewPlaceholder: Int = 0,
): LoadPainter<Any> {
}
The line of code I am having difficulty understanding is:
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)? = null
A dot appears after Builder followed by (size: IntSize)
This is the first time I've seen this construct in Kotlin and am not sure how to interpret it. This is a lambda. Normally the dot after an object refers to a sub component of a class or a package. But the ( ) after the dot isn't clear.
How do I implement the requestBuilder parameter?
This is a function with receiver type as described here: https://kotlinlang.org/docs/lambdas.html#function-types
Function types can optionally have an additional receiver type, which is specified before a dot in the notation: the type A.(B) -> C represents functions that can be called on a receiver object of A with a parameter of B and return a value of C. Function literals with receiver are often used along with these types.
It could be tricky to understand at first, but this is like you are providing a function/lambda that is a method of ImageRequest.Builder. Or in other words: your lambda receives one additional parameter of type ImageRequest.Builder and it is available in the lambda as this.
You can provide requestBuilder as any other lambda, but note that inside it you will have access to properties and methods of ImageRequest.Builder object that was provided to you.
What you are looking at is a "function literal with receiver". Speaking generically, a type A.(B) -> C represents a function that can be called on a receiver object of A with a parameter of B and return a value of C. Or in your example:
requestBuilder: (ImageRequest.Builder.(size: IntSize) -> ImageRequest.Builder)?
We have a function requestBuilder which can be called on a ImageRequest.Builder with a parameter size: IntSize and returns another ImageRequest.Builder.
Calling this function is just like calling any other function with a lambda as a parameter. The difference: You have access to ImageRequest.Builder as this inside your lambda block.
Hope the following example helps understand lambdas with receiver type:
data class Person(val name: String)
fun getPrefixSafely(
prefixLength: Int,
person: Person?,
getPrefix: Person.(Int) -> String): String
{
if (person?.name?.length ?: 0 < prefixLength) return ""
return person?.getPrefix(prefixLength).orEmpty()
}
// Here is how getPrefixSafely can be called
getPrefixSafely(
prefixLength = 2,
person = Person("name"),
getPrefix = { x -> this.name.take(x) }
)
How do I implement the requestBuilder parameter?
Hope this part of the code snippet answers the above:
getPrefix = { x -> this.name.take(x) }
PS: These lambdas with receiver types are similar to extension functions IMO.

Is there any function like ap2, ap3 in arrow-kt?

I saw scala code using cats in this post.
val a = Some(7)
val b = Some(9)
Applicative[Option].ap2(Some(add))(a,b)
And I tried migrating this code to kotlin and arrow like following.
Option.applicative()
.tupled(Some(7), Some(9))
.ap(Some(::add))
// works but dirty
fun add(tuple: Tuple2<Int, Int>): Int = tuple.a + tuple.b
// not work, compilation error
// fun add(a: Int, b: Int): Int = a + b
As you noticed, Tuple2 must be specified in the add function signature.
I searched the official document of arrow, but there is no apN function like ap2, ap3, ap4.
Is there any way to use the second function which not included Tuple2 type?
Once version 0.10 is available Arrow will have a .tupled() method on function types that handles this, so you will be able to write:
Option.applicative()
.tupled(Some(7), Some(9))
.ap(::add.tupled())
fun add(a: Int, b: Int) = a + b
for functions of up to 22 arguments.

What does the arrow ("->") operator do in Kotlin?

Probably a little bit broad question, but the official documentation doesn't even mentioning the arrow operator (or language construct, I don't know which phrase is more accurate) as an independent entity.
The most obvious use is the when conditional statement, where it is used to assign an expression to a specific condition:
val greet = when(args[0]) {
"Appul" -> "howdy!"
"Orang" -> "wazzup?"
"Banan" -> "bonjur!"
else -> "hi!"
}
println(args[0] +" greets you: \""+ greet +"\"")
What are the other uses, and what are they do?
Is there a general meaning of the arrow operator in Kotlin?
The -> is part of Kotlin's syntax (similar to Java's lambda expressions syntax) and can be used in 3 contexts:
when expressions where it separates "matching/condition" part from "result/execution" block
val greet = when(args[0]) {
"Apple", "Orange" -> "fruit"
is Number -> "How many?"
else -> "hi!"
}
lambda expressions where it separates parameters from function body
val lambda = { a:String -> "hi!" }
items.filter { element -> element == "search" }
function types where it separates parameters types from result type e.g. comparator
fun <T> sort(comparator:(T,T) -> Int){
}
Details about Kotlin grammar are in the documentation in particular:
functionType
functionLiteral
whenEntry
The -> is a separator. It is special symbol used to separate code with different purposes. It can be used to:
Separate the parameters and body of a lambda expression
val sum = { x: Int, y: Int -> x + y }
Separate the parameters and return type declaration in a function type
(R, T) -> R
Separate the condition and body of a when expression branch
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
Here it is in the documentation.
From the Kotlin docs:
->
separates the parameters and body of a lambda expression
separates the parameters and return type declaration in a function
type
separates the condition and body of a when expression branch

Function definition: fun vs val

I'm curious about what is the suggested way to define member functions in Kotlin. Consider these two member functions:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
These appear to accomplish the same thing, but I found subtle differences.
The val based definition, for instance, seems to be more flexible in some scenarios. That is, I could not work out a straight forward way to compose f with other functions, but I could with g. To toy around with these definitions, I used the funKTionale library. I found that this does not compile:
val z = g andThen A::f // f is a member function
But if f were defined as a val pointing to the same function, it would compile just fine. To figure out what was going on I asked IntelliJ to explicitly define the type of ::f and g for me, and it gives me this:
val fref: KFunction1<Int, Int> = ::f
val gref: (Int) -> Int = g
So one is of type KFunction1<Int, Int>, the other is of type (Int) -> Int. It's easy to see that both represent functions of type Int -> Int.
What is the difference between these two types, and in which cases does it matter? I noticed that for top-level functions, I can compose them fine using either definition, but in order to make the aforementioned composition compile, I had to write it like so:
val z = g andThen A::f.partially1(this)
i.e. I had to partially apply it to this first.
Since I don't have to go through this hassle when using vals for functions, is there a reason why I should ever define non-Unit member functions using fun? Is there a difference in performance or semantics that I am missing?
Kotlin is all about Java interoperability and defining a function as a val will produce a completely different result in terms of the interoperability. The following Kotlin class:
class A {
fun f(x: Int) = 42
val g = fun(x: Int) = 42
}
is effectively equivalent to:
public class A {
private final Function1<Integer, Integer> gref = new Function1<Integer, Integer>() {
#Override
public Integer invoke(final Integer integer) {
return 42;
}
};
public int f(final int value) {
return 42;
}
public Function1<Integer, Integer> getG() {
return gref;
}
}
As you can see, the main differences are:
fun f is just a usual method, while val g in fact is a higher-order function that returns another function
val g involves creation of a new class which isn't good if you are targeting Android
val g requires unnecessary boxing and unboxing
val g cannot be easily invoked from java: A().g(42) in Kotlin vs new A().getG().invoke(42) in Java
UPDATE:
Regarding the A::f syntax. The compiler will generate an extra Function2<A, Integer, Integer> class for every A::f occurrence, so the following code results in two extra classes with 7 methods each:
val first = A::f
val second = A::f
Kotlin compiler isn't smart enough at the moment to optimize such kind of things. You can vote for the issue here https://youtrack.jetbrains.com/issue/KT-9831. In case you are interested, here is how each class looks in the bytecode: https://gist.github.com/nsk-mironov/fc13f2075bfa05d8a3c3
Here's some code showing how f and g are different when it comes to usage:
fun main(args: Array<String>) {
val a = A()
exe(a.g) // OK
//exe(a.f) // does not compile
exe { a.f(it) } // OK
}
fun exe(p: (Int) -> Int) {
println(p(0))
}
Where f and g are:
fun f(x: Int) = 42
val g = fun(x: Int) = 42
You can see that g is an object that can be used like a lambda, but f cannot. To use f similarly, you have to wrap it in a lambda.

Does Go support operator type variables?

This is might not be such a good question, since I don't know of any compiled language that supports this feature, but since Go is constantly surprising me, I'll ask it anyway:
For my own practice, I am writing a little calculator program in Go. I'm wondering if there is a way I can declare and assign a variable of type "Operator", such that I could, for example, write:
var o Operator
o = +
var o1 Operator
o1 = /
and write function like this
func DoOperation(a,b int,o Operator) int{
return a o b
}
(No, I am not asking about operator overloading.)
Offhand, I don't know of any compiled language that supports such a thing (I'm not an expert in this). I did look at the docs under operators and found nothing. Can Go surprise me again?
Edit: The accepted answer states that Haskell supports this,
No, Go operators are not functions and hence no valid right-hand expressions. They work in a generic way e.g. the plus-operator works on all numeric types and infix-notation a la haskell is not supported either.
You would have to write your own "soft"-generic addition function using reflection.
One compiled language that covers all of your requirements is Haskell.
You can't do exactly what you say, but you can use functions instead. You have to write functions for each operator, but that's relatively little code.
type BinaryOperator func(a, b int) int
func OpAdd(a, b int) int { return a + b }
func OpSub(a, b int) int { return a - b }
func ApplyBinaryOperator(a, b int, op BinaryOperator) int {
return op(a, b)
}
Coming from an oop background I started doing this :
package main
import "fmt"
type MyInt int64
func (i * MyInt) Add(n MyInt) * MyInt {
*i += n
return i
}
func (i MyInt) String() string {
v := int64(i)
return fmt.Sprintf("0x%x (%d)", v, v)
}
func main() {
x := MyInt(10)
x.Add(10).Add(20).Add(30)
fmt.Println("x = ", x)
}