flocked
(Florian Zand)
1
Why can't I change the properties of a returned generic value?
Take a look at AnimationProvider fails().
Strangely the code isn't failing when I set the returned value to a variable/constant and change the properties of the variable/constant. See AnimationProvider works().
How can I change the code, so that I can change the returned value's properties directly?
protocol AnimatableProperty { }
extension CGFloat: AnimatableProperty { }
protocol Animation<Value>: AnyObject {
associatedtype Value: AnimatableProperty
var value: Value { get set }
var target: Value { get set }
}
class SpringAnimation<Value: AnimatableProperty>: Animation {
var value: Value
var target: Value
init(value: Value, target: Value) {
self.value = value
self.target = target
}
}
class AnimationProvider {
var animations: [PartialKeyPath<AnimationProvider>: any Animation] = [:]
func animation<Value: AnimatableProperty>(for keyPath: KeyPath<AnimationProvider, Value>) -> (any Animation<Value>)? {
animations[keyPath] as? SpringAnimation<Value>
}
var animatableProperty: CGFloat = 4
func crashesCompiler() {
animation(for: \.animatableProperty)?.value = 6.0
}
func compiles() {
let animation = animation(for: \.animatableProperty)
animation?.value = 6.0
}
}
Jens
2
Looks like a compiler bug.
Smaller demo:
protocol P<Value>: AnyObject {
associatedtype Value: SignedInteger
var value: Value { get set }
}
func foo<T: SignedInteger>(_: T) -> (any P<T>)? {
fatalError()
}
func crashesCompiler() {
foo(123)?.value = 1
}
func compiles() {
let x = foo(123)
x?.value = 1
}
Note that if we change foo to take the type rather than a value of the type, it works:
protocol P<Value>: AnyObject {
associatedtype Value: SignedInteger
var value: Value { get set }
}
func foo<T: SignedInteger>(_: T.Type) -> (any P<T>)? {
fatalError()
}
func noLongerCrashesCompiler() {
foo(Int.self)?.value = 1
}
func compiles() {
let x = foo(Int.self)
x?.value = 1
}