JavaScript allows writing properties that were not part of it's class originally throughout the runt...
r
JavaScript allows writing properties that were not part of it's class originally throughout the runtime
Copy code
Object.defineProperty(object1, 'property1', {
  value: 42
});
Is there any way for me to achieve something similar in Kotlin, regardless of how hacky or unadvised?
😄 1
j
Using a
Map<String, Any>
?
r
Copy code
class Foo {
  val x = 5
}

fun main() {
  val foo = Foo()
  defineProperty(foo, 'y', 7)
  println(foo.y) // 7!
}
j
This might be an XY problem. What are you trying to do?
r
create the appearance of removing or adding individual interfaces on an object
without losing all of the other interfaces that the object might have inherited
i want to create a function that takes in an interface and manually assign's the fields to the object
and when you remove an interface, it create a brand new object without that interface and go through every other interface and re-add them
j
But what are you trying to do in terms of business with this? It seems this is your solution to a problem
r
entity component system
here is examples pseudo code for what I want as a langauge feature
Copy code
fun fn(entity: Physics) {
  entity.position // OK!
}

fun main() {
  object entity : Health, Skills, Magical
  fn(entity) // error, lacks Physics component
  entity = entity with Physics
  fn(entity) // allowed! entity has Physics
  entity = entity without Physics // will still keep Health, Skills, Magical
  fn(entity) // error! lacks Physics component
}
the
with
and
without
is fake syntax i would imagine for adding or stripping interfaces from instaces
so at this point I am just trying to hack Kotlin to give the illusion of this as a syntax feature
i am fine reconstructing entire deep copies of the objects behind the scenes. just want type system to work.
y
You could mess around with intersection types to make this sorta work. I had a demo somewhere I wrote long ago for a database query DSL using this idea. Lemme find it one second
https://kotlinlang.slack.com/archives/C7L3JB43G/p1680065960980769?thread_ts=1679260580.903859&amp;cid=C7L3JB43G This was originally about code-generation, compiler plugins, and database queries, but I believe it can apply to your situation here too if you squint enough
Not sure if writing
without
would be possible here, but it's worth a try!
c
What you want is an object that contains arbitrary data and can be controlled. You can take inspiration from
CoroutineContext
to achieve this.
Copy code
class Entity {
    private val attributes = HashMap<EntityData.Key<*>, *>()
 
    override fun contains(key: EntityData.Key<*>): Boolean =
        attributes.containsKey(key)

    override fun <T : EntityData> get(key: EntityData.Key<T>): T =
        attributes[key]!! as T

    override fun <T : EntityData> set(key: EntityData.Key<T>, value: T) =
        attributes[key] = value
}

interface EntityData {
    interface Key<E : EntityData>
}

class Physics(
    …
) : EntityData {
    companion object : EntityData.Key<Physics>
}

class Health(
    …
) : EntityData {
    companion object : EntityData.Key<Health>
}

class Skills(
    …
) : EntityData {
    companion object : EntityData.Key<Skills>
}
Then, usage:
Copy code
fun main() {
  val entity = Entity()
  entity[Health] = Health(…)
  entity[Skills] = Skills(…)
  entity[Magical] = Magical(…)

  if (Physics in entity) fn(entity[Physics])
  entity[Physics] = Physics(…)  
  fn(entity[Physics])
}
Of course, this version isn't typesafe. You could make a typesafe version using phantom type parameters, but you would need one more type parameter for each property you want to test against.