Kotlin: Issue implementing interface with getters - kotlin

I am trying to implement an interface with getter method which matches the constructor parameter name of the implementing class.
interface Car{
fun getModel(): Int
}
class Honda(val model: Int): Car {
override fun getModel(): Int {
}
}
If Honda doesn't implement getModel(), we get an Accidental Override error. If Honda implements getModel(), we get a Platform declaration clash error.
I can change the name of the parameter in the Honda constructor, which fixes the problem, but it feels like a redundant getter method.
interface Car{
fun getModel(): Int
}
class Honda(val modelParam: Int): Car {
override fun getModel() = modelParam
}
Is there a better way to implement such interfaces?

You can declare properties in interface:
interface Car{
val model : Int
}
Then in implementation / constructor you need to add override keyword.
class Honda(override val model : Int): Car

For case where the accepted answer isn't applicable because you can't change the interface, or the interface is a Java one,
class Honda(private val model: Int): Car {
override fun getModel(): Int = model
}
For a Java interface, it can still be accessed as .model in Kotlin.

Related

Can kotlin interface detects, on which class is attached to, on its own?

I have generic interface...
interface Parent<T> {
fun function(entity: T): Int
}
And when I implement functionality with some child class...
class Other : Parent<Other> {
override fun function(entity: Other): Int {
return 42
}
}
I'm bothered with the fact that I have to pass the same class type while implementing the interface... I would really like for the interface to be able to detect on which class is attached on its own without me providing the same type again...
I would like code something like this...
class Other : Parent {
override fun function(entity: Other): Int {
return 42
}
}
Is it possible in kotlin to do that in some form?
Not in the general case, but sometimes when a generic is fully constrained by another: https://kotlinlang.org/docs/generics.html#underscore-operator-for-type-arguments

How to create a class with a method that returns a subtype with a type parameter in Kotlin?

I am struggling to understand how generics / type parameters work in Kotlin. I am working on a (fairly complex) app that is throwing some very confusing error messages during compilation. I've simplified things below to the minimum amount of code that will reproduce the error.
I have an interface and two abstract classes:
interface Player {
fun play()
}
abstract class Device <T : Player> {
abstract fun getPlayer(): T
}
abstract class DeviceFactory {
abstract fun <T : Player> create(): Device<T>
}
The problem arises when I try to create a class that implements DeviceFactory:
class MyDeviceFactory : DeviceFactory() {
class MyPlayer : Player {
override fun play() {
println("[sound plays here]")
}
}
class MyDevice : Device<MyPlayer>() {
override fun getPlayer() = MyPlayer()
}
override fun create() = MyDevice()
}
The last line of code is where the problem arises, yielding the following error message:
Conflicting overloads: public open fun create(): MyDeviceFactory.MyDevice defined in MyDeviceFactory,
public abstract fun create(): Device defined in DeviceFactory
Thinking that maybe the problem was the missing type parameter, I tried this instead:
override fun <T : Player> create() = MyDevice()
Now I have a different error message:
Return type of 'create' is not a subtype of the return type of the overridden member
'public abstract fun create(): Device defined in DeviceFactory'
This doesn't make sense — MyDevice is a subtype of Device<T>, right? To be sure, I tried making the return type explicit:
override fun <T : Player> create(): Device<T> = MyDevice()
No dice:
Type mismatch: inferred type is MyDeviceFactory.MyDevice but Device was expected
How can I create a class that derives from DeviceFactory and returns an instance of MyDevice?
You need to declare the type for DeviceFactory on it's class:
abstract class DeviceFactory<T : Player> {
abstract fun create(): Device<T>
}
Then you can define a factory that returns a concrete Player:
class MyDeviceFactory : DeviceFactory<MyPlayer>() {
override fun create(): Device<MyPlayer> = MyDevice()
}

Kotlin class does not implement interface methods but abstract class does implement methods

I'm using spring boot version 2.1.9 with spring-data. I've defined a repository
interface TokenRepository : CrudRepository<Token, Long> {
fun findBySubject(subject: String): Token?
}
For testing purposes I've created an abstract fake of a CrudRepository which implements all methods from the CrudRepository:
abstract class RepositoryFake<T> : CrudRepository<T, Long> {
...
override fun existsById(id: Long): Boolean {
...
}
override fun deleteById(id: Long) {
...
}
override fun findById(id: Long): Optional<T> {
...
}
...
}
Now when I create an implementation of the TokenRepository which extends the RepositoryFake
class TokenRepositoryFake : RepositoryFake<Token>(), TokenRepository {
override fun findBySubject(subject: String): Token? {
...
}
}
the compiler complains that the TokenRepositoryFake is not abstract and it does not implement the methods existsById, deleteById and findById despite those methods being implemented in RepositoryFake. It does not complain about the other methods defined in CrudRepository. Why is the compiler complaining about missing methods and not about all the other methods?
An example of the error message:
Class 'TokenRepositoryFake' is not abstract and does not implement abstract member public abstract fun deleteById(p0: Long): Unit defined in my.repositories.TokenRepository
I think I found the issue. If I change the type of the RepositoryFake to
abstract class RepositoryFake<T, ID> : CrudRepository<T, ID>
and then change the TokenRepositoryFake to
class HDChainRepositoryFake : RepositoryFake<HDChain, Long>(), HDChainRepository
everything compiles. I'm assuming it has something to do with the way that kotlin handles generics, but don't exactly know why.

Parcelable overload resolution ambiguity

I am trying to create a POJO (aka data classes in Kotlin) structure of a JSON response in Kotlin. I've implemented the Parcelable interface for each data class in the structure. In all of the data classes, I've auto generated the Parcelable implementation. The issue is the generated second constructor where the IDE is complaining about:
Overload resolution ambiguity
It states that it's being confused between these two constructors:
public constructor GeocodeRes(parcel: Parcel)
public constructor GeocodeRes(responset: ResponseRes)
Which I believe makes sense because ResponseRes is also of type Parcelable (ResponseRes implements Parcelable). So calling the GeocodeRes(parcel) method (within the createFromParcel companion method), it is getting confused.
That was until I removed ResponseRes from implementing the Parcelable class and it's still showing the same error.
Is there any reason to this? Am I setting this up properly? In all of the children data classes, they all implement the Parcelable interface (with dependence with eachother) but aren't running into any issues.
Here's my GeocodeRes class:
import android.os.Parcel
import android.os.Parcelable
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
data class GeocodeRes(
#SerializedName("Response") #Expose val responset: ResponseRes
) : Parcelable {
// this is the problem. the IDE is complaining that the usage is too ambiguous (). however, the only usage of this constructor is within this class - just doesn't tell me where exactly.
constructor(parcel: Parcel) : this(parcel.readParcelable(ResponseRes::class.java.classLoader)) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(responset, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<GeocodeRes> {
override fun createFromParcel(parcel: Parcel): GeocodeRes {
return GeocodeRes(parcel)
}
override fun newArray(size: Int): Array<GeocodeRes?> {
return arrayOfNulls(size)
}
}
}
Here's my ResponseRes class:
data class ResponseRes(
#SerializedName("MetaInfo") #Expose val metaInfo: MetaInfo,
#SerializedName("View") #Expose val views: List<View>
): Parcelable
{
[...]//parcel methods
}
however, the only usage of this constructor is within this class - just doesn't tell me where exactly
The problem is with the definition itself, not with any usage. It could never be used, and the error would still be there.
You should be able to fix this by specifying which Parcelable you want to read:
this(parcel.readParcelable<ResponseRes>(ResponseRes::class.java.classLoader))
The compiler can't decide if you mean that or
this(parcel.readParcelable<Parcel>(ResponseRes::class.java.classLoader))
Even though the second wouldn't be legal because Parcel doesn't implement Parcelable, if you look at the signature
<T extends Parcelable> T readParcelable(ClassLoader loader)
you can see only the return type can be used to infer T, not the argument. So the compiler need to pick the constructor overload before trying to infer T.

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).