Amo
08/20/2024, 2:31 PMinline infix fun <reified T : DataObject> Player.get(type: Class<T>): T {
return ComponentInit.PLAYER_DATA.get(this).get<T>(type)
}
Looking to ideally replace the class parameter with a type if thats somehow possible?
val testData = player get TestDataObject::class.java
feels a little obtuse,
val testData = player get TestDataObject
would be much nicerSzymon Jeziorski
08/20/2024, 2:43 PMtype
parameter altogether and use class reference on `T`:
inline fun <reified T : DataObject> Player.get(): T {
return ComponentInit.PLAYER_DATA.get(this).get<T>(T::class.java)
}
val testData = player.get<TestDataObject>()
Amo
08/20/2024, 2:45 PMDaniel Pitts
08/20/2024, 2:51 PMDaniel Pitts
08/20/2024, 2:51 PMDaniel Pitts
08/20/2024, 2:54 PMinline infix fun <reified T : DataObject> Player.get(type: Class<T>): T = TODO()
inline fun <reified T : DataObject> of() = T::class.java
fun main() {
val player = Player()
val item = player get of<DataObject>()
}
Szymon Jeziorski
08/20/2024, 3:04 PMval testData = player get TestDataObject
if you would use custom companion objects implementing some generic construct:
interface DataObjectKey<T : DataObject>
class TestDataObject : DataObject {
companion object Key : DataObjectKey<TestDataObject>
}
inline infix fun <reified T : DataObject> Player.get(key: DataObjectKey<T>): T {
return ComponentInit.PLAYER_DATA.get(this).get<T>(T::class.java)
}
val testData = player get TestDataObject // TestDataObject is a companion object reference here. T is inferred from companion object's generics
This technique of using custom companion objects can be seen for example in kotlinx-coroutines
, in CoroutineContext.Element
, it allows you to do stuff like coroutineContext[Job]
- Job is also a companion object reference there.
But that's just to show you the possibilities.
In your example player.get<TestDataObject>()
would be the most sensible choice.
The approach is readable and consistent with what's already in kotlin stdlib and most popular 1st and 3rd party librariesDaniel Pitts
08/20/2024, 3:07 PMoperator fun <T:DataObject> get(key: DataObjectKey<T>)
function rather than an infix. This would provide the more standard notation of player[TestDataObject]
Amo
08/20/2024, 3:20 PMSzymon Jeziorski
08/20/2024, 3:26 PMplayer[TestDataObject]
may be a little confusing at first, it's definitely non standard way of achieving class reference. Reading companion objects implement some custom construct also adds a little mental overhead.
That being said, if you're not in any commercial environment and you're just working on some personal project trying to have some fun and learn at the same time, then go for whatever you find coolest 🙂Amo
08/20/2024, 3:30 PMAmo
08/20/2024, 3:32 PMval testData = player get TestDataObject
or val testData = player[TestDataObject]
! sorta nice to haveDaniel Pitts
08/20/2024, 3:44 PMDaniel Pitts
08/20/2024, 3:45 PMAmo
08/20/2024, 3:57 PMDaniel Pitts
08/20/2024, 4:18 PMopen class AttributeKey<T : Any>(protected val type: KClass<T>) {
open fun from(map: Object): T? = type.safeCast(map.attributes[this])
fun isIn(map: Object) = type.isInstance(map.attributes[this])
}
open class AttributeKeyWithDefault<T : Any>(
kClass: KClass<T>,
private val default: (Object) -> T,
private val saveDefault: Boolean = true,
) : AttributeKey<T>(kClass) {
override fun from(map: Object): T {
return map.attributes[this]?.let(type::safeCast) ?: default(map).also {
if (saveDefault) map.attributes[this] = it
}
}
fun addTo(map: Object) {
map.attributes.getOrPut(this) { default(map) }
}
}
class Object {
internal val attributes = mutableMapOf<AttributeKey<*>, Any?>()
operator fun <T : Any> set(key: AttributeKey<T>, value: T) {
attributes[key] = value
}
fun <T : Any> add(key: AttributeKeyWithDefault<T>) {
key.addTo(this)
}
fun remove(key: AttributeKey<*>) {
attributes.remove(key)
}
operator fun contains(key: AttributeKey<*>) = key.isIn(this)
operator fun minusAssign(key: AttributeKey<*>) = remove(key)
operator fun <T : Any> plusAssign(key: AttributeKeyWithDefault<T>) = add(key)
operator fun <T : Any> get(key: AttributeKey<T>) = key.from(this)
operator fun <T : Any> get(key: AttributeKeyWithDefault<T>) = key.from(this)
}
Somethign similar that I'm working on.CLOVIS
08/20/2024, 4:29 PMplayer.get<TestDataObject>()
then you can also call it as:
val o: TestDataObject = player.get() // inferred
fun foo(o: TestDataObject) …
foo(player.get()) // inferred
CLOVIS
08/20/2024, 4:31 PMCLOVIS
08/20/2024, 4:31 PM