Return?

Here is a small bit of sugar that I would use near constantly (and I can't make it myself because it affects control flow):

return? myVar //Only returns if myVar is non-nil

//Equivalent to:
if let myVar = myVar {
    return myVar
}

It may not seem like much, but when you have a case where you have many potential sources for a result (which are too complex to setup to use ??), then all of the extra brackets make things much less readable. I often end up having to break things up into multiple methods just to make it comprehensible, but this would make it much more readable in a single method...

Here is some code from a project I am working on:

func defaultFill(usage:ThemeKey.Usage) -> ColorFill {
        if let fill = self.currentTheme.defaultFill(usage: usage) {
            return fill
        }
        for parent in self.currentTheme.inheritList {
            if let fill = parent.defaultFill(usage: usage) {
                return fill
            }
        }
        switch usage {
        case .text: return UIColor.darkText
        case .background: return UIColor.white
        case .chart: return UIColor.darkText
        case .data: return #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
        case .stroke: return UIColor.black
        case .unknown: return UIColor.black
        }
    }

and here is what it would look like with the sugar:

func defaultFill(usage:ThemeKey.Usage) -> ColorFill {
        return? self.currentTheme.defaultFill(usage: usage)
        return? self.currentTheme.inheritList.firstNonNil {$0.defaultFill(usage:usage)}

        switch usage {
        case .text: return UIColor.darkText
        case .background: return UIColor.white
        case .chart: return UIColor.darkText
        case .data: return #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
        case .stroke: return UIColor.black
        case .unknown: return UIColor.black
        }
    }
2 Likes

Perhaps you can just factor your code slightly differently.

func defaultFill(usage: ThemeKey.Usage) -> ColorFill {
    return currentTheme.defaultFill(usage: usage)
        ?? currentTheme.inheritList.compactMap { $0.defaultFill(usage: usage) }.first
        ?? usage.fallbackFill
}

extension ThemeKey.Usage {
    var fallbackFill: UIColor {
        switch self {
        case .text: return UIColor.darkText
        case .background: return UIColor.white
        case .chart: return UIColor.darkText
        case .data: return #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1)
        case .stroke: return UIColor.black
        case .unknown: return UIColor.black
        }
    }
}
1 Like

Right. That is often what I end up doing, but then I have all these extra methods littering my namespace that I would prefer not to have.

Also, I chose a particularly simple use case to get the point across. Even in this case there are several almost identical methods for fonts, etc.... These little things become maddening when you have to repeat them over and over.

Since optionals are a first-class part of the language, a little extra support here and there would go a long way. Two other methods I built myself and use all the time:

  • array.appendNonNil(_ value:Element?) //Appends if not nil
  • sequence.firstNonNil<U>(where: (Element)->U? ) -> U? //a map which returns the first non nil result