Sunday, 26 February 2023

Kotlin MutableIterable

This post is a sort of kotlin follow up to this post from last year. Kotlin follows the common iterable-iterator nomenclature (the only platform that uses a different naming, IEnumerable-IEnumerator is .Net...), and same as in Python, Iterators are also Iterables. They are iterable because there is an extension function for the Iterator interface that returns the iterator itself. This means that the Iterator interface does not inherit from the Iterable interface. I wonder if there's any reason for implementing it this way rather than as a default Interface method. From here:

Returns the given iterator itself. This allows to use an instance of iterator in a for loop.

Kotlin adds something new (to me) to the Iterable-Iterator pair, it features also a MutableIterable-MutableIterator couple. A MutableIterator has a remove method that removes from the underlying collection the last element returned by the iterator. You can see a usage example here


val numbers = mutableListOf(1,2,3,4,5,6)
val numberIterator = numbers.iterator()
while (numberIterator.hasNext()) {
    val integer = numberIterator.next()
    if (integer < 3) {
        numberIterator.remove()
    }
}

Including a remove-delete capabiliby in the iteration logic is not common. Neither JavaScript, nor Python nor .Net do this. I wrote an article about iteration and removal one decade ago and reading it again now has helped me to refresh ideas. I had forgotten that as I explain there Java iterators have a remove method. The Kotlin approach of having 2 different pairs, Iterable-Iterator, MutableIterable-MutableIterator seems much more correct. As Kotlin has had mutable and immutable collections since the beginning (I think) the need for this distinction had to seem evident to the smart guys that designed Kotlin.

Prompted by that old post of mine I've been thinking about deleting while iterating in Python. I'm talking about deleting from the original object, not about creating a new collection with the not removed ones (that is as simple as just filtering the collection) Of course you can always use the "universal" solution of using a normal while loop and an index, and either traversing backwards or moving forward and being careful with how you update your position. But what about a for in and a iterator? If we try this:


l1 = ["Paris", "Toulouse", "Torino", "Xixon"]

for i, v in enumerate(l1):
    if v.startswith("T"):
        del l1[i]

print(l1)
['Paris', 'Torino', 'Xixon']


We don't get an exception as we get in .Net (for that .version thing that I explain in the old post), but we skip from the iteration the next item, so in this case Torino does not go through the validation and remains in the list.

Googling around I came across an amazing solution, that uses slice assignment to do an in place replacement of the whole original list with the filtered one.


l1 = ["Paris", "Toulouse", "Torino", "Xixon"]

l1[:] = [v for i, v in enumerate(l1) if not v.startswith("T")]
print(l1)
['Paris', 'Xixon']


I have to admit that I had never heard about slice assignment. The idea is that when we do:



l1 = ["a", "b", "c", "d"]
l2 = ["X", "Y"]

l1[1:3] = l2
print(l1)
# ['a', 'X', 'Y', 'd'] 

We are are replacing that slice of the list on the left with the list on the right.

Saturday, 18 February 2023

Python Type Hints, Cast and Any

When I came back into Python programming 1 year ago and came across ype hints I was not particularly excited about them. I had the same feeling I'd had when TypeScript arrived to the JavaScript world, that it was somehow limiting the power of an almighty dynamic language, and started to use them occasionally, but now I'm totally hooked to type hints. I use them even for the most trivial scripts. The sort of "basic documentation" that type annotations provide, and the way they empower intellisense and prevent bugs is something that seems essential to me now. The amazing thing is that using Any, cast and Protocols you can have the best of 2 worlds, ultra dynamic, duck-typed code with object expansion, inheritance modification and so on, and the development friendliness provided by type hints.

Any is what in this post I qualified as Top and Bottom type. Objects of any type can be assigned to a variable hinted as Any, and an object hinted as Any can be assigned to a variable of whatever type.
We can use Any in sections of code where we don't care about type checking. Assign the Any type to a variable or parameter and the type-checker will not complain about anything that we try to do with that object.

Casting. The typing.cast function in python behaves like the rest of the type hints infrastructure, it's used only by they type checker (mypy for example) and has no effect at runtime (we know that the only effect that type hints have at runtime is that they are available as annotations). While in static typed languages like Java and C# casting an object to an incorrect type will cause a runtime error, in python it'll do nothing, as cast() just returns the instance object passed to it. Duck-typing is one of those Python features that we love so much, and we can make it play nicely with type hints just by using a cast. My object is not a Duck, but it quacks, and my function expects a Duck, but just to make it quack, so let's pretend to be a Duck by casting to a Duck, so that the function accepts it.


lass Animal:
    def __init__(self, name):
        self.name = name

    def move(self):
        print(f"Animal {self.name} is moving")

class Button:
    def __init__(self, name):
        self.name = name

    def move(self):
        print(f"Button {self.name} is moving")

def do_sport(item: Animal):
    print("doing sport")
    item.move()

a1 = Animal("Xana")
do_sport(a1)

b1 = Button("Slide")
# inferred type is Button

# at runtime this is fine thanks to Duck Typing
# but the type-checker complains:
# error: Argument 1 to "do_sport" has incompatible type "Button"; expected "Animal"
do_sport(b1)

# so let's cast it
do_sport(cast(Animal, b1))

# if we cast it to Any we get the same effect, but obviously we lose intellisense
do_sport(cast(Any, b1))

We have an interesting combined use of casting to Any and casting to an specific type when we are expanding an object (adding to it a method for example). Let's see it:


from typing import cast, Any
import types 

class Animal:
    def __init__(self, name):
        self.name = name

    def move(self):
        print(f"{self.name} is moving")

class Person:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print(f"{self.name} is speaking")

p1 = Person("Francois")
# let's add to this instance (expand it) the move method from the Animal class. We have to create a bound method, which we do with types.MethodType

# this works fine at runtime:
p1.move = types.MethodType(Animal.move, p1)
p1.move()
#but the type-checker complains
#expando.py:21: error: "Person" has no attribute "move"  [attr-defined]
#expando.py:22: error: "Person" has no attribute "move"  [attr-defined]


# we cast to Any to prevent this type-checker error: Cannot assign to a method  [assignment]
(cast(Any, p1)).move = types.MethodType(Animal.move, p1)
# and now we cast it to Animal and assign to a new variable so that we can use it comfortably
p2 = cast(Animal, p1)
p2.move()

Saturday, 11 February 2023

JavaScript arguments vs Python locals()

There's a technique in JavaScript combining the arguments (array-like) object and the spread operator that comes pretty handy. When I have a function receiving multiple parameters and invoking another function with those same parameters, I use the arguments object for convenience, rather than typing again the parameters list. I mean:


function format(name, age, city, country){
    console.log(`formatting: ${name} - ${age} [${city}, ${country}]`);
}

function validate(name, age, city, country){
    if (city == "Paris") {
        console.log("validation OK");
        format(...arguments);   //equivalent to: format(name, age, city, country)
    }
    else {
        console.log("validation KO");
    }
}


validate("Francois", 40, "Paris", "France");
validate("Francois", 40, "Lyon", "France");

// validation OK
// formatting: Francois - 40 [Paris, France]
// validation KO



One could wonder what happens if we modify the value of one of the function arguments before invoking the second function? Does the arguments-object that we are passing over reflect those changes? This is an important consideration in some use cases. Well, this is explained in this subsection. In not strict-mode the value gets updated, I mean:


function format(name, age, city, country){
    console.log(`formatting: ${name} - ${age} [${city}, ${country}]`);
}

function enhance(name, age, city, country){
    if (city == "Paris") {
        city = city.toUpperCase()
        age += 2;
        format(...arguments);  
    }
}

enhance("Francois", 40, "Paris", "France");

// formatting: Francois - 42 [PARIS, France]

What about using this same technique in Python? Well, Python does not have an equivalent to the arguments-object, but in many cases the locals function will do the trick.



def format(name, age, city, country):
    print(f"formatting: {name} - {age} [{city}, {country}]")

def validate(name, age, city, country):
    if city == "Paris":
        print("validation OK")
        format(**locals()) # equivalent to: format(name, age, city, country)
    else:
        print("validation KO");


validate("Francois", 40, "Paris", "France")
validate("Francois", 40, "Lyon", "France")

# validation OK
# formatting: Francois - 40 [Paris, France]
# validation KO

locals() returns a dictionary representing the current local symbol table, which includes the function arguments, that's why the above example works. But this means that if our function is a closure, the free vars trapped by the closure are also included, so this technique won't work for closures. There are more limitations. As we define new variables in our function they will be added to the dictionary returned by locals(), so again the technique would fail. Notice that different calls to locals() in one function return the same dictionary (I mean, it points to the same position in memory, the id()). As new variables are defined, they are added as new keys in that dictionary, and if values are updated, they are updated in the dictionary. This means that our second javascript example also works in Python:



def format(name, age, city, country):
    print(f"formatting: {name} - {age} [{city}, {country}]")
    
def enhance(name, age, city, country):
    if city == "Paris":
        city = city.upper()
        age += 2
        format(**locals()); 


enhance("Francois", 40, "Paris", "France")
# formatting: Francois - 42 [PARIS, France]


Thursday, 2 February 2023

Kotlin and inline functions

One of the many surprising (at least for me) features that one finds in Kotlin is inline functions. The Inline expansion of a function was not new to me. I know that compilers (either ahead of time compilers or JIT's) do it occasionally. They come across a small function and based on some rules consider that it will be faster to unroll its code in the callsite that invoking it. What was new to me is that the programmer can tell the compiler which functions to inline, it's the first time I come across with this option but I've been investigating and this exists also in F#, Scala and C-C++.

This excellent article explains pretty well why inlining is important in Kotlin (pretty interesting also how, as we saw in my previous post, the compiler creates either singletons or normal classes for hosting function references) . Long in short, in Kotlin we use functions (lambdas) in places where in other languages we just write the code in place (scope functions are a great example, and indeed I still don't find them particularly appealing save for DSL cases). This comes with a performance price, so Kotlin guys (that are really, really clever people) came up with the inline thing.

The article says:

When using inline functions, the compiler inlines the function body. That is, it substitutes the body directly into places where the function gets called. By default, the compiler inlines the code for both the function itself and the lambdas passed to it.

So with regards to inlining the functions passed to the inline function it only mentions lambdas (same as the kotlin documentation does), so I was wondering if an anonymous function would not be inlined. I've just done a fast test to verify that yes, it is inlined. In these 2 functions below (notice that the apply scope function is defined with the inline modifier) both the lambda expression and the anonymous funtion get inlined.


// notice that apply is defined like this:
// inline fun <T> T.apply(block: T.() -> Unit): T

class Person constructor (var name: String, var age: Int, var city: String) {
    fun sayHi(): String {
        return "Bonjour, je suis $name et j'habite a {city}"
    }
}

// lambda gets inlined
fun test1() {
    val p1 = Person("Francois", 4, "Xixón")
    p1.apply {
        name = name.uppercase()
        age += 1
    }
}

// anonymous function defined in place gets inlined
fun test2() {
    val p1 = Person("Francois", 4, "Xixón")
    p1.apply(fun(p: Person) {
        p.name = p.name.uppercase()
        p.age += 1
    })
}

All the examples for inlining that I've seen show the lambda being defined right in the place of the parameter to the function invokation, but what if we define it previously? It's clear that in most cases inlining can not be done. Normally when we have a variable that references the compiler can not know what specific function that variable will be referencing to (maybe the variable is initialized from a parameter, maybe there are conditionals...). But there are very specific cases where the compiler could check the whole function and know the real value being used and inline it. I mean cases that simple as this:


// lambda not defined right in place does not get inlined
fun test3() {
    val p1 = Person("Francois", 4, "Xixón")
    val fn: Person.() -> Unit = { 
        name = name.uppercase()
        age += 1
    }
    p1.apply(fn)
}

//anonymous function not defined right in place does not get inlined
fun test4() {
    val p1 = Person("Francois", 4, "Xixón")
    val fn: (Person) -> Unit = fun (p: Person) {
        p.name = p.name.uppercase()
        p.age += 1
    }    
    p1.apply(fn)
}

I've verified that it's not being inlined.

There's another topic that is a bit related to inlining, the usage of return. Believe it or not, apart from the normal "return" that we are used to in other languages (an unqualified return), Kotlin also has qualified returns, where the return is accompanied by a label. These labelled returns are also called non-local returns, as when we define and invoke a nested function, they allow it to return from the outer scope. Honestly I find this quite a bit confusing, but probably the most important thing to take from this is: Non qualified returns (unlabelled returns) are not allowed in lambda expressions, unless that the lambda expression is inlined.. In this case, returning from the lambda returns from the first "normal function" enclosing the lambda.

At first it seemed odd to me but now I think I understand the reasoning for this restriction. When we use a lambda as in my test1 function above, that is, define a lambda just in the place where it's being passed as parameter to another function, the visual effect is that it really does not look as function, it looks more as a language construct, like an if{}, while{}. In these cases, if we see a return written inside those {}, it could look more as a return from the enclosing function. If the lambda is being inlined that perception would be right as the return ends up as another statement of the enclosing function, but if it's not inlined, the lambda remains a function and that return would be just returning from it, not from the enclosing function. So in the end the programmer would have to be particularly attentive to what the return is really doing. For example in the same lambda expression a return would be doing different things depending on whether the lambda is declared, assigned to a variable and passed to a function, or whether it's directly defined and passed, in which case the behaviour would be different if the function gets inlined or not... So yes, it could be rather confusing, so restricting the usage of return makes things a bit more straight.

All this talking about "inlining" has reminded me of another very different kind of inlining, the possibility provided by C and C++ of writing inline assembly code. I've just learnt that the Rust also allows writing inline assembly!

Friday, 27 January 2023

Kotlin "::" Syntax

The :: symbol is used in Kotlin to address some syntactic particularities. We saw last week that functions are first-class citizens that can be passed around and returned, but it happens that the way to get a reference to a function or method is a bit odd. In Python and JavaScript we can assign a function (independent function, method...) to a variable just doing: let fn = functionName; let fn = obj.methodName;. In Kotlin we have to use ::: Maybe this has to do with the fact that in Kotlin there are at least 2 cases in which you can invoke a function without parentheses (trailing lambda expressions and infix notation) and because of that it could be difficoult for the compiler to determine if we are getting a function reference or invoking it.

Function References. So as I've just said, to assing, pass over, return... an existing function you have to obtain a function reference, using ::


fun sayHi(from: String, to: String) {
    println("Hi from $from to $to")
}

    // for this the compiler creates a Singleton class
    val greet = ::sayHi
    greet("Xose", "Francois")


The Kotlin compiler creates a singleton class implementing one of the "Function Types interfaces", kotlin.jvm.functions.Function2, that from its invoke method calls into the sayHi function.

Kotlin also allows you to immediatelly invoke the function reference. In that case, as you don't need a "Function object" to pass around, no class is created, it just generates exactly the same bytecodes than for a direct call to the function. I mean, these 2 lines are exactly the same:


   (::sayHi)("Xose", "Francois")
    sayHi("Xose", "Francois")  

Method References. We can get a reference to a method. If we get the method from the class it will be un Unbound Method Reference (when invoking it we have to pass as first parameter the "receiver"). If we get the method from an instance we get a Bound Method Reference.
Let's see an example for Unbound Method References


class Formatter constructor(val wrap: String) {
    fun format(msg: String): String {
        return "${wrap}-${msg}-${wrap}"
    }
}

fun testUnboundMethodReference2(){
    // for this one the compiler creates a new Singleton class
    val format: (Formatter, String) -> String = Formatter::format
    println(format(Formatter("|"), "AA"))
}   

For that case the compiler creates a Singleton class also implementing the Function2 "Function Type Interface", with an invoke method that receives 2 parameters and uses the first parameter as receiver for calling into format.

We can also invoke a method reference immediatelly, in that case no new class is created, it's just the same as doing a normal call through the receiver


fun testUnboundMethodReference1(){
    // no new class gets created. Indeed the bytecodes are basically the same as in testNormalMethodCall
    println((Formatter::format)(Formatter("|"), "AA"))
}

And now an example forBound Method References


fun testBoundMethodReference(){
    // obviously for this the compiler also creates a new class (not a singleton, it has the receiver (formatter object) as a property)   
    val formatter = Formatter("|")
    val format: (String) -> String = formatter::format
    println(format("AA"))
}   

The compiler creates a new class with a property pointing to the receiver and an invoke method that receives one string as parameter and invokes "format" through the receiver.

We can also get a references to a constructor by using: myFn = ::ClassName. Again a new singleton class is created by the compiler. As Kotlin does not use "new" to create instances, we can pass around that constructor reference as a factory to other methods, same as we can do in Python.


fun testConstructorReference(){
    val factory: (String) -> Formatter = ::Formatter
    val formatter = factory("|")
    println(formatter.format("AA"))
}

Finally we can also get bound and unbound refereces to properties.
I've just realized that what I've posted so far here is almost like a rewrite, with different samples and some information about what the Kotlin compiler generates, of what comes in the Callable References" documentation.

The additional use of the :: syntax is to obtain an object (an instance of KClass) that contains information about one class. We can get it directly from the class Person::class or from an instance myPerson::class. We should not confuse a Kotlin KClass with a Python metaclass. A KClass is just information about a class, while a Python metaclass is a class used to create other classes (this idea does not exist in Kotlin).

Sunday, 22 January 2023

Throw as en Expression

Thanks to learning Kotlin I've got introduced to some features and techniques that I had never thought about. I guess it's because Kotlin is the most funtional programming friendly language that I've used. I've read somewhere that in Kotlin every statement is either a declaration or an expression. Thanks to this we have "if-else expressions", "switch expressions", "try expressions", "throw-retur-break-continue expressions"... The idea of a throw expression seemed odd to me, until that I saw an example:


fun fooOffensive(value: String) {
     val number = value.toIntOrNull() ?: throw IllegalArgumentException("The given argument is not a valid number string")
    // do something with number
}


It's nice, really nice. Neither JavaScript nor Python (this is obvious, as while Python has many, many strengths, it's, among modern languages, one of the less functional programming friendly ones) has this feature, but I've realised that we can easily get the same effect of throw expressions. Just by defining a throwException function we can write code using the ternary operator in JavaScript like this:


function throwException(ex){
    throw ex;
}

function processMessage(msg){
    msg = msg.startsWith("Msg-") ? msg.toUpperCase() : throwException(new Error("Wrong format"));
    console.log(`Processing message: ${msg}`);
}

let msgs = ["Msg-Connect", "aaa"]
for (let msg of msgs){
    try{
        processMessage(msg);
    }
    catch (ex){
        console.log(`Error!!! - ${ex}`);
    }
}

// Processing message: MSG-CONNECT
// Error!!! - Error: Wrong format


And code using optional chaining like this:


let europe = {
    countries: {
        France: {
            population: 65000000,
            cities: {
                Paris: {
                    population: 2000000,
                    code: 75
                }
            }
        }
    }
}

function getCityInfo(city){
    let code = europe?.countries?.France?.cities?.[city]?.code ?? throwException(new Error("Missing City"));
    console.log(`getting city info for ${code}`);
}

let cities = ["Paris", "Lyon"]
for (let city of cities){
    try{
        getCityInfo(city);
    }
    catch (ex){
        console.log(`Error!!! - ${ex}`);
    }
}


// getting city info for 75
// Error!!! - Error: Missing City


In Python we can leverage an equivalent raise_exception function when using the (sort of) "ternary operator":


def raise_exception(ex: BaseException):
    raise ex

def process_message(msg):
    msg = msg.upper() if msg.startswith("Msg-") else raise_exception(Exception("Wrong format"))
    print(f"Processing message: {msg}")


msgs = ["Msg-Connect", "aaa"]
for msg in msgs:
    try:
        process_message(msg);
    except Exception as ex:
        print(f"Error!!! - {ex}")
        
# Processing message: MSG-CONNECT
# Error!!! - Wrong format


As we know Python lacks so far a "safe navigation - optional chaining" operator (there are renewed discussions, and the usual absurd oppositions based on "it's unpythonic, it makes code hard to read (for non real programmers)..." and so... As we saw in this post, we can get similar safe navigation effect with a rather clear syntax, just by using a function. I've adapted such function to throw exceptions if requested. It receives a lambda (already trapping in its closure the variable to "navigate") and an optional second parameter. If the safe navigation fails, if the second parameter has not been provided the function returns None, if provided, if it's an instance of Exception it throws it, otherwise returns the value.



def raise_exception(ex: BaseException):
    raise ex
    
def safe_access(fn, default = None):
    """ returns None by default if something in the chain fails. 
        If the default value is provided and it's an Exception, it throws it, otherwise it returns it
    """
    try:
        return fn()
    except (TypeError, KeyError, IndexError, AttributeError):
        return raise_exception(default) if isinstance(default, BaseException) else default


class Person:
    def __init__(self, name, age, profession):
        self.name = name
        self.age = age
        self.profession = profession

class Profession:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
    
    def format_profession(self, st1, st2):
        return f"{st1}-{self.name}-{st2}"

p1 = Person("Francois", 4, Profession("programmer", 50000))

print(safe_access(lambda: p1.name))
print(safe_access(lambda: p1.city))
print(safe_access(lambda: p1.city.name, "Paris"))
try:
    print(safe_access(lambda: p1.city.name, Exception("Missing city")))
except Exception as ex:
    print(f"Error: {ex}")
print(safe_access(lambda: p1.profession.salary))
print(safe_access(lambda: p1.profession.format_profession("¡¡", "!!").upper()[:6]))
print(safe_access(lambda: p1.profession.format_profession("¡¡", "!!").upper()[:6]))

# invoking a non callable
print(safe_access(lambda: p1.profession.salary()))


Thursday, 19 January 2023

Kotlin Function Types

I've recently started to fiddle with Kotlin and it's being a really nice experience. It reminds me a bit of my excitement in 2011 when I discovered Groovy. Well, as I've always been a fan of dynamic languages I would say that Groovy still seems more advanced to me, but given how much attention Kotlin has gained, Kotlin seems to me the best option to leverage the power of a JVM. There are tons of concepts that suddenly come up when you start to learn Kotlin, most of them sound more or less familiar from other languages, but they've helping me to rethink how I do things in other languages, why other languages do things differently, etc.

I'll talk today about Function Types, and anything that I'll say in this post is related to Kotlin code compiled for the JVM. So in Kotlin, as in any other modern language, functions are first-class citizens. They are like objects that can be assigned, passed around and returned. Kotlin is statically typed, and for the JVM functions are not objects, they are always methods of a class. Function Types are the mechanism that allows Kotlin to manage function as objects with well defined types (the type of their parameters and of its return). Hum, I've just realized that I have just rewritten with other words what I learnt 1 month ago in this excellent article.

From a Type Checking point of view Function Types are more or less the same that when in Python we use the Callable type with Type Hints. A Kotlin Function Type like this: (String, Int) -> String that represents a function that receives a string and an int and returns a string is equivalent to this Type Hint in Python: Callable[[str, int], str]. However, Function Types are more than a Kotlin facility to help with Type Checking. In the JVM everything is typed, so Function Types have to be expressed somehow at the JVM level, so in the end Function Types are syntactic sugar for an Interface containing an invoke method. As I aforementioned, when Kotlin code is compiled to Java bytecodes, Kotlin functions have to end up being methods in a class. So for each "function object" (lambda expression, anonymous function, function reference) that we define the Kotlin compiler will create a class that implements an interface that corresponds to the Function Type for that function. Decompiling with javap -c the .class files generated by kotlinc you'll see that these are the kotlin.jvm.functions.FunctionX interfaces, for the Function Type that I'm using as example we have: kotlin.jvm.functions.Function2<java.lang.String, java.lang.Integer, java.lang.String>. This is explained here.

Kotlin has also Function Types with Receiver, something like: String.(Int) -> String. This is used to represent functions that can be invoked as if they were methods of the first parameter (the receiver), I mean, "hi".say(2). We could say that they are an additional layer of Syntax Sugar, cause the interface for String.(Int) -> String is the same interface that we saw before for (String, Int) -> String, that is: kotlin.jvm.functions.Function2<java.lang.String, java.lang.Integer, java.lang.String>. Given that in the end both Function Types represent the same interface a Function Type with Receiver can be invoked through the receiver or with the receiver as its first explicit parameter. Also, I can do assignmet between compatible types of Funtion Types with and without receiver. What is not allowed is invoking a normal Function Type as a compatible Function Type with Receiver. I hope the code below makes a bit more clear what I mean.


class City constructor(var name: String, var population: Int) {
    fun multiplyPopulation(factor: Int){
        population *= factor
    }   
}

val paris = City("Paris", 2000000)

// declare a Function Type with Receiver
var multiplier2: City.(Int) -> Unit
// assign a function reference to it
multiplier2 = City::multiplyPopulation 

// can invoke it both through the receiver
paris.multiplier2(2)

// or passing the receiver as parameter
multiplier2(paris, 2)

// -------------------------------

// declare a Function Type
var multiplier3: (City, Int) -> Unit = City::multiplyPopulation 

multiplier3(paris, 2)

// I CAN NOT invoke a "normal function type" as a "function type with receiver"
//paris.multiplier3(2) // Compilation Error: unresolved reference: multiplier3


// I can assign a "normal" Function Type to a compatible Function Type with Receiver
multiplier2 = multiplier3
// and invoke it one way or another
multiplier2(paris, 2)
paris.multiplier2(2)

// I can also assign a Function Type with Receiver to a "normal" Function Type
multiplier3 = multiplier2
multiplier3(paris, 2)

// but as expected this does not compile
// paris.multiplier3(2)

With the examples that I've used so far one could think that this idea of Function Types with Receiver is not particularly interesting. Being able to write "a".say(2) rather than say("a", 2) is not something that makes the code particularly more expressive or beautiful. Right, but I think the main idea of Functions Types with receiver is using them with Lambda Expressions with Receiver when passing them as parameters to another function. The apply scope function is the perfect example. We can write code like this:


city.apply {
	name = "a"
	age = 47
}

because the apply function is defined as receiving a Function Type with Receiver, like this:


public inline fun  T.apply(block: T.() -> Unit): T {
    block()
    return this
}

I guess Kotlin guys (some of them coming from Java) will love the "implicit this" feature (the block() line is the same as this.block(), the name = "a" is the same as this.name = "a"), but for me sometimes it makes code less straightforward. I guess it's because I've got so used to JavaScript, where "this" can be dynamic or "static" ("bound" through function.bind or trapped as "lexical this" in arrow functions), but you have to explicitly type it, and to Python where the first parameter of a method is just named "self" by convention and you have to type it both in the method signature and when using it.