2

After updating xCode to version 10 (and swift 4.2), I have a strange behaviour on optional bindings

The code is below, and it ´s about reading json file, T is a generic type (here String)

// Are there values for configName ?
if let values = cfg[configName] as? [String: Any] {

    print("0 - values[langCode!] = ", values[langCode!] ?? "null")
    print("1 - values[langCode!] as? T = ", values[langCode!] as? T)

    // is there a value for langCode ?
    if let value = values[langCode!] as? T {
        print("2 - value to return= ", value)
        return value
    } else {
        print("3 - Do something else ")
    }
}

In xCode 9.4.1 and Swift 4.1 I have the following logs:

0 - values[langCode!] =  null
1 - values[langCode!] as? T =  nil
3 - Do something else 

That is what I want, values[langCode!] is nil and the cast also return nil so the else block is executed.

In xCode 10 with Swift 4.2, I have the following logs:

0 - values[langCode!] =  null
1 - values[langCode!] as? T =  Optional(nil)
2 - value to return=  nil

Here the if let block is executed even if values[langCode!] is "null".

One difference is that with swift 4.2 values[langCode!] as? T is an Optional(nil) and on Swift 4.1 values[langCode!] as? T is an nil.

I checked the changelog for version 4.2 and I could not see something that can explain that behaviour, I also checked that no changes have been done on JSONSerialization (used to serialize the json file)

Has someone also experienced that kind of thing when switching to Swift4.2 ? Does someone have an explanation ? And a work around ?

In this kind of code what is the advantage to use optional binding ? would it be bad to write if (values[langCode!] != nil) {... instead of the optional binding ?

Thanks

eqtèöck
  • 971
  • 1
  • 13
  • 27
  • 3
    Probably related to https://stackoverflow.com/q/52446097/2976878 – Hamish Oct 02 '18 at 15:18
  • 2
    @Hamish Looks to me like an actual duplicate - is it? – matt Oct 02 '18 at 15:23
  • 2
    @matt Probably – I'm just a little confused by the fact that OP says `T` is `String` in their example. If that's the case, then an output of `Optional(nil)` doesn't make much sense. It only really makes sense if `T` is something like `Any` – if that is the case, then yup I'd say it's a dupe. – Hamish Oct 02 '18 at 15:26
  • Are you sure `T` is inferred as `String` ? Isn't it `String?` ? – OOPer Oct 02 '18 at 15:50
  • Thanks a lot, I think my problem is what is described [https://stackoverflow.com/questions/52446097/ios-12-sdk-generic-function-returns-optional-somenil](stackoverflow.com/q/52446097/2976878).. and yes the type is `String?` – eqtèöck Oct 05 '18 at 08:30

2 Answers2

1

If you have not changed the code and it behaves differently, then that is probably a bug in Swift. If you can make a small test case, you should file a bug at https://bugs.swift.org.

Anyway, it sounds like in Swift 4.1, Swift deduces type T as some non-Optional type (e.g. Int), and in Swift 4.2, Swift deduces T as Optional instead (e.g. Int?). You could check by adding this statement:

print("Type T is bound to \(T.self)")

If it prints Int (or whatever) under Swift 4.1 and Optional<Int> under Swift 4.2, then that's the problem.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
0

I answer my question since the correct answer has been given in comments.

The difference observed between Swift4.1 and Swift4.2 is due to an intentional change. @Hamish explains everything in the answer is done here: stackoverflow.com/q/52446097/2976878

eqtèöck
  • 971
  • 1
  • 13
  • 27