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.
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.
I can force unwrap it in a short way: var arrayForCrash = arrayOfOptionals. map { $0! }
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.
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>>
.
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:
Let me make some examples:
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.
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 :)
Finally, and this is really the strongest argument I have
subviews
property of UIView
: it's var subviews: [UIView] { get }
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.
Finally, some references to very good articles, each of those
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With