[swift-users] Swift 4 emulating Decoder behaviour

Joanna Carter joanna at carterconsulting.org.uk
Mon Jul 17 02:50:22 CDT 2017


Hi Itai

> 	• 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.

Unfortunately, I am only too aware of this limitation 😌

Essentially, what I am trying to achieve is to extend the functionality of "any" type by wrapping it in a generic type that contains the functionality.

I have a perfectly valid, and very useful, hierarchy that provides, not only change observation but also validation of properties when an attempt is made to change their value. It also provides for encapsulation of all the property values in an object for storage or transmission.

The essentials are :

BaseObject
—PropertyBag
——[Property]

The BaseObject holds the PropertyBag and forwards all calls to property setters to the PropertyBag, which contains a subscript, indexed on the property name that accesses the relevant Property.

The Property contains metadata about e.g. : whether the property is readonly, a validation hook and a means of observing the change if it is valid.

In C#, it was easy to access the metadata of a type instead of having to create an instance of that type to get to it, as in Swift. Not having complete reflection is definitely a gaping hole in Swift.

All I really wanted, in this instance, is to be able to bind a Property<T> to the metatype of T, as in C#'s MakeGenericType([typeArgs]) method thus

// pseudocode
{
  let metatype = type(of: aType)
  
  for propertyType in metatype.propertyTypes
  {
    let property = type(of: Property<>).makeGenericType([propertyType])
    
    propertyBag.append(property)
  }
}

Once the generic properties are "in the bag", they are accessed and manipulated using the Visitor design pattern, thus allowing a heterogeneous collection of properties that are all treated correctly, according to their bound type.

In brief, I wanted a heterogeneous collection of generic types, all of which implement a non-generic protocol ; something that is perfectly possible now.

However, the "automatic" creation of the generic types into the non-generic protocol, based on the parameter type, seems to be unattainable ; unless I create a protocol that contains a factory method but that has then to be adopted by each individual type I wish to wrap in the generic type ; which is messy 😉

Joanna

--
Joanna Carter
Carter Consulting



More information about the swift-users mailing list