C++ Interop workgroup meeting notes (Mar 23rd 2022)

This post contains the summarized meeting notes from the Swift and C++ interoperability workgroup sync-up meeting from the 23rd of March.

Attendees: Adrian_Prantl, compnerd, Alex_L, CaelanMacArthur, bro4all, bulbazord, richard, mikepinkerton, dabrahams, plotfi, zoecarver, NuriAmari

Action Items

  • Alex_L: to add an issue that tracks the naming issue for std module and namespace as something that needs to be resolved before initial “supported” release of interop.


Alex_L went over some community updates:

  • The workgroup has a new private section on the Swift forums. Please post internal discussions/updates there.
  • JIRA bugs are moving to Github! We should do a pass over the interop bugs to re-classify them once the transition is complete. Zoecarver mentioned that it will help us track the adopter issues better, as we’ll create labels for each early adopter.
  • We will continue the workgroup’s contributor Q&A support meetings.

Alex_L: Last meeting (C++ Interop workgroup meeting notes (Mar 14th 2022)) we discussed the naming of imported libc++’s std module and namespace. For now we decided to shelf the discussion of this topic until we refine some of our other goals and problems. We’ll keep track of this in the roadmap as something we want to resolve by the initial supported version of interop.

Alex_L with the help of zoecarver wrote and/or transcribed from existing manifesto a number of sections of the overview/vision/goals high level document. We would like to land it on Github in the next week or two so it will be publicly accessible. Alex_L then presented the different sections of the document to the workgroup:

  • Editor integration and refactoring tooling goal section is essentially identical to the existing manifesto document.
  • Good debugging support is an important goal to have and we now have a section describing the desired workflow as well.
  • The reverse interop section briefly touches on what we want it to do and the high level goals we have for reverse interop (using Swift APIs from C++).
  • The forward interop section is not yet complete. We have some goals distilled from the existing manifesto and some goals we added.
  • The object model section is not yet complete but we will work on refining it.
  • The section on bridging standard library types is fairly complete. We do not intend to support automatic bridging between C++ and Swift standard library types like string and vector/Array. The user would need to use the specific language-dependent types and we will provide some utility APIs for them to convert between the related types from different languages. Dabrahams mentioned that in case of going from vector to Array, we should use the existing Array constructor that takes in a Sequence, as we intend to conform vector to it. Zoecarver mentioned that it will encourage people to write good Swifty generic code.

The workgroup the discussed the proposed overview/vision/goals document:

  • zoecarver: Two more goals for forward interop. One is just for preserving semantics that the APIs are written with. And C++ APIs should work out of the box, without shims and extensions, and they should still be usable without annotations.
  • dabrahams: I wonder about the goal of preserving semantics. C++ types can have a copy constructor with side effects. Are we saying that you get to be guaranteed that you'll observe the side effects for every potential copy. I think there's lots of reasons we don't need to do so many copies, so are people going to insist on strict preservation of semantics for that?
  • zoecarver: We want the copy constructor to be used when we copy something. For templates, we want them to be specialized. For copies specifically we can say that copy still has C++ language semantics for copying an object, but the Swift compiler doesn’t have to do so many copies.
  • dabrahams: It's a question of being really clear about what you consider the semantics of the API. There are semantics that come out of the combination of the behavior of the API and and the language. So in C++ when you pass something by value to a function, it gets copied and you can observe that copy. So if we want to not require that copy to happen on the Swift side, I think we should be kind of real clear about that rather than allowing that to be implied by some language about API semantics being preserved (in the doc).
  • zoecarver: I think there’s a way to separate out the semantics of the language from the semantics of the API. We can state that in C++ a copy operation happens when you pass something to a function and that’s the semantics of the language we don’t have to preserve, as Swift is a different language. And if the API defines a copy constructor for the type we should preserve those semantics so it’s not a bit copy, but a copy actually does invoke the copy constructor.
  • dabrahams: I'm a little unsure about the support for bridging specific types as reference types (in the object model section). Swift today has a concept of a reference type, which is a thing that has a reference count. The only way to bridge something as a reference type into Swift is to actually use Swift’s reference count and matching object layout as well.
  • Alex_L: We have experimental support for unsafe foreign objects that are bridged using reference semantics from C++.
  • dabrahams: We need more specificity. We could mention an unsafe reference type or something like that?
  • Alex_L: You’re right, we need to be more specific here.
  • compnerd: One thing to be careful about is, when you say foreign objects, there's already a concept of foreign object type within Swift that has exactly what you're describing. That's how core foundation is imported and it's confusing if you're saying that it's a foreign reference type.
  • Alex_L: Makes sense, we should not conflate the terminology here.
  • dabrahams: I think the way I think about the ability to bridge things as reference types is, that it’s a potentially good idea for some sugar that we won’t actually know is a right idea until we solve the move only type problem, because it might make sense to use those mechanisms instead. It might not make sense to mention unsafe foreign objects as that’s still a research topic. You could always use an UnsafePointer to create a reference to something instead, and so unsafe foreign objects just help you with the ergonomics.
  • zoecarver: What about non-movable non-copyable type? I don’t think we can use that with UnsafePointer as pointee copies.
  • dabrahams: That has to be fixed, Swift is generating a copy we do not need. So, there's no reason that that shouldn't be a guaranteed optimization (to elide the copy).
  • zoecarver: In that case the UnsafePointer type would need to become much more of a compiler thing than it already is and moved out of the library.
  • dabrahams: The standard library already blesses certain types and implements others with some specific compiler annotations that tell the optimizer to do certain things.
  • zoecarver: Right, that’s something we can do. But we need to figure out how we want to import that kind of type.
  • dabrahams: The difference is whether you use an existing thing in the language and change its implementation (i.e. UnsafePointer) or whether you add a whole new feature. It feels like the goals document should be at least starting by committing us to the minimum necessary features to actually use every piece of C++ that we want to use.
  • zoecarver: That's a fair point. We should probably rephrase this to say something about, like types with reference semantics and how they’re bridged instead of suggesting that we use unsafe foreign objects as the canonical solution for that.
  • dabrahams: Additionally, there should be a section in the list of problems with Swift that we need to overcome in order to make bridging effective. For example, too many copies is a problem that we need to resolve. So we should have a section that describes what are the other gaps that we have that need to be filled in in the language itself in order for this project to be successful.
  • richard: Is reference type semantic support required for C++ classes that acquire and release resources (RAII)?
  • dabrahams: That’s more on the destructor semantics side.
  • zoecarver: For structs/classes that are imported from C++ today on main when they are destroyed we use the C++ destructor.
  • Alex_L: Yes, the value will be destroyed at last use.
  • compnerd: How does RAII work currently? Would you need to use withExtendedLifetime?
  • Alex_L: Yes.
  • dabrahams: We should have guarantees on using defer to extend the lifetime of something. The compiler is allowed to optimize that out right now.
  • zoecarver: There’s another question of whether this should be done by default for all C++ types.
  • dabrahams: No.