Kotlin logo

Kotlin

A concise multiplatform language developed by JetBrains

Language design

Upcoming Change: “Class Objects” Rethought

Kotlin M11 is coming very soon, and as some of you expressed concerns about being informed about the upcoming changes, I will describe one of the features of M11 and ask you for some feedback.

Class Objects: a short reminder

As you all know, any Kotlin class can have an associated class object:

class KotlinClass {
    class object {
        fun classObjectMember() {}
    }

    fun classMember() {}
}

Members of a class object are roughly analogous to static members of Java/C# classes, as they can be called on the class name:

KotlinClass.classObjectMember()

(You can even use the [platformStatic] annotation to make those member actually static when seen from Java.)

In fact, Kotlin’s class objects and Java’s statics are not at all the same, because class objects are objects, i.e. they can extend classes, implement traits and serve as values at runtime:

val x = KotlinClass // reference to class object of KotlinClass is assigned to x

Terminology Change

As you might have noticed, the term “class object” sounds a little ambiguous in English, and this is why many people tend to think that class object of Foo must be an instance (in other words, object) of Foo, which is totally not so. This, among other reasons, is why we are looking for another term and syntax. The current proposal has it as follows:

class KotlinClass {
    default object {
        fun defaultObjectMember() {}
    }

    fun classMember() {}
}

So, what used to be called “class objects” will now be called “default objects”.

More motivation is coming below, but at this point, please note how you feel about this change: is it better now? more confusing? about the same as before?
Please share your opinion in the comments below, now, before reading the motivation. Thanks a lot!

Why Default Objects

NOTE: all syntax presented here is provisional (we have it implemented, but might decide to change it before M11).

The unfortunate wording is not the only reason for this change. In fact, we redesigned the concept so that it is more uniform with normal objects.

Note that a class can (and always could) have many objects (usual, named singletons) nested into it:

class KotlinClass {
    object Obj1 { ... }
    object Obj2 { ... }
    ...
}

Now, one of these objects may be declared with the default modifier, which means that its members can be accessed directly through class name, i.e. by default:

class KotlinClass {
    object Obj1 { ... }
    default object Obj2 { ... }
    ...
}

Accessing members of Obj1 requires qualification: KotlinClass.Obj1.foo(), for members of Obj2 the object name is optional: KotlinClass.foo().

One last step: the name of a default object can be omitted (the compiler will use the default name Default in this case):

class KotlinClass {
    object Obj1 { ... }
    default object { ... }
    ...
}

Now you can still refer to its members though the name of the containing class: KotlinClass.foo(), or through full qualification: KotlinClass.Default.foo().

As you can see, unlike what we used to have with class objects, default objects are completely uniform with normal objects.

Another important benefit is that now every object has a name (again, Default is used when the name of a default object is omitted), which enables writing extension function for default objects:

fun KotlinClass.Default.bar() { ... }

This can be called as KotlinClass.bar(). This is how we implement platform-specific extensions for built-in classes like Int: e.g. Int.MAX_VALUE is an extension for Int.Default defined only on the JVM (JS ony has floating-point numbers, so Int.MAX_VALUE is meaningless there).

Summary

  • We are changing the syntax and conceptual load of what was formerly known as “class objects”: they are now default objects.
    • The old syntax will be deprecated and kept around for a while, so that you can migrate your code (in which the IDE will assist you).
  • The new concept is uniform with normal named objects.
  • You can now write extensions to default objects that can be called on class names.

Your feedback is very welcome! A large part of this change is about terminology and wording, so if you think the new concept is confusing is some way, please tell us in the comments.

image description