0

I am new in Kotlin and I am trying to understand type alias and functions.
I have the following example:

interface EmptyInterface
typealias GenericCase<T> = T.(EmptyInterface) -> T

val myFunctionVariable: GenericCase<String> = {
    _ -> "Hello world!"
}

So far what I understand is that I extend what ever T is defined with a function that accepts as argument an EmptyInterface and returns a T. So the myFunctionVariable is a function that should be called passing an EmptyInterface

But the following code does not compile

class a: EmptyInterface
println("${myFunctionVariable(a())}")  

I need to pass a String as the first parameter:

class a: EmptyInterface
println("${myFunctionVariable("",a())}")

Why is the string needed as the first parameter? T.(EmptyInterface) -> T which in this case is String.(EmptyInterface) -> String has only 1 parameter. Could someone please explain this?

Jim
  • 3,845
  • 3
  • 22
  • 47

2 Answers2

1

The T. in the type T.(EmptyInterface) -> T means that this function is an extension function on T. So the regular way to call this function is to acquire a T instance, and call it on that instance, as if it was a member function. In the case of your example, where you chose T to be a String, you have to call the function on a String instance:

"foo".myFunctionVariable(a())

The syntax you've used is an alternative way to call this extension, passing in the receiver as if it was the first parameter of the function (which, at the bytecode level, it actually is):

myFunctionVariable("foo", a())

If you wish to use your function with this syntax, however, it's better to declare it to take two parameters, as this invocation of an extension function can be quite unexpected.

(There's some more info about how you can go back and forth between a function that's an extension on a type and one that takes it as a first parameter in this answer.

zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • But how does `typealias` come into play here? I thought that by the way I declared the typealias I was essentially doing exactly what you mention i.e. `"foo".myFunctionVariable(a())` – Jim Feb 17 '19 at 20:23
  • The `typalias` doesn't make much of a difference in this case, it doesn't introduce a completely new type, it's just shorthand to make your code more readable. Your variable of type `GenericCase` has the type that the alias represents, so in this case, `String.(EmptyInterface) -> String`. And that type is a function that extends a `String`, takes an `EmptyInterface` parameter, and returns a `String`. – zsmb13 Feb 18 '19 at 06:02
1

In the type T.(EmptyInterface) -> T, the first T is the receiver: an instance that the function is called upon, and which becomes this within the function definition.  (Similar to an extension function.)

Effectively, the receiver becomes a hidden first parameter to the function; as you discovered, if you try to call the function directly, you'll need to give it explicitly.

The language spec for it is here; some other answers may also help.

gidds
  • 16,558
  • 2
  • 19
  • 26
  • But I am using a `typealias`. Why is it like I am calling it passing `this`? – Jim Feb 17 '19 at 20:25
  • The receiver is as much a part of the type as the parameter types or the return type.  So the typealias means that your `myFunctionVariable` has a value which is a function taking a receiver, and that receiver needs to be specified somehow when calling the function. – gidds Feb 17 '19 at 20:34
  • But the function defined is `(EmptyInterface) -> T`. And that extends `String` in this case. So I can do `"".myFunctionVariable(a())`. Where I am stuck with is that I have not defined it as `{ _,_ -> "Hello world!"}` – Jim Feb 17 '19 at 20:45
  • The receiver is an _implicit_ parameter.  It's not passed like other formal parameters (so you don't include it in the parameter list); instead, it's passed as the value of `this` within the function. – gidds Feb 17 '19 at 21:11
  • Ok I got you about the implicit `this`. Isn't `typealias` like an alias for the type? So why in that case the `this` becomes explicit? – Jim Feb 17 '19 at 21:36
  • Yes, a `typealias` is just an alias for the type.  (Or so I believe; I've never used it myself.)  So this isn't to do with `typealias`; you'd get the same if you declared `val myFunctionVariable: String.(EmptyInterface) -> String`.  (Note the `String.` receiver.  As I said, that's part of the type.) – gidds Feb 17 '19 at 21:43