Why is possible to use a parameter and invoke it as a function?

Hi,

I am VERY new in Kotlin and still giving my first steps. Coming from Java I heard “is very similar” … but well, for me it is not :frowning:

I found trying to understand this code.

sealed class User {
}

data class ActiveUser(val name: String, val lastName: String, val email: String) : User () {

    fun <T> doSomething(nickname: String.() -> T?) =
            nickname(this.email) ?:  throw RuntimeException("Error")

}

so far I undertood this:

Sealed class is an abstract class used to handle inheritance in a better way.

ActiveUser class inherits from the sealed class and declare its own functions

doSomething accept one parameter of type string… THEN I get lost

I dont understand why is like this

String.() -> T?

I found the info for that https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver

But still I dont understand… what does it actually do?

T? is because I dont know the return type?

and the most shocking for me… how is possible that the parameter name can be used a method?

nickname(this.email)

I found no info about it…

Could someone please explain me a little? :sweat_smile:

Here is another example…

data class ActiveUser(val name: String) : User () {

    fun sayHello(value: String.() -> String) =
            value("hello ${this.name}")
}

fun main() {
val activeUser: ActiveUser
activeUser= ActiveUser("John")
println(activeUser.sayHello { "Charles" })
}

It prints Charles…

I have no idea of whats going on, its not clear for me what it does inside…

This is the type of a function with zero arguments (because of the ()) that returns a T? (a nullable T, can be any type here, the way the function is defined).

And the String. at the start means, that the function has a String as additional special receiver parameter, so it can be executed like this: "MyString".name() instead of name("MyString") and the string value will be called this inside the method instead of having a parameter name. Like if you would add a method to the String class.

Your code is confusing because you have multiple things in scope that are called name (the function parameter and the user-name), you should probably fix that.

Thanks for your reply! I understand more now, but I still have doubt about this part…

name is a field value of type String, how can it be referenced as a method? Not sure what exactly that code does :s

In Kotlin you can pass methods or lambdas as parameters. Under the hood, name implements a Function<> interface with an invoke method, similar to Java functional interfaces and name("String") is simply translated to name.invoke("String") or something similar by the compiler.

Thanks Jonathan

I understand the fact you can pass a methods or lambdas, but in my case I am sending a String… and name.invoke should do nothing actually, am I wrong?

for example, I can do this

activeUser.sayHello { toUpperCase() }

and this works, and will actually make sayHello return an Uppercased message with

HELLO JOHN

so, does it mean that if I put String.() , I can send practically whatever I want?

this is equivalent to Java

activeUser.sayHello(it -> it.toUpperCase())

or

activeUser.sayHello(new Function<String, String>() {
    @Override public String apply(String val) {
        return val.toUpperCase();
    }
})

What is Kotlin specific is that inside the {} you’re essentially inside the String class because of the (String.(...)) and can execute all the methods, that String has without needing a String variable. this is essentially the object that sayHello passes as argument, in this case the user name.

1 Like

I understand it now! so the magic is due the receiver, I just understood the concept and now is much clear for me! thanks a lot for the explanation!!