Optionals and non-nil values in Swift

11 Aug 2015

This is somewhat in response to Brent Simmon’s Objective-Swift article. I came across something at work just today where Swift-style nil handling would have been exactly the right thing, but at work we use Java, so I get to null check everything.

The thing in question: I was putting together an interface for something that provides an editor for text styles and the like:

public interface TextPropertiesDisplay {
    public HasValue<Font> getFontPicker();
    public HasValue<Integer> getFontSizePicker();
    public HasValue<Boolean> getFontBoldToggle();
    public HasValue<Boolean> getFontItalicToggle();
    public HasValue<Boolean> getFontUnderlineToggle();
    public HasValue<Color> getTextColorPicker();
    public HasValue<Color> getBackgroundColorPicker();
}

In Java, there’s no way for me to tell the compiler that those methods are never allowed to return null. I write a comment in the file and have to include null-checks everywhere that I use that interface.

I could use Java 8’s Optional (or Guava’s Optional in our case; we’re not on Java 8 yet), but that doesn’t save me from having to verify that the returned thing is safe to use every time I use it.

To make matters more annoying in this case, two of those methods are supposed to return an optional value: not all the things we’re editing support underlining or background colors, so really the interface looks like this:

public interface TextPropertiesDisplay {
    public HasValue<Font> getFontPicker();
    public HasValue<Integer> getFontSizePicker();
    public HasValue<Boolean> getFontBoldToggle();
    public HasValue<Boolean> getFontItalicToggle();
    public Optional<HasValue<Boolean>> getFontUnderlineToggle();
    public HasValue<Color> getTextColorPicker();
    public Optional<HasValue<Color>> getBackgroundColorPicker();
}

I have a way of marking which ones are optional for others working on the code (and myself later down the road), but no way of enforcing it.

With Swift, I can do this:

protocol TextPropertiesDisplay {
    // These ones can't return nil, ever.
    var fontPicker: HasValue<Font> { get }
    var fontSizePicker: HasValue<Int> { get }

    // These ones can.
    var fontUnderlineToggle -> HasValue<Boolean>? { get }
    var fontBackgroundColor -> HasValue<Boolean>? { get }
}

The compiler can enforce the contract completely: those first properties cannot return nil, ever. The ones marked optional can, and the compiler will make me check those for safety.

All that said, nil-messaging would probably have solved the problem too, so it’s kind of a wash.