6

I know the recommended way in Swift is to use:

class Address {
var firstLine : String?
var secondLine : String?
}

but sometimes I see other developers write their code this way:

class Address {
var firstLine : String = ""
var secondLine : String = ""
}

Is this the unrecommended way because whenever you have nil you will just crash and there's no outlet for your to recover. Is that right? Or there are some use cases where using non-optionals with default can be good. If so then where?

I saw this other question which is asking about efficiency rather than which better suits your needs. I'm looking for an answer where it says "This is a good place to use non-optionals and this is a good place to use optionals". Sometimes I see folks just dump optionals everywhere and it makes me think do we not ever need non-optionals? Sometimes I see people trying to avoid optionals as much as possible and just code in an Objective-C kind of style.

The above question's answer doesn't represent a valid case for where non-optionals are good. It's mute about that. As for choosing optionals: I'm guessing for models which get populated by network calls, optionals are the right choice, because you don't know whether it's nil or not.

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • Duplicate of https://stackoverflow.com/questions/26028504/swift-model-structs-using-optionals-vs-initialization-of-empty-values ? – Martin R May 31 '17 at 15:15
  • 2
    @MartinR I think the other question is more about efficiency, while this one is about design principles. – Sergey Kalinichenko May 31 '17 at 15:16
  • 1
    This really is a matter of opinion and personal preferences. I like the options as the compiler warns you the value may not be there so you are forced to handle it. On the other hand, a lot of languages do not have the same checks and developers carry these habits with them into Swift. You are ignoring a compiler's feature if you choose non-optional default. – Code Different May 31 '17 at 15:19
  • 1
    @CodeDifferent This is not a matter of opinion: there is always one correct answer depending on a situation that you model. – Sergey Kalinichenko May 31 '17 at 15:21
  • MUST SEE vide: [Optionals in practice](https://engineers.sg/episodes/2053) by [Rop Napier](https://stackoverflow.com/users/97337/rob-napier). Also I find myself recently using the `??` operator more and more. It just simplifies a lot of stuff. e.g. instead of doing a `guard` to see if an array exists and then loop through it...I just do: `for item in optionalArray ?? []{...}` – mfaani Apr 27 '18 at 19:52

2 Answers2

7

The choice depends on what you model.

If a property of the object that you model may be absent completely, e.g. a middle name, a name suffix, an alternative phone number, etc., it should be modeled with an optional. A nil optional tells you that the property is not there - i.e. a person does not have a middle name or an alternative phone number. You should also use optional when you must distinguish between an empty object and a missing object.

If a property of the object must be set, and has a meaningful default, use an non-optional with a default:

class AddressList {
    var addresses : [Address]
    var separator : String = ";"
    ...
}

If users of your class need to change the separator, they have a way to do that. However, if they do not care about the separator, they can continue using the default without mentioning it in their own code.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I understand your answer completely. You gave a valid case where it wouldn't make sense for `separator` to be optional...you always need one. Correct me if I'm wrong: specifically for my question: I'm guessing no one can have an address without a `firstLine` so it must be non-optional.Yet from the perspective of calling an API, you never know...it may be `nil` because this customer's address wasn't filled properly or some other issue. So I guess it also depends on how it's being fed and `firstLine` should be optional...perhaps the same applies to your `addresses` – mfaani May 31 '17 at 15:39
  • 1
    @Honey This depends on the purpose that `Address` objects serve in your design. If you use them for data transfer, and validate them on the server, then objects of the class must be able to represent both valid and invalid states of the address. In this situation making both address lines optional is correct. If you use address objects in your app as representations of fully validated addresses, then `firstLine` should be non-optional. – Sergey Kalinichenko May 31 '17 at 15:50
  • @Honey: in your situation, you declare the variable `address` as optional i the class that holds it. And the `firstLine` (of the class Address) is non-optional. It correspond to the requirements: a person can declare or not his address, if he declared an address, this address must have at least the `firstLine`. I'm totally agree with @dasblinkenlight that it depends on the design of your models. – Duyen-Hoa May 31 '17 at 16:24
  • Would it ever makes sense to initialize your Strings to an empty string? Or that would be an abuse? (What you demonstrated here with `";"` is kind of different and more obvious than an empty string) – mfaani Jun 12 '17 at 15:54
  • 1
    @Honey There are situations when an empty string is a suitable default for an optional `String`. For example, a string representing a page footer may be empty by default in a solution that allows three states: `nil` for a missing footer that does not occupy any space at the bottom of a page, `""` for a footer that forces some empty space at the bottom, or a non-empty footer that prints at the bottom of the page. – Sergey Kalinichenko Jun 12 '17 at 16:02
  • Agreed. Anywhere an empty string is suitable for a **non**-optional `String`? – mfaani Jun 12 '17 at 16:06
  • @Honey I can't think of a good use case where an empty string would be a good default for a field that must be non-optional by design (i.e. not through an omission of the class designer). – Sergey Kalinichenko Jun 12 '17 at 16:16
  • I'm having a hard time convincing another member to not: use `String` defaulted to `""` in place of `String?` For when you make a network call. What he's doing at the end to 'replace checking for `nil`s or using optionals is to just check if the String is empty or not'. To him there is no value to use `nil` and do safe checking. My response is 1: It's not Swift-like and we would have differences of paradigms with other frameworks, other projects, people 2. What if something wants to actually be `""`, then you no longer can communicate that. Can you think of any other argument? – mfaani Oct 04 '17 at 19:55
  • Also I can't say how many times I've came back here, just so I can read [this](https://stackoverflow.com/questions/44288488/when-should-i-use-optionals-and-when-should-i-use-non-optionals-with-default-val) comment. I would be great if you could add that to the answer... – mfaani Oct 04 '17 at 19:57
  • @Honey It's hard to convince someone who actively refuses to take advantage of a language feature specifically designed to simplify what he's doing. I mean, `if let nonNullStr = optionalStr { ... }` and `guard let nonNullStr = optionalStr else { ... }` constructs, which simplify your code, and make error handling more explicit. Your comment link is broken. If you'd like to add to the answer, you are welcome to edit it. – Sergey Kalinichenko Oct 04 '17 at 20:07
  • So we decided to follow your suggestion, now I'm facing a (possible) drawback. I have an object which its properties are populated by an API call, and then you need to use this object at 5 different views, at each view, you would need to make that decision of defaulting or not, what to default it to. Had we defaulted them all initially then it be easier. I'm guessing I should default them **only if** they all follow the same logic of defaulting. Otherwise still follow this approach so we can customize the defaulting of each object however we like – mfaani Oct 18 '17 at 19:34
  • @Honey Defaulting does get tricky. If the same logic needs to be applied in multiple places, it's best to place that logic in the same place, where the data from an API call comes in. If the resultant field is always present, make fields non-optional, and add "object defaulting" layer between the API and the construction of the objects for your data model. – Sergey Kalinichenko Oct 18 '17 at 19:38
  • so before you were saying `struct Person{ var firstName: String?`} but now **IF** the same logic needs to be applied in multiple places then: by 'defaulting layer' you mean `struct Person{ var firstName: String = ""}`? – mfaani Oct 18 '17 at 19:59
  • @Honey No, it would be `var String` without `= ""`, but the defaulting logic would call the `init` and pass a non-optional `String` for initializing `firstName`. – Sergey Kalinichenko Oct 18 '17 at 20:02
  • I _think_ lost you here, I can't properly differentiate between defaulting layer and API layer. Can you add that to your answer? Yet if I understand you correctly, you mean the object itself should take `non-nil` parameters, so it could be an empty `String` or whatever default you like, but the **upon instantiating this object *after* you parse through the JSON you default any `nil` values**. (sorry for the too many comments) – mfaani Oct 18 '17 at 20:15
  • 1
    @Honey Yes, your understanding is spot-on: you parse your JSON from the API, default any null values that you may get in it, and create the object using a constructor that takes non-`nil` parameters. – Sergey Kalinichenko Oct 18 '17 at 20:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/157031/discussion-between-honey-and-dasblinkenlight). – mfaani Oct 18 '17 at 22:10
0

Well you should use optionals if you think that the variable might not have a value. But if you're really sure that it's gonna have a value then you don't need to use them.

So only use non-optionals if you're sure that the variable will have a value else use optionals.

Lennart P.
  • 316
  • 1
  • 6
  • 20