Is it possible to preserve the static type information for the following API? Basically what I need is a key/value collection that provides a static type relationship between key and value but allows different key/value pair types.
extension View {
func onIntent<D>(for data: D.Type, perform action: @escaping (D) -> Void) -> some View where D: Hashable {
let intents = [
ObjectIdentifier(data): { value in
if let value = value as? D { // although the type information is statically known, it must be checked dynamically here
action(value)
}
} as (any Hashable) -> Void
]
return environment(\.intents, intents)
}
}
The API itself provides the type information for the call side, but the implementation does not preserve it statically. Do you have any ideas how to solve the problem without losing the static type?
The problem (and I wasn't clear enough in my question) is that intents need to be able to contain key/value pairs of different types, while preserving the type relationship between key and value. Your solution would force intents to have only values of type (D) -> Void, but what I need is a collection that allows key/value pairs that share a (generic) type, but allows different types for those key/value pairs.
At some level of the implementation, you'll need to use dynamic type information to store your heterogeneous values, but you can contain the problem by wrapping a dictionary (or some other keyed container) in a type that only publicly provides a generic subscript<T>(key: T) -> ValueType<T>. That way only that subscript needs to deal with the dynamic type assertion and the rest of the program can work with static types.
You can take some inspiration from https://github.com/apple/swift-service-context (which is used by swift-distributed-tracing) which is basically a type-safe dictionary, using types as keys.
I have a question about the implementation of ServiceContext: what is the runtime cost of a force-cast? This is the only part that could be improved if full static knowledge of the dictionary were possible (which it is not).