orome
orome

Reputation: 48466

Is 'x?.y' in Swift the same as 'x?' followed by '.y'?

I understand that in Swift, if I define

var opt:String? = "Optional"

I will get an error if I attempt

opt.isEmpty 

since opt is of type String? which does does not have an isEmpty method. And I thought that I understood that

opt?.isEmpty

does not produce an error because opt? unwraps (any non-nil) opt, resulting in a String, which does have an isEmpty method. But

opt?

on its own results in a String? and not a String.

Is ?. a different operator from ? followed by .?


Try

(opt?).isEmpty 

and get a suggestive error.

Upvotes: 0

Views: 321

Answers (2)

newacct
newacct

Reputation: 122439

But opt? on its own results in a String? and not a String.

Yes. According to the Swift language reference, Expressions, Postfix Expressions, Optional-Chaining Expression:

On its own, the postfix ? operator simply returns the value of its argument as an optional.

So putting a ? by itself at the end of an optional is a complete no-op. It has no effect.

Is ?. a different operator from ? followed by .?

Yes. More specifically, ? has the optional-chaining effect when used in any "postfix expression", including when followed by () (function call), . (member access), and [] (subscript).

Upvotes: 1

codester
codester

Reputation: 37189

Yes opt?.isEmpty is different from String?.It is called optional chaining.From swift programming guide:

You specify optional chaining by placing a question mark (?) after the optional value on which you wish to call a property, method or subscript if the optional is non-nil. This is very similar to placing an exclamation mark (!) after an optional value to force the unwrapping of its value. The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.

This creates optional as you thinking var opt:String?

Now

 opt?.isEmpty //it will not crash if opt is nil 

is same as except

opt!.isEmpty //it will crash if opt is nil 

if opt! is nil than it will not crash at runtime.Optional chaining is used to call long sequences of optional without calling.Every optional chain returns optional i.e opt? returns optional unwraps it and if nil than not call isEmpty else call isEmpty and reutns value. Also

  (opt?).isEmpty 

When you are writing above statement it is just optional(not optional of optional) and it fails to unwrap because of braces.So error is showing

$T2?? does not have a member named `isEmpty`

to unwrap it use

(opt?)!.isEmpty

it will return false

Edit: To clarify more

   var o1 = opt?
   var o2 = ((opt?)?)

is doing nothing in its own it just assign same value to o1,o2 i.e String?. to unwrap opt and o1,o2 they both are optional and need single ! operator to unwrap it.

Also please do not misunderstood between String? and opt? they both are different when ? is used after some type in decleration it makes optional and when ? used after variable optit is used for unwrap in optional chaining and return optional value it is returning

Extra Stuff:

try this to more clarify

(((opt?)?)!).isEmpty     //it will unwrap with single !
((((opt?)?)!)?).isEmpty   //compiler will show suggestion to remove ?

the below statement makes optional of optional of optional

   var opt:String??? = "Optional"

to unwrap

   opt!!!.isEmpty

EDIT2

opt? always return optional but if opt is defined as String! it is implicit optional and opt? will return optional(explicit).But if opt is already optional opt? will do nothing

From swift programming guide

To put it another way:

If the type you are trying to retrieve is not optional, it will become optional because of the optional chaining.
If the type you are trying to retrieve is already optional, it will not become more optional because of the chaining.

Therefore:

If you try to retrieve an Int value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.
Similarly, if you try to retrieve an Int? value through optional chaining, an Int? is always returned, no matter how many levels of chaining are used.

Upvotes: 2

Related Questions