Friday 17 May 2024

Kotlin Interface 'Invokation'

In general I like Kotlin syntax a real lot (mainly the "almost everything is an expression" thing) but there are things that I find surprising/confusing (time ago we saw one of them). Recently, when reading a bit about Ktorm, the object-relation mapper, I came across some rather surprising syntax. The article itself mentions it and explains what's going on (otherwise I don't think I had manages to understand how that was working), but I think it'll be useful to me to put it here.


interface Department : Entity {
    companion object : Entity.Factory()
    val id: Int
    var name: String
    var location: String
}

val department = Department()


So the above code seems as if we were somehow creating an instance of an interface (Department), which is obviously not possible. I can think of 2 other situations where we write code that looks similar, but with a different explanation.

One case is the special syntax for functional interfaces/SAM conversions


val runnable = Runnable { println("This runs in a runnable") }

And the other case are object expressions with the object (of the anonymous class) implementing an interface. But the object: syntax, and the "class body" makes clear that we are not "instantiating that interface".


interface Writable {
    fun write(): String
}

//object expressions implementing interface, there's not () after the interface name
val o2 = object: Writable {
    var name = "Francois"
    override fun write() = name
}


The case we're dealing with in this post is a different thing. The original article explains it:

The Entity.Factory class overloads the invoke operator, so we can use brackets to call the companion object as it’s a function. The code creating a department object:

val department = Department()

That’s the charm of Kotlin, Department is an interface, but we can still create its instances, just like calling a constructor function.

What that means is that in the end that code that seemed as if we were invoking a sort of "interface constructor" indeed was calling the invoke method of the companion object of that interface, that is:


val department = Department()

// is right the same as:

val department = Department.Companion.invoke()

Friday 10 May 2024

Kotlin iteration, toList vs asIterable

In this previous post I talked about Iterables and Sequences in Kotlin, about the eager vs deferred and lazy nature of their extension functions (this StackOverflow discussion is pretty good). As I read somewhere "Collections (that are classes that implement Iterable) contain items while Sequences produce items". What I did not mention in that post is that the fact that Sequences are not Iterables feels quite strange to me (and I see no reason for the Sequence[T] interface not to implement the Interface[T] interface, it would not interfere with using the right extension function). In Python and JavaScript (where we don't have an Iterable class or interface) an iterable is a sort of "protocol". Anything that can be iterated (we can get an iterator from it) is iterable. In Kotlin we have an Iterable interface, but there are things (Sequences) that can be iterated (both the Iterable and Sequence interfaces have an iterator() method) without implementing that Interface. I guess what is confusing for me is saying "X is iterable" cause it seems very similar to saying "X is (implements) an Iterable". Saying "X can be iterated" seems more appropriate, a Sequence can be iterated but it's not an Iterable.

Well, let's put semantic discussions aside and let's see something more concrete. We can obtain a Sequence from an Iterable by means of the asSequence() extension function or the Sequence() function. We'll do that if we want to leverage the lazy extension functions for mapping, filtering, etc... In the other direction we can "materialize" a sequence into a Collection using the toList() extension function. That way we force the sequence to "produce" all its items and we store them in a collection. Additionally we also have the Sequence[T].asIterable() extension function. When/why would we use asIterable() rather than toList()?

Let's say we have a sequence on which we will be applying some filtering/mapping, and we want those functions to be applied in one go, eagerly, as soon as one item would be needed in an ensuing iteration. BUT we don't want to do it now. We can use asIterable() to get an object that implements the Iterable interface but contains no elements (so we are deferring the execution). Then, when we first invoke the map/filter extension function (on Iterable) the whole original sequence will be iterated and processed in one go (egarly). If we use .toList() the whole iteration of the sequence occurs immediatelly, before calling map/filter to process the items. I'm using the deferred/immediate execution and lazy/eager evaluation terms as explained in this excellent post.



fun createCountriesSequence() = sequence {
    println("Before")
    yield("France")
    println("next city")
    yield("Portugal")
    println("next city")
    yield("Russia")
}

    var countriesSequence  = createCountriesSequence()
    // converting the sequence to list immediatelly iterates the sequence
    var countries = countriesSequence.toList()
    println("after converting to list")

    // Before
    // next city
    // next city
    // after converting to list

    println()

    // what's the use of calling .asIterable() rather than directly .toList()?
    // with .asIterable we obtain a deferred collection (nothing runs until we first need it)
    // but as the extension functions in Iterable are eager, first time we apply a map or whatever the whole iteration is performed 
 
    countriesSequence = createCountriesSequence()
    //converting to iterable does not perform any iteration yet
    var countriesIterable = countriesSequence.asIterable()
    println("after creating iterable")

    println("for loop iteration:") //no iteration had happenned until now
    for (country in countriesIterable) {
        println(country)
    }

    // after creating iterable
    // for loop iteration:
    // Before
    // France
    // next city
    // Portugal
    // next city
    // Russia
    
    println()

    countriesSequence  = createCountriesSequence()
    countriesIterable = countriesSequence.asIterable()
    println(countriesIterable::class)
    println("after creating iterable") //no iteration has happenned yet (deferred execution)

    //applying an Iterable extension function performs the whole iteration (eager evaluation)
    val upperCountries = countriesIterable.map({ 
        println("mapping: $it")
        it.uppercase() 
    })
    println("after mapping")
    println(upperCountries::class.simpleName)


    // after creating iterable
    // Before
    // mapping: France
    // next city
    // mapping: Portugal
    // next city
    // mapping: Russia
    // after mapping
    // ArrayList


One more note. The iterator() method of an Iterable or Sequence has to be marked as an operator, why? This is the explanation I found in the documentation and in some discussion:

The for-loop requires the iterator(), next() and hasNext() methods to be marked with operator. This is another use of the operator keyword besides overloading operators.

The key point is that there is a special syntax that will make use of these functions without a syntactically visible call. Without marking them as operator, the special syntax would not be available.

Remember than in Kotlin (as in Python) we can not define custom operators, we can just overload the predefined ones.

Saturday 4 May 2024

Kotlin Companion Objects

Some weeks ago I wrote a post reviewing how static members work in different languages. I was prompted to perform such review to better understand the motivations for Kotlin designers to come up with that odd feature called companion objects (I think the only other well-known language with such concept is Scala).

As you can read here Kotlin features object expressions (let's think of it as an advanced form of object literals) and object declarations that initially I thought were only used for declaring singletons. Well, object declarations are also used for declaring companion objects. I won't repeat here the basis explained there in the official documentation.

So, what's the point with this companion objects thing? Honestly, for the moment I don't see them as providing any revolutionary advantage over static members in Python or JavaScript (as per my previous post static members in these 2 languages seem a bit richer than those in Java and C#), but it's an interesting approach. I should also note that this nice article explains that thinking of companion objects as just a different way to implement static members is missing part of the picture and that they should be seen more like "a powerful upgrade to static nested classes". As I very rarely use inner/nested classes I have little to say about this.

At one point in this discussion someone gives a good summary of how to think about companion objects:

Think of each member of the ‘real class’, being instanced with a reference to the same singleton of a special ‘secondary class’ designed to hold data shared by all members of the ‘main class’. You are actually calling a method the secondary class with calling a companion object method, and not actually having a static method at all.

I remember having read somewhere that from a theoretical point companion objects are superior to static members because we use objects to gather together all the members belonging to the class rather than to an instance of the class, instead of throwing them "in the middle of the class" as we do with static members. That's right, and thanks to using a single object for all those elements (methods and properties) belonging to the class, that object can inherit from another object, which seems to me (and others) like the main distinctive feature of companions.

On the other side, there are a couple of things that can be seen as limitations. First, companion objects are not inherited. If I define a companion object in class A, and have a class B that inherits from A, I can not access to the companion through B (while in Python and JavaScript static members are inherited). Second, I can not access the companion through an instance of the class, only through the class (this is possible in Python, but not in JavaScript). Notice that inside a method of the companion "this" (the receiver) points to the companion itself, so we can use "this" explicitly or omit it (implicit this). We can also use just the class name. I'll add here some code showing this:


package companionObjects


open class Country(var name: String) {
    var xPos = 0
    var yPos = 0
    companion object {
        val planetName = "Earth"
        fun formatPlanet(): String {
            // KO. We have no access to the "name" property in the Country instance 
            //return "${name} - ${planetName}"
            
            // OK, "this" refers to the companion
            //return "${this.planetName}"

            //so we can just use the implicit "this" (that refers to the companion itself)    
            return "${planetName}"

            // OK, access through the class rather than through "this"
            //return "${Country.planetName}"
            
        }
    }

    fun move(x: Int, y: Int) {
        xPos += x
        yPos += y
    }
}

class ExtendedCountry(name: String): Country(name) {}


// kotlinc Main.kt -d myApp.jar
// kotlin -cp myApp.jar companionObjects.MainKt

fun main(){
    val country1 = Country("France")
    
    // KO: Unresolved reference (so I can not access the companion through an instance, only through the class)
    //println(country1.formatPlanet())
    
    println(Country.formatPlanet())
    //Earth
    
    // KO: Unresolved reference (I can not access the companion from the derived class)
    //println(ExtendedCountry.formatPlanet())
}

So all in all we can say that a companion object is like having a single static member in our class, with that member pointing to an object. The members in that object are accessible directly through the containing class (no need to write MyClass.companion.member, just MyClass.member), so it's a form of delegation.