Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

211
Views
Odd Generics & Optional Behavior in Swift 4.2 after upgrading to iOS 12.2 (Xcode 10.2)

We have just updated Xcode to 10.2 (hence iOS 12.2 SDK) and started seeing odd behavior with respect to the behavior of Swift Generics and Optionals. We have kept the Swift version at 4.2, so no Swift 5 update. The only change was updating to Xcode 10.2 from Xcode 10.1.

Here is a sample code that illustrates the oddities. The comments show what has changed between versions. Ideally, there shouldn't be any changes.

class Phone<T> {}

extension Phone {
    class func create(initial: T? = nil) -> Phone<T> {
        if let _ = initial { print("Regular: Unwrapping worked.") }
        return Phone()
    }
}

extension Phone where T == Void {
    class func create(initial: T? = nil) -> Phone<T> {
        if let _ = initial { print("T == Void: Unwrapping worked.") }
        return Phone()
    }
}

var phone: Phone<Int?> = Phone()
var phone2: Phone<Int?> = Phone()
var phone3: Phone<Int?> = Phone()

// unwrapping works iOS 12.1, doesn't work in 12.2
phone = Phone.create(initial: Optional(nil))

// unwrapping works iOS 12.1, doesn't work in 12.2
phone2 = Phone.create(initial: Optional<Int?>(nil))

// doesn't compile in iOS 12.1, unwrapping works in iOS 12.2
phone3 = Phone.create(initial: Optional<Int>(nil))

// doesn't compile in iOS 12.1, unwrapping doesn't work in 12.2 (uses the T == Void function)
let phone4 = Phone.create(initial: Optional(nil))

We have gone through the release notes of Xcode 10.2 but haven't spotted any changes around Optionals or Generics. It is really hard to understand what is causing this change in behavior between versions.

It is especially very interesting how phone2 and phone3 behave differently. There are few odd things happening in the code sample above, so the question is if anyone knows what might have caused the behavioral changes in this release?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

This is due to SE-0213: Literal initialization via coercion which means that Optional(nil) is now treated as nil as Optional by the compiler. Previously with Optional(nil), you'd get a wrapped nil value e.g Int??.some(nil), however now you get just nil.

So for the following:

let phone: Phone<Int?> = Phone.create(initial: Optional(nil))

the compiler is treating it as:

let phone: Phone<Int?> = Phone.create(initial: nil as Optional)

which is equivalent to:

let phone: Phone<Int?> = Phone.create(initial: nil)

Because you've specified the generic parameter T to be Int?, the initial: parameter takes an Int??. Therefore by passing nil you're passing Int??.none, and therefore the unwrapping fails.

One way to restore the old behaviour is to specify .init explicitly in order to force the compiler to call the initialiser:

let phone: Phone<Int?> = Phone.create(initial: Optional.init(nil))

Now you're passing an Int??.some(nil) to the parameter and the unwrapping succeeds.

However I would question why you're dealing with doubly wrapped optionals in the first place – I would strongly encourage avoiding them unless absolutely necessary.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!