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

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
}

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

Tell Kotlin that a generic type is an interface

Let's say I have a class Foo
class Foo {
val noProblem = "Hakuna Matata"
}
I now want to decorate it with an ID. Kotlin's delegates make this relatively painless:
class IdentifiableFoo(
val id: Int,
foo: Foo,
): Foo by foo
interface Foo {
val noProblem: String
}
class FooImpl: Foo {
override val noProblem = "Hakuna Matata"
}
but let's say I have another class Bar that I also want to decorate, and then another Baz, and then another ...
I could just create a IdentifiableXYZ for each of them, of course.
But what I really want is something akin to
class Identifiable<T> (
val id: Int,
thing: T
): T by thing
That I could just use for all of them.
And yes, there's a very good chance that the language doesn't support something like that, but the error message made me think:
Only classes and interfaces may serve as supertypes
so can I do some where magic or something to tell Kotlin that T is required to be an interface?
It is not possible in Kotlin. Kotlin only allows super type to be either a class or an interface. Type parameter cannot be a super type of some class or interface.
One workaround might be using a base interface for all the interfaces you are using. But not sure it solves your problem.
class IdentifiableFoo<T : BaseFoo>(
val id: Int,
val foo: T,
) : BaseFoo by foo {
fun doSomething(a: T.() -> String) {
println(a.invoke(foo))
}
}
interface Foo0 : BaseFoo {
val noProblem: String
}
interface Foo1 : BaseFoo {
val someProblem: String
}
class FooImpl : Foo0 {
override val noProblem = "Hakuna Matata"
}
class Foo1Impl() : Foo1 {
override val someProblem: String = "Some Problem"
}
interface BaseFoo {}
Usage:
IdentifiableFoo<Foo0>(2, FooImpl()).doSomething {
this.noProblem
} // Prints "Hakuna Matata"
IdentifiableFoo<Foo1>(2, Foo1Impl()).doSomething {
this.someProblem
} // Prints "Some Problem"
Playground link

Cloning object of subclass type in Kotlin

I wanted to be able to define a method to clone an object that is the same type of itself. I define the interface requesting such, but the following does not compile or run.
interface Foo {
fun <T: Foo> copy() : T
}
class Bar(private val v:Int) : Foo {
override fun copy():Bar = Bar(v)
}
main() {
val bar1 = Bar(1)
val bar2 = bar1.copy()
}
If however I write the implementing class in Java, it will compile
class Bar implements Foo {
private int v;
public Bar(int v) {this.v = v;}
public Bar copy() {
return new Bar(v);
}
}
I can rewrite the code like the following that compiles:
interface Foo<out Foo>{
fun copy(): Foo
}
class Bar(private val v:Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
However the following will fail with error: no type arguments expected for fun copy(): Foo
val newF = f.copy()
fun <T: Foo> addFoo(
foo: T,
fooList: List<T>,
): MutableList<T> {
val result: MutableList<T> = arrayListOf()
for (f in fooList) {
val newF = f.copy<T>()
result.add(newF)
}
result.add(foo)
return result
}
Is there a good solution to the problem?
The problem here is that Foo doesn't know the exact type of the implementing class, so has no way to specify that its method returns that same type.
Unfortunately, Kotlin doesn't have self types (see this discussion), as they would handle this situation perfectly.
However, you can get close enough by using what C++ calls the curiously-recurring template pattern. In Kotlin (and Java) you do this by defining Foo with a type parameter explicitly extending itself (including its own type parameter):
interface Foo<T : Foo<T>> {
fun copy(): T
}
Then the implementing class can specify itself as the type argument:
class Bar(private val v: Int) : Foo<Bar> {
override fun copy(): Bar = Bar(v)
}
And because T is now the correct type, everything else works out. (In fact, the : Bar is redundant there, because it already knows what the type must be.)
Your addFoo() method will then compile with only a couple of changes: give it the same type parameter <T: Foo<T>>, and remove the (now wrong, but unnecessary) type parameter when calling f.copy(). A quick test suggests it does exactly what you want (creates a list with clones of fooList followed by foo).
Since it's often useful for a superclass or interface to refer to the implementing class, this pattern crops up quite often.
BTW, your code is easier to test if Bar has its own toString() implementation, as you can then simply print the returned list. You could make it a data class, or you could write your own, e.g.:
override fun toString() = "Bar($v)"

Override getters in Kotlin?

So I have an abstract class Composition, which has two children: one is a Track, and one is an Album (which is a group of Tracks).
class Composition(val name: String, ...)
class Track(name: String): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name)
So far, so good. Now, I have the duration that is added. It is abstract in Composition, so I can override it in the children:
abstract class Composition(...){
abstract fun getDuration(): Int
}
Now, I can add override the method in the Track, which takes it as a parameter:
class Track(..., private val duration: Int): Composition(...){
override fun getDuration() = duration
}
And finally, I make the Album, whose duration is the sum of the Tracks:
class Album(..., val tracks: List<Track>): Composition(...){
override fun getDuration() = tracks.sumBy { it.getDuration() }
}
It works as intended, but I do not understand why I cannot simply use tracks.sumBy { it.duration }, since in Kotlin properties are nothing more than getters and setters (I'm thinking about the getDuration in Composition).
I feel like I'm missing something, because if the same code was written in Java, I would be able to call composition.duration as a property -- so that makes me think that Kotlin allows it from Java code, but not from Kotlin code, which is sad.
An other example:
Let's say I have a class named Artist, who wrote multiple Compositions:
class Artist(
val nom: String,
private val _compositions: MutableList<Composition> = ArrayList()
) {
// HERE (I wrote the extension method List<E>.toImmutableList)
fun getCompositions() : List<Composition> = _compositions.toImmutableList()
}
This is standard in Java (exposing immutable versions of Collections via getters, so they are not modified) ; Kotlin doesn't recognize it though:
val artist = Artist("Mozart")
artist.getCompositions() // Legal
artist.compositions // Illegal
I thought about making this a property, but:
- If I choose the type List<E>, I can override the getter to return the immutable list, but I cannot use regular methods (add...) as the List is immutable
- If I choose the type MutableList<E>, I cannot override the getter to return ImmutableList (which is a subclass of List that I wrote, and is obviously not a subclass of MutableList).
There's a chance I'm doing something ridiculous while there is an easy solution, but right now I cannot find it.
In the end, my question is: Why aren't manually-written getters considered properties when written from Kotlin?
And, if I'm mistaking, What is the expected way of solving both of these patterns?
If you want to use it as property, you should use Kotlin-way to override getter.
For example:
abstract class Composition(...){
abstract val duration: Int
}
// You can use "override" in constructor
// val - is immutable property that has only getter so you can just
// remove private modifier to make possible get it.
class Track(..., override val duration: Int): Composition(...){
...
}
class Album(..., val tracks: List<Track>): Composition(...) {
override val duration: Int
get() = tracks.sumBy { it.duration }
}
Also there are may be case when you need mutable property that can be changed only inside of object. For this case you can declare mutable property with private setter:
class SomeClass(value: Int) {
var value: Int = value
private set
}
Read more in docs: https://kotlinlang.org/docs/reference/properties.html#getters-and-setters
You have to define duration as an abstract property and not as an abtract function (https://kotlinlang.org/docs/reference/properties.html#getters-and-setters):
abstract class Composition(val name: String) {
abstract val duration: Int
}
class Track(name: String, override val duration: Int): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name) {
override val duration: Int
get() = tracks.sumBy { it.duration }
}
The getter/setter conversion as properties does only work for Java classes (https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters).

How to access extension property inside object from outside class?

Example:
class Foo {
fun foo() = Unit
}
object Bar {
val Foo.foo get() = Unit
}
fun Foo.bar() = Bar.foo
Extension symbols aren't static when inside a class instance, so I don't see why this wouldn't be possible by simply passing in the receiver.
You can do this, but you have to bring the Bar into the context as a receiver as well, along with reference to someFoo.foo otherwise you are saying Bar has a property foo which it does not. It has within its scope (and its instance) the extension of Foo.foo. Therefore change your last line from:
fun Foo.bar() = Bar.foo
to:
fun Foo.bar() = with (Bar) { foo }
which is conceptually this:
fun Foo.bar() = with (Bar) { this#bar.foo }
So we use with to stack the Bar receiver under the Foo instance receiver of this#bar and access the property foo.

What is the correct way to add an abstract private getter and a public setter?

I have an interface where I want a property that can be modified innside the class, but not outside. I cannot use val because it needs to be mutable and the var keyword can not have a specified private setter since this is in an interface.
In Java I would have done this:
public <T> getMyProperty();
I can use the same approach in kotlin and just write the getter function dirrectly, but this does not seem like a kotlinlike approach. Is there a better way to achieve the same as this?
fun getMyProperty()
In Kotlin, you can actually override a val with a var, so, I think, what you want can be expressed as follows:
interface Iface {
val foo: Foo
}
class Impl : Iface {
override var foo: Foo
get() = TODO()
private set(value) { TODO() }
}
Or you can override the val with a property with a backing field and default accessors:
class ImplDefaultGetter : Iface {
override var foo: Foo = someFoo
private set
}
In both cases, the mutability and the presence of a private setter become an implementation detail of the classes and are not exposed through the interface.