OctarineSorcerer
OctarineSorcerer

Reputation: 445

How to make a concrete secondary constructor in Kotlin, when the primary constructor is generic?

I'm trying to figure out how to make a secondary constructor for a generic class, so I can essentially create a "default" version of it easily. This code seems reasonable to me - the secondary constructor calls the primary one with a concrete T: Table. But the compiler doesn't seem to recognise this, giving "Type mismatch: inferred type is Scratch_5.Furniture.table but T was expected" for the secondary constructor.

sealed class Furniture {
    class NamedChair(name: String) : Furniture()
    object Table : Furniture()
}

class Blah<T : Furniture>(
    data: T
) {
    constructor() : this(Furniture.Table)
}

var blah = Blah(Furniture.Table)
var equalBlah = Blah()

However, the var blah = Blah(Furniture.Table) line using the primary constructor works perfectly fine. Is there anything I'm missing here? How would I modify this to have it work?

Upvotes: 1

Views: 271

Answers (1)

Giorgio Antonioli
Giorgio Antonioli

Reputation: 16214

You can't have a concrete secondary constructor while the primary has a generic parameter.

However you can achieve the same effect with a little trick using the operator fun invoke() on Blah:

class Blah<T : Furniture>(data: T) {
  companion object {
    operator fun invoke(): Blah<Furniture.Table> = Blah(Furniture.Table)
  }
}

Or you can use a fun named Blah (thanks to @AlexeyRomanov):

fun Blah(): Blah<Furniture.Table> = Blah(Furniture.Table)

Now you can successfully call:

var blah = Blah(Furniture.Table)
// Calls the invoke operator fun which invokes the primary constructor.
var equalBlah = Blah()

Upvotes: 1

Related Questions