Generics and the Art of Inference Part 2 of 3

Our example this round will be constructing/deconstructing a struct to and from a Dictionary.

Here is the basic definition of the struct we would like to encode/decode.
We can define a protocol for this as simply:

Now we can extend our type to implement these, but before we do that let’s extend some functions into optional to make decoding easier.

Underneath unbox() casts our optional to an optional inferred result type. This is useful in the next two functions:
unboxString() and unboxArray. unboxString() clearly returns a String but unboxArray still needs to infer a result type for the generic Element type enclosed in the array.

The destruct() function is as we would expect, we create a dictionary and add the properties’ values in. Since subSorts is an array of the same type we can call destruct() on it as well and add it to the dictionary.

Using .unboxString() on the contents of our array is straight forward. The next line though, retrieving the AnyObject result from the construct array and working with it as a [String: AnyObject] result is a little more work. We take the construct array passed in, retrieve the SortItems in an encoded state(AnyObject) and call unboxArray on it. We then map that result with an initializer SortItem.init in hopes that the generic return type on unboxArray can be inferred through this mapping step. To our dismay, even though we only have one init that takes in a single parameter:init(_ construct: [String: AnyObject]) we get an ambiguous use of init error..
If we try commenting out all of the other initializers the error still persists because the basic initializer for our struct is there by default.

As we are of course unwilling to give into the defeat of ambiguity, let’s try tricking the compiler with just a bit of indirection back in our struct definition.

We did two things here. First we wrote out the default initializer for the struct and second we added default values for the second property in both of the two-param initializers. Now our compiler has forgotten about these and we no longer have an ambiguity error. And finally, we can return to this line of code to appreciate our generic array type inferring correctly through our map function.