Why is a method defined in the Foundation module available when the module is not imported?

In a single view application project for iOS, I am able to use the contains(_:) method of the String type defined in the Foundation module in the ViewController file where the Foundation module is not imported. Why is this possible? The only module imported in this file is the UIKit module. Is the definition of the contains(_:) method provided through the UIKit module indirectly? If it is, how?

ViewController.swift:

import UIKit

class ViewController: UIViewController {
     override func viewDidLoad() {
          super.viewDidLoad()
          let s = "Hello"
          print(s.contains("H")) 
     } 
}

UIKit is an "umbrella" framework, which imports a lot of other frameworks, including Foundation, so it really is imported.


There's actually more to this than meets the eye. As it happens, Swift contains a re-implementation of the NSString APIs within the String class. That means it doesn't bridge or call through to actual NSString functions when you use a String type natively. Presumably this was done for performance reasons, and to resolve basic semantic differences (such as what constitutes a "character").


However, these APIs are only made fully available if you import Foundation. If not, there is a subset of the String APIs that's available to Swift apps via the Swift standard library. Presumably, anything whose implementation depends on the Obj-C runtime is left out, so that this subset can be available on non-Mac systems. In other words, there is a String implementation in Swift.stdlib that's different from the implementation in Swift.Foundation which is different from the implementation in [traditional] Foundation.


This means that if you try to compile lines 06-07 in a Swift file that does not import anything, you'll still be able to use String.contains. Strange but true.

let s = "Hello"
print(s.contains("H"))


Thanks for the response, but the code above doesn't work alone. I tried it in a playground. The error is "Value of type 'String' has no member 'contains'". It works if Foundation is imported before it. In the definition of UIKit, accessed by Command + Click, the first line is

import Foundation

. Is that line the reason why importing UIKit allows the code in question to work? If that is the reason, why does the code below also work?


import Accounts
let s = "Hello"
print(s.contains("H"))


The Account module doesn't seem to import Foundation.

Yes, "contains" doesn't work in a playground. I tried it in a context (a source file belonging to an app) where Foundation must have been imported implicitly, so I mistakenly concluded this was one of the base String APIs. It's not, but my point is still the same. If you type this in a playground:


let s: String = "Hello"


then command-click on "String" it will take you to the standard library definition of the String type, and you'll see there's lots of stuff there, but not the complete NSString-compatible API set.


>> Is that line the reason why importing UIKit allows the code in question to work?


Well, yes, that's what I said before.

If UIKit importing Foundation makes the contains method of String available when UIKit is imported. Why does the following code work?


import Accounts  
let s = "Hello"  
print(s.contains("H")) 


Accounts doesn't seem to import Foundation.

Why is a method defined in the Foundation module available when the module is not imported?
 
 
Q