Thursday, August 2, 2018
Swift The quiet affair of the failable initializer and the nil coalescing operator
Swift The quiet affair of the failable initializer and the nil coalescing operator
It seems strange to me that no mention of "failable" initializers is made on the page of the Swift documentation detailing the nil coalescing operator, and that equally there is nothing about nil coalescing on the failable initializer page.
Nor does the Apple blog post that introduced failable initializers link them with the nil coalescing operator. And yet, the nil coalescing operator makes working with failable initializers a simple affair and appears well matched to classes like UIFont, where should a bespoke request fail it is possible to have the fallback of a system font delivered through a type method.
For example consider this:
let font = UIFont(name: "Georgia", size: 18.0) ?? UIFont.systemFontOfSize(18.0)where the initializer can fail if the font named does not exist but the type (or class) method guarantees that a font will be returned. It seems a match made in heaven and results not in an optional or implicitly unwrapped instance but a straightforward one. So why not do this all the time?
Silence is not always a virtue
Before we mount a campaign for the union of the failable initializer and the nil coalescing operator, we need to consider two types of situations (1) where you might need to know that nil has been returned and (2) where silence is a virtue. Lets take the example of selecting a font and envisage two scenarios:- the user selected a font for their document on a different device, the font does not exist on the current device where the document is now being edited
- the user is reading an article that was downloaded to the app in JSON or XML format. The article has preferred fonts defined for it but those fonts dont exist on the device
In the second scenario, if we know its going to be the difference between Times New Roman and the system font then the typical reader wont be fussed. And the beauty of the system font is that it will be matched to the location and needs of the users language. Besides if the requested fonts arent available then theres very little to be done. It will only be the most discerning of readers who seeks out and downloads the correct font. While most would be fazed and even irritated by an apps request to download a font before allowing them to read an article because it was specified as the preferred font.
Adding complexity
Silent substitution can even work for a multilingual user, if he or she is reading well-composed articles with relevant language metadata. But still there are situations where an app might build a strategy for missing fonts, if fonts are known to be of importance to the content. For example for a design or typography magazine, to take an obvious example. In which case nil coalescing might either not be used or be used in combination with a test for nil.var fontAvailable = falseThe font can then be silently downloaded if this is possible (and substitute the fallback one once available) or noisily alert the user where appropriate for their action.
if let font = UIFont(name: "Georgi", size: 18.0) {
fontAvailable = true
}
fontAvailable
Dealing with data
As soon as we break beyond the simplest of scenarios, it becomes a decision based on an app by app basis whether to combine the nil coalescing operator with the failable initializer or whether to make more use of nil. And even if the nil coalescing and failable combo is used it is likely that the font names at the very least will need to be interrogated to know whether it is italic or bold fonts that are being substituted, because we wont want to simply replace every unavailable font with the vanilla system one.
But even with these considerations, fonts are still an example where nil coalescing might work well. However, think of a scenario where the data or string for an article doesnt load. Do we silently ignore it and supply instead an empty page or do we use nil as a call to action and save the user the time and effort of navigating to (and away from) empty pages by letting them know the content is unavailable? The latter seems the obvious choice here. But this runs contra to the actions we might take with UIFont. And so it becomes important to note that there is no blanket decision to be made about failable initializers and the nil coalescing operator. This is because the way in which failable initializers are dealt with depends on two things: type and scenario.
If we know in advance that an article is corrupted or unavailable and will return nil, then there will be no need to navigate away from the current view when the user selects it from a table. But if we navigate to an empty page, and if this happens more than once, the user will start to become frustrated.
We might even take the occurrence of one missing article to start working through the list of others that have been presented to the user in a table to test whether they are available at all. In the hope that this will further reduce user frustration.
Conclusion
Sometimes optionals, nil and failability are a bore it must be admitted, but this doesnt mean we should always choose the easy way out. But having written this, at times the easy way out is the best and most valid route. And so it becomes that failable initializers must always be approached with an open mind and a strategy built to accommodate them.
Note: Thanks to Richard Turton (@richturton) for his generosity in pointing out an error in this post (one that was repeated many times).
Note: Thanks to Richard Turton (@richturton) for his generosity in pointing out an error in this post (one that was repeated many times).
Follow @sketchytech