Rob Elliot
02/03/2023, 11:25 AMStephan Schröder
02/05/2023, 8:43 AMproperties.apply { put(prop.name, initialValue) }
instead of the way easier to read
properties.put(prop.name, initialValue)
??Sam
02/05/2023, 8:45 AMSam
02/05/2023, 8:46 AMapply lets you modify and return it in a single line. As usual there's definitely a trade-off between succinctness and readability though 👍 two lines might be easier to understandStephan Schröder
02/05/2023, 8:52 AMproperty is implicit 😆Rob Elliot
02/05/2023, 1:33 PMclass Props : AbstractPropertyMap<Any>() {
val anInt by property(1)
}
anInt has compile time type Any. I couldn't find a way to make its type defined by the type of the argument to property.Rob Elliot
02/05/2023, 1:36 PMclass Props : AbstractPropertyMap<Any>() {
val notAnInt: Int by property("a string")
}
compiles (I don't understand why! properties.getValue("a string") returns Any...) but fails at runtime with the inevitable ClassCastException when you dereference notAnInt.
Oddly you can call Props().entries happily, and it will contain "notAnInt" to "a string" so the type of notAnInt must be late bound despite the by property being evaluated on construction.Rob Elliot
02/05/2023, 1:40 PMV on AbstractPropertyMap has to be invariant despite AbstractPropertyMap being effectively immutable, because V is both a parameter to protected fun property and a return type. It would have been nice to make it out V as from a client's perspective it could be.)Rob Elliot
02/05/2023, 2:07 PM@UnsafeVariance 🙂Sam
02/05/2023, 3:18 PMMap<String, V> as the property delegate, meaning the property type is always just V, never a subtype. Not very useful if V is Any. I think it can be improved like this, though:
abstract class AbstractPropertyMap<V>(
private val properties: MutableMap<String, V> = mutableMapOf()
) : Map<String, V> by properties {
protected fun <V2: V> property(initialValue: V2) =
PropertyDelegateProvider<Any, ReadOnlyProperty<Any, V2>> { _, prop ->
properties[prop.name] = initialValue
ReadOnlyProperty(properties::getValue)
}
}Sam
02/05/2023, 3:19 PMMap as a property delegate that provides a specific type (V2) for whichever property it's currently trying to provide.Sam
02/05/2023, 3:19 PMSam
02/05/2023, 3:23 PM@UnsafeVariance to get the out V variance, which would make it protected fun <V2: @UnsafeVariance V> property(initialValue: V2) ... and I've got to be honest, I'm not entirely sure what that means 😅Rob Elliot
02/05/2023, 10:40 PMMatteo Mirk
03/14/2023, 2:19 PMMatteo Mirk
03/15/2023, 1:02 PMRob Elliot
03/15/2023, 3:27 PMMatteo Mirk
03/16/2023, 2:32 PMget(Symbol<T>): T
put(Symbol<T>, T): UnitRob Elliot
03/16/2023, 2:56 PMclass Foo: AbstractPropertyMap<Any>() {
val prop1 by property("value1")
val prop2 by property(21)
}
The two things seem to have different goals to me; SymbolMap is about having a Map<Symbol<Any>, Any> where you can be sure you put and retrieve a specific type. AbstractPropertyMap is about having something which is both a Map<String, T> and an object such that the fields on the object are also entries in the Map with the same name and value.Rob Elliot
03/16/2023, 2:59 PMval symbolMap: SymbolMap = map().put($bool, boolValue).put($int, intValue).put($null, null).solid() you cannot do `symbolMap.bool`; you'd have to wrap it in a class with a val bool: Boolean = symbolMap[$bool] field, wouldn't you? At which point you've repeated bool multiple times, which is what I was trying to avoid.Matteo Mirk
03/16/2023, 3:06 PMMatteo Mirk
03/20/2023, 10:43 AM