Another "Value of protocol type cannot conform because only struct/enum/class types can conform to protocols" post

Consider a protocol JSON which represents any valid JSON object. We might define it like so:

protocol JSON { }
extension String: JSON { }
extension Int: JSON { }
... // and so on
extension Array: JSON where Element: JSON { }
extension Dictionary: JSON where Key == String, Value: JSON { }

The above implies that a dictionary of type [String: JSON] itself should be a JSON. Yet, I am unable to use it like below without the following warnings:

// Case 1: Error: Cannot convert value of type 'Int'
// to expected dictionary value type 'String'
let foo: JSON = ["name": "Bob", "age": 25]

// Case 2: Error: Value of protocol type 'JSON'
// cannot conform to 'JSON'; only struct/enum/class
// types can conform to protocols
func foo(_ json: JSON)

let json: [String: JSON] = ["name": "Bob", "age": 25]
foo(json) // error

I have a hunch this has to do with the some P/any P stuff. Can someone tell me why what I'm trying to do is not yet possible?

Edit: this post seems extremely related. I am reading through it.

I think you want Value == JSON { }. The type of ["name": "Bob", "age": 25] is effectively [String: JSON] but JSON doesn't conform to itself.

Value == JSON won't allow me to call JSON.staticMethod(). I'm not actually sure what the difference is between T == P and T: P. Can you elaborate on that for me?

Value == JSON is a same-type constraint, which means Value has to be exactly JSON and Value: JSON is a conformance constraint, which means Value has to be a concrete type that conforms to JSON (there are exceptions to it, like Error which self-conforms). In your dictionary example, Value is inferred to be String so other values need to be String as well. If you change it to Value == JSON, it compiles because you can have different types of values boxed/erased into JSON. It' effectively makes it a heterogenous dictionary, kind of like [String: Any].

I see. Is that similar to the difference between some P and any P?

Why does using == remove my ability to call static methods on P?

Edit: Never mind, I just needed to change dict.mapValues(Value.staticMethod()) to dict.mapValues(staticMethod()) for some reason?

Edit 2: Okay so the above just ended up calling the method I was already in, never mind. I now understand when and why I would use == over :, thank you!

For future readers.

protocol JSON { }
extension String: JSON { }
extension Int: JSON { }
//.....
extension Array: JSON where Element == JSON { }
extension Dictionary: JSON where Key == String, Value == JSON { }
Terms of Service

Privacy Policy

Cookie Policy