[swift-evolution] Conditional casting and conditional binding: Wierd edge case or flawed design

Erica Sadun erica at ericasadun.com
Sun Oct 9 15:10:22 CDT 2016

Normally in guard and if condition lists, you look up a value in a dictionary and conditionally cast:

    if let value = dict[key] as? T, ...

The "as?" operator passes the Any? type through, and the lhs result is T, not T?.

* dict[key] returns Any?
* Any? as T returns T?, not T??
* the conditional binding binds T? to T

However, this (somewhat illogical) "sugar" doesn't happen when you conditionally cast T? to U, for example, when a dictionary is [AnyHashable: String]:

guard let value = dict["Key"] as? NSString
    else { fatalError() }

(see http://i.imgur.com/SkXkk6o.jpg <http://i.imgur.com/SkXkk6o.jpg>)

* dict[key] returns String?
* String? as T is guaranteed to fail

In this case, the compiler asserts that a cast from String? to an unrelated type NSString always fails. You can mitigate this by sticking an "Any" cast in the middle:

guard let value = dict["Key"] as Any as? NSString
    else { fatalError() }

If that's not "magic", I don't know what is.  (You can also cast the dictionary to [AnyHashable: NSString], etc.)

Jack L's initial response: "oh, that's a weird bridging edge case 😕 it seems like we should just make that work..."  http://twitter.com/_jackhl/status/784998768898744320 <http://twitter.com/_jackhl/status/784998768898744320>) but he asked me to follow up here on SwiftEv. It seems to me that in conditional binding with conditional casting, you're asking the compiler to do not one but *two* magical things:

1. Apply what *looks* like assignment (I have a similar issue with if case/guard case) but is actually something else
2. Apply what *looks* like conditional casting but which magically passes Any? through to T?, not T??

I handwave this (but just the moment) and say "it's not really an assignment, so it's not really a conditional cast". Jack asked me to bring this discussion over to Swift Evolution and ask the greater community whether Swift is doing these things right, and if not, how it should fix them. 

Where I stand:

* If there's going to be magic, it should be documented (and it is not) in the Swift Programming Language
* If there's going to be magic, it should work for T?, not just Any?
* I'd rather there not be magic here

-- E
p.s. I'd also rather that if-case/guard-case would use ":" like in switch statements not "=", but no one seems to be responding to that thread, dagnabit
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161009/7c5d4a73/attachment.html>

More information about the swift-evolution mailing list