Vampire
06/05/2020, 9:07 AMenum class Boo(private val fooDelegate: String? = null) {
BAZ,
BAM(fooDelegate = "bar");
val foo: String
get() = fooDelegate ?: error("no foo set for ${javaClass.simpleName}.${name}")
}
I want that if foo
is needed, it must have been set, but if it is not used, it is not necessary to set it.
Optimally I like to access it by name foo
and also set it by name foo
instead of setting it by name fooDelegate
or optionalFoo
.
When getting foo
, I want it to be of type String
though, not String?
.tddmonkey
06/05/2020, 9:10 AMVampire
06/05/2020, 9:11 AMtddmonkey
06/05/2020, 9:12 AMobject
if you only want 1 instanceVampire
06/05/2020, 9:13 AMBoo.values()
to iterate over all of them and similar things. I would effectively need to recreate the enum functionality I use, wouldn't I?bezrukov
06/05/2020, 9:17 AMcompanion object {
fun values() = Boo::class.sealedSubclasses.mapNotNull { it.objectInstance }
}
Vampire
06/05/2020, 9:19 AMsealed class Boo(val ordinal: Int) : Comparable<Boo> {
val name: String = javaClass.simpleName
open val foo: String get() = error("no foo set for ${javaClass.superclass.simpleName}.${name}")
final override fun compareTo(other: Boo) = compareValues(ordinal, other.ordinal)
object BAZ : Boo(0)
object BAM : Boo(1) {
override val foo: String = "bar"
}
companion object {
fun values() = Boo::class.sealedSubclasses.mapNotNull { it.objectInstance }
}
}
enum class Boo {
BAZ,
BAM {
override val foo = "bar"
};
open val foo: String get() = error("no foo set for ${javaClass.simpleName}.${name}")
}
What would be the benefit of using a sealed class hierarchy instead @tddmonkey?tddmonkey
06/05/2020, 12:45 PMfoo
would only exist in the hierarchy that needs it, so no need for runtime errorsVampire
06/05/2020, 12:47 PMfoo
outside.
So I have a method with parameter Boo
and I want to get foo
on the argument.
If someone gives a Boo
to the method that does not have a value defined for foo
, this is a programming error.tddmonkey
06/05/2020, 12:49 PMfoo
from a value that doesn’t have it you get a runtime exception. My preference would be to switch that around so the type system doesn’t allow itVampire
06/05/2020, 1:01 PMBoo
, BooWithFoo : Boo
and then giving BooWithFoo
to the class, I see, makes sense of course ... maybe. Thanks for that, I'll think about it.tddmonkey
06/05/2020, 1:10 PMVampire
06/05/2020, 1:17 PMsealed class Boo(val ordinal: Int) : Comparable<Boo> {
val name: String = javaClass.simpleName
final override fun compareTo(other: Boo) = compareValues(ordinal, other.ordinal)
sealed class BooWithFoo(
ordinal: Int,
val foo: String
) : Boo(ordinal)
object BAZ : Boo(0)
object BAM : BooWithFoo(1, "bar")
companion object {
fun values() = Boo::class.sealedSubclasses.mapNotNull { it.objectInstance }
}
}
does not work, BAM needs to be defined inside BooWithFoo
and values()
only finds BAZ
as only direct subclasses are returned 😕sealed class Boo(val ordinal: Int) : Comparable<Boo> {
val name: String = javaClass.simpleName
final override fun compareTo(other: Boo) = compareValues(ordinal, other.ordinal)
sealed class BooWithFoo(
ordinal: Int,
val foo: String
) : Boo(ordinal) {
object BAM : BooWithFoo(1, "bar")
}
object BAZ : Boo(0)
companion object {
fun values() = listOf(Boo::class, BooWithFoo::class)
.flatMap { it.sealedSubclasses }
.mapNotNull { it.objectInstance }
}
}
😕tddmonkey
06/05/2020, 2:06 PMvalues()
in another object so its explicit that way, so something like:
object Boos{
val allBoosInOrder() = listOf(
Foo
Bar
)
}
Vampire
06/05/2020, 2:09 PMvalues()
is not my main concern, more the ripped apart constants.sealed class Boo(val ordinal: Int) : Comparable<Boo> {
val name: String = javaClass.simpleName
final override fun compareTo(other: Boo) = compareValues(ordinal, other.ordinal)
interface WithFoo {
val foo: String
}
object BAZ : Boo(0)
object BAM : Boo(1), WithFoo {
override val foo = "bar"
}
companion object {
fun values() = Boo::class.sealedSubclasses.mapNotNull { it.objectInstance }.sorted()
}
}
But then I still need to receive Boo
in the method and then check for is WithFoo
as other classes could implement the WithFoo
interface and I also need the other properties in the method.sealed class Boo(val ordinal: Int) : Comparable<Boo> {
val name: String = javaClass.simpleName
final override fun compareTo(other: Boo) = compareValues(ordinal, other.ordinal)
interface WithFoo {
val foo: String
}
object BAZ : Boo(0)
object BAM : Boo(1), WithFoo {
override val foo = "bar"
}
companion object {
fun values() = Boo::class.sealedSubclasses.mapNotNull { it.objectInstance }.sorted()
}
}
fun <T> hoo(boo: T) where T : Boo, T : Boo.WithFoo {
println(boo.name)
println(boo.foo)
}
sealed class Boo(val ordinal: Int) : Comparable<Boo> {
val name: String = javaClass.simpleName
init {
if (!usedOrdinals.add(ordinal)) {
throw IllegalArgumentException("${javaClass.superclass.simpleName}.$name: " +
"The ordinal $ordinal is already used by another instance")
}
}
final override fun compareTo(other: Boo) = compareValues(ordinal, other.ordinal)
object BAZ : Boo(0)
object BAM : Boo(1), WithFoo {
override val foo = "bar"
}
companion object {
private val usedOrdinals = mutableSetOf<Int>()
fun values() = Boo::class
.sealedSubclasses
.mapNotNull { it.objectInstance }
.sorted()
}
interface WithFoo {
val foo: String
}
}
// verify ordinals are unique
private val booValues = Boo.values()
fun <T> hoo(boo: T) where T : Boo, T : Boo.WithFoo {
println(boo.name)
println(boo.foo)
}
tddmonkey
06/06/2020, 9:57 AMVampire
06/08/2020, 8:25 AMtddmonkey
06/08/2020, 8:41 AMVampire
06/08/2020, 8:45 AMtddmonkey
06/08/2020, 8:57 AMVampire
06/08/2020, 9:02 AMsealed class Boo() : Comparable<Boo> {
val name: String = javaClass.simpleName
final override fun compareTo(other: Boo): Int {
val indexOfThis = order.indexOf(this)
if (indexOfThis == -1) {
throw AssertionError("$name is missing in 'order' list")
}
val indexOfOther = order.indexOf(other)
if (indexOfOther == -1) {
throw AssertionError("${other.name} is missing in 'order' list")
}
return compareValues(indexOfThis, indexOfOther)
}
object BAZ : Boo()
object BAM : Boo(), WithFoo {
override val foo = "bar"
}
companion object {
private val order = listOf(
BAZ,
BAM
)
fun values() = Boo::class
.sealedSubclasses
.mapNotNull { it.objectInstance }
.sorted()
}
interface WithFoo {
val foo: String
}
}
So I need each twice and with a list of 60 values it is two long listsbezrukov
06/08/2020, 9:07 AMVampire
06/08/2020, 9:08 AMsealedSubclasses
tddmonkey
06/08/2020, 9:09 AMsealed class Boo() : Comparable<Boo> {
val name: String = javaClass.simpleName
object BAZ : Boo()
object BAM : Boo(), WithFoo {
override val foo = "bar"
}
companion object {
private val order = listOf(
BAZ,
BAM
)
fun values() = order
}
interface WithFoo {
val foo: String
}
}
values()
and make order
publicVampire
06/08/2020, 9:11 AMsealedSubclasses
reflection anymore if I define the order explicitly.
I don't see how I could remove the compareTo
method override though.tddmonkey
06/08/2020, 9:14 AMComparable
anymore - you did that to do the sorting in the old values()
method.Vampire
06/08/2020, 9:14 AMsealed class Boo() : Comparable<Boo> {
val name: String = javaClass.simpleName
final override fun compareTo(other: Boo): Int {
val indexOfThis = values.indexOf(this)
if (indexOfThis == -1) {
throw AssertionError("$name is missing in 'order' list")
}
val indexOfOther = values.indexOf(other)
if (indexOfOther == -1) {
throw AssertionError("${other.name} is missing in 'order' list")
}
return compareValues(indexOfThis, indexOfOther)
}
object BAZ : Boo()
object BAM : Boo(), WithFoo {
override val foo = "bar"
}
companion object {
val values by lazy {
listOf(
BAZ,
BAM
)
}
}
interface WithFoo {
val foo: String
}
}
Which still has the problem of both listsComparable
anymore
Yes it does, or is not comparable
> you did that to do the sorting in the old values()
method.
You are assuming too much, I made it comparable because I need it comparable, I just used it in values
as the list should be sorted
> Again - im not sure why you have 2 lists?kotlin-reflect
is there and I can get the sealedSubclasses
.
But unfortunatley there is a SecurityManager
in place that denies ("java.lang.RuntimePermission" "accessDeclaredMembers")
, so the it.objectInstance
fails with AccessControlException
. :-(enum
.
What I really would like to have is (https://youtrack.jetbrains.com/issue/KT-39466)
enum class Boo {
BAZ,
BAM : WithFoo {
override val foo = "bar"
};
}
interface WithFoo {
val foo: String
}
But I guess I'll go with
enum class Boo {
BAZ,
BAM {
override val foo = "bar"
};
open val foo: String
get() = error("no foo set for ${javaClass.simpleName}.${name}")
}
for now, that at least removes the fooDelegate
naming needtddmonkey
06/08/2020, 1:57 PMVampire
06/08/2020, 2:00 PMenum class Boo {
BAZ,
BAM {
val foo = "bar"
};
}
fun foo(t: Boo) = "${t.name}: ${t.javaClass.kotlin.memberProperties.find { it.name == "foo" }?.get(t) ?: error("no foo")}"
if that works.
But I think the other variant where I only have to do the erroring centrally and do not need reflectiontddmonkey
06/08/2020, 2:01 PMVampire
06/08/2020, 2:03 PMtddmonkey
06/08/2020, 2:14 PM