Swift Dictionary Literal Convertible
A practical example of Swift’s
DictionaryLiteralConvertible protocol application.
If “Literal Convertibles” sounds strange to you then a good place to start is an excellent NSHipster’s post.
OK, let’s say we have some struct in Swift.
This is a structure holding timeout options for some abstract waiting function. If waiting takes longer that
timeout then waiting is terminated and the
message is displayed. For convenience default values are provided.
Now, wouldn’t it be nice to add some syntactic sugar and pass a dictionary with key-value pairs for waiting options, instead of calling
Of course compiler doesn’t like this code, though it fails to tell us exactly why.
Let’s experiment a bit.
Doesn’t make much sense but this time compiler complains with more sane error message.
Basically it doesn’t know how to construct and instance of
Options type from
So when we used dictionary before, compiler had no idea how to create an instance of
Options from a dictionary, but sadly couldn’t communicate it back to us in a human-friendly form.
To be able to create
Options objects from dictionaries
Options has to conform to
To conform to this protocol we need to implement
init and define type aliases for
Value. This was somewhat of a surprise for me, even when reading NSHipster’s post for the first time I didn’t realize that typealias are part of the protocol and had to be “implemented” (declared) too. I must have confused
typealias with C’s
typedef for a while, hence misunderstanding of
OK, first attempt in conforming to the protocol.
For dictionary keys the
String type is used, and for values use
AnyObject since we can pass either
String as a value.
I’m sure there’s a better more type-safe way to type alias
Value to make it more “functional”. Probably using enums. I’m still learning though.
init iterates over the contents of the dictionary and initializes struct’s members with values from the dictionary. The
as is used to type cast
I’m aware that use of
self is not strictly required in this case and
self.timeout = works same as just
timeout =, but I tend to explicitly use
self. syntax in initializers, kind of rule of thumb.
Let’s try it again.
It works. Also notice that we can now provide partial arguments, like only timeout but no message in this case, something we couldn’t with default struct initializer (would have to implement additional initializers).
Yet there are few things that smell in this code (apart from
AnyObject I suppose).
- Use of hard-coded string literals like “timeout” is not good, typos happen all the time and it’s quite painful to debug this type of errors.
Let’s now fix both these issues. First we will use a custom enum type for keys.
Note that’s it not even backed up by a raw
String type, there’s no need for that at the moment.
Now can rewrite the
Main changes are
- Get rid of
default:case, wrong key errors are now handled at compile time, not at run time.
wait function is now as simple as
You can grab the swift code and try it yourself in playground or just by running from command line with
blog comments powered by Disqus