As you may have gathered, I have found an interest in Swift. I have always found it easier to pick up new languages by comparing it to the one I know best, Java.
Please note, this series is intended for experienced Java Developers. I will not go into details of Java or its API. Where sensible I will provide relevant links.
Tony Hoare, inventor of null (aka nil), famously proclaimed it to be his “…billion dollar mistake”. This should not be interpreted as null/nil being evil per se, denoting the absence/not-existence of a value is essential for data processing, but rather the absence of sensible language features to handle null/nil values.
To fully appreciate this you have to jump a couple of sentences further: “… More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965.”
Unlike Java, Optional is an integral part of Swift language. In Swift variables may not be assigned nil (null), either they have to be initialized with a value or declared as an ? optional.
var nonNill: String = "Foo" //may not be nil var optNil: String? //optional may contain nil var optNonNill: String? = "Bar" //Bar wrapped in an optional
Any attempt to assign a non-optional variable with a nil value results in a compilation error.
Java on the other hand leaves null handling completely open, the introduction of Optional in Java 8 has provided API level functionality, sadly it has several design flaws which mitigate its usefulness (see Java 8 Optional: What’s the Point? and Why Isn’t Optional Serializable? ).
String nullString = null; //can be null String nonNullString = "Foo"; Optional optNull = Optional.ofNullable(null); //optional may contain null Optional optNonNull = Optional.ofNullable("Bar");
Just like in Java optionals have to be unwrapped, this can either be done by force unwrapping the optional with !.
if optNonNill != nil { print(optNonNill) //Optional("Bar")
The preferred way of handling optionals is optional binding, if the value exists it is unwrapped and assigned to a temporary variable/constant.
if let unwrapped = optNonNill { print(unwrapped) //Foo }
Force unwrapping a nil optional will still cause a runtime error, and as such should be avoided.
var unwarpped: String = optNull! fatal error: unexpectedly found nil while unwrapping an Optional value Current stack trace: 0 libswiftCore.so 0x00007fe2b790cc90 swift_reportError + 117 1 libswiftCore.so 0x00007fe2b791e1d0 ...
In contrast Java’s null handling can seem rather archaic, with the one exception being Optional in combination with lambdas.
if(nonNullString != null) { ... } if(optNonNull.isPresent()) { String value = optNonNull.get(); ... } //optional with lambda optNonNull.ifPresent(x -> {...}); optNull.orElseGet(() -> {...});
In plain vanilla Java code ternary operator are often employed, to assign default values in case of null, with Java 8 Optional you can also use .orElse(…).
//Ternary operator String default = nullString != null ? nullString : ""; String default = optNull.orElse("");
Swift has an explicit nil coalescing operator ??, allowing for easy assignment of default values.
var myVal1: String = optNil ?? "default" print(myVal1) //default //Optional binding requires an optional even with nil coalescing. if let myVal2 = optNil ?? Optional("default") { print(myVal2) //default }
Swift allows optional chaining, enabling the chaining of multiple optional calls. The output will be an optional which may be nil.
var address: Address? = Address(street: "Foo Lane", city: "Bar Town", postcode: "42") var customer: Customer? = Customer(surname: "Baz", firstname: nil, address: address) let streetLC = customer?.address?.street?.lowercased() print(streetLC) //Optional("foo lane") if let streetUC = customer?.address?.street?.uppercased() { print(streetUC) //FOO LANE }
Doing the same in Java requires a long chain of multiple null checks, or the use of null objects (see Null Object Pattern).
if(customer != null && customer.getAddress() != null && customer.getAddress().getStreet() != null) { ... }
Sadly it is not advisable to use Optional in domain models since they are not Serializable, which makes serializing across system boundaries (e.g. RMI, JAX-RS, JAX-WS, etc…) difficult. It can also wreak havoc when employed in passivatable context in stateful applications (such as CDI).
IBM hosts a public Swift-Sandbox, that allows you to try out Swift. This posts Swift code is published in a sandbox here for you to try out.
The next post will cover Swifts handling of variables, constants and types.
Further Resources:
Swift – The Basics
Swift – Optional Chaining
Understanding Optionals in Swift
Optionals Brocken (Java)
Java 8 Optional: What’s the Point?
IBM Swift Sandbox
One thought on “Swift for Beans – about null, nil and Optional.orElse(“?!”)”