Files
swift-mirror/docs/CppInteroperability/UserGuide-CallingSwiftFromC++.md
Alexander Cyon ae0e94a555 [docs] Fix typos
2024-07-06 13:16:16 +02:00

1418 lines
50 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[** ‼️ The official C++ interoperability documentation is live at Swift.org and provides an up-to-date guide for mixing Swift and C++ ‼️ **](https://www.swift.org/documentation/cxx-interop/)
# Guide: Calling Swift APIs from C++
A Swift library author might want to expose their interface to C++, to allow a C++ codebase to interoperate with the Swift library. This document describes how this can be accomplished, by first describing how Swift can expose its interface to C++, and then going into the details on how to use Swift APIs from C++.
**NOTE:** This is a work-in-progress, living guide document for how Swift APIs can be imported and used from C++. This document reflects the current state of the experimental design, and it will evolve over time
as this feature will go through Swift's evolution process. This document does not specify the final target
design for the Swift to C++ interoperability layer.
**NOTE:** This document does not go over the following Swift language features yet:
* Closures
* overridden methods/properties in classes
* Existential types (any P)
* Nested types
* Operators
* Tuples & functions returning multiple parameters
* class subclass generic constraint
* Type casting
* Recursive/indirect enums
* Associated types in generic where clauses
* Error handling
* Opaque return type `-> some P` (should we not support it)
* Character type & character literal
## Exposing Swift Codebase to C++
A Swift codebase is organized into units called modules. A module typically corresponds to a specific Xcode or Swift package manager target. Swift can generate a module interface file that presents a source view of the public Swift interface provided by the module. In addition to a Swift module interface, Swift can also generate a header file that contains C++ functions and classes that allow us to work with the Swift functions and types. We can import this header file into our C++ program to start using the Swift APIs from C++.
### Compiler Requirements
The header files generated by the Swift compiler can only be compiled by the Clang compiler, as
the generated header relies on specific ABI attributes that are only supported by Clang.
### C++ Language And Library Requirements
Importing Swift APIs into C++ requires certain C++ features introduced in newer C++ language standards. The following C++ standards are expected to work:
* C++20. It is the recommended standard, as C++ 20 concepts enable type checking for imported Swift generic APIs.
* C++17 and C++14 are supported with some restrictions. Some generic APIs might not be available prior to C++20.
## Importing Swift Modules
A Swift module can be imported over into C++ by using an `#include` that imports the generated C++ header for that module:
```swift
// Swift module 'MyModule'
func myFunction();
// C++
#include "MyModule-Swift.h"
```
A C++ namespace is used to represent the Swift module. Namespacing provides a better user experience for accessing APIs from different modules as it encapsulates the different module interfaces in their own namespace. For example, in order to use a Swift module called `MyModule` from C++, you have to go through the `MyModule::` namespace in C++:
```c++
// C++
#include "MyModule-Swift.h"
int main() {
MyModule::myFunction(); // calls into Swift.
return 0;
}
```
## Calling Swift Functions
Swift functions that are callable from C++ are available in their corresponding module namespace. Their return and parameter types are transcribed to C++ primitive types and class types that represents the underlying Swift return and parameter types.
Fundamental primitive types have a C++ fundamental type that represents them in C++:
|Swift Type |C++ Type |C Type (if different) | |target specific |
|--- |--- |--- |--- |--- |
|Void (or no return) |void | | | |
|Int |swift::Int |ptrdiff_t |long or long long (windows) |YES |
|UInt |swift::UInt | size_t |unsigned long or unsigned long long (windows) |YES |
|Float |float | | | |
|Double |double | | | |
| | | | | |
|CInt |int | | | |
|CUnsignedInt |unsigned int | | | |
|CShort |short | | | |
|CUnsignedShort |unsigned short | | | |
|CLong |long | | | |
|CUnsignedLong |unsigned long | | | |
|CLongLong |long long | | | |
|CUnsignedLongLong |unsigned long long | | | |
| | | | | |
|OpaquePointer |void * | | | |
|UnsafePointer<T> |const T * | | | |
|UnsafeMutablePointer<T> |T * | | | |
**NOTES**: Need static_assert that std::is_same(size_t, unsigned long) or unsigned long long to ensure we can match the right type metadata using a template specialization.
A function that takes or return primitive Swift types behaves like any other C++ function, and you can pass in the C++ types when calling them, just as youd expect.
```swift
// Swift module 'MyModule'
func myFunction(x: float, _ c: Int) -> Bool
```
```c++
// C++
#include "MyModule-Swift.h"
int main() {
return !MyModule::myFunction(2.0f, 3); // myFunction(float, swift::Int) -> bool
}
```
### In-Out Parameters
A Swift `inout` parameter is mapped to a C++ reference type in the C++ function signature thats generated in the C++ interface. You can then pass in a value directly to an `inout` parameter from C++ side, like the example below:
```swift
// Swift module 'MyModule'
func swapTwoInts(_ a: inout Int, _ b: inout Int)
```
```c++
// C++ interface snippet
void swapTwoInts(swift::Int &a, swift::Int &b) noexcept;
// C++
#include "MyModule-Swift.h"
void testSwap() {
swift::Int x = 0, y = 42;
MyModule::swapTwoInts(x, y);
}
```
### Function Overloading
Swift allows you to specify which overload of the function you would like to call using argument labels. For example, the following snippet is explicitly calling the second definition of `greet` because of the call using `greet(person:,from:)` argument labels:
```swift
func greet(person: String, in city: String) {
print("Hello \(person)! Welcome to \(city)!")
}
func greet(person: String, from hometown: String) {
print("Hello \(person)! Glad you could visit from \(hometown).")
}
greet(person: "Bill", from: "San Jose") // calls the second overload of greet.
```
C++ only allows us to select which overload of the function we want to call by using type-based overloading. In cases where type-based overloading isnt sufficient, like when the arguments have the same type but a different argument label, you can use the `exposed` attribute to provide a different C++ name for the C++ function, like in the following example:
```swift
@expose(C++, greetPersonIn)
func greet(person: String, in city: String) {
print("Hello \(person)! Welcome to \(city)!")
}
@expose(C++, greetPersonFrom)
func greet(person: String, from hometown: String) {
print("Hello \(person)! Glad you could visit from \(hometown).")
}
```
### Default Parameter Values
Default parameter values allow you to provide a default value for Swift function parameter, allowing the program to not specify it when calling such function. The generated C++ interface for a Swift function contains default parameter values as well, just like in the following example:
```swift
// Swift module 'MyModule'
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
}
```
```c++
// C++ interface snippet
void someFunction(swift::Int parameterWithoutDefault, swift::Int parameterWithDefault = 12) noexcept;
// C++
#include "MyModule-Swift.h"
using namespace MyModule;
void testSwap() {
someFunction(3, 6); // parameterWithDefault is 6
someFunction(4); // parameterWithDefault is 12
}
```
Swift default parameter values that are set to a `#file` or `#line` call site specific literal are not represented in the generated C++ interface. The user need to pass them explicitly from the C++ call site instead.
**TODO:** Any constraints for default parameter values?
**OPEN QUESTIONS:** Are there any problems here?
* YES : a problem with Swift allowing non-last parameter orders.
### Variadic Parameters
A variadic parameter is a parameter that accepts zero or more values of the specified type. It gets exposed in C++ using a `swift::variadic_parameter_pack` class template. You can pass values to a variadic parameter using the C++ initializer list syntax. For example, the following Swift function with a `Double` variadic parameter:
```swift
func arithmeticMean(_ numbers: Double...) -> Double {
...
}
```
can be called from C++ using a C++ initializer list:
```c++
arithmeticMean({ 1.0, 2.0 });
```
## Using Swift Structure Types
Swift structures that are usable from C++ are available in their corresponding module namespace. Theyre bridged over as a C++ `class` that has an opaque representation and layout whose size and alignment matches the size and alignment of the Swift structure.
You can construct an instance of a structure using the static `init` method in the C++ class:
```swift
// Swift module 'Weather'
struct WeatherInformation {
var temperature: Int
}
```
```c++
// C++ use site.
#include "Weather-Swift.h"
int main() {
auto weather = Weather::WeatherInformation::init(/*temperature=*/ 25);
}
```
### Initialization
Swifts structures that have a default initializer are given a default C++ constructor. For example, the following structure:
```swift
struct ScreenSize {
var width = 0
var height = 0
}
```
Will have a default initializer that will initialize a `width` and `height` to zero, which you can then use from C++ directly:
```c++
void constructScreenSize() {
auto size = ScreenSize();
// size.width and size.height is 0
}
```
The other initializers are bridged over as static `init` methods. The C++ initializers use type-based overloading to select the right overload for the initializer.
For example, given the following structure with two initializers:
```swift
struct Color {
let red, green, blue: Float
public init(red: Float, green: Float, blue: Float) {
self.red = red
self.green = green
self.blue = blue
}
public init(white: Float) {
self.red = white
self.green = white
self.blue = white
}
}
```
The following C++ `init` methods will be available:
```c++
class Color {
public:
Color() = delete;
static Color init(float red, float green, float blue);
static Color init(float white);
};
```
**NOTE**: Swift doesnt allow calling constructor without argument labels. Is that a problem for us?
### Providing renamed C++ overloads for Swift Initializers
The C++ `init` overloads for Swift initializers can sometimes conflict between each other because C++ doesnt allow us to use argument labels to select the correct overload, and so instead we need to rely on the type of the argument when calling it from C++. In order to avoid ambiguities on the C++ side, you can rename one specific initializer using something like the `@expose` attribute.
As an example, this structure renames its second `init` overload in C++ to expose them both to C++:
```swift
// Swift module 'Weather'
struct Celsius {
var temperatureInCelsius: Double
// FEEDBACK: could provide a constructor here?
// NOTE: concern about encouraging people not to use labels
init(_ t: Double) { self.temperatureInCelsius = t }
// FEEDBACK: could the compiler construct the 'initFromFahrenheit' c++ name?
@expose(c++, initFromFahrenheit)
init(fromFahrenheit fahrenheit: Double) { ... }
}
```
Both initializers can then be used from C++:
```c++
#include "Weather-Swift.h"
using namespace Weather;
void makeSunnyDay() {
auto morningTemperature = Celsius::init(25);
auto noonTemperature = Celsius::initFromFahrenheit(90);
}
```
**NOTE**: The compiler should warn here about overload ambiguities.
### Convenience Initialization of Swift Structures that conform to ExpressibleBy...Literal protocol
Certain types like Swifts `String` and `Array` are bridged over with convenience initializers that are inferred from their conformance to the `ExpressibleByStringLiteral` and the `ExpressibleByArrayLiteral` protocols. In general, any type that conforms to a protocol like `ExpressibleByStringLiteral` will receive a C++ constructor in its interface that resembles the following constructor for Swifts `String` type:
```c++
String(const char *value) {
*this = String::init(value);
}
```
Similarly, any type that conforms to `ExpressibleByArrayLiteral` will receive a C++ constructor that takes in a C++ initializer list so that it can be initialized from a C++ array literal.
### Resilient Swift Structures
Swift resilient structures are bridged over as a C++ class that boxes the Swift value on the heap. Their generated C++ interface resembles the C++ interface for a non-resilient structure, so all the methods and properties can be accessed in the same manner. For example, you can call methods and access the properties on `Foundation::URL` , which is a resilient Swif structure, in the same manner as you would for any other fixed layout Swift structure:
```c++
#include "Foundation-Swift.h"
using namespace Weather;
void workWithURL() {
auto url = Foundation::URL::init("https://swift.org");
std::cout << "Is File URL:" << url.isFileURL() << "\n";
auto absoluteURL = URL.absoluteURL();
}
```
The boxing implies that the following operations will allocate and store a new value on the heap:
* Returning a value from a call to a Swift method/function allocates a new value on the heap.
* Returning a value from a getter call to a Swift property `get` accessor allocates a new value on the heap.
* Creating a new instance of a resilient structure in C++ using the static `init` method allocates a new value on the heap.
* Copying a C++ `class` that represents a resilient Swift structure using a C++ copy constructor allocates a new value on the heap.
**NOTE**: A fixed-layout structure that contains a resilient structure as a stored property is also boxed on the C++ side.
## Calling Swift Methods
Swifts structures, enumerations and classes can define instance methods. An instance method thats declared in a Swift type gets its own C++ member function declaration in the C++ class that corresponds to the underlying Swift type in the generated C++ interface for a Swift module.
Instance methods in structures and enumerations are marked as `const` in C++, unless theyre marked as `mutating` in Swift. Here's how one could call a mutating method on a Swift structure from C++:
```swift
// Swift module 'Geometry'
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
```
```c++
// C++ use site:
#include "Geometry-Swift.h"
using namespace Geometry;
int main() {
auto point = Point();
point.moveBy(1.0, 2.0);
std::cout << "The point is now at " << point.getX() << ", " << point.getY() << "\n";
// Prints "The point is now at 1.0, 2.0"
return 0;
}
```
Calling `mutating` methods on a value that is declared as `const` is not allowed:
```
int main() {
const auto point = Point();
point.moveBy(1.0, 2.0);
//` reports a compile time error.`
}
```
### Static Methods
A static method declared in a Swift structure or enumeration gets its own C++ static member function declaration in the C++ class that corresponds to the underlying Swift type in the generated C++ interface for a Swift module. It can be called using its qualified name directly from C++, like in the following example:
```swift
// Swift module 'Geometry'
struct Rectangle {
var left, right: Point
static func computeDeviceScreenSize() -> Rectangle {
...
}
}
```
```c++
// C++ use site:
#include "Geometry-Swift.h"
int main() {
auto screenSize = Geometry::Rectangle::computeDeviceScreenSize();
// Use screen size...
return 0;
}
```
**TODO:** Dispatching overriding / class methods
## Using Swift Enumeration Types
A Swift enumeration is imported as class in C++. That allows C++ to invoke methods and access properties that the enumeration provides. Each enumeration case is represented by a static variable that can be used in a switch to match the case of the enum, and to construct new enums values as well.
For example, given the following enum:
```swift
// Swift module 'Navigation'
enum `CompassDirection {`
case north
case south
case east
case west
}
```
The following interface will be generated:
```c++
// "Navigation-Swift.h" - C++ interface for Swift's Navigation module.
class CompassDirection {
public:
inline const static struct { ... } north;
inline const static struct { ... } south;
inline const static struct { ... } east;
inline const static struct { ... } west;
private:
// type representation details.
...
};
```
This will let you construct enumeration values from C++ using the C++ call operator on the case:
```c++
#include "Navigation-Swift.h"
void testConstructEnumValue() {
auto direction = CompassDirection::north();
}
```
### Matching Swift Enumeration Values with a C++ Switch Statement
The C++ values that correspond to Swift enumeration case values can be used directly inside the switch statement. The generated C++ interface provides a convenience C++ enum called cases inside of the generated C++ class that represents the enumeration that the switch actually operates over. This C++ enum can then be used in a switch, as the class that represents the enumeration implicitly converts to it, and so do the C++ case values. This allows us to switch over the CompassDirection class from the example above in the following manner:
```c++
#include "Navigation-Swift.h"
using namespace Navigation;
CompassDirection getOpposite(CompassDirection cd) {
switch (cd) { // implicit conversion to CompassDirection::cases
case CompassDirection::north:
return CompassDirection::south();
case CompassDirection::south:
return CompassDirection::north();
case CompassDirection::east:
return CompassDirection::west();
case CompassDirection::west:
return CompassDirection::east();
}
}
```
### Enumerations With Raw Values
Swift allows you to declare enumerations whose cases are represented using an underlying raw value type. The C++ interface for such a Swift enumeration allows you access both the raw value of such an enumeration, and also to construct such an enumeration from a raw value.
For example, given the following enum with a String type:
```swift
// Swift module 'Airport'
enum Airport : String` {`
case LosAngeles = "LAX"
case SanFrancisco = "SFO"
}
```
You can access the underlying rawValue from C++ using the `getRawValue` method:
```c++
#include "Airport-Swift.h"
using namespace Airport;
void printAirport(Airport dest) {
swift::String airportCode = dest.getRawValue();
std::cout << "landing at " << airportCode << "\n";
}
```
You can use the static `init` method to construct an optional enumeration from a raw value:
```c++
void constructRoute() {
swift::Optional<Airport> arrivingTo = Airport::init("LAX");
// arrivingTo is now Airport::LosAngeles
auto departingFrom = Airport::init("HTX");
// departingFrom is none
}
```
### Enumerations With Associated Values
Swift allows an enumeration to store values of other types alongside the enumerations case values. This additional information is called an associated value in Swift. Enums with associated values are represented in a different manner than enums without associated values.
For example, the following enum with two cases with associated values:
```swift
// Swift module 'Store'
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
```
Will get a C++ interface that resembles this class:
```c++
// "Store-Swift.h" - C++ interface for Swift's Store module.
class Barcode {
public:
Barcode() = delete;
inline const static struct { ... } qrCode;
inline const static struct { ... } upc;
bool isUpc() const;
using UpcType = swift::Tuple<swift::Int, swift::Int, swift::Int, swift::Int>;
// Extracts the associated values from Barcode.upc enum case
UpcType getUpc() const;
bool isQrCode() const;
// Extracts an associated value from Barcode.qrCode enum case
swift::String getQrCode() const;
};
```
The C++ user of this enumeration can then use it by checking the type of the value in a switch and getting the associated value using the get member functions:
```c++
#include "Store-Swift.h"
using namespace Store;
Barcode normalizeBarcode(Barcode barcode) {
switch (barcode) {
case Barcode::qrCode: {
auto qrCode = barcode.getQrCode();
swift::Array<swift::Int> loadedBarcode = loadQrCode(qrCode);
return Barcode::upc(loadedBarcode[0], loadedBarcode[1], loadedBarcode[2], loadedBarcode[3]);
}
case Barcode::upc:
return barcode;
}
}
```
The use of a `get` associated value accessor for an invalid enum case for the given
enum value will abort the program.
### Resilient Enums
A resilient Swift enumeration value could represent a case that's unknown to the client.
Swift forces the client to check if the value is `@unknown default` when switching over
the enumeration to account for that. C++ follows a similar principle,
by exposing an `unknownDefault` case that can then be matched in a switch.
For example, given the following resilient enumeration:
```swift
// Swift module 'DateTime'
enum DateFormatStyle {
case medium
case full
}
```
In C++, you need do an exhaustive switch over all cases and the unknown default
case to avoid any compiler warnings:
```c++
using namespace DateTime;
void test(const DateFormatStyle &style) {
switch (style) {
case DateFormatStyle::medium:
...
break;
case DateFormatStyle::full:
...
break;
case DateFormatStyle::unknownDefault: // just like Swift's @unknown default
// Some case value added in a future version of enum.
break;
}
}
```
The `unknownDefault` case value is not a constructible case and you will get a compiler error if you try to construct it in C++.
## Using Swift Class Types
Swift class types that are usable from C++ are available in their corresponding module namespace. Theyre bridged over as a C++ class that stores a referenced counted pointer inside of it. Its initializers, methods and properties are exposed as members of the C++ class.
### Reference counting in C++
C++ class types that represent Swift classes perform automatic
reference counting (ARC) operations when the C++ value that represents
the reference to the Swift class is copied and destroyed.
For example, the following Swift class:
```swift
// Swift module 'People'.
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
func createRandomPerson() -> Person {
return Person(name: getRandomName())
}
```
Can be used from C++ with reference counting performed
automatically:
```c++
#include "People-Swift.h"
using namespace People;
void doSomething(Person p) {
...
}
void createAndUsePerson() {
Person p = createRandomPerson();
doSomething(p); // 'p' is copied. Person referenced by p is referenced twice.
// Destructor for copy of 'p' is called. Person referenced by p is referenced once.
// Destructor for 'p' gets called here. Person referenced by p is deallocated.
}
```
The Swift `Person` class instance that C++ variable `p` referenced gets deallocated
at the end of `createAndUsePerson` as the two C++ values that referenced it
inside of `createAndUsePerson` were destroyed.
### Class inheritance
A Swift class that inherits from another class is bridged to C++ with that inheritance
relationship preserved in the C++ class hierarchy generated for these Swift classes. For example, given the following two Swift classes:
```swift
// Swift module 'Transport'
public class Vehicle {
}
public final class Bicycle: Vehicle {
}
```
Get a corresponding C++ class hierarchy in C++:
```c++
class Vehicle { ... };
class Bicycle final : public Vehicle {};
```
This allows C++ code to implicitly cast derived class instances to base class reference values, like in the example below:
```c++
#include "Transport-Swift.h"
using namespace Transport;
void doSomethingWithVehicle(Transport::Vehicle vehicle) {
...
}
void useBicycle() {
auto bike = Bicycle::init();
doSomethingWithVehicle(bike);
}
```
Swift classes that are marked as `final` are also marked `final` in C++.
Swift classes that are not marked as `final` should not be derived from in C++.
## Accessing Properties In C++
Swift allows structures and classes to define stored and computed properties. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. The stored and the computed properties from Swift types are bridged over as getter `get...` and setter `set...` methods in C++. Setter methods are not marked as `const` and should only be invoked on non `const` instances of the bridged types.
For example, given the following structure with a stored and a computed property:
```swift
// Swift module 'Weather'
struct WeatherInformation {
var temperature: Int
var temperatureInFahrenheit: Int {
...
}
}
```
Both properties can be accessed with getters and setters, as demonstrated by the interface and example below:
```c++
// "Weather-Swift.h" - C++ interface for Swift's Weather module.
class WeatherInformation {
public:
WeatherInformation() = delete;
swift::Int getTemperature() const;
void setTemperature(swift::Int);
swift::Int getTemperatureInFahrenheit() const;
private:
// opaque storage representation for the Swift struct.
};
// C++ use site.
#include "Weather-Swift.h"
#include <iostream>
void printWeatherInformation(const Weather::WeatherInformation &info) {
std::cout << "Temperature (C): " << info.getTemperature() << "\n";
std::cout << "Temperature (F): " << info.getTemperatureInFahrenheit() << "\n";
}
void updateWeather(Weather::WeatherInformation &info) {
info.setTemperature(25);
}
```
Please note, however, that a getter method for property returns a copy of the value stored in the property. This means that when you mutate a value returned by the getter, it does not update the original property value. We can mutate property values using `withMutable...` member function described in the next section.
Getter-only properties of type `bool` that start with `is` or `has` can be used by their exact name from C++. For example Arrays `isEmpty` maps to `isEmpty()` call in C++:
```c++
int printArray(const swift::Array<int> &array) {
if (array.isEmpty()) {
std::cout << "[]";
return
}
...
}
```
### Mutating Property Values
Swift allows you to mutate a property by using additional operations like assignments, mutating method calls, or property mutations when accessing a property:
```swift
// Swift module 'Shapes'
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rectangle {
var position: Point
var size: Size
}
func updatePosition(shape: inout Rectangle, by value: Double) {
shape.position.x += value // mutate `position.x` inside of given shape
shape.position.y += value // mutate `position.y` inside of given shape
}
```
The generated C++ interface allows you to mutate a property value using a `withMutating...` method, which takes in a C++ lambda that receives a reference to the underlying value that can be safely mutated within the lambda:
```c++
#include "Shapes-Swift.h"
void updatePosition(Shapes::Rectangle &shape, double value) {
shape.withMutablePosition([&](auto &position) {
position.withMutableX( [&](auto &x) { x += value; }
position.withMutableY( [&](auto &y) { y += value; }
});
}
```
Its illegal to escape the passed reference to the value from the lambda, as that can create a dangling reference in your program.
### Static Properties
Type properties are mapped as `static` getter, setter, and mutation member functions in the C++ class that represents the Swift type. They can be accessed directly from C++ by invoking the function using its qualified name directly, like in the following example:
```swift
// Swift module 'GlobalSettings'
struct Config {
static var binaryName = ""
}
```
```c++
// C++
#include "GlobalSettings-Swift.h"
int main(const char *argv[], int argc) {
if (!GlobalSettings::Config::getBinaryName().isEmpty())
GlobalSettings::Config::setBinaryName(swift::String::init(argv[0]));
...
}
```
Open Property Questions:
* What happens when we have a name collision between a Swift `get` method that wed like to bridge and the bridged property getter?
## Accessing Subscripts In C++
Swift subscripts allow users to use the `[]` operator to access elements in a collection. The getter of a Swift subscript is bridged over as `operator []` to C++. It takes in the index parameter and returns the subscripts value over to C++. This is how you would use the subscript to access an element from a Swift `Array` :
```c++
#include "Swift-Swift.h"
#include <iostream>
void printElementsInArray(const swift::Array<swift::Int> &elements) {
for (size_t i = 0; i < elements.getCount(); ++i) {
std::cout << elements[i] << "\n";
}
}
```
The setter of a Swift subscript is bridged over as method named `setElementAtIndex` . It takes in the index parameter and a new value thats being set. This how you would invoke the subscript setter for a Swift `Array`:
```c++
#include "Swift-Swift.h"
void updateArrayElement(swift::Array<swift::String> &elements) {
elements.setElementAtIndex(0, "hello world!");
}
```
### Mutating Subscript Values
Swift allows you to mutate a value thats yielded by the subscript. For example, you can append an element to an array inside of another array by using the subscript operator:
```swift
// Swift module 'Matrix'
func appendColumn(to matrix: inout [[Int]], value: Int) {
for rowIndex in matrix.indices() {
matrix[rowIndex].append(value)
}
}
```
The generated C++ interface allows you to mutate a subscript value using a `mutateElementAtIndex` method, which takes in a C++ lambda that receives a reference to the underlying value that can be safely mutated within the lambda:
```c++
#include "Matrix-Swift.h"
void appendColumn(swift::Array<swift::Array<int>> &matrix, swift::Int value) {
for (auto rowIndex : matrix.indices()) {
elements.mutateElementAtIndex(rowIndex, [](auto &row) {
row.append(value);
});
}
}
```
Its illegal to escape the passed reference to the value from the lambda, as that can create a dangling reference in your program.
Open Questions:
* Bridging over overloaded subscripts.
## Using Swift Optional Values
An optional type represents a value that may be absent. Swifts optional type can be used from C++ using the `swift::Optional` class template. It must be instantiated with a C++ type that represents some Swift type.
### Constructing an Optional
The `swift::Optional` class provides a default constructor that can be used to initialize it to `none`:
```c++
auto x = swift::Optional<int>(); // x is none
```
The optional can be initialized to be `Some` using a constructor which takes the value that should be stored in the optional:
```c++
swift::Optional<int> y = 0; // y is some(0)
```
The optional class also provides a constructor that receives `nullptr_t` , so that it can be initialized from a `nullptr`, similar as to how you could initialize an optional from `nil` in Swift:
```c++
swift::Optional<double> a = nullptr; // a is none
```
An alternative constructor can receive `nullopt_t` type, so that it can be initialized from `nullopt`, just like an `std::optional`:
```c++
swift::Optional<float> b = std::nullopt; // b is none
```
### Checking If an Optional Has Value
The `swift::Optional` class provides an explicit `operator bool` that be used to check if it contains a value using an `if` statement:
```c++
void printOptionalInt(const swift::Optional<int> &x) {
if (x) {
std::cout << ".some(" << x.value() << ")";
} else {
std::cout << ".none";
}
}
```
You can also use the `hasValue` member function to check if it has a value as well.
### Extracting Value From an Optional
The `swift::Optional` class provides a `value` member function that can be used to extract the value from the optional. The C++ dereference operator `*` can also be used to extract the stored value:
```c++
void getXOrDefault(const swift::Optional<int> &x) {
return x.hasValue() ? *x : 42;
}
```
Its illegal to try to extract a value from an optional when it has no value. A fatal error will be reported at runtime if one attempts to do that:
```c++
swift::Optional<int> x = nullptr;
std::cout << x.value() << "\n";
// Fatal error: Unexpectedly found nil while unwrapping an Optional value
```
### Mutating Value In an Optional
Swift provides optional chaining syntax that allows you to invoke mutating methods and property accessors on the stored value in a convenient manner:
```swift
func getXPerhaps() -> [Int]? { ... }
var x = getXPerhaps()
x?.append(42); // append `42` to x when it's not nil
```
The C++ interface for `Optional` provides a similar mutation mechanism, where the mutation occurs only when an optional has a value in it. The provided `withMutableValue` method allows you to pass a lambda that receives a reference to the underlying value that can be safely mutated within the lambda:
```c++
swift::Optional<swift::Array<swift::Int>> x = getXPerhaps();
x.withMutableValue([](auto &val) {
// append `42` to the array x only when x is not nil
val.append(42);
});
```
Its illegal to escape the passed reference to the value from the lambda, as that can create a dangling reference in your program.
## Extensions
Swift extensions can be used to add new functionality to an existing class, structure, enumeration or a protocol in Swift. The C++ interface generator in the Swift compiler is capable of exposing an extension for a type or a protocol thats defined in the same Swift module as the type/protocol itself. An extension thats exposed to C++ can add the following members to the C++ class that represents a Swift type in the generated C++ interface:
* Getter and setter methods that expose computed instance or type properties added in the extension
* Instance and static methods that expose Swift methods added in the extension
* Static `init` methods that expose new initializers added in the extension
* Subscript operator and `setElementAtIndex` method that expose subscripts added in the extension
* Nested types added in the extension
**Note:** C++ does not have a language feature that would allow us to represent Swift extensions in their full fidelity. This is why the current implementation of the C++ interface generator in the Swift compiler only lets us expose extensions defined in the same module as the type thats being extended.
### Accessing Extension Members
The exposed extension members are added to the C++ class that corresponds to the underlying Swift type. For example, the following extensions for a Swift type:
```swift
// Swift module 'Geometry'
struct Rect {
var x, y, width, height: Double
}
extension Rect {
init(size: Int) {
self.init(x: 0, y: 0, width: size, height: size)
}
func squareThatFits() -> Rect {
let size = max(width, height)
return Rect(x: x, y: y, width: size, height: size)
}
}
extension Rect: `CustomDebugStringConvertible` {
var debugDescription: String {
return ""
}
}
```
Are exposed in the C++ `class` Rect, as per the sample interface below:
```c++
// C++ interface for 'Geometry'
class Rect {
public:
// init(x:,y:,width:,height:)
static Rect init(double x, double y, double width, double height);
// init(size:)
static Rect init(double size);
Rect squareThatFits() const { ... }
swift::String getDebugDescription() const { ... }
};
```
### Protocol Extensions
Swift protocols can be extended to provide method, initializer, subscript, and computed property implementations to the conforming types. The exposed members from such a protocol extension are added to the C++ class that corresponds to the underlying Swift type. For example, if `Rect` receives a conformance for `Shape` like below:
```swift
protocol Shape {
var area: double { get }
}
extension Rect: Shape {
var area: double { width * height }
}
extension Shape {
func fits(inArea otherArea: double) -> Bool {
area < otherArea
}
}
```
The members from the extension of `Shape` are then added to the C++ class that corresponds to the `Rect` Swift structure:
```c++
// C++ interface for 'Geometry'
class Rect {
public:
...
bool fits(double inArea) const { ... }
};
```
A protocol extension need to be in the same Swift module as the type that conforms to such protocol in order for the extension to get exposed in the C++ interface for the module.
## Generics
Swifts generics allow programmer to write reusable functions and types that can work with any type, subject to any requirements that are specified by the programmer. C++ templates provide similar facilities for generic programming in C++. While Swifts generics and C++ templates look similar, there are some important differences between them:
* Generic Swift functions and types are type checked at their definition using their stated requirements. C++ templates type check the generic code only after a template is specialized for a concrete type.
* Generic Swift functions and types provide generic implementation of their generic code, that can work with any type that conforms to their stated requirements. C++ templates, however, **do not** provide generic implementation of C++ functions or classes, as they only provide concrete implementations that operate on specific types that get generated whenever a C++ template is instantiated.
Even though C++ templates have different semantics than Swift generics, they are used in the generated C++ interface to provide type parameters for Swift functions or types that are then passed to Swift generic code. A generic Swift function or a generic Swift type is represented using a C++ function template, or a C++ class template, with certain constraints on the template parameters. The constraints are checked at compile time in C++ using `requires` in C++20 , or `enabled_if` when compiling using an older C++ standard.
Generic Swift code thats invoked from C++ always goes through Swifts generic codepath. A programmer thats calling Swift generic APIs from C++ should keep that in mind, as the generic Swift code is most likely going to be less performant than a comparable C++ code generated by a template instantiation, as the C++ code is specialized for a specific type instead of being generic.
### Calling Generic Functions from C++
A generic function is represented using a function template in C++. The template type parameters must represent a type that is usable from a generic context in Swift, and must conform to any other generic constraints that are specified in Swift. These requirements are verified at compile time by the template requirements specified alongside the C++ function.
A generic function can be called from C++ by calling the C++ function template that represents it. For example, the generic function `swapTwoValues` with one type parameter `T` :
```swift
// Swift module 'Swapper'
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
...
}
```
Gets exposed to C++ via the following C++ function template:
```c++
template<typename T>
void swapTwoValues(T &a, T& b)
requires swift::isUsableInGenericContext<T> {
...
}
```
And can then be called from C++ just like any other Swift function, as long as `T` is a type that can be used in a generic context in Swift:
```c++
#include "Swapper-Swift.h"
int main() {
int x, y;
Swapper::swapTwoValues(x, y); // ok.
std::string s1, s2;
Swapper::swapTwoValues(s1, s2);
// error: no matching function for call to 'Swapper::swapTwoValues'
// `because 'swift::isUsableInGenericContext<...>' evaluated to false`
return 0;
}
```
When compiling in C++ 17 mode, the C++ function template relies on `std::enable_if` to verify that `T` is a type that can be used in a generic context instead of `requires`:
```c++
template<typename T,
typename = std::enable_if_t<swift::isUsableInGenericContext<T>>>
void swapTwoValues(T& a, T& b)
```
Generic methods from Swift types are represented using a member function template in C++. They must obey the same requirements as Swift generic functions as well.
### Using Generic Types
A generic Swift structure, enumeration or class is represented using a class template in C++. The template type parameters must represent a type that is usable from a generic context in Swift, and must conform to any other generic constraints that are specified in Swift. These requirements are verified at compile time by the template requirements specified alongside the C++ class.
A generic Swift type can be used in C++ by specifying its class name and type parameters using the C++ template syntax. For example, the generic structure `Stack` with one type parameter `Element` :
```swift
// Swift module 'Datastructures'
struct Stack<Element> {
mutating func push(_ item: Element) {
...
}
...
}
```
Can then be used in C++ just like a C++ class template:
```c++
#include "Datastructures-Swift.h"
void useSwiftStack() {
Datastructures::Stack<int> intStack;
intStack.push(22);
}
```
Its illegal to instantiate a class template for a Swift generic type like `Stack` with a type parameter that cant be represented in a generic context in Swift. The compiler will verify that at compile-time by checking the constraints specified in the `requires` clause of the class template:
```c++
// Snippet from Datastructures-Swift.h
template<class Element>
requires swift::isUsableInGenericContext<Element>
class Stack {
...
};
// C++ use site
#include "Datastructures-Swift.h"
void useSwiftStackIncorrectly() {
Datastructures::Stack<std::string> cxxStringStack;
// error: constraints not satisfied for class template 'Stack'
// note: because 'swift::isUsableInGenericContext<...>' evaluated to false
}
```
**Open Questions:**
* How do the opaque layout type type parameters that affect structs layout work - do they need template specializations, or can we do this with constexpr if - they need to be boxed?
### Generic Type Constraints
Swift programers can specify type constraints on the types that can be used with generic functions and generic types. These constraints are exposed to C++s type system through a set of requirements that must be satisfied by the C++ function or class template that represents a Swift generic function or type. They are verified in C++ at compile-time to ensure that the program is not invoking generic Swift code with types that dont satisfy the specified constraints.
A generic constraint that specifies that a generic type parameter must conform to a particular protocol or protocol composition is verified using a `swift::conformsTo` type trait in C++. For example, the following generic function with a `Comparable` protocol constraint on `T`:
```swift
// Swift module 'MyModule'
func isWithinRange<T: Comparable>(_ value: T, lowerBound: T, upperBound: T) -> Bool {
...
}
```
Gets exposed to C++ via the following C++ function template with a `requires` clause that verifies conformance of the C++ type that represents some Swift type:
```c++
template<typename T>
bool isWithinRange(const T& value, const T& lowerBound, const T& upperBound)
requires swift::isUsableInGenericContext<T> &&
swift::conformsTo<T, swift::Comparable>
```
And can then be called from C++ as long as the Swift type thats being represented by the C++ type `T` actually conforms to `Comparable` in Swift:
```c++
#include "MyModule-Swift.h"
int main() {
MyModule::isWithinRange(1, 0, 2);
return 0;
}
```
Its illegal to instantiate a template with such a requirement when the template type parameter does not conform to `Comparable` in Swift. The compiler will verify that at compile-time by checking the template constraints:
```c++
void useWithinRangeWithCustomSwiftType() {
MyModule::isWithinRange<MyModule::SomeSwiftStruct>({}, {}, {});
// error: no matching function for call to 'MyModule::isWithinRange'
// because 'swift::conformsTo<MyModule::SomeSwiftStruct, swift::Comparable>' evaluated to false
}
```
**TODO:** Inherit from a specific class constraint
### Extensions with a Generic Where Clause
Swift extensions can use a generic `where` clause to limit the extension to types that match certain generic constraints. The members of such extensions get exposed to C++ as described in the “Extensions” section above. These exposed members receive additional template requirements in C++ to ensure that they are available only from a C++ class template that satisfies the template requirements imposed by the generic `where` clause of the extension.
For example, an extension to the generic `Stack` structure from the previous example:
```swift
extension Stack where Element: Equatable {
`func isTop(_ item: Element) -> Bool {`
...
}
}
```
Gets exposed to C++ inside of the `Stack` class template with the added member constraint which validates that the C++ `Element` type represents a Swift type that conforms to `Equatable` :
```c++
template<class Element>
requires swift::isUsableInGenericContext<Element>
class Stack {
...
bool isTop(const Element &) const
requires swift::conformsTo<Element, swift::Equatable> {
...
}
};
```
Its illegal to access extension members in C++ class templates that dont satisfy the where clause imposed by such an extension. The compiler will verify that at compile-time by enforcing the requirements on the member:
```c++
void useStackInCxx() {
Datastructures::Stack<MyModule::SomeSwiftStruct> stack;
stack.push(MyModule::SomeSwiftStruct()); // ok
stack.isTop(MyModule::SomeSwiftStruct());
// error: invalid reference to function 'isTop': constraints not satisfied
// note: because 'swift::conformsTo<MyModule::SomeSwiftStruct, swift::Equatable>' evaluated to false
}
```
**TODO:** Support nested types inside of generic where clause extensions. - add a requires on them.
**TODO:** Add an example for Protocol Extensions With Contextual Where Clauses>
## Using Swifts Standard Library Types
### Using String
String conforms to `StringLiteralConvertible` , so you can implicitly construct instances of `swift::String` directly from a C++ string literal, or any `const char *` C string:
```c++
swift::String string = "Hello world";
string.hasPrefix("Hello"); // Implicit construction of swift::String.
```
You can convert a `swift::String` to a `std::string` using `std::to_string`:
```c++
void printSwiftString(const swift::String &swStr) {
std::string str = std::to_string(swStr);
std::cout << "swift string is " << str << "\n";
}
```
You can convert an `std::string` into a `swift::String` using an explicit constructor:
```c++
void setSwiftString(swift::String &other, const std::string &str) {
other = swift::String(str);
}
```
In Objective-C++ mode, you can also convert a `swift::String` to an `NSString *` value using
a cast or by assigning to an `NSString *` value directly:
```c++
void useObjCString(const swift::String &swStr) {
// This cast will bridge the Swift String to an Objective-C NSString value.
NSString *nsStr = swStr;
}
```
Open questions:
* How do the `StringLiteralConvertible` rules work in practice?
* What happens when String.init fails for a literal? (fatalError most likely). Check what Swift does, does it ever allow an invalid utf8 sequence, and will the actual initializer fail at runtime?
* String.init - implicit initializer from C++ string is problematic potentially. Make Pointers have to go through force casting? (I think thats probably not a problem - C++ string literal type just wont conform to swift::isUsableInGenericContext)
### Using Array
A Swift array type can be used from C++ using the `swift::Array` class template. It must be instantiated with a C++ type that represents a Swift type.
An array can be initialized using a C++ initializer list because it conforms to `ArrayLiteralConvertible`:
```c++
swift::Array<int> intArray = {};
swift::Array<swift::String> languages = { "Swift", "C++", "Objective-C" };
```
You can iterate over the array elements using a `for` loop:
```c++
for (auto language : languages)
std::cout << std::to_string(language) << "\n";
```
You can modify the elements in the array using the `setElementAtIndex` member function:
```c++
for (size_t i = 1; i < languages.getCount(); ++i)
languages.setElementAtIndex(i, languages[i] + languages[i - 1]);
```
You can convert a `swift::Array` to a `std::vector` using the following explicit constructor of `std::vector`:
```c++
auto cxxVector = std::vector<int>(intArray.begin(), intArray.end());
```
This constructor copies over the elements from the Swift array into the constructed C++ vector.
You can also convert a vector to a `swift::Array` using the following explicit constructor of `swift::Array`:
```c++
auto swiftIntArray = swift::Array<int>(cxxVector);
```
This constructor copies over the elements from the C++ vector into the constructed Swift array.
## Appendix A: Type Traits That Model Swifts Type System In C++
The C++ interface thats generated by the Swift compiler for a Swift module uses a number of C++ type traits that can be used to query information about Swifts type system from C++. These type traits are listed in this section.
### swift::isUsableInGenericContext
```c++
template<class T>
inline constexpr const bool swift::isUsableInGenericContext
```
This type trait can be used to check if a type can be passed to a generic Swift function or used as a generic type parameter for a Swift type. It evaluates to `true` in the following cases:
* When `T` is a primitive type like `int` , `float`, `swift::Int`, etc. that has a corresponding Swift primitive type.
* When T is a class or a class template that acts a proxy for a Swift type and is defined in the C++ interface generated by the Swift compiler for a Swift module.
* **TODO:** Objective-C ARC pointers , etc?
The following example illustrates how this type trait evaluates to true for types that have a Swift representation, but to false for regular C++ types:
```c++
static_assert(swift::isUsableInGenericContext<int> == true);
static_assert(swift::isUsableInGenericContext<swift::String> == true);
static_assert(swift::isUsableInGenericContext<std::string> == false);
```
### swift::conformsTo
```c++
template<class T, class P>
inline constexpr const bool swift::conformsTo
```
This type trait evaluates to true when a specific Swift type that is being proxied by the given C++ type `T` conforms to a Swift protocol thats being proxied by the given C++ class `P`.