C++ / Objective-C++ Interop

I recently started working at Facebook, and one of our big barriers to adopting Swift internally is our substantial use of C++/Objective-C++. (Primarily for ComponentKit) There are also concerns about ABI stability and the binary size increase, but these will improve over time. Are there plans for supporting Objective-C++ / C++ interop from Swift? Or would we have to shim / reimplement all of the C++ code if we wanted to adopt it?

14 Likes

(Objective-C)++ interoperability is something we absolutely want to support at some point. It's a large feature with some significant dependencies (e.g. modules will need to be built as (Objective-)C++ rather than (Objective-C)), so while we have a rough outline of how we would tackle things, it's not a solid plan. The outline, courtesy of @John_McCall:

  1. Switch Swift's Clang importer over to "Objective-C++" or "C++" mode (probably based on C++14 or even C++17), and start dealing with the fallout---we'll likely have to cope with C++ namespaces and using declarations, for example.

  2. Making C++ language features with obvious analogues just work in Swift: non-trivially-copyable C++ classes as value types, member functions as methods, non-const references as inout parameters, extensions on C++ types, etc. Much of this is straightforward, but will be a lot of work.

  3. Figuring out what to do with C++ language features without obvious analogues: non-copyable C++ classes, member pointers, reference members (C++ assignment semantics do not match our value semantics), etc.

  4. Figuring out what to do with uses of templates from Swift. This is difficult because the generics models are so different, and a "complete" solution likely involves intertwining Clang and Swift if we're going to, e.g., instantiate a C++ template with a Swift type as a template argument.

  5. C++ pattern recognition / annotation to become a more native-feeling API in Swift: importing types as reference types, std::shared_ptr, std::pair and std::tuple, etc. Lots of little pieces to design, implement, and test.

It's not clear how far one has to get to make a usable C++ interoperability story.

Doug

12 Likes

Hey Doug, thanks for the thorough response! I’m curious, several of the C++ features you mentioned have been often requested (or are planned) for Swift. (E.g. C++’s variadic generics, templating over a value for fixed size arrays, and namespaces). Do you think the problem will become more tractable as progress is made on those features? Also do you think it’s possible we’ll see some kind of Swift++ developed to improve the interoperability? I think one of the great things about Obj-C++ was its opt-in nature. You use it where/when you need it.

None of these things will make the implementation easier. Rather, they'll allow more of C++ to be mapped over to Swift in a reasonable manner... and make the Swift/C++ interoperability implementation effort bigger because there are more C++ constructs that have Swift equivalents.

I don't think we need a "Swift++" or similar; we should map those C++ constructs that can be mapped well, and let people wrap up those that don't map well.

Doug

2 Likes

What exactly do you mean by "let people wrap up [constructs] that don't map well"? Is this similar to what we currently do with Objective-C, or will it end up being "add a shim to convert things that don't work in Swift to things that do work"?

If some C++ construct cannot be mapped to a Swift equivalent, then that entity will not be visible to Swift. There are a small number of cases where this happens with Objective-C code, e.g., variadic functions get completely dropped, e.g., this C function:

extern void someFunc(float x, float y, float z...);

won't be visible in Swift at all. The same will happen with any C++ construct we can't handle. The fix is to write wrappers in C(++) that can be mapped to Swift:

inline static void someFuncForSwift(float x, float y, float z) { someFunc(x, y, z); }
inline static void someFuncForSwift(float x, float y, float z, float a) { someFunc(x, y, z, a); }
inline static void someFuncForSwift(float x, float y, float z, float a, float b) { someFunc(x, y, z, a, b); }

Doug

4 Likes

My strongest language is C++ (vanilla not Objective C++) so it would be splendid if Swift adds interop support for C++! I'm glad this is something you guys would like to implement in the future :slight_smile:

There are also certain data structures which Swift seems to refuse to want to implement natively, like a map container that supports both hashing and can be walked inline in sorted order without duplicating the data.

Basically any data structure which simultaneously supports n lg n or better performance and maintains sort order is not implemented natively in Swift or any other language which Swift currently supports in interop. But it does exist in vanilla C++. Like std::map

Not having support in Swift for C++ interop will cause its slow demise, so please implement soon lol

The fact that a particular data structure doesn’t exist in the standard library today isn’t a refusal to implement it, but a matter of priorities. We’d like to flesh out the data structures supported in the standard library over time. You can also look at libraries outside the standard library, like @lorentey’s BTree library: BTree/README.md at master · attaswift/BTree · GitHub Sorted tree data structure libraries are available in almost every language, not only C++. C++’s std::map is convenient to use from C++, but it makes some design tradeoffs that limit its performance potential compared to other tree implementations, so it would be unlikely to be the best choice of data structure to use from Swift even if C++ interop were available (and there are almost always better choices even from C++).

7 Likes

thanks for thoughtful reply! in the many many years since objective-c or objective c++'s inception, sorted map or sorted dictionary never came to them. based on that i have reason to believe apple devs don't want the data structure natively supported. 30+ years is a long time to wait for a native optimized always-sorted data structure implementation. i hope you open source swift folk are more forgiving to allow the data structure native support in swift despite its drawbacks (which i know of thanks for bringing that up).

please leave it up to the dev to choose the data structure. map has been implemented in c++ standard specification for how many years? and your feedback not to implement it natively in swift is that there are more efficient data structures! for shame :hushed:. there is a time and place where this data structure is the best for the job. not out of convenience, but for it to truly be the best data structure for the job. otherwise we should look down upon C++ condescendingly that they should ever dare to include such an inferior data structure such as std::map into the standard.

it is ok if you don't like std::map and would prefer it not to be a native data structure in swift then give me c++interop instead. i would prefer not to use a 3rd party solution. one or the other please, native always-sorted n lg n or better optimized data structure in swift or c++interop to use std::map. if you took the time to implement it natively i'm sure it could be made better past the current academic progress. you hinder advances to the data structure by believing it cannot be improved i'm sure once it is in there and part of the swift standard it can have new discoveries and may be the topic of a future phd dissertation. it stays slower and less optimized because no one uses it.

it is ok to get to it later but maybe take less than 30 more years i am hoping.

my colleague created a custom hiearchical hash map structure three layers deep with an alternate data structure for fallback. this data structure always maintained sorted order and could be iterated through at any time in order. i think its purpose was part of a realtime image processing tool for cheating at online gambling (this was like 16 years ago). after the third collision, it would start as array in fallback and manually maintain sort after each operation within the same colliding hash. but eventually it would change from array to red-black tree based on a heuristic for when a large enough array would become more expensive to maintain than a red-black tree (his hash map, my red-black tree because at the time std::map and his own red-black tree implementations were both slower than mine). my red-black tree also had built-in internal memory management either as fixed size or non-fixed similar to ideal deque. that experience alone seems like it would make an always-sorted optimized data structure a worthy candidate to 1st party inclusion in any sufficiently complex programming language that includes a standard library as a part of its standard specification.

its the same like double double or quad double, when i originally ported QD from C into C++ / C# and had to maintain it myself (I think it has its own lightweight C++ wrapper now which they added years later).

http://crd-legacy.lbl.gov/~dhbailey/mpdist/

for lower level data structures there is something lost for their implementation as 3rd party versus 1st party. core data structures should be played close to the chest, and have a bigger benefit to being 1st party versus a higher level 3rd party library like a UI framework.

a high quality always-sorted data structure if 3rd party can eventually be adopted as an optional part of the standard similar to how c++ technical reports sometimes start as optional components in current versions of the standard and are eventually rolled into a future version of the standard as a requirement.

i am glad any compatible implementation exists 3rd party or not but i've been burned enough by 3rd party low level data structures that i am confident ease of use, adoption, and finding and fixing bugs may be an order of magnitude easier if such a thing were a 1st party component.

also i already have my own custom implementation of self-balancing red-black trees which is another reason i am less interested in a 3rd party solution. i've brought this up several years ago in the apple dev forums before swift went open source and got basically the same reaction, except last time there was not even a good 3rd party solution.

i think my original threads are gone since the apple dev forums revamp in 2015, so these links probably don't work (a quick try seems to fail though i might have to be logged in first)

my original red-black balanced binary tree code is here (2003 self-extracting zip as exe) but i've rewritten it at least twice since then (this is before i started using source control). so the code linked here is total crap but i thought i would put my money where my mouth is. i'll have to dig in my backup drive or dropbox for newer versions including the swift port i did and had linked to in the apple dev forum threads back in 2015 and had given away the ip to use as an example for a native implementation (i was between jobs at the time so could give away my code).
http://robert.seattleholograms.com/Robert_Aldridge.exe

ah i checked in dropbox i had a version that was heavy on C interop i don't remember if the native swift version ever worked. this may have been a work-in-progress swift version. i was still figuring out the subtleties between swift's struct and class. copy-on-write may not have been well understood at the time. early 2015.

right the community owes me nothing. i understand that. though i am also talking about the 30+ year history of objective c and slightly shorter history of objective c++ never rolling in an always-sorted optimized data structure. the history of the issue is not just with swift. sorry if i come off so negative i've been waiting almost as long for a similar data type to be added to native java i still don't think it exists. c# i think has SortedList though i'm not sure that data structure is optimized internally.

c++ might be unique in that it tackles so many data types natively even the ones that are either inefficient or difficult to implement. stp::map is great though my favorite is std::deque since a perfectly implemented deque is effectively constant cost for nearly all operations including the cost of underlying memory management if you fudge the bit depth as a constant factor and then drop it out (though a properly abstracted list data type could internally use deque). some of the pushback may also be that swift prefers to not expose underlying data types but only what is at the higher level. it makes sense to have a few highly-abstracted high level data types though i think it would be a mistake to not also expose some of the inner data types directly for specialized use.

i am grateful for all the responses even the negative ones thank you.

ps off topic: i'm also waiting for apple's custom a series gpus to add native double precision support (i can't deal with single precision). the hard ai push for half precision support in gpu is not helping my cause (it practically mocks me). i am an evangelist for double double and quad double. though unless i am pushing for ieee quad double support in swift this is unrelated.

:+1:

...So C++ interop is really coming see https://mobile.twitter.com/jeremyphoward/status/1154974115893149696 ? Great. Is it already in the snapshots (5.1?), where can I follow the progress?

2 Likes

That’s currently being worked on by the TensorFlow team at Google. As far as I know that particular work has not made an appearance in the swift /master branch. You could follow along at the Swift /tensorflow branch. That’s not to say the efforts aren’t in line with the broader Swift roadmap.

1 Like

All the work has been done in swift/master protected behind a frontend flag. The linked example (and more) should already work from nightly snapshots.

6 Likes

Has anyone done some early tests with the snapshots?

sounds great!

This was more than a year ago, did those snapshots land in a release yet? In other words - does Swift 5.3.2 support direct C++ interop?

1 Like