Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional array vs. empty array in Swift

I have a simple Person class in Swift that looks about like this:

class Person {
    var name = "John Doe"
    var age = 18
    var children = [Person]?

    \\ init function goes here, but does not initialize children array
}

Instead of declaring children to be an optional array, I could simply declare it and initialize it as an empty array like this:

var children = [Person]()

I am trying to decide which approach is better. Declaring the array as an optional array means that it will not take up any memory at all, whereas an empty array has at least some memory allocated for it, correct? So using the optional array means that there will be at least some memory saving. I guess my first question is: Is there really any actual memory saving involved here, or are my assumptions about this incorrect?

On the other hand, if it is optional then each time I try to use it I will have to check to see if it is nil or not before adding or removing objects from it. So there will be be some loss of efficiency there (but not much, I imagine).

I kind of like the optional approach. Not every Person will have children, so why not let children be nil until the Person decides to settle down and raise a family?

At any rate, I would like to know if there are any other specific advantages or disadvantages to one approach or the other. It is a design question that will come up over and over again.

like image 257
Aaron Rasmussen Avatar asked Nov 07 '14 23:11

Aaron Rasmussen


People also ask

How check array is empty or not in Swift?

To check if an array is empty, use Swift function isEmpty on the array. Following is a quick example, to check if an array is empty. The function returns a boolean value. If the array is empty, isEmpty returns true, else false.

How do I unwrap an array in Swift?

I can force unwrap it in a short way: var arrayForCrash = arrayOfOptionals. map { $0! }

How do you create an empty array in Swift?

To create an empty string array in Swift, specify the element type String for the array and assign an empty array to the String array variable.


3 Answers

I'm going to make the opposite case from Yordi - an empty array just as clearly says "this Person has no children", and will save you a ton of hassle. children.isEmpty is an easy check for the existence of kids, and you won't ever have to unwrap or worry about an unexpected nil.

Also, as a note, declaring something as optional doesn't mean it takes zero space - it's the .None case of an Optional<Array<Person>>.

like image 71
Nate Cook Avatar answered Oct 17 '22 01:10

Nate Cook


The ability to choose between an empty array or an optional gives us the ability to apply the one that better describe the data from a semantic point of view.

I would choose:

  • An empty array if the list can be empty, but it's a transient status and in the end it should have at least one element. Being non optional makes clear that the array should not be empty
  • An optional if it's possible for the list to be empty for the entire life cycle of the container entity. Being an optional makes clear that the array can be empty

Let me make some examples:

  • Purchase order with master and details (one detail per product): a purchase order can have 0 details, but that's a transient status, because it wouldn't make sense having a purchase order with 0 products
  • Person with children: a person can have no children for his entire life. It is not a transient status (although not permanent as well), but using an optional it's clear that it's legit for a person to have no children.

Note that my opinion is only about making the code more clear and self-explainatory - I don't think there is any significant difference in terms of performance, memory usage, etc. for choosing one option or the other.

like image 21
Antonio Avatar answered Oct 17 '22 00:10

Antonio


Interestingly enough, we have recently had few discussions regarding this very same question at work.

Some suggest that there are subtle semantic differences. E.g. nil means a person has no children whatsoever, but then what does 0 mean? Does it mean "has children, the whole 0 of them"? Like I said, pure semantics "has 0 children" and "has no children" makes no difference when working with this model in code. In that case why not choosing more straightforwards and less guard-let-?-y approach?

Some suggest that keeping a nil there may be an indication that, for example, when fetching model from backend something went wrong and we got error instead of children. But I think model should not try to have this type of semantics and nil should not be used as indication of some error in the past.

I personally think that the model should be as dumb as possible and the dumbest option in this case is empty array.

Having an optional will make you drag that ? until the end of days and use guard let, if let or ?? over and over again.

You will have to have extra unwrapping logic for NSCoding implementation, you will have to do person.children?.count ?? 0 instead of straightforward person.children.count when you display that model in any view controller.

The final goal of all that manipulation is to display something on UI. Would you really say

"This person has no children" and "This person has 0 children" for nil and empty array correspondingly? I hope you would not :)

Last Straw

Finally, and this is really the strongest argument I have

  • What is the type of subviews property of UIView: it's var subviews: [UIView] { get }
  • What is the type of children property of SKNode: it's var children: [SKNode] { get }

There's tons of examples like this in Cocoa framework: UIViewController::childViewControllers and more.

Even from pure Swift world: Dictionary::keys though this may be a bit far fetched.

Why is it OK for person to have nil children, but not for SKNode? For me the analogy is perfect. Hey, even the SKNode's method name is children :)

My view: there must be an obvious reason for keeping those arrays as optionals, like a really good one, otherwise empty array offers same semantics with less unwrapping.

The Last Last Straw

Finally, some references to very good articles, each of those

  • http://www.theswiftlearner.com/2015/05/08/empty-or-optional-arrays/
  • https://www.natashatherobot.com/ios-optional-vs-empty-data-source-swift/

In Natasha's post, you will find a link to NSHipster's blog post and in Swiftification paragraph you can read this:

For example, instead of marking NSArray return values as nullable, many APIs have been modified to return an empty array—semantically these have the same value (i.e., nothing), but a non-optional array is far simpler to work with

like image 15
i4niac Avatar answered Oct 17 '22 02:10

i4niac