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 AMVampire
06/05/2020, 9:20 AMVampire
06/05/2020, 11:47 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 }
}
}Vampire
06/05/2020, 11:57 AMenum 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.Vampire
06/05/2020, 1:04 PMtddmonkey
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 😕Vampire
06/05/2020, 1:19 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 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.Vampire
06/05/2020, 2:20 PMsealed 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.Vampire
06/05/2020, 2:40 PMsealed 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)
}Vampire
06/05/2020, 3:28 PMsealed 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)
}Vampire
06/05/2020, 4:27 PMtddmonkey
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 AMsealedSubclassestddmonkey
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
}
}tddmonkey
06/08/2020, 9:10 AMvalues() 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.Vampire
06/08/2020, 9:12 AMtddmonkey
06/08/2020, 9:14 AMComparable anymore - you did that to do the sorting in the old values() method.tddmonkey
06/08/2020, 9:14 AMVampire
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 listsVampire
06/08/2020, 9:16 AMComparable 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?Vampire
06/08/2020, 1:10 PMkotlin-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. :-(Vampire
06/08/2020, 1:44 PMenum.
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 reflectionVampire
06/08/2020, 2:01 PMtddmonkey
06/08/2020, 2:01 PMVampire
06/08/2020, 2:03 PMtddmonkey
06/08/2020, 2:14 PM