g i i k
g i i k

Reputation: 393

What does it mean that a type is "bridged"

In "The Swift Programming Language (Swift 5.6 beta)" by Apple, in the Language Reference/Statements section, there is a formal definition of a guard statement

guard <condition> else {
  <statements>
}

where, I quote “...The value of any condition in a guard statement must be of type Bool or a type bridged to Bool. The condition can also be an optional binding declaration, as discussed in Optional Binding...”

What does it mean for a type to be bridged to Bool (or to whatever other type T assuming bridging to T is possible)? Is this something specific to Bool, like an implicit cast? Is it a built-in or can one generally bridge to any T by following a formal procedure.

I've searched far and wide but have not been able to find a formal-ish description of bridging in the same publication or elsewhere (if one exists please point it out to me).

Upvotes: 1

Views: 724

Answers (1)

Itai Ferber
Itai Ferber

Reputation: 29843

The term "bridging" for Swift comes from the older Cocoa frameworks concept of Toll-Free Bridging. In Objective-C, certain Foundation class types have the same underlying layout as their CoreFoundation counterpart types such that it's possible to cast between one type and another and have them work identically: you can create a CoreFoundation object in C, then pass it to Objective-C and call methods on it — or you can create a Foundation object in Objective-C, and pass that object to a function in C expecting the CoreFoundation equivalent. Toll-Free Bridging allows you to cross the "bridge" between languages/levels of abstraction, without paying a "toll" to convert between the types (since the cast is direct in memory, there's no runtime cost to converting these types).

Not all types are like this, and these types are designed specifically to behave in this way.

The concept was carried over to Swift, where certain Foundation types can be similarly "bridged" to Swift types, such as String ↔︎ NSString, Array ↔︎ NSArray, Dictionary ↔︎ NSDictionary, etc. The bridging isn't necessarily always "toll-free" (as in, the objects can be cast directly in memory without their underlying representation being changed), but close enough.

The statement, then, saying

The value of the condition must be of type Bool or a type bridged to Bool.

means that the condition must be a Bool, or a type which can be converted directly into a Bool in this way.

The tricky thing about this description is that there isn't a type which can be unconditionally bridged into a Bool from Objective-C anymore. You can bridge an NSNumber to a Bool with a conditional cast (e.g. let b = NSNumber(value: true) as? Bool), but that's not enough to allow you to substitute an NSNumber in place of the condition:

while NSNumber(value: true) as? Bool { // error: Value of type 'Bool?' must be unwrapped to a value of type 'Bool'
    print("Hello")
}

I believe this sentence is a holdover from previous versions of the language where the rules are a little bit different — and is sort of confusing now.


Is it a built-in or can one generally bridge to any T by following a formal procedure.

  • If you know that a type T bridges to a type U unconditionally (e.g., Array ↔︎ NSArray, or String ↔︎ NSString), you can bridge between them with an as cast: let a1: [Int] = [1, 2, 3]; let a2 = a1 as NSArray, or let s1: NSString = "Hello"; let s2 = s1 as String)
  • If you know that a type T bridges to a type U conditionally (e.g., NSNumber ↔︎ Bool above, since not all numbers can be converted to a Bool), the same can be done with an as? cast

Otherwise, bridging is a feature that's you can't meaningfully opt into outside of the compiler, standard library, and Apple frameworks. The Swift standard library has an underscored _ObjectiveCBridgeable that Foundation uses to add bridging implementations (e.g., bridging Array ↔︎ NSArray, or e.g., bridging UUID ↔︎ NSUUID), but a lot of bridging mechanisms are also built into the compiler.

Upvotes: 3

Related Questions