Hi Joanna,
Your example doesn’t work for a few reasons:
1. You’re getting a compiler error because of the difference between
the representation of metatypes (`Foo.Type` for some type `Foo`) of
concrete types (e.g. `String`, `Int`), and protocols (e.g.
`DefaultValueProvider`). Some of the compiler folks can correct my exact
use of terminology here, but the essence is this: when you `as?`-cast a
type to a concrete type (e.g. `type as? String.self`), you’ll get a
concrete metatype which can be used dynamically as you would a concrete
type elsewhere. When you `as?`-cast a type to a protocol type (`type as?
DefaultValueProvider`), however, you get a protocol-constrained metatype
which is not concrete and cannot be used dynamically as you would
statically. You can call statically-known protocol methods on the
metatype (e.g. `(type as! DefaultValueProvider).init()`), but the
concrete type is not known. You can see this with a small example:
```swift
protocol P {
init()
}
extension Int : P {}
let type: Any.Type = Int.self
if let specific = type as? P.Type {
// type of specific.init() is P, not Int
print(specific.init())
}
```
This, then coincides with:
2. The fact that methods generic on types can only take concrete type
parameters. Protocol metatypes cannot be passed in as you would a
concrete metatype:
```swift
protocol P {}
extension Int : P {}
func foo<T>(_ type: T.Type) {
print(type)
}
let type: Any.Type = Int.self
foo(type) // cannot invoke 'foo' with an argument list of type
'(Any.Type)'
foo(type as! P.Type) // cannot invoke 'foo' with an argument list of
type '(P.Type)'
foo(type as! Int.Type) // works just fine
```
Arguments to generic methods _must_ be statically knowable for the
method to be dispatched; otherwise you’ll get the compiler error that
you see.
This is also why you can’t `decode(Decodable.self)` or
`decode(Any.self)` — those are not concrete types.
(On a side note, though, this would never be possible with the
`Decodable` protocol. We need a concrete type to decode because values
are otherwise ambiguous. Is `5` an `Int8`, `UInt8`, …, `Int`, `UInt`,
…, `Int64`, `UInt64`, `Float`, or `Double`? Is `"2017-07-14"` a
`String` or a `Date`? What would you expect to get for
`decode(Decodable.self)`?)
— Itai
On 13 Jul 2017, at 11:46, Joanna Carter via swift-users wrote:
Greetings
I notice that, with Swift 4, I can decode an object like this :
• let retrievedSpot = try decoder.decode(ParkingSpot.self, from:
retrievedData)
And that will return a ParkingSpot, as expected, into retrievedSpot.
However, I thought I would try the same technique with one of my pet
projects…
I have a protocol and an implementing struct :
• public protocol PropertyProtocol
• {
• static var propertyType: Any.Type { get }
•
• var untypedValue: Any? { get }
• }
•
• public struct Property<valueT : DefaultValueProvider> :
PropertyProtocol
• {
• public static var propertyType: Any.Type
• {
• return valueT.self
• }
•
• public var untypedValue: Any?
• {
• return value
• }
•
• public var value = valueT()
• }
Now, I want to be able to use a "factory" method to create an instance
of Property<T>, bound to its parameter type. So, I followed the same
principal as Decoder :
• struct PropertyFactory
• {
• static func createProperty<T>(_ type: T.Type) ->
PropertyProtocol where T : DefaultValueProvider
• {
• return type.createProperty()
• }
• }
DefaultValueProvider is defined as follows and String is extended to
conform to it :
• public protocol DefaultValueProvider
• {
• init()
• }
•
• extension String : DefaultValueProvider { }
Now, this works fine if I pass a known type :
• let pproperty = PropertyFactory.createProperty(String.self)
But, if I hold the type to be passed in in an Any.Type or
DefaultValueProvider.Type variable, then doing this :
• let type: Any.Type = String.self
•
• if let propertyType = type as? DefaultValueProvider.Type
• {
• let p = PropertyFactory.createProperty(propertyType)
•
• …
Fails to compile with the message : Cannot invoke 'createProperty'
with an argument list of type '(DefaultValueProvider.Type)'
Likewise Decoder.decode(…) will not accept storing the type in an
Any.Type or Decodable.Type variable.
I find this odd and perplexing. Is this a known issue or has nobody
yet realised that this could be useful ?
Joanna
--
Joanna Carter
Carter Consulting
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users