Hi everyone, is there a way to simplify this bit o...
# getting-started
a
Hi everyone, is there a way to simplify this bit of code ?
Copy code
sealed interface Namespaced : Argument {
    val name: String
    val namespace: String

    override fun asString() = "$namespace:$name"
}


interface Biome : Namespaced {
    companion object {
        operator fun invoke(biome: String, namespace: String = "minecraft") = object : Biome {
            override val name = biome
            override val namespace = namespace
        }
    }
}

interface MobEffect : Namespaced {
    companion object {
        operator fun invoke(name: String, namespace: String = "minecraft") = object : MobEffect {
            override val name = name
            override val namespace = namespace
        }
    }
}
// etc
So I can avoid having the same companion object again and again, some of the interfaces might change so I would prefer to have an interface the
companion object
implements, but I can't figure out how to do it I have to stick with interfaces because every one of them are implemented by an enum listing the native data of each in the game (for example there is a
Biome
enum implementing the
Biome
interface so you can use the raw values of the enum as an
Argument
object). It helps me for serialization also with the
asString()
method which is custom in enums to include the name of the enum entry as lowercase.
s
I like using interface delegation for problems like this:
Copy code
interface Argument {
    fun asString(): String
}

private interface Named {
    val name: String
    val namespace: String
}

private class NameImpl(override val name: String, override val namespace: String): Named

sealed interface Namespaced : Argument {
    val name: String
    val namespace: String

    override fun asString() = "$namespace:$name"
}

interface Factory<out T: Namespaced> {
    operator fun invoke(name: String, namespace: String): T
}

interface Biome : Namespaced {
    companion object: Factory<Biome> {
        override fun invoke(name: String, namespace: String): Biome =
            object: Biome, Named by NameImpl(name, namespace) {}
    }
}

interface MobEffect : Namespaced {
    companion object: Factory<MobEffect> {
        override fun invoke(name: String, namespace: String): MobEffect =
            object: MobEffect, Named by NameImpl(name, namespace) {}
    }
}
Not exactly simpler than your version, though…
e
Copy code
interface Namespaced {
    open class Factory<out T : Namespaced>(private val make: (name: String, namespace: String) -> T) {
        operator fun invoke(name: String, namespace: String = "minecraft"): T =
            make(name, namespace)
    }
}

interface Biome : Namespaced {
    private class Impl(override val name: String, override val namespace: String) : Biome
    companion object : Namespaced.Factory<Biome>(::Impl)
}
a
Thanks this looks great 🙂