Kotlin supports a great deal of extension functions, allowing us to customize classes from other libraries a lot. The only feature we cannot extend is constructors.
Constructors are commonly imitated in libraries like JetBrains Compose:
class MyFunnyClass(val string: String)
fun MyFunnyClass(int: Int?) : MyFunnyClass = MyFunnyClass(int.toString())
However, there are a few problems with this syntax:
- IDE highlighting - the IDE considers this a function, not a constructor. As such, custom theming (like bold constructors) doesn’t work, and the IDE complains the function starts with an uppercase letter.
- Repetitive - this declaration repeats the name of the extended class three times when using
explicitApi. - Java Interopability - Java will call this function
MyFunnyClass(42), notnew MyFunnyClass(42)ormyFunnyClassOf(42).
I’m suggesting to introduce Extension Constructors, their syntax as such:
class MyFunnyClass(val string: String)
MyFunnyClass.constructor(int: Int?) : this(int.toString())
// or alternatively
constructor MyFunnyClass(int: Int?) : this(int.toString())
// and if you need more than one line...
MyFunnyClass.constructor(int: Int?) {
println(int ?: 42)
return this(int.toString())
}
Extension constructors always return the same type they extend.
Extension constructors won’t be able to use super(...), but only this(...), and won’t be appliable to enums and objects.
Extensions constructors can also be useful when creating default implementations for interfaces.
And for my third point - interopability with Java - I suggest adding a default @JvmName annotation:
@JvmName("myFunnyClassOf") // default, implicit unless overriden
MyFunnyClass.constructor(int: Int?) : this(int.toString())
As for interaction with the proposed context syntax:
context(Int?) // extension inner class?
MyFunnyClass.constructor() : this@MyFunnyClass(this@Int?.toString())
fun main() {
val num: Int? = 42
with(num) {
MyFunnyClass()
}
num.MyFunnyClass()
}
Additionally, inline extension constructors will be especially useful.