Why the main routine in Kotlin is accepted as a single-expression? - function

The entry point of the c-like languages is almost identical, so Kotlin's fun main() {}
This is quite understandable for me, however; when using this routine as a single-expression function and (assign?) it any output method it will be compiled and print the parameter's value of the print method not its return type (which is Unit). I guess this snippet will make it clear..
fun main() = print("Do I return something?")
This will be compiled as a basic hello world program!
Why is this acceptably compiled? does the main method returns something else than the 0?
Is the equal operator acts as assignment operator? and if so; what does the print() method returns? is it something other than Unit?
If so, why it returns Unit when assign it to a variable?
fun main() {
val x= println()
print(x)
}
Then also, why it doesn't return Unit in this case:
fun main() = foo()
fun foo(): Unit {}

I'm not understanding everything you ask. = here is not an assignment operator. It's just a shorter way of writing the method:
fun main() = print("Do I return something?")
is equivalent to
fun main(): Unit {
return print("Do I return something?")
}
And since print()'s return type is Unit, it's equivalent to
fun main() {
print("Do I return something?")
}
See the documentation for details.
In the following snippet, however, = is the assignment operator:
fun main() {
val x = println()
print(x)
}
So this code calls println(), and assigns what it returns (Unit) to the variable x. Printing x thus produces the output kotlin.Unit.

I hope that helps:
The entry point to a Kotlin program is fun main(): Unit or fun main(args: Array<String>): Unit, which are functions that return Unit
Unit is something that is returned by default from Kotlin functions when there is nothing interesting to return
println() returns Unit
A Unit return type is often omitted in the code, but it is implied
fun foo(): T = boo() is a short syntax for fun foo(): T { return boo() }
Since fun main(): Unit and fun println(...): Unit have the same return type Unit, it is valid to write fun main() = println()

Related

Kotlin send function arguments using a data class

Let's say I have class:
class Foo {
fun doSomething(param1: Int, param2: String, param3: String)
}
and a data class
data class Params(
val param1: Int,
val param2: String,
val param3: String)
Now I want to use the data class arguments to send them to the function, is there a way to do that? Lets say something similar to:
val myParams = Params(1, "2", "3")
val foo = Foo()
foo.doSomething(myparams)
Or by some sort of transformation or method naming. as:
execute(foo, foo::doSomething, myParams)
I doubt this is possible in Kotlin without some tricks. Possible solutions are reflection API and code generation.
Example using reflection:
fun main() {
val myParams = Params(1, "2", "3")
val foo = Foo()
invokeWithParams(foo::doSomething, myParams)
}
fun <T : Any, R> invokeWithParams(func: KFunction<R>, params: T): R {
val paramValues = func.parameters.map { kparam ->
(params::class as KClass<T>)
.memberProperties
.single { it.name == kparam.name }
.get(params)
}.toTypedArray()
return func.call(*paramValues)
}
It should work for static functions, member functions, and extension functions. It may fail with some rarer cases. You should probably add some error handling, e.g. checks if params match.
It won't work on anything else than JVM as reflection is still very limited on other targets.
Also, I'm not entirely sure about this unsafe cast. I think it can't fail, but I'm not 100% sure about it.
Update:
We can make it a little more funny by converting the function to extension operator invoke:
operator fun <T : Any, R> KFunction<R>.invoke(params: T): R
Then we can use it with any function like this:
(foo::doSomething)(myParams)
I'm not sure if this is a good idea though as it is more confusing than an explicit call to the utility function.

extension lambdas accept wrong parameters

I think an extension lambda requires that you pass in the correct argument, but i seems not to do so in the following example.
open class Base {
open fun f() = 1
}
class Derived : Base() {
override fun f() = 99
}
fun Base.g(): Int { return f()}
fun Base.h(xl: Base.() -> Int): Int { return xl()}
fun main() {
val b: Base = Derived() // Upcast
println(b.g())
println(b.h { f()}) // [1]
}
I understand that Base.h takes a function that takes a Base object as its parameter. But line [1] shows that it accepts f(), which is a function that takes no parameter. I was thinking hard about this and I prefixed it with this.f() and it still worked. Not convinced, I modified the code as follows:
open class Base {
open fun f() = 1
}
class Derived : Base() {
override fun f() = 99
}
fun Base.g(): Int { return f()}
fun Base.h(xl: (Base) -> Int): Int { return xl(Base())}
fun test(i:Int) = 1
fun main() {
val b: Base = Derived() // Upcast
println(b.g())
println(b.h { test(1) })
}
This code works. I've run it to verify. And as you can see, b.h() accepts test(), which takes an Int. And this is contrary to the fact that Base.h() takes a Base.
Could you explain this? Thank you for reading.
Note the curly brackets around the functions that are passed in! They change everything.
In the second code, b.h { test(1) } is not passing the function test to b.h. The syntax to pass test to b.h would be b.h(::test), and that does produce an error as you would expect.
b.h { test(1) } passes a function (a lambda expression) that takes a Base as parameter, ignores that parameter, calls test(1) and returns the result. You are basically passing a function that looks like this to b.h:
fun foo(p: Base) = test(1)
You might be wondering how Kotlin knows about Base when you did not write the word Base in the call at all. Well, it can just look at the declaration of b.h, and see that { test(1) } must take a parameter of Base.
The first code snippet is a bit different, because b.h accepts a Base.() -> Int in that case. Base.() -> Int represents a function whose receiver type is Base, that is, a function func that can be called like someBaseObject.func(). Compare this to a function func that takes a Base object as parameter, which can be called like func(someBaseObject).
Again, { f() } is not passing the function f. It is a lambda expression that does nothing but calls f. In this case though, f itself can be passed to b.h (b.h(Base::f)), because it is a function with a receiver type of Base! You can do someBaseObject.f(), can't you? Passing the lambda is similar to passing an extension function that is declared like this (you're just "wrapping" f in another function):
fun Base.foo() = f()
And since the receiver of the function is Base, you are able to access other functions that has Base as the receiver (such as f) in the lambda. You can also specify the receiver (which is this) explicitly.

How to convert function output to Unit with Kotlin

I have troubles with a function in Kotlin that should return Unit, but due to a usage of another function returning a Boolean, there is a type mismatch.
Here is a contrived example:
fun printAndReturnTrue(bar: Int): Boolean {
println(bar)
return true
}
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}
Here, I actually do not care about the fact that printAndReturnTrue returns a boolean. I just want foo to perform side-effect operations. But the compiler warns about a type mismatch: my else should return a Unit value.
Is there a nice way to convert a value to Unit?
The simplest solutions I see are:
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> {
printAndReturnTrue(bar)
Unit
}
}
or:
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> eraseReturnValue(printAndReturnTrue(bar))
}
fun eraseReturnValue(value: Any) = Unit
Or I use the full function form:
fun foo(bar: Int): Unit {
when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}
}
I am sure there are some idiomatic ways to do that (or is is the last example?), but for now I did not find them.
Unfortunaly, there's no idiomatic way to do this. A similiar problem, passing a lambda of type (T) -> Boolean to a function accepting (T) -> Unit lambdas has come up before, and the auto conversion required there is supposed to come to the language at some future point.
For now, you could use an extension function at the end of the when expression to coerce it back into a Unit value:
fun Any?.toUnit() = Unit
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}.toUnit()
Alternatively, an extension property, if you happen to like that better:
val Any?.unit get() = Unit
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar)
}.unit
Of course you can omit the explicit Unit return type of the function if you use either of these.
I think the last is most idiomatic. Though you don't need explicit : Unit, it's the default for block form if no return type is specified and if you try to return something else you'll get an error.
But note a subtle detail: when when is used as an expression, else is required unless the compiler can prove all cases are handled; in the block form it's "used as a statement" and unhandled cases are ignored.
As another alternative, you could make a higher order function that swallows the output of the function returning a value:
fun consume (fn: () -> Any): Unit {
fn()
}
Giving:
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> consume { printAndReturnTrue(bar) }
}
I just use a semicolon if I write in a line.
someExpression; Unit
I think you should change return type of function to optional, it's more clear, like below:
fun printAndReturnTrue(bar: Int): Boolean {
println(bar)
return true
}
fun foo(bar: Int): Unit? = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar) as? Unit
}
You could also do something like
fun foo(bar: Int): Unit = when(bar) {
0 -> println("0")
else -> printAndReturnTrue(bar).let{ Unit }
}
You can just call .let {} on a non-unit value to discard it (while keeping the side-effect):
// ...
else -> printAndReturnTrue(bar).let {}
// ...
{} is a Unit-returning function that ignores its arguments. let is an extension function that passes its receiver to the given lambda -- in this case, the lambda ignores it, and produces Unit, as needed.

Kotlin function declaration: equals sign before curly braces

In Kotlin, the function declaration syntax allows you to write equals sign before the curly braces.
Consider these two examples:
Without = sign:
fun foo1() {
println("baz1")
}
The code inside the body gets executed by just calling foo1().
With = sign:
fun foo2() = {
println("baz2")
}
Here, when foo2() is called, nothing happens, but to get the body executed one can write foo2()().
What is the difference in these two declarations and why do they behave differently?
You can run the code using the following program:
fun main() {
foo1()
foo2()
}
/*
This code example produces the following results:
baz1
*/
This question, though having not much meaning, is [intentionally asked and answered by the author][1], because a few questions have already been posted where people got problems because of incorrect function definitions.
Despite visual similarity, the idea of these two declarations is completely different.
1. Function declaration without equals sign
Function declaration without equals sign is a Unit-returning function (similar to Java's void functions).
What's inside the curly braces is its body, which gets executed right on the function call. The function can be rewritten with Unit explicitly specified:
fun foo1(): Unit {
println("baz1")
return Unit
}
Kotlin doesn't require the return statement and explicit return type for Unit-returning functions, and both are usually omitted.
2. Function declaration with equals sign
Function declaration with equals sign is a single-expression function, and what it does is just return what's to the right of equals sign.
A simpler example: fun getInt() = 1 is just a shorter form of fun getInt(): Int { return 1 }.
In foo2, the right hand side is a lambda expression. The code inside the lambda code block is not executed. In other words, foo2 is a function that returns another function.
Return type of foo2 is () -> Unit, a function itself, and thus foo2 is a higher-order function.
Without the syntactic sugar and with explicit type, foo2 can be rewritten as
fun foo2(): () -> Unit {
val result: () -> Unit = { println("baz2") }
return result
}
As to the usage, the function which foo2 returns can be stored in a variable, passed around and can later be invoked:
val f = foo2()
f() //equivalent to
f.invoke()
This is also why foo2()() in the example executes the code from the lambda body.
Alternatively, we can add () at the end when we declare foo2(), as shown in the following example. As such, the lambda expression will be invoked when calling foo3(). But this is not a good pattern.
fun foo3() = {
println("baz3")
}()

Scala: Overloaded function with function as parameter

Given an overloaded function, with one taking a function as parameter. This parameter-function takes no arguments:
def func(param: () => Unit): Unit = {
param()
}
def func(param: Int): Unit = {
println(param)
}
While calling func with an anonymous function works perfect:
func(() => println("it works"))
Using a plain function fails:
def functionAsParam(): Unit = {
println("it works")
}
func(functionAsParam)
Obviously, Scala evaluates functionAsParam and don't pass the function itself to func. Question: How can I (as a user of a library which provides funcs) pass in a non-anonymous function?
There are several ways to do this. Either you explicitly pass the function as parameter:
scala> func(() => functionAsParam)
it works
scala> func (functionAsParam _ )
it works
(These two cases are slightly different though, in the sense that in the first example, you construct new anonymous function with your other function, and in the second example, you indicate that this function should not yet be evaluated, by adding _)
Or you create a variable which is a function and pass it along:
val fval = () => println("It works")
scala> func(fval)
It works
The error comes from the fact that you defined a method, but your func expects a function. Yeah, there is a problem with overloading in scala (in other areas as well). To fix it you need manually convert your method into a function (it's called eta-expantion):
func(functionAsParam _)
If you turn on -Xprint:typer you'll see that scalac expands you method into a function:
val res4: Unit = func({
(() => functionAsParam())
});