1

I know that optional chaining like this:

someOptional?.someProperty

is basically

someOptional.map { $0.someProperty }

However, I found that doing both at the same time is not possible:

// someOptional?.someProperty evaluates to an optional type, right?
// so the map method should exist!
someOptional?.someProperty.map(someClosure) // can't find "map"

Here's an MCVE:

let s: String? = "Hello"
s?.hashValue.map(Double.init)

I think writing something like the above is more readable than:

s.map { Double($0.hashValue) }

So I would really like a way to use optional chaining and map at the same time.

How do I do this?

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Closely related: [Optional chaining with Swift strings](https://stackoverflow.com/questions/38699734/optional-chaining-with-swift-strings). – Martin R Sep 12 '18 at 07:17

1 Answers1

1

Apparently, for some reason, wrapping the first part in brackets worked:

(s?.hashValue).map(Double.init)

I think this is somehow due to the ? having a lower precedence, or that optional chaining doesn't work the same way as other expressions. Adding the brackets might have caused s?.hashValue to become an expression.

Edit:

Here is the relevant excerpt from the Swift reference:

If a postfix expression that contains an optional-chaining expression is nested inside other postfix expressions, only the outermost expression returns an optional type. In the example below, when c is not nil, its value is unwrapped and used to evaluate .property, the value of which is used to evaluate .performAction(). The entire expression c?.property.performAction() has a value of an optional type.

So s?.hashValue doesn't actually evaluate to an optional type, because it is nested inside another expression. By adding (), I separated it into another expression, manually making it evaluate to an optional type.

Sweeper
  • 213,210
  • 22
  • 193
  • 313