Zoltan Demant
05/30/2025, 2:15 PMpackage aggregate.common
abstract class Keyed(
val key: String,
) {
// Does not compile, Id is value class that wraps String
constructor(id: Id) : this(
key = id.value,
)
constructor(keyed: Keyed) : this(
key = keyed.key,
)
}
CLOVIS
05/30/2025, 2:16 PMZoltan Demant
05/30/2025, 2:16 PMZoltan Demant
05/30/2025, 2:17 PM@JvmInline
value class Id(
val value: String = Uuid.random().toString(),
)
CLOVIS
05/30/2025, 2:18 PMString
constructor if you have an Id
type already written?Zoltan Demant
05/30/2025, 2:19 PMphldavies
05/30/2025, 2:20 PMCLOVIS
05/30/2025, 2:20 PM@JvmInline
).Zoltan Demant
05/30/2025, 2:20 PMphldavies
05/30/2025, 2:22 PM@JvmInline value class Id(val value: String)
abstract class Keyed(
val key: String,
val _marker: Unit = Unit
) {
// Does not compile, Id is value class that wraps String
constructor(id: Id) : this(
key = id.value,
)
constructor(keyed: Keyed) : this(
key = keyed.key,
)
}
fun main() {
val myKeyed = object : Keyed("hello") {}
println(myKeyed.key)
val myKeyedById = object : Keyed(Id("world")) {}
println(myKeyedById.key)
val myKeyedByKeyed = object : Keyed(myKeyed) {}
println(myKeyedByKeyed.key)
}
the trick is to make one of the constructors uniqueZoltan Demant
05/30/2025, 2:22 PMZoltan Demant
05/30/2025, 2:23 PMphldavies
05/30/2025, 2:23 PMZoltan Demant
05/30/2025, 2:23 PMCLOVIS
05/30/2025, 2:23 PMphldavies
05/30/2025, 2:24 PMphldavies
05/30/2025, 2:24 PMval
, just _marker: Unit = Unit
will doCLOVIS
05/30/2025, 2:25 PMphldavies
05/30/2025, 2:25 PMZoltan Demant
05/30/2025, 2:26 PMphldavies
05/30/2025, 2:26 PMZoltan Demant
05/30/2025, 2:26 PMabstract class Keyed(
val key: String,
) {
constructor(
id: Id,
marker: Unit = Unit,
) : this(key = id.value)
constructor(keyed: Keyed) : this(
key = keyed.key,
)
constructor(first: Keyed, second: Keyed) : this(
key = first.key + second.key,
)
}
This is quite simple imo, and I think Ill roll with it!Zoltan Demant
05/30/2025, 2:27 PMphldavies
05/30/2025, 2:27 PMZoltan Demant
05/30/2025, 2:28 PMRuckus
05/30/2025, 4:24 PMKeyed(id, Unit)
, which isn't a big deal, but a little strange. if instead you declare a new helper class class Nope private constructor()
, you could change the constructor to constructor(id: Id, vararg marker: Nope) ...
, and then the user couldn't pass in anything other than the ID.
(I used to use this trick with vararg x: Nothing
to force users to used named parameters back in the day, but Nothing
has since been banned as a vararg type, and I've learned that if I think I need to force named params on the users to make things clear, it's a good sign my design is garbage)Eugen Martynov
05/31/2025, 4:09 PMCLOVIS
05/31/2025, 4:09 PMsuper()
that constructor when extending the abstract classEugen Martynov
05/31/2025, 4:10 PM