Kotlin implement `fun` as `val` (Similar to Scala implementing a `def` as `val`)

Viewed 74

In Scala you can define a trait with an undefined def to be implemented in the implementing class. Additionally a def can be implemented as a def or as a val.

trait Foo { def bar: Int }

class Baz(val bar: Int) extends Foo // ok

For Context

  • val has the same meaning in Scala and Kotlin
  • fun and def are more or less the same in Scala and Kotlin
  • trait and interface are more or less the same in Scala and Kotlin.

The advantage here is that some implementations of trait can return a static value for bar that is set when the class initializes, and some implementations can generate the value every time bar is accessed.

Is there similar functionality built into Kotlin?

I already tired implementing a fun as a val and that does not work. I currently have the code below, but it feels like there is more boiler plate here than necessary.

interface Foo {
    fun bar(): Int
}

class Baz : Foo {
    private val _bar: Int = TODO("Some heavy init function.") 
    override fun bar(): Int = _bar
}
1 Answers

It can be done with a val property instead of a function. When you define a property with just = and no get(), the initialization code is called a single time and assigned to the backing variable, so when the property is accessed, it simply reads the value stored in the backing variable without computing it again:

interface Foo {
    val bar: Int
}

class Baz : Foo {
    override val bar: Int = TODO("Some heavy init function.")
}

And the interface gives you the flexibility to make it something that is computed on demand (possibly different each time accessed) using a custom getter:

class Baz : Foo {
    override val bar: Int get() = Random.nextInt(10)
}

Or computed lazily using a property delegate (the first time it is accessed instead of at class instantiation time):

class Baz : Foo {
    override val bar: Int by lazy { TODO("Some heavy init function.") }
}

Or you can upgrade it to be a var and allow external classes to overwrite what is set in the property:

class Baz : Foo {
    override var bar: Int = 5
}

Or only internal to the class:

class Baz : Foo {
    override var bar: Int = 5
        private set
}

With the custom getter, you could do something more complicated involving backing properties, similar to your code with the fun. Or you can design your own property delegate if there's a pattern you use repeatedly.

Related