GistTree.Com
Entertainment at it's peak. The news is by your side.

Interoperability Between Swift and C++

0

This file discusses the compose and tradeoffs for bidirectional API-stage
interoperability between Swift and C++.

Assumptions:

  • We can fabricate changes to the Swift language and the commonplace library.
    • The proposed changes must fit Swift’s targets and philosophy. In other phrases,
      the proposed changes must hold an cheap probability to be licensed by the
      Swift group. As an illustration, a alternate that requires an ABI spoil on Apple
      platforms is a non-starter.
    • Forking the Swift language or commonplace library, or establishing a dialect
      without a fork (and attributable to this reality, being in a situation to manufacture radical changes to Swift’s
      targets, philosophy, security, or ergonomics) are no longer attention-grabbing suggestions, and
      attributable to this reality, are no longer regarded as or discussed.
  • We can fabricate minute changes to the C++ code, toolchain, commonplace library
    implementation, and runtime atmosphere.

    • The value of such changes would possibly presumably well also tranquil be taken into consideration. Changes that require an
      ABI spoil for C++ would possibly presumably well also very successfully be attention-grabbing for customers who protect watch over your full
      toolchain, however are non-starters for the group at colossal; attributable to this reality, such
      changes can easiest be regarded as an optimization. Changes that require
      fundamental handbook work on present C++ code by terminate customers would possibly presumably well also additionally be
      regarded as easiest as optimizations or enhancements for ergonomics.

What are the properties of a factual interoperability layer? Exercising
interoperability is no longer in itself a design of any Swift or C++ person. Attributable to this reality,
for API customers interoperability would possibly presumably well also tranquil be maximally transparent in all aspects:
API compose and ergonomics, editor integration and tooling, and performance. For
API distributors, interoperability would possibly presumably well also tranquil no longer be a gigantic further burden, whereas
allowing API distributors to maintain and curate the imported API floor. Let’s talk about
what these parts mean.

API compose and ergonomics. Ideally, customers working in Swift would possibly presumably well also tranquil no longer feel
any inequity between native Swift APIs and imported C++ APIs.

As an illustration, whereas it is doable to jot down a custom hashtable in Swift, it is
completed extremely no longer continuously, and most code uses the vocabulary forms Location and
Dictionary. Attributable to this reality, if C++ APIs that frail std::unordered_map or
flat_hash_map forms, when imported in Swift, would continue utilizing those C++
plan forms, they would see irregular and foreign in Swift. Idiomatic Swift code that
uses Location and Dictionary will must remodel the knowledge into these foreign
hashtable forms earlier than calling imported C++ APIs.

As yet another instance, C++ capabilities continuously receive values by const reference or by
const pointer. Semantically, the closest equivalent in Swift is UnsafePointer.
Nonetheless, UnsafePointer is no longer as regular in Swift as const references are in
C++; it is rarely idiomatic for Swift APIs to find UnsafePointer outdoors of a
couple distinctive instances (as an illustration, implementations of low-stage
services and products, performance-soft code, etc.) Attributable to this reality, if C++ APIs, when
imported in Swift, would exercise UnsafePointer plenty, they would see irregular and
foreign in Swift. Imported C APIs, when they construct no longer appear to be working on Aim-C
forms, already exercise UnsafePointer plenty, and see non-idiomatic attributable to
that. Swift offers some affordances that fabricate calling them more easy.

Editor integration and tooling would possibly presumably well also tranquil transparently enhance code in each and every
languages. To the extent likely, all editor operations would possibly presumably well also tranquil “note via”
the interop. As an illustration, if the person invokes the “rename characteristic” refactoring,
it’ll also tranquil rename all definitions, declarations, and usages across Swift and C++
code. This design has been largely executed for Swift/Aim-C interop, and we
are planning to depend on the identical mechanisms for Swift/C++ interop.

Efficiency. C++ APIs, when frail from Swift, ideally, would possibly presumably well also tranquil hold
performance traits identical to when they’re frail from C++.

Interop must no longer be a burden for API distributors. Enabling Swift code to name a
particular C++ library would possibly presumably well also tranquil invent minimal burden for the owners of that C++
library. Ideally, it’ll also tranquil be likely with none involvement of the owners.

As an illustration, requiring the API owners to invent an API description file (indulge in in
CLIF for Python), or a glue layer (indulge in in JNI for Java) is a gigantic
burden. Most API owners are no longer going to full it without specific requests from
customers, and even when such request is bought, many API owners will carefully
save in thoughts if they must plan terminate on maintenance of this further file.

It’ll also very successfully be likely to permit customers to full the work an valuable to expose a C++
library to Swift, on the other hand, that’s no longer a spacious choice both. A C++ library
would possibly presumably well also terminate up with multiple (incompatible) bindings of varying quality, overlaying
so much of parts of the API. As successfully as, the owner of the API loses protect watch over of
the API floor.

Allow API distributors to maintain and curate the imported API floor. Whereas the
minimal quantity of work to expose a C++ library to Swift would possibly presumably well also tranquil be ideally “none”
(it’ll also tranquil factual work), API distributors would possibly presumably well also tranquil maintain the Swift API floor of their C++
libraries, and would possibly presumably well also tranquil be in a situation to adjust it the establish the automated interop is no longer
first-fee.

Tension and conflicts between targets. These targets are conflicting. For
instance, API ergonomics are in battle with performance: we can present a extra
ergonomic API if we robotically bridge C++ forms to corresponding Swift
vocabulary forms on the API boundary, on the other hand, these sort conversions will price
CPU cycles. The solutions shall be designed on a case by case basis: most frequently,
we have to always buy one aspect of the tradeoff, most frequently we have to always buy one aspect however allow
the person to override the default, and most frequently we can add multiple services and products
that buy so much of sides, forcing the person to plan terminate.

Swift/C++ interoperability builds on top of the Swift/C interoperability, so it
helps to be familiar with Swift’s strategy for importing C
modules
.

Now let’s talk about extending present principles to address C++.

Names, identifiers and keywords

C++ lets in defining names which can also very successfully be no longer identifiers:

  • Destructors
  • Overloaded operators
  • Literal operators

Member capabilities with non-identifier names are discussed in the fragment about
classes. Other constructs are discussed in their respective sections.

Capabilities

Non-const pointer and reference parameters

In C++, there are no longer any language requirements for pointers handed as characteristic
arguments. As an illustration, given a characteristic signature indulge in this:

void increment(int *price);

C++ as a language poses no requirements for price to dwell long sufficient for the interval of
the characteristic name, or even that price parts to legitimate reminiscence when the
characteristic is named; price would possibly presumably well also additionally be null or it’ll also additionally be an invalid (as an illustration,
freed) pointer. There are also no requirements about the reminiscence pointed to by
price being initialized, or legitimate to dereference without files races. Pointers
are also allowed to alias other reminiscence, so long as the forms are appropriate.
Pointers also construct no longer imply something else about possession or non-possession.

Ideas in C++ about references are a microscopic bit tighter, however no longer remarkable. The most attention-grabbing
variations are that a reference can’t be null, and that it’ll also tranquil be lumber to a
legitimate object when it is firstly created.

In follow, engineers working in C++ continuously fabricate the following assumptions about
third-party APIs, although these properties are no longer assured by the
language, and are most frequently no longer explicitly documented by the API:

  • All pointers handed to a characteristic are legitimate to dereference.

  • Nearly all pointers handed to a characteristic stay legitimate to dereference whereas the
    characteristic is working.

  • Nearly all pointers handed to a characteristic are legitimate to dereference without files
    races.

  • Nearly all pointers handed to a characteristic show hide initialized files. Passing a
    pointer to uninitialized reminiscence and expecting the characteristic to initialize it
    occurs now and all once more, however it surely is no longer regular.

  • Regularly sufficient, pointers handed to a characteristic are no longer null.

  • Regularly sufficient, pointers of so much of forms construct no longer alias every other’s subobjects.

  • Nearly all const &T parameters are semantically equivalent to passing T by
    price.

In Swift, passing unsafe pointers as characteristic arguments is no longer idiomatic.
Idiomatic code passes structs by price, and classes by reference. inout
parameters in Swift allow capabilities to be taught and regulate storage specified by the
caller. The argument for the inout parameter would possibly presumably well also tranquil be a storage reference
expression.

func increment(_ price: inout Int) {
  price += 1
}

struct TwoInts {
  var x:  Int = 0
  var y:  Int = 0
}

func caller() {
  var ints = TwoInts()
  increment(&ints.x)
  // ints.x is 1
  // ints.y is 0
}

To take hold of the constraints that Swift puts on inout parameters, let’s plan terminate
a see on the mental model for introduced in the Ownership
manifesto
and in SE-0176 Establish into note Distinctive Win admission to to
Memory
.
When the caller binds a storage reference to an inout parameter, it starts a
non-instantaneous ranking admission to to your entire price that occupies the storage. This
ranking admission to ends when the callee returns. Overlapping accesses are no longer allowed, and
attributable to this reality, whereas an inout parameter is dwell, usual price would possibly presumably well also no longer be
accessed.

(Camouflage that earlier than the possession manifesto, inout parameters had been outlined in
terms of a so much of model that will presumably well also very successfully be more easy to personal. Nonetheless,
each and every fashions are equivalent. The archaic model acknowledged that on characteristic entry, the
price is moved from the caller-specified storage reference into the inout
parameter, and moved from the inout parameter lend a hand into the original storage
on characteristic exit. For the interval of the execution of the characteristic, the original storage
remains uninitialized, and attributable to this reality, your entire price that occupied that storage
remains inaccessible unless the characteristic returns.)

In follow, inout parameters are applied as passing a pointer to the
storage that will presumably well also tranquil be mutated, whereas affirming behavior identical to the
fashions outlined above. Consequently of these fashions, inout parameters
present the following ensures:

  • the reminiscence backing an inout parameter is legitimate to ranking admission to for the interval of the
    execution of a characteristic.

  • since inout parameters are no longer pointers, there is rarely any such ingredient as “null
    inout parameter”.

  • inout parameters are legitimate to be taught and regulate for the interval of the execution of
    a characteristic without files races, except the characteristic itself has shared the
    parameter with multiple threads.

  • inout are backed by initialized reminiscence on characteristic entry and characteristic exit
    (an implication of the copy-in/copy-out semantics). Destroying the article in
    inout requires utilizing unsafe construts. Attributable to this reality, in good Swift inout
    parameters are backed by initialized reminiscence for the interval of characteristic execution.

  • inout parameters construct no longer alias every other or another values that program is
    allowed to ranking admission to at that level. Take into account that the original price that’s
    lumber to an inout parameter is inaccessible for the interval of the inout
    binding.

In follow, non-const pointers and references in characteristic parameters are most
continuously frail for the identical design as Swift’s inout, so it is orderly to plan
them to one yet another.

// C++ header.

void incrementBoth(int *value1, int *value2);
// C++ header imported in Swift (likely mapping).

func incrementBoth(_ value1: inout Int, _ value2: inout Int)

The incrementBoth characteristic imported indulge in this has extra restrictions in Swift
than in C++ (as an illustration, arguments would possibly presumably well also no longer alias). Calling this C++ characteristic
from Swift would now not invent a brand fresh roughly security components in Swift, as a result of a
language with extra restrictions calls a language with fewer restrictions. From
the API level of detect, it’ll also tranquil no longer be an argument both, except the caller
desires to pass arguments that alias (Swift’s enforcement of exclusivity will
terminate that).

Essentially essentially based totally on the comparison above, it appears to be like to be to be like indulge in Swift’s inout offers strictly
extra ensures than C++’s non-const pointers and references. Attributable to this reality, it is
no longer good to plan them to one yet another in all cases. As an illustration, we can’t practice
this mapping when Swift is enforcing a characteristic uncovered to C++, as an illustration:

// C++ header.

class Incrementer {
public: 
  digital void incrementBoth(int *value1, int *value2) = 0;
};
// C++ header imported in Swift (likely mapping).

protocol Incrementer {
  func incrementBoth(_ value1: inout Int, _ value2: inout Int)
}

struct MyIncrementer: Incrementer {
  func incrementBoth(_ value1: inout Int, _ value2: inout Int) {
    // The language requires that `value1` and `value2` construct no longer alias.
  }
}

It would be unsafe to expose an Swift implementation of
Incrementer.incrementBoth via the C++ signature, except the C++ characteristic
already has Swift-indulge in preconditions for pointer arguments. For lovely inout
parameters in C++, those preconditions would possibly presumably well also tranquil genuinely protect, although the C++
characteristic would now not formally file them.

Const reference parameters

In C++, const references in characteristic arguments are most continuously frail to steer clear of
copying objects handed to capabilities. Swift solves this hiss in two ways:

  • by providing language parts that allow the engineer to introduce
    indirections (as an illustration, reference forms, existential forms, oblique enum
    cases, tools for defining copy-on-write forms),

  • by robotically passing colossal arguments no longer straight away without copying them,
    the establish likely.

It’s no longer feasible to robotically plan C++ const references to Swift-specific
indirections indulge in class forms, as a result of that will presumably well presumably require changing the reminiscence
structure via non-trivial bridging.

Option 1: Import const T& as UnsafePointer.

We can without concerns plan C++ const references in characteristic parameters to
UnsafePointer in Swift, on the other hand, the ensuing APIs is no longer going to see
idiomatic. They’re going to be usable from Swift, as a result of Swift code can fabricate an unsafe
pointer with the & operator, on the other hand, it must easiest be applied to mutable
storage locations. Attributable to this reality, extra variables shall be mutable in Swift than
an valuable. Furthermore, to manufacture some values mutable, the code will have to
fabricate a copy that shall be kept in a mutable variable — defeating the level of
the C++ API taking a const reference.

void printInt(const int &price);
// C++ header imported in Swift.

void printInt(_ price:  UnsafePointer<Int>)
// Utilization instance.

void caller() {
  var x = 42
  printInt(&x) // OK

  let y = 42
  printInt(y) // error: sort mismatch: `Int` is no longer an `UnsafePointer`
  printInt(&y) // error: can't practice `&` to an immutable price
}

Enchancment for choice 1: Allow utilizing & on immutable values.

To ranking rid of the further copies that the code would must save to manufacture some
values mutable, we would possibly presumably well also prolong the Swift language to permit applying & to
immutable values, producing an UnsafePointer.

// Utilization instance.

void caller() {
  let x = 42
  printInt(&x) // OK
}

Option 2: Import const T& as T.

A extra ergonomic method would possibly presumably well presumably be to import C++ const references to price forms
as values, however tranquil exercise a by-reference calling conference in the lend a hand of the scenes.

void printInt(const int &price);
// C++ header imported in Swift.

void printInt(_ price:  Int)
// Utilization instance.

void caller() {
  let x = 42
  printInt(y) // OK
}

The imported printInt characteristic that takes an Int by price would possibly presumably well presumably be a thunk
that calls the precise C++ entry level that takes an Int by a const reference.
A fundamental optimization pass would inline that thunk into its callers, and
ranking rid of the copies that now turned pointless.

It’s indispensable to personal that this method easiest works in cases the establish the
compiler can insert a thunk. Right here’s an instance the establish the compiler can’t
transparently wrap a characteristic pointer into a thunk, and attributable to this reality can’t import
const int& as Int32:

struct Instance {
  void (*printInt)(const int &);
};

This style is some distance extra ergonomic. Nonetheless, it has a couple of disadvantages.

One drawback is that this method offers much less protect watch over: the caller can’t
specify or predict the precise address that’s handed to the C++ characteristic (as a result of
Swift can fabricate copies of values or dart them round in reminiscence). Most capabilities
receiving const T& parameters would possibly presumably well also tranquil no longer care about the precise address, however
some would possibly presumably well also.

One other drawback of this method is that it is good in so much of cases in
follow, however customers can save unsafe cases. Namely, if the C++ code
being known as persists the reference that became handed by Swift previous the interval
of the characteristic name, that reference can develop into invalid (as a result of Swift code
would possibly presumably well also pass an address of a transient, implicitly materialized by the compiler).
The personality of unsafety is identical between choice 1, choice 2, and present
Swift/C interop, on the other hand, in choice 2, the establish we import C++ references as Swift
values, it is rarely considered to the Swift programmer that the characteristic being known as
accepts an address.

Mapping overload items

C++ has advanced overload choice principles, in allotment to enhance particular API compose
patterns. Some API compose patterns appeared due to the overload
choice principles. Attributable to this reality, in C++ an “API atom” is an an overload establish, no longer an
person characteristic (CppCon 2018: Titus Winters “Modern C++ Like (allotment 1 of
2)”
). The same is also the case in
Swift, so, fundamentally, there is rarely any impedance mismatch right here.

Nonetheless, C and Aim-C interoperability imports every characteristic and method
one at a time. For C++ interoperability, we would possibly presumably well also tranquil acknowledge compose patterns that
exercise overload items, and plan them precisely to Swift.

One such C++ sample is providing two overloads: one who takes a const T& and
yet another that takes a T&&. If we are trying to naively plan them to Swift, they
would plan to the identical signature. If we import factual one in every of them and ignore the
other, we would possibly presumably well presumably be leaving performance on the table.

The finest technique to plan such overload items is to import the T&& overload as a
characteristic that takes the argument by price, and ignore the const T& overload.
This style does invent a tiny quantity of performance overhead (an further
dart), however would now not require changing the Swift language or sort checker to
acknowledge the thought of temporaries. The SIL optimizer appears to be like to be indulge in the
appropriate establish to opportunistically reclaim that performance, by putting off
pointless strikes of temporaries the establish likely, and replacing calls to the
thunk with calls to basically the most appropriate C++ entry level.

// C++ header.

struct Tensor { ... };

void processTensor(const Tensor&);
void processTensor(Tensor&&);
// C++ header imported in Swift.

struct Tensor { ... }

func processTensor(_: Tensor) {
  // name `void processTensor(Tensor&&)`
}
// Utilization instance.

func useTensor() {
  var x = Tensor()
  processTensor(x)
  processTensor(x)
}
// Identical of SIL code after optimizations.

// void processTensor(const Tensor&);
func processTensorByConstRef(_: UnsafePointer)

// void processTensor(Tensor&&);
func processTensorByRvalueRef(_: UnsafeMutablePointer)

func useTensor() {
  var x = Tensor()
  processTensorByConstRef(x)
  processTensorByRvalueRef(x) // Routinely dart the price as a result of it is clearly no longer frail anymore.
}

Once dart-easiest forms are added to Swift, the identical mapping methodology becomes
appropriate to C++ dart-easiest price forms as successfully, with basically the most nice inequity that
argument of the imported characteristic would possibly presumably well presumably be marked as being consumed.

Inline capabilities

Inline capabilities (each and every free and member capabilities) are frail in C++ plenty extra
than inline capabilities in C. For inline capabilities in C++, Swift would possibly presumably well also tranquil exercise the
same strategy as it uses for the time being for C: exercise Clang’s CodeGen libraries to
emit definitions of inline capabilities into one LLVM module alongside with Swift
code.

Namespaces and modules

Namespaces and modules in C++ are orthogonal ideas. Namespaces in C++ can
span multiple modules; C++ namespaces would possibly presumably well also additionally be nested. In Swift, modules are
namespaces.

Option 1: Draw C++ namespaces to empty enums in Swift.

There are precedents for utilizing empty enums as namespaces in Swift (as an illustration,
CommandLine, Unicode, Unicode.UTF8 in the commonplace library).
Nonetheless, empty enums are no longer a supreme change for C++ namespaces:

  • Swift has no utilizing-indulge in save that lets in code to steer clear of qualifying names
    nested in an enum (in other phrases, names nested within an enum would possibly presumably well also tranquil be always
    licensed with the name of that enum when frail).

  • C++ namespaces can span multiple modules. We construct no longer need every imported C++
    module to account for its maintain empty enum, as that will lead to name collisions,
    that will require even extra qualification from customers.

// C++ header in module `CppButton`.

namespace widgets {
class Button {};
}
// C++ header in module `CppTextbox`.

namespace widgets {
class Textbox {};
}
// C++ module `CppButton` imported to Swift.

enum widgets {
  struct Button {}
}
// C++ module `CppTextbox` imported to Swift.

enum widgets {
  struct Textbox {}
}
// Utilization instance: the entirety works successfully when we import easiest `CppButton`.

import CppButton

func makeButton() {
  var b1 = Button() // error: no such sort
  var b2 = widgets.Button() // OK
}
// Utilization instance: ambiguities when we import each and every `CppButton` and `CppTextbox`.

import CppButton
import CppTextbox

func makeButton() {
  var b1 = Button() // error: no such sort
  var b2 = widgets.Button() // error: name `widgets` is ambiguous, did you mean `CppButton.widgets` or `CppTextbox.widgets`?
  var b3 = CppButton.widgets.Button()
}

Enchancment for choice 1: Shuffle all empty enums to one synthetic module.

We would possibly presumably well also repair the paradox between same-named namespace enums outlined by
multiple C++ modules by synthesizing an further Swift module that will indulge in
easiest the enums that fabricate up the namespace construction, and then making all other
C++ modules account for extensions for those enums.

// Swift module `CppNamespaces` synthesized by the C++ importer.

enum widgets {}
// C++ module `CppButton` imported to Swift.

import CppNamespaces

extension widgets {
  struct Button {}
}
// C++ module `CppTextbox` imported to Swift.

import CppNamespaces

extension widgets {
  struct Textbox {}
}
// Utilization instance.

import CppButton
import CppTextbox
// Implicitly injected: import CppNamespaces

func makeButton() {
  var b1 = Button() // error: no such sort
  var b2 = widgets.Button() // OK
}

An incidental readability profit of utilizing enum extensions is that the
magnificent-printed module interface for C++ modules will exercise basically the most valuable phrase extension
for namespaces as a change of enum, cutting again the confusion skill.

Enchancment for choice 1: Add a utilizing-indulge in save to Swift.

Some C++ libraries account for namespaces with long names, or deeply nested
namespaces. C++ customers of such libraries continuously plan terminate to steer clear of typing and seeing
such namespace qualifiers in their code. To abet exercise these libraries in Swift,
we would possibly presumably well also add a save equivalent to C++ utilizing, that will presumably well presumably amplify the name
look up into the given empty enum.

// Utilization instance.

import CppButton
import CppTextbox
// Implicitly injected: import CppNamespaces
import CppNamespaces.widgets

func makeButton() {
  var b1 = Button() // OK
}

We would possibly presumably well also restrict this save to easiest work with enums in the CppNamespaces
module, if such feature is no longer deemed to be appropriate for APIs outlined in
Swift.

Option 2: Introduce namespaces into Swift as a C++ interoperability feature.

From the implementation level of detect, choice 1 feels indulge in a pile of hacks and
recommendations. We would possibly presumably well also add C++-style namespaces to Swift, and easiest allow the C++
importer to account for them, clearly designating namespaces as a C++
interoperability feature. From the level of detect of customers, there shall be very
few, if any, variations between choice 1 and choice 2.

Option 3: Introduce namespaces into Swift.

We would possibly presumably well also add C++-indulge in namespaces to Swift as a on the total available language
feature, and then exercise it to import C++ into Swift.

The “std” namespace

A attention-grabbing establish a question to is how one can import the std namespace in Swift.
Persevering with to name it std would possibly presumably well also invoke unsuitable associations, as a result of APIs in
std are no longer a allotment of the Swift commonplace library. We would possibly presumably well also rename std to
something that means that it is the C++ commonplace library, indulge in cxx_std.

Structs and classes

Mapping the kind itself and its special member capabilities

For the capabilities of this dialogue, we can save in thoughts C++ classes easiest. There
are no longer any valuable technical variations between C++ structs and classes, each and every
hold precisely the identical capabilities. In C++, structs and classes fluctuate in how
they’re most frequently frail, on the other hand, it is rarely enforced by the compiler. Diverse
style guides hold so much of principles about when to account for a struct or a class, and
these principles are most frequently no longer toolable in precept. Attributable to this reality, struct/class
distinction in C++ would possibly presumably well also additionally be frail at most attention-grabbing as a hint to manual the API importer.

Swift’s structs and classes are two totally so much of ideas. Structs are
the constructing block for price forms, and classes are the constructing block for
reference forms. References to Swift class instances are equivalent to
std::shared_ptr in C++ (however are extra atmosphere qualified, as a result of they exercise an
intrusive refcount), and attributable to this reality are no longer qualified for mapping an arbitrary C++
class sort.

As some distance as price/reference semantics dart, C++ classes are equivalent to structs in
Swift: each and every inherit price/reference semantics from constituent parts (if you
save price forms in a C++ class or a Swift struct, you ranking a price sort; if
you embed a reference sort in a C++ class or in a Swift struct, the composite
sort behaves indulge in a reference sort). They’re also identical in their reminiscence
allocation strategy: each and every are allocated inline (local variables are allocated on
the stack, member variables are allocated in the containing object without an
indirection).

C++ classes allow the API owner to one at a time protect watch over whether the price is
copyable, movable, copy-assignable, dart-assignable, and destructible. Furthermore,
behavior for those operations would possibly presumably well also additionally be customized. User-outlined structs in Swift
can’t customise such operations. User-outlined Swift classes can easiest customise
the deinit, which corresponds to the destructor in C++. Nonetheless, this
limitation easiest applies to person-outlined Swift structs and classes. There are
extra mechanisms in the Swift object model, compiler, and runtime, which can also very successfully be no longer
uncovered as language parts, however exist as hooks for future extension (e.g.,
some had been added particularly for skill C++ interop), or exist to enhance
Swift language parts indulge in resilience.

Let’s plan terminate a see at what forms see indulge in in the compiler and runtime, and what
types of customization hooks come in.

The compiler classifies forms as loadable or address-easiest (both one or the
other). Take care of-easiest forms are always manipulated via a pointer. Loadable
forms would possibly presumably well also additionally be loaded from reminiscence into SIL and LLVM IR values, and then
reconstructed lend a hand in reminiscence.

The compiler uses so much of recommendations to ranking admission to and establish up values looking out on
the classification of the kind. As an illustration, trivial loadable forms would possibly presumably well also additionally be
freely copied, destroyed, and moved round in reminiscence without working any
person-outlined code. Structs imported from C are regarded as loadable in Swift. C
structs are easiest light of C primitives, and attributable to this reality are regarded as trivial
— would possibly presumably well also additionally be initialized, assigned, and moved round with memcpy.

Resilient Swift forms are for your full reverse terminate of the spectrum.
Resilient forms are forms supplied by a third-party library that would now not need
to make your mind up to a particular ABI for that kind. Resilient forms are opaque values
that will presumably well also tranquil be manipulated via a price gawk table — a table of characteristic
pointers that defines the following operations:

Swift Cost Search for Operation C++ equivalent
initializeWithCopy copy constructor
assignWithCopy copy assignment operator
initializeWithTake dart constructor, adopted by a name to destructor on the provision
assignWithTake dart assignment operator, adopted by a name to destructor on the provision
murder destructor
measurement sizeof(T) minus trailing padding
trek sizeof(T)
flags amongst other records, contains alignment, i.e., alignof(T)

Cost gawk tables also indulge in composite operations that will additionally be derived from
the operations above.

We can plan an arbitrary copyable C++ class sort to a Swift struct sort whose
price witnesses name the corresponding special member characteristic of the C++ class.

We can plan particular C++ classes to a extra optimizable illustration in Swift.
As an illustration, C++ classes that indulge in easiest primitives and hold trivial special
member capabilities (i.e., POD forms) would possibly presumably well also additionally be mapped to trivial loadable Swift
structs, factual indulge in C structs are on the present time.

Will we plan extra advanced C++ classes to loadable Swift structs? Any individual with a
extra thorough records of runtime and SIL would possibly presumably well also tranquil respond, however that is what the
author of the file would possibly presumably well also fetch.

From swift/clinical doctors/SIL.rst:

Loadable forms are forms with a in reality uncovered concrete illustration:

  • Reference forms
  • Builtin price forms
  • Fragile struct forms in which all element forms are loadable
  • Tuple forms in which all element forms are loadable
  • Class protocol forms
  • Archetypes constrained by a class protocol

“Fully uncovered concrete illustration” appears to be like to be to be like indulge in a definition of a loadable
sort, on the other hand, other comments convey a microscopic bit of so much of issues, and it is rarely particular
what “fully uncovered” in actuality method.

From swift/embrace/swift/SIL/TypeLowering.h:

/// Is a diminished SIL sort address-easiest?  That's, is the fresh context
/// required to protect the price in reminiscence for some design?
///
/// A form would possibly presumably well also very successfully be address-easiest as a result of: 
///
///   - it is rarely fastened-measurement (e.g. as a result of it is a resilient sort) and
///     attributable to this reality can no longer be loaded into a statically-boundable establish of
///     registers; or
///
///   - it is semantically lumber to reminiscence, both as a result of its storage
///     address is frail by the language runtime to place in power its semantics
///     (as with a outmoded reference) or as a result of its illustration is by hook or by crook
///     address-dependent (as with something indulge in a relative pointer).
///
/// An address-easiest sort would possibly presumably well also additionally be fastened-structure and/or trivial.
/// A non-fastened-structure sort is always address-easiest.
enum IsAddressOnly_t : bool {
  IsNotAddressOnly = spurious,
  IsAddressOnly = lovely
};

C++ classes are fastened-measurement, so we construct no longer care about the principle bullet level. The
2nd bullet level is extra attention-grabbing — a form would possibly presumably well also tranquil be address-easiest if an
event of that kind cares about which address it is kept at.

From Slava Pestov’s weblog post “How one can talk to your younger folk about SIL sort
exercise”
:

Whenever you happen to account for a C++ class describing a shipshape pointer to a reference-counted
object, the presence of a custom copy constructor and destructor power the
price to be materialized in reminiscence the entire time, for the reason that compiler
would now not know what the hell you too can very successfully be doing for the interval of the custom constructor; perhaps
you too can very successfully be taking the address of ‘this’ and storing it somewhere.

If C++ had loadable forms, they would indulge in some roughly special annotation
that told the compiler that the dart constructor can factual trivially terminate a
memcpy() of the price, although there is a custom copy constructor or
destructor. At this level, your shipshape pointer would possibly presumably well also very successfully be loaded into a register
and handed round without components.

This situation says that a C++ shipshape pointer, with a custom copy constructor, copy
assignment operator, and destructor, would possibly presumably well also additionally be loadable, so long as all dart
special member capabilities are trivial. This explanation aligns successfully with the
earlier one.

A C++ class is loadable in Swift so long as transferring it is trivial. If we ignore
C++ classes with inconsistent copy and dart semantics, a trivial dart implies
that reproduction constructor and reproduction assignment construct no longer care about the explicit address,
which works Swift’s requirements.

Special member capabilities with unsuitable semantics

C++ classes can account for special member capabilities with unsuitable or inconsistent
semantics. It’ll also additionally be completed intentionally; as an illustration, the copy constructor of
auto_ptr in actuality strikes the price. It’ll also additionally be completed unintentionally: it is
regular to account for easiest the special member capabilities that the C++ code occurs to
exercise lovely now — as an illustration, easiest account for the copy constructor however no longer the copy
assignment.

Attributable to this reality, we have to reach to a name whether the Swift/C++ interoperability layer would possibly presumably well also tranquil
have confidence special member capabilities of C++ classes to hold expected semantics, or
whether some verification is very well-known.

Non-person-supplied special member capabilities hold simply semantics by
construction if the C++ class contains successfully-behaved forms. Given the
fresh command of the work in static analysis, it would now not seem indulge in the
interoperability layer even remotely has of mission of proving that person-supplied
special member capabilities hold simply semantics. There are two handy
suggestions: both have confidence the person on this regard and allow them to adjust the
inference completed by the interop layer with annotations, or construct no longer fabricate any
assumptions about the semantics and quiz that the person annotates forms as
price forms, dart-easiest, or non-movable.

Special member capabilities that throw exceptions

If C++ classes are imported in Swift as structs, there appears to be like to be to be no life like
technique to plan exceptions thrown from special member capabilities to an error that can
be dealt with in Swift.

Whereas it is doable to propagate C++ exceptions thrown by regular
member capabilities to Swift code, special member capabilities are so much of as they
frail frail to place in power price witnesses, which can also very successfully be known as by the compiler
implicitly. Attributable to this reality, both such exceptions have to be mapped to lethal errors
(as we terminate for other unhandled C++ exceptions), or calls to such special member
capabilities would possibly presumably well also tranquil be prevented statically.

Combating such calls statically appears to be like to be no longer easy. Additionally, in follow, special
member capabilities throw largely attributable to out-of-reminiscence stipulations, which is
regarded as unrecoverable in Swift. Attributable to this reality, the handy solution is to
plan exceptions from special member capabilities to lethal errors.

If the person must exercise a C++ class with throwing special member capabilities from
Swift, an cheap workaround would possibly presumably well presumably be to jot down a wrapper that exposes these
operations as regular APIs. Wrappers can also be synthesized by the importer, if
such classes are discovered to be regular.

// Can't be imported in Swift.
class MyThrowingType {
public: 
  MyThrowingType() { if(...) throw ...; }
  ~MyThrowingType() { if(...) throw ...; }
  void method();
};

// May perhaps presumably be imported in Swift.
class MyThrowingTypeWrapper {
private: 
  std::unique_ptr value_;
public: 
  MyThrowingTypeWrapper(): value_(nullptr) {}
  void init() /* can throw */ { value_ = std::make_unique(); }
  void deinit() /* can throw */ { value_ = nullptr; }
  void method() { value_.method(); }
};

True destruction semantics

C++ language specifies the precise level in program execution at which destructors
would possibly presumably well also tranquil speed, whereas Swift would now not. Some C++ APIs depend on these ensures to work
successfully (as an illustration, RAII forms indulge in mutex locks).

// A pure C++ program.

class PickyCxxClass {
public: 
  ~PickyCxxClass() { ... }
};

void test1() {
  PickyClass c;
  printf("Hi there");
  // `c`'s destructor is assured to be known as exactly right here.
}
// A pure Swift program, equivalent to the C++ program above.

struct SwiftStruct { ... }

func test1() {
  var s = SwiftStruct()
  // `s` would possibly presumably well also additionally be deallocated right here.
  print("Hi there")
  // `s` would possibly presumably well also additionally be deallocated right here.
}

But how regularly terminate C++ APIs depend on precise destruction? A gut feeling is that
it occurs magnificent continuously, however it surely is no longer always intentional and acknowledged by
the API vendor. All C++ forms ranking an actual destruction level, and attributable to this reality,
it is terribly easy to beginning out inadvertently relying on it in API compose.

There are multiple ways to address this impedance mismatch.

Ignore the variations, and practice Swift destruction semantics to C++
classes.
This style will work for many C++ classes. Nonetheless, C++ classes
that depend on C++ destruction semantics would possibly presumably well also no longer work successfully in Swift.

Force the person to always buy a destruction level for values of C++ forms.
Too remarkable burden on the person, and the code would possibly presumably well also no longer see indulge in regular Swift.

Allow the person to buy a destruction level, in another case let the compiler buy.
This style will work, however it surely trusts the person to full the lovely ingredient every
time a particular C++ class is frail. Regularly, whether precise destruction level is
required or no longer will depend on the kind.

Clarify a destruction level for C++ classes. This can’t be completed universally
in all Swift code, however it surely is doable for local variables of concrete forms.

An instance the establish it is rarely likely to protect precise destruction semantics
for C++ classes is in a generic Swift characteristic that’s named with a C++ class
as a form parameter. On this case, we would possibly presumably well also tranquil be in a situation to assemble one definition of
a Swift characteristic, which must work regradless of the nature of the kind (be it a
Swift sort or a C++ class). This limitation would now not seem too depraved, as a result of RAII
forms are no longer continuously handed as sort parameters to templates in C++, which creates
a design to imagine it’ll also no longer be regular in Swift both.

Allow the API owner to annotate the C++ class as requiring an actual
destruction level.
An pronounce upon the earlier method the establish uncommon
semantics are easiest applied to C++ classes that need them, as an illustration, RAII
forms indulge in mutex locks.

The pragmatic choice is to place in power one in every of the final two suggestions.

If an actual destruction level is outlined for annotated C++ classes, that is an
instance of behavior that we ranking:

// C++ header.

[[swift::requires_precise_destruction]]
class PickyCxxClass {
public: 
  ~PickyClass() { ... }
};
// C++ header imported in Swift.

struct PickyCxxClass {
  // The destructor is no longer imported as a declaration into Swift, on the other hand,
  // it is mapped to a price gawk characteristic, and it is named when the
  // lifetime of the article ends, indulge in in C++.
}
func testConcreteType() {
  var c = PickyCxxClass()
  print("Hi there")
  // `c` shall be deallocated right here.
}

func testTypeParameter<T>(_ t: T.self) {
  var c = T()
  // `c` would possibly presumably well also additionally be deallocated right here, although `c` is a `PickyCxxClass`.
  print("Hi there")
  // `c` would possibly presumably well also additionally be deallocated right here.
}

testTypeParameter(PickyCxxClass.self)

Member capabilities that return interior pointers

When a member characteristic in a C++ class returns a pointer (or a reference), most
regularly the lifetime of that pointer is minute to the lifetime of the article
itself. C++ code continuously relies on precise destruction semantics to be particular
the article that owns the reminiscence lives long sufficient. One other hiss is that the
Swift compiler can dart the article round in reminiscence on every occasion it wants,
invalidating those prominent interior pointers.

// C++ header.
class Employee {
private: 
  std::string company_;
public: 
  std::string *mutable_company() { return &company_; }
};
// C++ header imported in Swift.

struct Employee {
  func mutable_company() -> UnsafeMutablePointer
}
func take a look at() {
  var worker:  Employee = ...
  var firm = worker.mutable_company()

  // HAZARD: `worker` would possibly presumably well also hold been moved to a so much of spot in reminiscence
  // by now, invalidating the `firm` pointer.
  firm.pointee = "A"

  print(worker)

  // HAZARD: `worker` would possibly presumably well also additionally be deallocated right here, on the other hand, `firm` is tranquil
  // accessible.
  firm.pointee = "B"
}

To repair the hiss of values being moved round in reminiscence, we have to expose the
Swift compiler about the connection between pointers and objects that maintain the
reminiscence.

// C++ header.

class Employee {
private: 
  std::string company_;
public: 
  [[swift::returns_inner_pointer]]
  std::string *mutable_company() const { return &_company; }
};

The returns_inner_pointer attribute would possibly presumably well also additionally be added manually to the C++ headers,
or it’ll also additionally be safely inferred on all member capabilities that return a pointer or
reference, to slash annotation burden. Inferring this annotation on capabilities
that construct no longer of course prefer it is harmless (would now not alternate semantics, and would now not
invent unsafety), however would possibly presumably well also terminate some optimizations.

To repair the lifetime hiss, the lifetime of a neighborhood variable would possibly presumably well also additionally be prolonged
unless the terminate of the scope if the fresh scope known as a strategy that returns an
interior pointer.

func take a look at() {
  var worker:  Employee = ...
  var firm = worker.mutable_company()

  // ... any quantity of code...

  // `worker` is destroyed on the terminate of the scope attributable to the `mutable_company` name.
}

This methodology is no longer going to work for temporaries (as a change, they must be prolonged
to the terminate of the beefy expression). It’s miles generally no longer very distinguished to name recommendations
that return interior tips about temporaries.

Variations in dart semantics between C++ and Swift

Swift’s “dart” operation will dart away the provision price uninitialized (note
possession manifesto); this operation is named a
“negative dart”. C++ has “non-negative strikes” that dart away the provision price
initialized, however in an indeterminate command.

The following sections address assorted aspects of this impedance mismatch
between the 2 languages.

Shuffle-easiest C++ classes

For the capabilities of this file, we can name C++ classes that will additionally be moved
however construct no longer hold a public copy constructor and a public copy assignment operator
“dart-easiest C++ classes”.

Swift would now not hold dart-easiest forms on the time this file became written
(January 2020). There is a necessity so that you just would possibly add them, and hundreds of compose work has been
completed (note the Ownership Manifesto), on the other hand, this
compose has no longer been proposed yet.

Attributable to this reality, we can first talk about mapping dart-easiest C++ classes to Swift earlier than
dart-easiest forms are applied. On this hiss there is clearly no factual
reveal mapping. There are some non-ergonomic suggestions although.

2nd, we can talk about mapping dart-easiest C++ classes to dart-easiest forms in
future Swift versions.

Shuffle-easiest C++ classes: mapping in Swift 5

Import dart-easiest C++ classes as Swift structs, and statically be particular
copies are by no method wished.

This appears to be like to be doable, although the usability and predictability of the language
feature will depend on the compiler stage the establish the checks are completed. It’s miles straightforward
to save such checks on the SIL stage, on the other hand, the language would possibly presumably well also no longer behave
predictably. It’s miles a extra no longer easy to full such checks on the AST, however the
language shall be extra predictable from the person’s level of detect. Additionally, AST-essentially essentially based
checks would possibly presumably well also reject extra programs than folk query of.

Since price gawk tables require a legitimate copy gawk, it’ll be also
an valuable to restrict passing such pseudo-dart-easiest forms into generic code as
sort parameters, or power beefy specialization of generic capabilities, and save
the checks on fully-specialised SIL.

Right here’s a sketch of principles for dart-easiest forms which can also very successfully be moderately straightforward to take a look at
at collect-time and present factual diagnostics, on the expense of the ensuing
code being non-ergonomic. Shuffle-easiest C++ classes would possibly presumably well also additionally be imported in Swift as
structs as unheard of, on the other hand, such structs can’t be frail as values. The compiler
would easiest allow UnsafePointers to them, and would allow calling recommendations on
UnsafePointer.pointee. When dart-easiest forms are frail as C++ class contributors,
Swift can import them as opaque blobs, and expose a withUnsafePointer-style
API to ranking an UnsafePointer to the knowledge member.

// C++ header.

// `File` is a dart-easiest C++ class.
class File {
private: 
  int file_descriptor_;
public: 
  File(std::string_view filename);
  File(const File &) = delete;
  File(File &&) = default;
  ~File();

  File& operator=(const File &) = delete;
  File& operator=(File &&) = default;

  std::string ReadAll();
};

// `TwoFiles` is dart-easiest as a result of it contains dart-easiest parts.
struct TwoFiles {
  File firstFile;
  File secondFile;
};
// C++ header imported in Swift.

struct File {
  public init(_ filename: std.string_view)
  public func ReadAll() -> std.string
}

struct TwoFiles {
  private var _firstFile:  <unspecified-opaque-storage>
  private var _secondFile:  <unspecified-opaque-storage>

  func withUnsafePointerToFirstFile<Result>(
    _ body: (UnsafePointer)->Outcome
  ) -> Outcome {
    body(&_firstFile)
    _fixLifetime(self)
  }

  func withUnsafePointerToSecondFile<Result>(
    _ body: (UnsafePointer)->Outcome
  ) -> Outcome {
    body(&_secondFile)
    _fixLifetime(self)
  }
}
// Utilization instance.

func useOneFile(_ f: UnsafeMutablePointer) {
  // var f2 = f.pointee // collect-time error: can easiest name a strategy on 'pointee'.
  print(f.pointee.ReadAll()) // OK

  // Shuffle `f` to a so much of reminiscence spot.
  var f2 = UnsafeMutablePointer<File>.allocate(ability: 1)
  f2.moveInitialize(from: f, depend: 1)
  // `f` is left uninitialized now.

  print(f2.pointee.ReadAll()) // OK
  f2.deallocate() // OK
  // The file is closed now.
}

func useTwoFiles(_ files: UnsafeMutablePointer) {
  // Love `print(files.first.ReadAll())`, if it became likely to assemble it: 
  files.pointee.withUnsafePointerToFirst { print($0.ReadAll()) }
}

If we add enhance for marking APIs as returning interior
pointers
, we would possibly presumably well also fabricate the
imported API nicer:

// C++ header imported in Swift.

struct TwoFiles {
  private var _firstFile:  <unspecified-opaque-storage>
  private var _secondFile:  <unspecified-opaque-storage>

  @_returnsInnerPointer
  var firstFile:  UnsafePointer<File> { ranking }

  @_returnsInnerPointer
  var secondFile:  UnsafePointer<File> { ranking }
}

Shuffle-easiest C++ classes: mapping to dart-easiest Swift forms (in future Swift versions)

This fragment is in line with the compose for dart-easiest Swift forms that has no longer been
officially proposed yet. Gaze possession manifesto for
the compose for possession and dart easiest forms that we put off on this fragment.

Shuffle-easiest C++ classes correspond to moveonly structs in Swift. Semantic
analysis ensures that they’re by no method copied.

Moves that murder the provision are spelled dart(x) in Swift. Swift would now not
hold a thought of non-negative dart; a fraction beneath discusses likely
compose suggestions.

// C++ header.

class File {
private: 
  int file_descriptor_;
public: 
  File(std::string_view filename);
  File(const File &) = delete;
  File(File &&) = default;
  ~File();

  File& operator=(const File &) = delete;
  File& operator=(File &&) = default;

  std::string ReadAll();
};
// C++ header imported in Swift.

moveonly struct File {
  public init(_ filename: std.string_view)
  public deinit

  public func ReadAll() -> std.string
}

moveonly struct TwoFiles {
  var first:  File
  var 2nd:  File
}
// Utilization instance.

func useOneFile(_ f: File) {
  print(f.ReadAll()) // OK

  // Shuffle `f` to a so much of reminiscence spot.
  var f2 = dart(f)

  // print(f.ReadAll()) // collect-time error: can't ranking admission to `f`, its price became moved

  print(f2.ReadAll()) // OK
  endScope(f2) // OK
  // The file is closed now.
}

func useTwoFiles(_ files: TwoFiles) {
  print(files.first.ReadAll()) // OK
}

Non-negative strikes

On the total, Swift code that uses values of C++ class forms would possibly presumably well also tranquil exercise Swift’s
negative strikes most frequently the establish C++ code would hold frail a non-negative
dart. Nonetheless, particular C++ APIs are designed to be frail with non-negative
strikes, attributable to this reality, non-negative strikes would possibly presumably well also tranquil be made available in Swift.
Adding non-negative strikes to Swift as a local language feature is a
non-starter.

Take care of show hide of the following C++ code:

// Instance of C++ API compose that requires customers to save non-negative
// strikes.

class Instance { /* dart-easiest */ };

std::elective getExample();
void processExample(Instance e);

void take a look at() {
  std::elective e = getExample();
  processExample(std::dart(e.price()));
}

Identical Swift code would see indulge in this:

// Identical Swift code.

func take a look at() {
  var e:  cxx_std.elective<Example> = getExample();

  processExample(dart(e.price()));
  // If we put off that the earlier line compiled, now we hold an argument: 
  // `cxx_std.elective` would now not know that the price became destructively moved
  // and would possibly presumably well also tranquil are trying to delete it all once more.
}

After all, one would possibly presumably well also argue that the interoperability layer would possibly presumably well also present special
enhance for std::elective, and fabricate it work with negative strikes greater.
Whereas that’s lovely, the level tranquil stands: there shall be C++ APIs that question of
customers to save non-negative strikes, and would possibly presumably well also tranquil be particular they’re usable
from Swift without overlays or special compiler enhance.

Option 1: Non-negative strikes in Swift are swaps with an arbitrary legitimate
price.

It’s miles straightforward to model a non-negative dart in Swift as a swap with a
default-initialized price.

// Swift commonplace library, C++ enhance module.

public protocol DefaultInitializable {
  init()
}

public moveonly func cxxMove<T: DefaultInitializable>(_ price: inout T) -> T {
  var result = T()
  swap(&price, &result)
  return result
}

public moveonly func cxxMove(_ price: inout T, replacingWith newValue: T) -> T {
  var result = newValue
  swap(&price, &result)
  return result
}
// Utilization instance.

// This characteristic takes a `File` by price, enthralling it.
func consumeFile(_ f: File) { ... }

func useArrayOfFiles() {
  var files:  [File] = ...
  // consumeFile(files[0]) // collect-time error: can't copy a `File`

  // Swift's dart would now not abet.
  // consumeFile(dart(file[0]))
  // collect-time error: transferring one element of an array will design a
  // double-destruction of `File` when the array is destroyed.

  consumeFile(cxxMove(&file[0])) // OK, changed `file[0]` with a `File()`.

  consumeFile(cxxMove(&file[1], replacingWith: File("/tmp/instance.txt")))
  // OK, changed `file[1]` with a newly-opened file.
}

The profit of this method is that we steer clear of creating “legitimate however
indeterminate” values, which is in a situation to be hazardous. Nonetheless, such values would possibly presumably well also additionally be
handed from C++ to Swift at any time, although Swift code can’t invent them
straight away. It’s miles generally awkward to require the person to reach lend a hand up with a dummy legitimate
price when the kind is no longer default-constructible.

Option 2: Non-negative strikes in Swift invoke the C++ dart constructor.

So, we have to save a staunch C++ dart and dart away a “legitimate however indeterminate”
price in the provision. For that, we must enable the Swift to name the C++ dart
constructor.

If class File has a dart constructor in C++, the imported Swift struct defines
a corresponding initializer:

// C++ header imported in Swift.

public moveonly struct File {
  // File(File &&);
  public init(cxxMovingFrom: inout File)
}
// Utilization instance.

func useArrayOfFiles() {
  var files:  [File] = ...
  consumeFile(File(cxxMovingFrom: &files[0]))
}

The dart syntax, File(cxxMovingFrom: &files[0]), in all equity verbose and requires
repeating the name of the kind, whereas the corresponding C++ save,
std::dart(x), would now not. When sort context is accessible, the expression would possibly presumably well also additionally be
abbreviated to .init(cxxMovingFrom: &files[0]). We can fabricate it extra concise by
synthesizing a helper method in movable forms:

// C++ header imported in Swift.

public moveonly struct File {
  // File(File &&);
  public init(cxxMovingFrom: inout File)

  public mutating func cxxMove() -> File {
    return File(cxxMovingFrom: &self)
  }
}
// Utilization instance.

func useArrayOfFiles() {
  var files:  [File] = ...
  consumeFile(files[0].cxxMove())
}

Even although recommendations are extra in line with Swift API compose than free capabilities,
injecting names into C++ forms can backfire attributable to naming collisions.

Alternatively, we would possibly presumably well also model non-negative strikes with a free characteristic,
imitating the C++ syntax. To full this we need a protocol for non-destructively
movable forms, and a free characteristic that calls the dart constructor:

// Swift commonplace library, C++ enhance module.

public protocol NonDestructivelyMovable {
  public init(cxxMovingFrom: inout Self)
}

public moveonly func cxxMove<T: NonDestructivelyMovable>(_ price: inout T) -> T {
  return T(cxxMovingFrom: &price)
}
// C++ header imported in Swift.

public moveonly struct File: NonDestructivelyMovable {
  public init(cxxMovingFrom: inout File)
}
// Utilization instance.

func useArrayOfFiles() {
  var files:  [File] = ...
  consumeFile(cxxMove(&files[0]))
}

It’s miles generally distinguished to expose the dart assignment operation in Swift. Even although
dart assignment is no longer an valuable to place in power cxxMove(), it’ll also additionally be frail for
optimization.

// C++ header imported in Swift.

public moveonly struct File {
  // File(File &&);
  public init(cxxMovingFrom: inout File)

  // File& operator=(File &&);
  public func moveAssignFrom(_ price: inout File)
}

The compiler would possibly presumably well also save a excessive-stage optimization replacing x = cxxMove(&y)
(which creates a transient, and calls the dart constructor twice) with
x.moveAssignFrom(&y) (which would now not invent a transient and calls dart
assignment easiest once).

Non-movable C++ classes

By non-movable C++ classes we mean C++ classes that construct no longer hold a copy
constructor or a dart constructor.

Swift would now not hold any struct-indulge in equivalent to non-movable C++ classes, and
there is nothing deliberate in that establish. Attributable to this reality, now we must both creatively
reuse one in every of present Swift’s parts, or add some fresh parts to Swift.

Option 1: Draw non-movable C++ classes to Swift structs.

If we have to plan all C++ classes to structs in Swift, one technique to manufacture
non-movable C++ classes work is easiest importing pointers to non-movable forms;
this method is described intimately in the fragment about importing dart-easiest
forms in Swift 5
. Non-movable classes
in C++ are most frequently frail as polymorphic detestable classes. Allowing to easiest exercise pointers
to such forms is no longer a depraved limitation. The principle drawback of this method
is ergonomics.

Option 2: Draw non-movable C++ classes to Swift classes.

Whereas Swift structs are a depraved match for non-movable C++ classes, Swift classes
match semantics greater. As an illustration, instances of Swift classes, once allocated,
personal on the identical address unless deinit. Situations of Swift clasess are always
worked and not utilizing a longer straight away, eradicating the necessity to dart them round in reminiscence.

Even although person-outlined Swift classes hold a particular reminiscence structure particular by
the Swift compiler (as an illustration, the reminiscence block would possibly presumably well also tranquil beginning with an object
header that contains a metadata pointer and a refcount), that particular reminiscence
structure is no longer an valuable for a form to successfully masquerade as a Swift class.
As an illustration, Swift already imports CoreFoundation forms as “foreign classes”;
from the person’s level of detect they see indulge in unheard of classes.

The supreme semantic impedance mismatch between C++ classes and Swift classes is
that Swift classes are reference-counted. It’s miles successfully likely to import a
C++ class as a Swift class whether it is intrusively reference counted, or wrapped in
a shared_ptr.

But what about non-movable C++ classes which can also very successfully be no longer reference counted? This
hiss would possibly presumably well also very successfully be worked round by making withhold and begin operations on C++
classes be a no-op, and introducing an explicit “delete” operation, successfully
making C++ class references in Swift equivalent to UnsafeMutablePointer.

// C++ header.

class NonMovable {
public: 
  NonMovable(const NonMovable &) = delete;
  NonMovable(NonMovable &&) = delete;
  ~NonMovable();

  NonMovable &operator=(const NonMovable &) = delete;
  NonMovable &operator=(NonMovable &&) = delete;

  void debugPrint() const;
};
// C++ header imported in Swift.

class NonMovable {
  // Runs `delete this`.
  func delete()

  func debugPrint()
}
func useNonMovable(nm: NonMovable) {
  var nm2 = nm
  // `nm2` now parts to the identical object as `nm`. No reference-counting.

  nm.debugPrint() // OK
  nm2.debugPrint() // OK

  nm2.delete() // OK
  // The article is deallocated now. From this level, utilizing `nm` or `nm2`
  // is undefined behavior.
}

All the pieces appears to be like to be to work of course successfully, except that we broke Swift’s security
ensures about classes. Swift manages lifetime of regular person-outlined classes
robotically; in good Swift code it is rarely likely to ranking a dangling class
reference; it is generally irregular that customers would must manually deallocate class
instances. Attributable to this reality, classes imported from C++ would behave very in a different way
from person-outlined Swift classes; most importantly, they’re unsafe. This hiss
appears to be like to be incompatible with Swift’s compose and philosophy. Otherwise, importing C++
classes as Swift classes appears to be like to be to be like indulge in a viable implementation strategy.

The unsafety hiss would possibly presumably well also very successfully be mitigated by adding the note “unsafe” somewhere in
the provision code. As an illustration, importing a non-movable C++ class Instance as a
Swift class UnsafeExample, or requiring the person to jot down basically the most valuable phrase “unsafe”
earlier than the kind name:

func useNonMovable(nm: unsafe NonMovable) { ... }

Member capabilities

Member capabilities of C++ classes are most naturally mapped to recommendations in Swift
structs. C++ lets in so that you just would possibly add assorted qualifiers to member capabilities, which we
talk about in the following sections.

Const-licensed member capabilities in C++ classes

Member capabilities of C++ classes would possibly presumably well also additionally be marked with a const qualifier; on the other hand,
this qualifier would now not present any semantic ensures. Const-licensed recommendations
can alternate the command of the article via a unfold of mechanisms.

const_cast is the principle language feature that involves thoughts when one thinks
about editing a const object. As long as an object became to beginning out with allocated as
non-const, its const-licensed recommendations can solid const away and mutate the
object. Detecting skill const_casts in all equity no longer easy, because it requires
inspecting the entirety that a const member characteristic can name, transitively.
Nonetheless, in follow, const_casts are rare, and given the extra pervasive
components described beneath, const_casts would possibly presumably well also additionally be disregarded.

class SneakyMutation {
private: 
  int price = 0;
public: 
  void mutateSneakily() const { opaqueMutator(this); }
  void setValue(int newValue) { price = newValue; }
};

// in a so much of file: 
void opaqueMutator(const SneakyMutationsm) {
  const_cast(sm)->setValue(42);
}

One other C++ feature that lets in const-licensed member capabilities to mutate the
object is “mutable” files contributors. Mutable files contributors are plenty extra regular
than const_casts, however fortunately they’re trivial to detect statically.

class SneakyMutation {
private: 
  mutable int price = 0;
public: 
  void mutateSneakily() const { price = 42; }
};

Yet yet another C++ feature that lets in const-licensed mutate the article
is aliasing. A const member characteristic can create a pointer to the identical object
via some opposite direction, and alternate the pointed-to files.

class SneakyMutation {
private: 
  int price = 0;
public: 
  void mutateSneakily(SneakyMutation *other) const {
    other->price = this->price + 1;
    // What if `other` occurs to be equal to `this`? If that's the case, a const
    // member characteristic has mutated `this`!
  }
};

void take a look at() {
  SneakyMutation sm;

  // A const method mutates the article that it is invoked on: 
  sm.mutateSneakily(&sm);
}

Camouflage that mutateSneakily() can create the different this pointer via a
fluctuate of how, no longer necessarily as a characteristic argument. The strategy in which can fetch
yet another non-const pointer equal to this in a world variable or in a files
construction accessible from this itself. It also needn’t mutate other so
clearly: it must pass other to yet another characteristic that will mutate it. It’s miles
no longer easy to estimate how regular such mutation is, on the other hand, it is rarely a factor
of an everyday compose sample.

Swift’s change for C++ const member capabilities are non-mutating capabilities:

struct Instance {
  private var price:  Int = 0
  mutating func mutatingFunction() { price = 42 }
  func nonMutatingFunction() {
    // price = 42 // would no longer collect
    print(price) // OK
  }
}

The supreme inequity from C++ is that non-mutating capabilities in Swift are
of course no longer allowed to mutate self; there are no longer any backdoors. Some equivalents of
C++’s mutation backdoors are disallowed statically, some are disallowed
dynamically, some are undefined behavior.

The backdoors are disallowed by the exclusivity rule (from SE-0176 Establish into note
Distinctive Win admission to to
Memory
):

two accesses to the identical variable are no longer allowed to overlap except each and every
accesses are reads

If we plan C++ classes to Swift structs, how can we plan C++’s const qualifier on
member capabilities? There are a couple of suggestions.

  • Ignore const, and tag all Swift struct capabilities as mutating. Allow API
    owners to manually annotate capabilities as non-mutating. Right here’s a
    conservative and simply-by-default method, however it surely is no longer ergonomic.

  • Draw const to non-mutating in Swift. This style is terribly orderly from
    the level of detect of ergonomics, however it surely is no longer good in the regular case.
    Nonetheless, in so much of cases such inference shall be simply.

How can we fabricate the 2nd, ergonomic, method safer? To begin with, we would possibly presumably well also tranquil
allow C++ API owners to override the inferred mutating/non-mutating with an
annotation. API owners must hold protect watch over over what their APIs see indulge in in
Swift.

As successfully as, the compiler would possibly presumably well also terminate a delicate-weight static analysis to acknowledge
regular problematic patterns, indulge in mutable contributors and obvious const_casts.
If the compiler finds something else alarming, it’ll also tranquil refuse to save inference
and require the person to manually annotate recommendations in C++ as mutating or
non-mutating.

Unstable-licensed member capabilities

Unstable-licensed member capabilities are so rare that there is rarely always sufficient price in
spending non-trivial engineering effort for them in the interop layer guaranteeing
that they plan correctly. There are two easy ways to address them:

  • construct no longer import volatile-licensed member capabilities,

  • plan member capabilities as if the volatile qualifier became no longer show hide.

Ref-licensed member capabilities

TODO

Closing capabilities

TODO

Getters and setters

Getters and setters in C++ classes most straight away correspond to properties in
Swift. Whereas it is successfully likely to plan getters and setters to regular
recommendations, properties would possibly presumably well presumably be extra ergonomic.

To begin with, we have to search out getter/setter pairs in a C++ class. We would want
to exercise name-essentially essentially based heuristics for that, whereas allowing the API owner to override
the inference with annotations (particularly, with the swift_name attribute).
There are a unfold of naming types for getters and setters in C++, however we easiest
have to duvet basically the most regular ones.

Getters plan terminate no arguments, return a T or a const T. Conventional naming patterns
are: AaaBbb(), GetAaaBbb(), aaaBbb(), getAaaBbb(), aaa_bbb(),
get_aaa_bbb()

Setters plan terminate a T, a const T&, or a T&&, and return void. Conventional naming
patterns are: SetAaaBbb(), setAaaBbb(), set_aaa_bbb()

Mutable accessors plan terminate no arguments and return a T& or a T*. Conventional naming
patterns are: MutableAaaBbb(), mutableAaaBbb(), mutable_aaa_bbb().

The C++ importer can synthesize a Swift property from a getter, from a
getter/setter pair, or from a getter and a mutable accessor. Swift would now not hold
establish-easiest properties, so unpaired setters and mutable accessors shall be imported
as regular recommendations.

// C++ header.

class Employee {
public: 
  const std::string &getName() const;
  void setName(std::string newName);
};
// C++ header imported in Swift.

struct Employee {
  public var name:  std.string { ranking establish }
}
// Implementation details of the imported API.

struct Employee {
  // const std::string &getName();
  private func _getName() -> UnsafePointer

  // void setName(std::string newName);
  private mutating func _setName(_ newName: std.string)

  // Swifty API.
  public var name:  std.string {
    _read {
      yield _getName().pointee
    }
    establish {
      _setName(newValue)
    }
  }
}

Customarily the kind returned by the getter is no longer going to compare the kind taken by the
setter. As an illustration, the getter can return a std::string_view, whereas a setter
takes a std::string. std::string_view is indulge in a const std::string&, so it
makes sense from the API standpoint in C++. Swift, on the other hand, requires the getter
and setter to exercise the identical sort exactly.

We would possibly presumably well also advise the C++ importer about basically the most broadly frail sort pairs, and
insert the suitable sort conversions in the synthesized property accessors.
Nonetheless, these sort conversions will elevate a performance penalty, and the
ensuing Swift API shall be much less performant than the original C++ API. For
instance, save in thoughts a C++ class the establish a getter returns a std::string_view, and
the setter takes a std::string. If we synthesize a std::string_view property
in Swift, its setter would always copy the personality files, although in C++
the setter would dart the std::string. If we synthesize a std::string
property in Swift, its getter would must materialize a std::string from a
std::string_view.

Attributable to this reality, it appears to be like to be indulge in the suitable method is to coach the C++ importer about
facing such mismatched forms, however easiest save property synthesis on quiz,
precipitated by an annotation in C++ code.

// C++ header.

// Unique attribute.
#account for SWIFT_PROPERTY(sort, name) __attribute__((swift_property(#sort, #name)))

class Supervisor {
public: 
  std::string_view getName() const SWIFT_PROPERTY(std::string, name);
  void setName(std::string newName) SWIFT_PROPERTY(std::string, name);

  std::span<const Employee> getReports() const;
  void setReports(std::vector newReports);
};
// C++ header imported in Swift.

struct Supervisor {
  // Property is synthesized as requested by the annotation.
  public var name:  std.string { ranking establish }

  // Property is no longer synthesized as a result of getter and setter characteristic on
  // so much of forms.
  public func getReports() -> std.span>
  public func setReports(_ newReports: std.vector)
};

Pointers to contributors

Pointers to contributors are moderately rare in C++, so no longer importing them at all, at
least firstly, would no longer be a huge loss. Nonetheless, importing them is
likely.

Pointers to files contributors most attention-grabbing correspond to keypaths in Swift. (TODO: need an
instance.)

Pointers to member capabilities would possibly presumably well also very successfully be ergonomically mapped to curried capabilities,
factual indulge in struct and class recommendations in Swift would possibly presumably well also additionally be converted to curried
capabilities.

// Inspiration from Swift: recommendations would possibly presumably well also additionally be converted to curried capabilities.

// An everyday person-outlined struct.
struct Point {
  var x:  Double
  var y:  Double

  func distanceTo(_ line: Line) -> Double { ... }
}

var distanceToFunc:  (Point) -> (Line) -> Double = Point.distanceTo

The most attention-grabbing inequity is that C++ member characteristic pointers exercise a so much of reminiscence
structure than Swift closures. Attributable to this reality, they must be imported with a
special calling conference, let’s name it @conference(cxx_method). Right here’s an
instance:

// C++ header.

class Point {
public: 
  double distanceTo(Line line) const;
};

void CallMemberFunctionPointer(Point p, double (Point::*ptr)(Line));
// C++ header imported in Swift.

public struct Point {
  public func distanceTo(_ line: Line) -> Double { ... }
}

func CallMemberFunctionPointer(
  _ p: Point,
  _ ptr: @conference(cxx_method) (Point) -> (Line) -> Double
)

Digital member capabilities

If we plan C++ classes to Swift structs, it makes basically the most sense to plan digital
member capabilities to struct recommendations in Swift. Nonetheless, Swift structs construct no longer
enhance inheritance. So, whereas we can plan digital capabilities to recommendations and
attain C++ dynamic dispatch precisely, we can’t relate the indisputable reality that the
struct is subclassable, and that the style is overridable in Swift.

TODO: compose how one can plan inheritance.

Inherited APIs

Swift structs construct no longer allow inheritance. If we plan C++ classes as Swift structs,
we would possibly presumably well also replicate APIs from all detestable classes in every derived class.

// C++ header.

class Nefarious {
public: 
  void doBaseStuff();
};

class Derived : public Nefarious {
public: 
  void doDerivedStuff();
};
// C++ header imported in Swift.

public struct Nefarious {
  public func doBaseStuff()
}

public struct Derived {
  public func doBaseStuff()
  public func doDerivedStuff()
}

Conversions between derived and detestable classes

Swift structs construct no longer allow inheritance, so it is rarely likely to straight away relate
the is-a relationship between derived classes and detestable classes. The is-a
relationship is no longer an valuable for non-polymorphic C++ classes, the establish
inheritance is mostly frail as an implementation methodology, moderately than an
intentional allotment of the API. In polymorphic classes the is-a relationship is
moderately valuable and is an intentional allotment of the API.

So how one can portray conversions between derived and detestable classes? There are two
cases to save in thoughts: changing values and changing pointers.

Converting values of derived sort to values of detestable sort is diagnosed as “object
slicing” in C++. It’s miles successfully-diagnosed to be error-prone, however since some C++ APIs
would possibly presumably well also depend on it, we would possibly presumably well also tranquil are trying to expose it in Swift.

Object slicing is doable with none language extensions:

var derived:  Derived = ...
var detestable:  Nefarious = UnsafeRawPointer(&derived).load(as: Nefarious.self)

It’s no longer very ergonomic, however no longer too depraved for an operation that’s diagnosed to be
error-prone. APIs that intentionally depend on object slicing would possibly presumably well also add helper
forms that intentionally plan terminate part in slicing:

// Manually written overlay for a C++ API.

extension Nefarious {
  public init(_ other: Derived) {
    self = UnsafeRawPointer(&other).load(as: Nefarious.self)
  }
  public init(_ other: UnsafePointer) {
    self =  UnsafeRawPointer(other).load(as: Nefarious.self)
  }
}

Now let’s talk about conversions between pointers to derived sort and pointers
to detestable sort. These operations have to be ergonomic easiest for polymorphic
classes.

To begin with, let’s reject extending Swift’s sort casting operators as and
as? to address casts between pointers to C++ objects. Now we must remodel
between UnsafePointer and UnsafePointer, which can also very successfully be no longer
linked with a subtyping relationship in Swift. Enforcing a conversion in
sort casting operators (as and as?) that would now not replicate a subtyping
relationship is no longer a factual advice. Swift already has a couple of such conversions,
and they also design hundreds of complexity in the compiler and the runtime. Furthermore,
most frequently such casting behavior would possibly presumably well also additionally be unexpected by customers. Attributable to this reality, we are
going to detect API-essentially essentially based approaches to relate upcasts and downcasts for C++
objects.

It’s indispensable to personal that interleaved accesses to an UnsafePointer
that aliases an UnsafePointer violate Swift’s sort-essentially essentially based aliasing
principles. These principles would possibly presumably well also very successfully be relaxed for forms imported from C++.

To terminate the person from by chance violating sort-essentially essentially based aliasing principles, Swift
intentionally would now not present a straightforward technique to freely convert between pointers of
unrelated forms. Swift lets in to temporarily invent an aliasing pointer;
on the other hand, that pointer has a scoped lifetime, and for the interval of that scope having access to the
usual pointer is no longer allowed.

// Pointer conversion instance in present Swift language.

var basePtr:  UnsafePointer<Base> = ...
basePtr.withMemoryRebound(to: Derived.self) {
  // On this closure, `$0` has sort `UnsafePointer` and
  // aliases `basePtr`.
  $0.doBaseStuff()
  $0.doDerivedStuff()
}

Form conversions are most frequently expressed as initializers in Swift. Nonetheless, adding
an initializer to UnsafePointer for detestable/derived C++ class pair is going to
invent a huge overload establish, that will negatively influence compilation performance.
Attributable to this reality, we would possibly presumably well also tranquil are trying to distribute the conversion APIs amongst the imported
forms themselves. The importer would possibly presumably well also synthesize conversion APIs on detestable and
derived classes:

// C++ header imported in Swift.

public struct Derived {
  @returnsInnerPointer
  public var asBase:  UnsafePointer<Base> { ranking }

  public static func downcast(from basePointer: UnsafePointer<Base>) -> UnsafePointer?
}

public struct Nefarious {
  public static func upcast(from basePointer: UnsafePointer) -> UnsafePointer<Base>
}
// Utilization instance.

func useBasePtr(_ basePtr: UnsafePointer<Base>) { ... }
func useDerivedPtr(_ derivedPtr: UnsafePointer) { ... }

func testDowncast() {
  var d = Derived()
  useBasePtr(d.asBase)

  // or: 
  useBasePtr(Nefarious.upcast(from: &d))
}

func testUpcast(_ basePtr: UnsafePointer<Base>) {
  if let derivedPtr:  UnsafePointer<Derived> = Derived.downcast(from: basePtr) {
    useDerivedPtr(derivedPtr)
  }
}

The asBase property operates on a price, so it’ll need a method to pin the
usual price in reminiscence whereas the aliasing pointer is dwell. If we ignore that
API, the “sort-upcast-from-price” and “sort-downcast-from-price” syntax in other
APIs would now not be taught successfully, for the reason that expose appears to be like to be to be like reversed.

Let’s note what an API in line with free capabilities would see indulge in. Now we must
separate the upcast and downcast APIs as a result of they must return so much of forms:
upcasts can’t fail, whereas downcasts can.

// C++ enhance module in the Swift commonplace library.

public func cxxUpcast<Source, Destination>(
  _ offer: UnsafePointer,
  to sort: Destination.Form
) -> UnsafePointer

public func cxxDowncast<Source, Destination>(
  _ offer: UnsafePointer,
  to sort: Destination.Form
) -> UnsafePointer

public func cxxDynamicDowncast<Source, Destination>(
  _ offer: UnsafePointer,
  to sort: Destination.Form
) -> UnsafePointer?

The Swift sort checker would hold special records about these capabilities, and
easiest allow calling them when Source and Destination are fully concrete forms
that belong to the identical class hierarchy in C++.

These capabilities will know the concrete offer and plod space forms, so they
shall be in a situation to save any an valuable pointer adjustments, attributable to this reality multiple
inheritance and digital detestable classes would no longer be an argument.

Subclassing C++ classes in Swift

TODO

Making C++ classes conform to Swift protocols

TODO

Enums

In Swift 5, C enums which can also very successfully be no longer annotated (with both of enum_extensibility,
NS_ENUM, or NS_OPTIONS) are imported into Swift as structs, and enumerators
are imported as computed world variables. This would presumably well also hold been the lovely name
for importing Aim-C code, the establish enums no longer declared with NS_ENUM are
highly seemingly to hold a “non-enum nature”: they’re both a bitfield, or factual
a fetch of constants. C++ has extra ways, and further flexible ways to relate
constants, so utilizing enums in C++ to relate constants is no longer very idiomatic.
Bitfield enums are frail in C++ although, on the other hand, compared to total enum utilization,
bitfield enums are tranquil rare. Attributable to this reality, fresh strategy of importing
non-annotated enums as Swift structs is the depraved default for C++.

There are multiple recommendations we would possibly presumably well also plan terminate to import C++ enums into Swift.

(1) Adopt the strategy frail for C enums in C++: unannotated C++ enums are
imported as Swift structs, C++ enums annotated as open/closed are imported as
Swift enums.

Execs:

  • Conservatively simply. This strategy would now not have confidence enums to hold the “enum
    nature” except they’re annotated in another case.

  • Easier compose: identical principles across C, Aim-C, and C++.

Cons:

  • Non-ergonomic. In idiomatic C++ codebases most enums hold enum nature, so
    customers would want so that you just would possibly add a full bunch annotations.

(2) Take care of non-annotated C++ enums hold “enum nature” and import them
as non-frozen Swift enums
; (optionally) put in power an annotation for C++ enums
with “non-enum nature” and import such enums as Swift structs.

Execs:

  • Correct default. In an idiomatic C++ codebase, the spacious majority of enums terminate
    hold enum nature.

  • Keeping offer compatibility by no longer changing how C enums are imported.

Cons:

  • Non-annotated enums of non-enum nature would possibly presumably well presumably be imported incorrectly from the
    API level of detect (on the other hand, there is rarely any undefined behavior hazard).

  • No particular technique to expose aside C and C++ enums. In an finest world, extern "C" would possibly presumably well also tranquil allow to detect C declarations in C++, however no longer all C code is
    wrapped in extern "C". As an illustration, most Aim-C headers are no longer wrapped
    in extern "C" as a result of most Aim-C constructs hold a appropriate ABI
    between Aim-C and Aim-C++.

(3) Apply strategy #2 in C, Aim-C, and C++. Doing so will alternate the
mapping strategy for non-annotated enums coming from Aim-C code, breaking
offer stability to a diploma.

Execs:

  • Correct default in C++.

  • Seemingly simply default in C.

  • Easier compose: same principles in C and C++.

  • Glaring how one can put in power, as a result of there is rarely any have to distinguish between
    so much of header kinds.

Cons:

  • Seemingly no longer simply default in Aim-C. In idiomatic Aim-C code enums
    with “enum nature” are declared with NS_ENUM, and bitfields are declared
    with NS_OPTIONS, which leaves undeniable enums to duvet the uncommon cases.

  • Breaking offer compatibility by changing how C enums are imported. There are
    ways to mitigate this hiss, as an illustration, continue importing enumerators as
    computed world variables, marking them deprecated.

Technique #3 is most attention-grabbing for C++ code, however it surely is unclear if penalties for
Aim-C would possibly presumably well presumably be acceptable. We would possibly presumably well also tranquil take hold of files about utilization of undeniable
enums in idiomatic C++ code and in Apple’s SDKs and evaluate absolutely the quantity
of offer breakage.

Templates

From 10,000 feet, C++ templates are equivalent to Swift generics. Nonetheless, there
are multiple semantic gaps between them.

C++ templates save a syntactic substitution. Any sort that helps the
syntax invoked in the template is a legitimate template argument. Nonetheless, we construct no longer
know exactly what syntax a form is required to enhance unless we are trying to
change that kind into a template. Generics in Swift are constraint-essentially essentially based and
require modular sort checking.

C++ templates require instantiation at collect time. It’s no longer likely to
collect a template without substituting concrete forms in. It’s no longer specified
whether Swift generics are instantiated or no longer, the compiler can fabricate both
choice and the person can’t expose the inequity.

C++ templates enhance specialization. Swift generics construct no longer allow specialization;
they provide a so much of mechanism (protocol requirements) to manufacture one generic
characteristic behave in a different way for so much of forms.

C++ class templates enhance specialization, which lets in defining totally
so much of APIs across specializations of the identical class. All instantiations of a
generic sort in Swift hold the API described in the generic declaration (with
sort parameters substituted), plus appropriate conditional extensions.

C++ templates enhance non-sort template parameters, template template
parameters, and parameter packs (variadic generics), all of which can also very successfully be no longer
supported in Swift.

Neutral templates

Since C++ uses an instantiation-essentially essentially based model for templates, basically the most shimmering method
to import C++ characteristic templates in Swift is to easiest import beefy specializations
as regular capabilities. Nonetheless, it would possibly presumably well presumably be most ergonomic to import characteristic
templates as Swift generic capabilities. Let’s detect each and every suggestions and note how some distance
we can dart.

Neutral templates: import as Swift generic capabilities

Let’s plan terminate explicit specializations out of the image for the capabilities of
presenting the API in Swift. Since overload choice in C++ ignores
specializations of characteristic templates, we can ignore them, too, when importing a
characteristic template into Swift.

// C++ header.

template<typename T>
void functionTemplate(T t) { ... }

// Any choice of explicit specializations would possibly presumably well also follow.
template<>
void functionTemplate(int x) { ... }
// C++ header imported in Swift.

func functionTemplate<T>(_ t: T)

// No have to import explicit specializations as separate APIs.

After all, when Swift code calls functionTemplate with an Int32, it’ll also tranquil
name the simply explicit specialization, functionTemplate, although
it is rarely shown in the imported Swift API.

Neutral templates: allow to specify template arguments

Calls to Swift generic capabilities always deduce generic arguments from the selection.
C++ lets in the caller to both deduce the arguments, or specify them
explicitly. Customarily it is vitally well-known to invoke C++ characteristic templates with
specific template arguments, so it would fabricate sense to expose this functionality in
Swift.

We counsel to permit Swift code to exercise the angle bracket syntax to explicitly
specify characteristic template arguments on the callsite. If template arguments are
no longer specified, we would possibly presumably well also tranquil speed template argument deduction. (TODO: show hide in extra
element how template argument deduction will work beginning from Swift forms.)

// Utilization instance in Swift.

functionTemplate<Int>(42)

How one can specify C++ forms that plan ambiguously into Swift, as an illustration, int &
or int *, each and every of which plan to UnsafePointer? The C++ enhance module in
the Swift commonplace library would possibly presumably well also present Swift typealiases that will presumably well presumably plan
unambiguously to C++.

// C++ enhance module in the Swift commonplace library.

typealias CxxPointer<T> = UnsafeMutablePointer      // T*
typealias CxxConstPointer<T> = UnsafePointer        // const T*

typealias CxxRef<T> = UnsafeMutablePointer          // T&
typealias CxxConstRef<T> = UnsafePointer            // const T&

typealias CxxRvalueRef<T> = UnsafeMutablePointer    // T&&
typealias CxxConstRvalueRef<T> = UnsafePointer      // const T&&
// Utilization instance in Swift.

var x = 42

// Calls `functionTemplate`.
functionTemplate<Int>(x)

// Calls `functionTemplate`.
functionTemplate<CxxConstPointer<Int>>(&x)

// Calls `functionTemplate`.
functionTemplate<CxxRef<Int>>(&x)

Even although it is orderly to plan rvalue references to Swift’s inout, it is rarely
likely to full so when importing a C++ characteristic template as a C++ generic
characteristic; “inout”-ness of an argument can’t alternate across instantiations of a
generic characteristic in Swift.

Neutral templates: calls to specific specializations

From an implementation level of detect, it is straightforward to assemble Swift code that
calls C++ characteristic templates if template arguments are concrete forms which can also very successfully be
obvious on the callsite (both deduced or specified explicitly). In other
phrases, it is straightforward to assemble the selection if Swift compiler can without concerns deduce which
specialization of the C++ characteristic template to name. The imported API would possibly presumably well also
tranquil see indulge in a Swift generic characteristic:

// C++ header imported in Swift.

func functionTemplate<T>(_ t: T)

// No have to import explicit specializations as separate APIs.
// Utilization instance in Swift, works.

func callFunctionTemplate() {
  functionTemplate(0) // OK: calls the `functionTemplate` specialization.
}

If we terminate right here, functionTemplate would see indulge in a generic characteristic in Swift,
however it surely would no longer be callable from generic code. This choice would possibly presumably well also very successfully be factual sufficient
for basically the most total mapping of characteristic templates in Swift. But can we allow
calling C++ characteristic templates from Swift generics?

Neutral templates: calls with generic sort parameters

The principle implementation hiss in allowing generic Swift code to name C++
characteristic templates is that the C++ compiler can easiest collect beefy
specializations, however Swift generics can speed unspecialized.

// Utilization instance in Swift.

func myGenericFunction<T>(_ t: T) {
  functionTemplate(0) // OK: calls the `functionTemplate` specialization.

  functionTemplate(t) // compilation error: can't name a C++ characteristic template, as a result of we construct no longer know what `T` is, and attributable to this reality, can't buy out which specialization to name.
}

We would possibly presumably well also power Swift generics to be instantiated if they exercise a C++ template.
Fully generic entry parts shall be tranquil emitted to meet ABI expectations,
however they would entice.

// C++ header imported in Swift.

@_must_specialize
func functionTemplate<T>(_ t: T)
// Utilization instance in Swift.

@_must_specialize
func genericFunction<T>(_ t: T) {
  functionTemplate<T>(t) // OK!
}

struct GenericStruct<T> {
  init GenericStruct(_ t:  T) { self.t = t }
  var t:  T

  @_must_specialize
  func callGenericFunction() {
    genericFunction(t) // OK!
  }
}

func instance() {
  GenericStruct(42).callGenericFunction()
}

We introduce a @_must_specialize attribute for generic capabilities that will presumably well also tranquil be
instantiated in expose to be known as. The importer marks all Swift generic
capabilities which can also very successfully be backed by a C++ template as @_must_specialize, and from
there the Swift compiler infers the attribute for all customers.

This analysis relies on over-approximating the dynamic callgraph with the static
callgraph. The static callgraph is doable to compute most frequently, since
Swift has very minute ways to abstract over an unspecialized generic characteristic.
Speicifically, Swift would now not hold generic closures. Swift does allow protocols
to hold requirements for generic capabilities although.

Neutral templates: importing as staunch generic capabilities

If all americans knows your full establish of allowed sort arguments to a C++ characteristic
template, we would possibly presumably well also import it as an precise Swift generic characteristic that performs
dynamic dispatch.

// C++ header.

template<typename T>
void functionTemplate(T t) { ... }

// Any choice of explicit specializations would possibly presumably well also follow.
template<>
void functionTemplate(int x) { ... }

As an instance it is diagnosed that functionTemplate can easiest plan terminate Int and UInt.

// C++ header imported in Swift.

func _cxx_functionTemplate<T>(_ t: T) // Imported as outlined earlier than.

func functionTemplate<T>(_ t: T) {
  if T == Int.self {
    return _cxx_functionTemplate(t as! Int)
  }
  if T == UInt.self {
    return _cxx_functionTemplate(t as! UInt)
  }
  fatalError()
}

The person can write this code themselves (in an overlay, as an illustration), or if we
can keep up a correspondence the allowed listing of forms to the importer, it must synthesize the
characteristic for us. Both method, the is that we ranking an even generic Swift
characteristic.

Class templates

Class templates pose the identical challenges as characteristic templates relating to
separate compilation. As successfully as to that, we can’t ignore explicit
specializations of sophistication templates when importing the API to Swift.
We would possibly presumably well also ignore explicit specializations of characteristic templates, as a result of they
construct no longer hold an influence on the API. Explicit specializations of sophistication templates can
dramatically alternate the API of the kind.

Class templates: Importing beefy class template instantiations

A category template instantiation would possibly presumably well also very successfully be imported as a struct named
__CxxTemplateInst plus Itanium mangled style of the instantiation (note the
sort production in the Itanium specification). Camouflage that Itanium mangling is
frail on all platforms, whatever the ABI of the C++ toolchain, to manufacture particular
that the mangled name is a legitimate Swift sort name (that is no longer the case for MSVC
mangled names). A prefix with a double underscore (to manufacture particular now we hold a reserved
C++ identifier) is added to restrict the probability for conflicts with names of
person-outlined structs. The struct is notionally outlined in the __C module,
in the same style to regular C and C++ structs and classes. Take care of show hide of the following C++
module:

// C++ header.

template<class T>
struct MagicWrapper {
  T t;
};
struct MagicNumber {};

typedef MagicWrapper WrappedMagicNumber;

WrappedMagicNumber shall be imported as a typealias for a struct
__CxxTemplateInst12MagicWrapperI11MagicNumberE. Interface of the imported
module will see as follows:

// C++ header imported to Swift.

struct __CxxTemplateInst12MagicWrapperI11MagicNumberE {
    var t:  MagicNumber
}
struct MagicNumber {}
typealias WrappedMagicNumber = __CxxTemplateInst12MagicWrapperI11MagicNumberE

Class templates: importing specific specializations

Correct indulge in with calls to C++ characteristic templates, it is straightforward to assemble a exercise of a
C++ class templates if the utilization in Swift code unambiguously specifies which
specialization would possibly presumably well also tranquil be frail.

// C++ header.

template<typename T>
class ClassTemplate {};
// C++ header imported to Swift.

struct ClassTemplate<T> {}
// Utilization instance.

func useClassTemplate() {
  var x = ClassTemplate<Int32>() // OK, uses `ClassTemplate`.
}

If the category template offers specializations with totally so much of APIs,
we construct no longer hold a hiss, as a result of we easiest have to import specific
specializations into Swift.

// C++ header.

template<typename T>
class ClassTemplate {
  void func1();
};

template<>
class ClassTemplate<int> {
  void func2();
};

template<typename T>
class ClassTemplate> {
  void func3();
};
// C++ header imported to Swift.

// A shell of a generic struct easiest frail for name look up.
struct ClassTemplate<T> {}
// Utilization instance.

func useClassTemplate() {
  var x1 = ClassTemplate<Int8>() // OK
  var x2 = ClassTemplate<Int32>() // OK
  var x3 = ClassTemplate<cxx_std.vector<Int32>> // OK
}

When the Swift compiler sees ClassTemplate, it interprets the kind to
C++, that’s, ClassTemplate. Then Swift compiler asks the Clang importer
to import that specialization. Clang importer instantiates the principle template
with T=char and imports the ensuing ClassTemplate. Same for all
other rereferences to ClassTemplate. On the terminate, we ranking:

// C++ header imported to Swift, as wished for the program above.

// A shell of a generic struct easiest frail for name look up.
struct ClassTemplate {}

struct ClassTemplate {
  func func1()
}

struct ClassTemplate {
  func func2()
}

struct ClassTemplate> {
  func func3()
}

Successfully, ClassTemplate, ClassTemplate, and
ClassTemplate> are totally unrelated forms; they factual
hold angle brackets in their name. (By the style, the identical is the case in C++.)

Advantages of this method:

  • Quite easy to place in power.

  • Uncomplicated model, few or no nook cases.

Disadvantages of this method:

  • Users can easiest exercise full specializations. In other phrases, customers can’t exercise a
    C++ template from Swift generic and pass a generic sort parameter to the C++
    template.

Class templates: utilizing with generic sort parameters

Many class templates construct no longer account for specializations that dramatically alternate the
API, or exercise parts indulge in non-sort template parameters that construct no longer exist in Swift
generics. It’s miles orderly to import such templates as Swift generics straight away.
With a delicate-weight static analysis, or with annotations in the C++ header, the
compiler would acknowledge the sort of form and import the API shared by all
instantiations into Swift.

Equally to our remedy of characteristic templates described above, we can
annotate the transitive closure of generic Swift code that uses C++ class
templates with @_must_specialize.

Class templates: utilizing in generic code via a synthesized protocol

Class templates which hold a uniform API across all specializations would possibly presumably well also very successfully be made
to conform to a Swift protocol, which would facilitate passing them to generic
code.

// C++ header.

template<typename T>
class MyClassTemplate {
  void func1(T t);
};
// C++ header imported in Swift.

protocol MyClassTemplateProtocol {
  associatedtype T
  func func1(_ t: T)
}

struct MyClassTemplate<T> : MyClassTemplateProtocol {}

On this model, the Swift compiler can tranquil import easiest specific specializations
of MyClassTemplate. The fresh allotment is that the Swift compiler will synthesize a
protocol, MyClassTemplateProtocol, that contains APIs shared by all
specializations. The Swift compiler can even fabricate every imported specialization
of MyClassTemplate conform to MyClassTemplateProtocol.

This style, we solved the hiss of specializations being unrelated forms: now they
all conform to an everyday protocol, and attributable to this reality, generic code can characteristic
transparently on any specialization.

// Utilization instance.

// Notify a C++ class template from a Swift generic characteristic without naming a
// specific specialization.
func useGeneric<SomeSpecialization>(_ classTemplate: SomeSpecialization, _ t: SomeSpecialization.T)
  the establish SomeSpecialization:  MyClassTemplateProtocol
{
  classTemplate.func1(t)
}

func useConcrete() {
  var classTemplate = MyClassTemplate<Int32>()
  classTemplate.func1(0)
  useGeneric(classTemplate, 0)
}

Class templates: importing as staunch generic structs

If all americans knows your full establish of allowed sort arguments to a C++ struct
template, we would possibly presumably well also import it as an precise Swift generic struct. Every method of
that struct will save dynamic dispatch in line with sort parameters. Gaze
the fragment about characteristic templates for extra details.

Mapping SFINAE

We can plan SFINAE to generic constraints and to conditional extensions.

TODO

Variadic templates

TODO

Non-sort template parameters

TODO

Template template parameters

TODO

Overloaded operators

TODO: Mapping C++’s operators to Equatable, Comparable, Hashable.

operator*, operator->

TODO

operator[]

operator[] semantically maps successfully to Swift’s subscript.

// C++ header.

class MyCxxContainer {
public: 
  const double& operator[](int i) const;
  double& operator[](int i);
};
// C++ header imported in Swift.

struct MyCxxContainer {
  public subscript(_ i:  Int) { ranking establish }
}

The synthesized subscript uses the _read and _modify generalized accessors
to ahead the reminiscence address to the caller.

// Implementation details of the imported API.

struct MyCxxCollection {
  // const double& operator[](int i) const;
  private func _operatorBracketsConst(_ i: Int) -> UnsafePointer<Double>

  // double& operator[](int i);
  private func _operatorBrackets(_: Int) -> UnsafeMutablePointer<Double>

  // Swifty API.
  public subscript(_ i:  Int) -> Double {
    _read {
      yield _operatorBracketsConst(i).pointee
    }
    _modify {
      yield &_operatorBrackets(i).pointee
    }
  }
}

operator()

Swift has an equivalent for C++’s operator(): callAsFunction (introduced in
SE-0253: Callable values of person-outlined nominal
forms
).

// C++ header.

class MultiplyIntDouble {
public: 
  double operator()(int x, double y);
};
// C++ header imported in Swift.

struct MultiplyIntDouble {
  public func callAsFunction(_ x: Int, _ y: Double) -> Double { ... }
}

This mapping rule would address the selection operator of std::characteristic,
function_ref and identical forms.

Literal operators

TODO

Exceptions

Background

C++ sadly has the reverse default to Swift the establish exception throwing is
concerned. Any C++ characteristic that’s no longer explicitly marked noexcept would possibly presumably well also tranquil be
assumed to be potentially throwing, although many such capabilities construct no longer throw
in follow.

If we imported all of these capabilities into Swift as throws capabilities, the code
calling them would possibly presumably well presumably be littered with are trying!s. Requiring all imported capabilities (and
the entirety they name transitively) to be marked noexcept also appears to be like to be excessively
burdensome and is no longer idiomatic C++.

Baseline functionality: Import capabilities as non-throwing, terminate on uncaught C++ exceptions

In the principle iteration of C++ interop, we can import all C++ capabilities as
non-throwing Swift capabilities. If a C++ characteristic known as from Swift throws an
exception that’s no longer caught for the interval of the C++ code, the program will terminate.

This style is equivalent to that taken by the Python interop
library
,
which also terminates the program by default if a Python exception is raised and
no longer caught for the interval of the Python code.

If exceptions thrown in C++ have to be dealt with in Swift, this would possibly be completed by
writing a C++ wrapper that catches the exception and returns a corresponding
error object.

Prolonged functionality: Optionally propagate exceptions to Swift

If we uncover that builders robotically have to address C++ exceptions in Swift,
writing C++ wrappers as described above will clearly no longer be a first-fee
solution. On this case, we can add an choice to propagate C++ exceptions as
Swift exceptions; this would possibly be backward appropriate with the baseline method
described above.

We all once more plan terminate inspiration from Python interop. There, appending .throwing to
the characteristic name calls a variant of the characteristic that propagates the Python
exception to Swift.

It’s no longer handy to full something exactly analogous in C++ interop. We
would possibly presumably well also import every characteristic twice and name the throwing version by a name
suffix or a dummy parameter. Nonetheless, this solution would bloat the interface of
imported classes, and it would no longer be standard: Title suffixes can’t be frail
with constructors or operators; a dummy parameter would possibly presumably well also very successfully be frail with most
constructors, however tranquil would now not work for default constructors or operators.

As an different, we recommend extending Swift with a throws! marker. A characteristic marked
with throws! can potentially throw exceptions, however the characteristic would now not need
to be known as with are trying. If the characteristic is known as with are trying, exceptions are
dealt with as they would presumably well be for an everyday throwing characteristic. If the characteristic is no longer
known as with are trying and the characteristic raises an exception, the program is
terminated. These semantics are terminate to C++ exception facing semantics.

All C++ capabilities which can also very successfully be no longer marked noexcept would possibly presumably well presumably be imported as throws!
capabilities; noexcept capabilities would possibly presumably well presumably be imported as non-throwing capabilities.

This short sketch clearly leaves many questions unanswered on the detailed
semantics that a throws! feature would hold, as an illustration whether person-written
Swift code would possibly presumably well also tranquil be allowed to exercise throws! — note also this dialogue board
dialogue
. Earlier than we
plan terminate any steps in opposition to enforcing C++ exception proagation, we can submit a
formal Swift Evolution proposal for the throws! feature.

The other establish a question to to respond to is how we would plan the C++ exception to a
corresponding Swift object enforcing Error. In theory, C++ lets in
objects of any copy-initializable sort to be thrown. In follow, most
person-outlined C++ exceptions win from std::exception, so it would possibly presumably well presumably be pure
to propagate C++ exceptions as the Swift-imported equivalent of
std::exception and fabricate that kind put in power Error. We would possibly presumably well also add a separate
fallback error sort (e.g. CxxUnknownException) for the case the establish the
exception would now not win from std::exception.

As std::exception is a polymorphic sort, the principle points of how std::exception
shall be represented in Swift will have to relieve unless now we hold finalized how
polymorphism is dealt with (note also the fragment on digital member
capabilities
).

Implementation

Many regular C++ ABIs allow the default behavior (terminate the program if a
C++ exception is thrown) to be applied at zero price. In particular, it is rarely
an valuable to wrap every C++ characteristic in a synthesized are trying-plan terminate block.

As an illustration, the Itanium C++ ABI defines a so-known as persona routine that’s
known as for every stack frame as the stack is being unwound. The thought is that
so much of languages can hold so much of persona routines, so as that so much of
languages can co-exist on the stack and can every account for their maintain stack frame
cleanup good judgment.

The stack unwinding infrastructure finds the simply persona routine by
consulting a so-known as unwind table, which maps program counter ranges to
persona routines.

We would account for unwind table entries overlaying all Swift code that would now not
are trying to address C++ exceptions and hold these entries plan to a persona
routine that simply terminates the program.

If exception enhance is turned off in the C++ compiler by passing -Xcc -fno-exceptions to swiftc, we put off that the C++ code by no method throws
exceptions and would possibly presumably well also tranquil no longer emit any unwind table entries for Swift code.

Atomics

TODO

Importing non-const pointer as further return values

TODO

Bridging files forms with so much of reminiscence structure

Once we import a C++ T into Swift as a form U, in the regular case we must
be particular T and U hold identical reminiscence structure. As an illustration, Swift’s Int8
and C++’s int8_t hold identical reminiscence structure, and attributable to this reality, we can import
int8_t as Int8 in each place.

If T and U hold even a microscopic bit of so much of reminiscence layouts, we must invoke a
bridging characteristic on the interop boundary. Additional sections on this file
present many examples of such sort pairs, however to offer an instance, save in thoughts
std::vector in C++, which is semantically equivalent to Array in Swift,
however has an fully so much of reminiscence structure. If we have to plan them to one
yet another, however must protect the reminiscence structure of each and every forms unchanged, we must
convert the std::vector price into an Array price when the program
execution crosses the language boundary.

As an illustration:

// C++ header.

std::vector<int> IncrementVectorValues(std::vector<int> v);
// C++ header imported in Swift.

// Camouflage: no C++ vectors!
func IncrementVectorValues(_ v: [CInt]) -> [CInt]
// Utilizing the imported C++ API in Swift.

func callIncrementVectorValues() -> CInt {
  var xs:  [CInt] = IncrementVectorValues([10, 20, 30])
  return xs[0] // = 11.
}

Bridging: in the lend a hand of the scenes

Right here’s a simplified description of how Swift implements bridging. In the lend a hand of the
scenes, the characteristic IncrementVectorValues is imported as is, with C++ files
forms:

// C header imported in Swift, in the lend a hand of the scenes: 

func _cxx_IncrementVectorValues(std.vector v) -> std.vector

C++ bridging enhance code offers a characteristic that converts a std::vector to a
Swift Array and vice versa:

// Swift commonplace library, C++ enhance module.

func StdVectorToArray<T>(_ vector: std.vector) -> [T]
func ArrayToStdVector<T>(_ array: [T]) -> std.vector

Every caller is transformed to name the bridging characteristic:

// Utilizing the imported C++ API in Swift: code written by the person.

func callIncrementVectorValues() -> CInt {
  var xs: [CInt] = IncrementVectorValues([10, 20, 30])
  return xs[0] // = 11.
}
// Utilizing the imported C++ API in Swift: code rewritten by the kind checker.

func callGetVector() -> CInt {
  var xs:  [CInt] =
    StdVectorToArray(_cxx_IncrementVectorValues(ArrayToStdVector([10, 20, 30])))
  return xs[0] // = 11.
}

A naive implementation of StdVectorToArray and ArrayToStdVector would hold
to repeat the container’s parts. Nonetheless, with sufficient cooperation between the
C++ commonplace library and the Swift commonplace library, Swift Array would possibly presumably well also plan terminate
possession of std::vector‘s storage and vice versa in O(1), averting making a
copy. Such cooperation would seemingly require changing the ABI of no longer much less than one in every of
the forms, so it would no longer be feasible to place in power in all environments.

Bridging would now not work in every context

Bridging between forms with so much of reminiscence layouts would now not work universally.
As an illustration, factual as a result of a C++ sort T would possibly presumably well also additionally be bridged to a Swift sort U, it
would now not follow that we can bridge a T* to an UnsafeMutablePointer.

// C++ header.

const std::vector<int> *GetPtrToVector();
// C++ header imported in Swift.

// We can't bridge forms indulge in in the instance beneath, it is rarely implementable.
// The underlying C++ characteristic returns a vector with unclear possession semantics,
// however we have to reach lend a hand a pointer to a Swift Array.
// If the bridging code allocates the Swift Array on the heap, what would maintain it?
// If the bridging code would now not allocate a brand fresh Array, the establish does it ranking the
// storage from?
func GetPtrToVector() -> UnsafePointer<[CInt]>

// OK.
func GetPtrToVector() -> UnsafePointerCInt>>

Attributable to this reality, we can save non-trivial bridging easiest in a minute choice of
contexts. In all final locations C++ forms would possibly presumably well also tranquil be imported in line with the
regular principles.

As a consequence, every non-trivial bridging solution wants a fallback that does
no longer require adjusting the reminiscence structure.

Bridging std::characteristic

std::characteristic in C++ is equivalent to closures in Swift. The principle inequity
is that std::characteristic has an empty command, in the same style to characteristic pointers,
whereas Swift closures construct no longer.

Attributable to allowing an empty command, std::characteristic would possibly presumably well also tranquil be mapped to an elective
Swift closure, except annotated as non-nullable.

To noticeably change a non-empty std::characteristic price to a Swift closure, we have to
account for a thunk and allocate a closure context on the heap. The fresh closure
context will show hide a copy of the std::characteristic price. The thunk will exercise a
Swift calling conference, and it will ahead the arguments to
std::characteristic::operator()() utilizing the C++ calling conference.

A thunk indulge in that is no longer going to price remarkable when it involves code measurement. The principle price of
the thunk will reach from dynamic dispatch. We can hold double dynamic dispatch:
first one on the callsite that calls the Swift closure and ends up calling the
thunk, and 2nd one from the thunk to the C++ code wrapped in std::characteristic.
One other hiss is department predictor pollution: there shall be a single thunk
backing all closures with the identical signature. Indirect branches from thunk will
be no longer easy to foretell for the department predictor.

There would possibly be further price contributed by reference counting: closures in Swift
are reference counted, whereas std::characteristic is no longer.

In the extinguish, allocating a brand fresh closure context on the heap is a price to be paid on
every conversion from a C++ std::characteristic to a Swift closure.

Bridging std::string

Ergonomically, the suitable mapping of C++’s std::string is Swift’s String. Both
forms enhance nul bytes (the conversion has to plan terminate them into consideration and can no longer
put off nul-terminated strings). Nonetheless, there is a semantic gap: Swift strings
require textual sigh material to be legitimate UTF-8.

Now we hold a couple of suggestions to address the UTF-8 hiss:

  • Trust C++ code to easiest retailer UTF-8 textual sigh material in strings, and plan them to Swift’s
    String the establish likely. Compose a runtime take a look at for UTF-8 validity for the interval of the
    conversion. Allow to annotate std::strings that retailer binary files, and plan
    those as both Swift’s Array or std::string.

  • Take care of std::strings retailer binary files, and plan them to in line with the
    regular interop principles to cxx_std.string. Allow customers to annotate UTF-8
    strings as such, and plan them to Swift’s String.

The annotations would possibly presumably well also very successfully be inferred with a dynamic analysis tool that will presumably well presumably music
which std::strings indulge in binary files.

Right here’s an instance of API mapping if we reach to a name to have confidence std::strings to retailer
UTF-8 files.

// C++ header.

class Employee {
public: 
  std::string DebugDescription() const;
  [[swift::import_as_std_string]] std::string SeriaziledAsProtobuf() const;
};
// C++ header imported in Swift.

struct Employee {
  func DebugDescription() -> String
  func SerializedAsProtobuf() -> std.string
}

To steer clear of copying files unnecessarily, we need the C++ and Swift commonplace
libraries to cooperate, so as that Swift’s String can plan terminate possession of
std::string‘s heap allocation, and vice versa.

Personality files in Swift.String is kept in a reference-counted object.
Swift.String can plan terminate possession of std::string by transferring possession of
std::string to a newly-allocated reference-counted object. Swift/Aim-C
bridging of NSString already works exactly this method.

On non-Aim-C platforms, Swift.String assumes that the personality files is
tail-allocated in the reference-counted object; this assumption will have to be
changed with a department. Attributable to this reality, adding this form of bridging on
non-Aim-C platforms will invent a particular (tiny) performance penalty. It
is very well-known to show hide that this performance penalty has been always affecting
Aim-C platforms and it is regarded as acceptable.

We would possibly presumably well also ranking rid of the department on non-Aim-C platforms by changing
Swift.String there to always exercise a reference-counted object with an
std::string in it as the backing storage. The drawback of such reminiscence
structure is that Swift.String must dereference two phases of
indirection to ranking admission to to personality files, as a change of one indulge in now we hold on the present time.

std::string can’t plan terminate possession of Swift.String‘s reference-counted object,
as a result of std::string has no branches in its code that retrieves the pointer to
the personality files and in its deallocation code. Adding branches there is
surely likely, however will seemingly lead to regressions for many C++
capabilities, including ones that construct no longer exercise Swift. Attributable to this reality, this method
appears to be like to be to be like indulge in a non-starter.

Attributable to this reality, basically the most nice viable method for O(1) bidirectional bridging is having
Swift.String exercise std::string as its backing storage, and taking the penalty
of a double-indirection to ranking admission to personality files.

If one-method C++-to-Swift bridging is sufficient, it’ll also additionally be applied with a
department in the Swift.String code that retrieves a pointer to personality files.

We can put in power one-method O(1) Swift-to-C++ bridging by embedding a fraudulent
std::string in the Swift.String buffer. This sort of std::string event would
no longer be beefy-fledged, and would possibly presumably well presumably be easiest factual for reading from it; its destructor
can by no method be known as.

Bridging std::vector

Ergonomically, the suitable mapping of C++’s std::vector is Swift’s Array.

Excluding for the case of std::vector, the constraints for Swift.Array
taking possession of std::vector‘s element buffer and vice versa are identical
to string bridging.

Bridging std::establish, std::plan

Swift commonplace library would now not present collections with semantics equivalent to
std::establish and std::plan, so they are now not meaningfully bridged to any Swift
vocabulary sort. Attributable to this reality, they’ll be imported as std.establish and std.plan.

It would be distinguished to offer ergonomic ways to remodel std.establish and std.plan
to Swift.Location and Swift.Dictionary, since std::establish and std::plan are
most frequently frail in C++ APIs (particularly older ones) when the element expose
would now not topic.

Bridging std::unordered_set, std::unordered_map

The most ergonomic mapping of std::unordered_set and std::unordered_map are
Swift.Location and Swift.Dictionary.

The constraints for these Swift forms taking possession of C++’s storage buffers
and vice versa are moderately equivalent to string bridging. A attention-grabbing fresh show hide
spotlight is that the Swift.Location and Swift.Dictionary forms must exercise
the hash characteristic outlined in C++ for C++ forms. It’ll also tranquil be likely to expose
the C++ hash characteristic in Swift as a conformance to the Hashable protocol, or
as a conformance to a brand fresh C++-specific protocol for hashing.

Bridging std::tuple, std::pair

Ergonomically, the suitable mapping of C++’s std::tuple and std::pair are
Swift’s tuples.

Tuple and pair parts have to be copied to place in power non-trivial bridging. It
is unreasonable to introduce a dual illustration and require a department to
ranking admission to tuple parts both in C++ or Swift.

Nonetheless, there are easiest so many different routes to envision out a std::pair in
reminiscence. In truth, it is sort of surely a struct with exactly two files contributors,
first and 2nd, in that expose. When std::pair and Swift’s tuple
(T, U) happen to exercise the identical structure, we would possibly presumably well also bridge them trivially, without
copying the knowledge.

// C++ header.

std::pair<int, int> *GetPairPtr();
// C++ header imported in Swift.

UnsafeMutablePointer<(Int, Int)> GetPairPtr()

std::tuple is extra advanced and has extra viable implementation suggestions compared
to std::pair. As an illustration, std::tuple is specified by ahead expose by
libc++, and in backward expose by libstdc++. Attributable to this reality, if libc++ is frail,
there is a factual probability that the reminiscence structure of std::tuple matches the reminiscence
structure of the corresponding Swift tuple, and we would possibly presumably well also bridge them trivially.

The drawback of the methods described above is that they depend on
implementation details of the commonplace library, and as those alternate (or if the
person switches to a so much of commonplace library altogether), the API in Swift
would possibly presumably well also alternate as successfully.

Bridging std::span

The hiss with std::span is that it has a so much of API in Swift
looking out on whether T is const or no longer.

// C++ commonplace library.

template<typename T>
class span {
public: 
  constexpr T& entrance() const noexcept;
};
// C++ commonplace library imported in Swift.

// When T is non-const.
struct span {
  public func entrance() -> UnsafeMutablePointer
}

// When T is const.
struct span {
  public func entrance() -> UnsafePointer
}

// Must plan terminate one technique to import, can't hold each and every!

The finest technique to address that is to easiest import std::span as beefy
specialization (the fallback technique to import templates). Nonetheless, that will presumably well presumably no longer
be very ergonomic, and would terminate other templates that exercise std::span from
being imported as generics in Swift.

A extra ergonomic method would possibly presumably well presumably be to import std::span as two generic structs in
Swift, deciding on the suitable one looking out on constness.

// C++ commonplace library imported in Swift.

struct mutable_span<T> {
  public func entrance() -> UnsafeMutablePointer
}

struct const_span<T> {
  public func entrance() -> UnsafePointer
}
// C++ header.

std::span<int> GetMutableIntSpan();
std::span<const int> GetConstIntSpan();
// C++ header imported in Swift.

func GetMutableIntSpan() -> std.mutable_span<Int>
func GetConstIntSpan() -> std.const_span<Int>

Long-established C++ containers in regular

It appears to be like to be appropriate to offer an overlay that provides Swift.Sequence
conformances to C++ container forms.

Custom C++ containers

The importer would possibly presumably well also are trying to acknowledge custom C++ containers and synthesize
Swift.Sequence conformances, on the other hand, that appears to be like to be fragile: custom containers
continuously construct no longer put in power your full container API as required by the commonplace, or
deviate from it in delicate ways.

It appears to be like to be most attention-grabbing so that you just would possibly add Swift.Sequence conformances in overlays.

Bridging absl::flat_hash_{establish,plan}, absl::node_hash_{establish,plan}

Initiatives that exercise Abseil continuously exercise Abseil hash tables plenty extra than commonplace
containers. Nonetheless the identical is also lovely about other libraries, indulge in Enhance or
Qt. Attributable to this reality, privileging a third-party library in C++/Swift interop appears to be like to be
immoral. Abseil, Enhance, and Qt would possibly presumably well also tranquil be treated factual indulge in person-written
code. Library distributors can present annotations and Swift overlays to improve the
API in Swift.

Annotation workflow

Annotations in C headers are employed by the Swift / C interop on the present time (for
instance, nullability annotations). Nonetheless, these annotations would possibly presumably well also tranquil be added to
headers manually. How would possibly presumably well also tools infer annotations?

On-line inference at collect-time. The Swift compiler would possibly presumably well also infer annotations
from records available in the headers. As an illustration:

// instance.h

class Instance {
public: 
  int *get_mutable_value() { return &price; }
  // The Swift compiler infers that the return sort is `int _Nonnull` as a result of
  // the characteristic by no method returns nullptr.
};

The hiss with this method is that it is making API choices in line with API
implementation details, without letting the API owner to intervene. It’s miles going
to be fragile in the long speed: no-op changes to implementation details of C++
APIs can tip annotation inference one method or the opposite, and unintentionally
alternate the Swift API. Imagine that the instance above is refactored to:

// instance.h

class Instance {
public: 
  int *get_mutable_value() { return get_mutable_value_impl(); }
private: 
  int *get_mutable_value_impl(); // outlined in instance.cc
};

// The Swift compiler would now not know whether `get_mutable_value_impl()`
// can return nullptr or no longer, attributable to this reality its return sort is
// `int _Null_unspecified`. Attributable to this reality, the return style of
// `get_mutable_value()` is now changed to `int _Null_unspecified` as successfully.

API declarations would possibly presumably well also tranquil be the provision of truth for API records; this also
aligns with expectations of C++ API owners.

Offline inference. The troubles about inspecting implementation details for
inference would possibly presumably well presumably be alleviated if inference tooling produced a offer code patch
that is seemingly to be reviewed by a human and adjusted if an valuable earlier than being
committed.

The suitable choice is so that you just would possibly add annotations straight away to the header, to manufacture the API
contract obvious to all readers and API owners. Nonetheless, most frequently API owners
construct no longer have to alternate the header, or can’t be reached. In those cases,
annotations would possibly presumably well also additionally be added to a sidecar file, putting off the necessity to alternate the
header.

A sidecar annotation file lets in so that you just would possibly add arbitrary attributes to declarations
parsed from a header file. Yow will detect examples of such files in the apinotes
directory
. APINotes files
are dealt with by the APINotes library in
Clang
.
Clang reads an APINotes file alongside the header file; Clang injects attributes
specified by APINotes into the AST parsed from the header.

Tooling to infer nullability annotations

Nullability annotations in C++ headers are distinguished no longer easiest for Swift / C++
interop; they also file the supposed API contract to C++ API customers.
Nullability annotations would possibly presumably well also additionally be validated by static and dynamic analysis tooling
in C++ (e.g., UBSan would possibly presumably well also additionally be prolonged to detect assignments of nullptr to
_Nonnull pointers).

To infer nullability annotations we can exercise a combination of static and dynamic
analysis. Static analysis would possibly presumably well also infer nullability in extra obvious cases — alongside
with some self belief ranking, whereas dynamic analysis would possibly presumably well also present perception into
arbitrarily advanced APIs and files structures, with the unheard of caveat that the
inference outcomes are easiest as factual as the take a look at cases.

There would possibly be hundreds of present analysis about detecting nullability components in C and
C++ with static analysis, so we’re no longer discussing the compose of skill
static analysis tooling right here. Nonetheless, we’re no longer attentive to present dynamic
analysis tooling that infers nullability.

Nullability inference in line with dynamic analysis will exercise collect-time
instrumentation that’s equivalent to UBSan for references, however as a change of
producing a lethal error upon a nullptr retailer, we can fable this reality and
continue. For every offer-stage pointer variable and class member declaration,
the compiler will allocate a world boolean flag that tracks nullability, and a
utilization counter, that shall be frail to gauge self belief. The nullability flags are
initialized to “spurious” at program startup, utilization counters are initialized to
zero. Every retailer into the pointer variables is instrumented, and when a nullptr
is kept, the corresponding flag is determined to “lovely”. Both method, the utilization
counter is incremented. At program shutdown (or when signalled by hook or by crook), the
inferred nullability flags and utilization counters are saved to disk.

APIs that plan terminate a pointer and depend

Many C and C++ APIs plan terminate a pointer and depend. It would be nice if we would possibly presumably well also
import them as a buffer pointer in Swift, given appropriate annotations:

// C++ header.

void instance(int *xs, int depend);
// TODO: resolve out what annotations would possibly presumably well also see indulge in.
// C++ header imported in Swift.

func instance(_ xs: UnsafeMutableBufferPointer<CInt>)

The Swift compiler generates a header that C code can exercise.

TODO: add details.

TODO

Resilient forms

The semantic gap right here is connected to resilient forms — their measurement is unknown at
collect time. std::vector desires to take hold of sizeof(T) at collect time. This
is an everyday hiss in Swift-to-C++ bridging in regular, and it would possibly presumably well presumably be solved
with boxing. Containers for resilient Swift forms would hold a fastened measurement.

The topic of Swift/C++ interoperability has been discussed on Swift forums
earlier than:

Read More

Leave A Reply

Your email address will not be published.