Bridging Swift Enums with Associated Values to C++ (GSoC)

Hello, @Alex_L and everyone in the Swift community,

My name is Tongjie Wang, and currently I am a Master student in Computer Science at the University of Southern California. I am looking forward to participating in this year's GSoC event, and I am interested in the Bridging Swift Enums project.

I have some experience in Swift and C++. For example, I have created an iOS keyboard in Swift, and I am currently using C++ for my 3D graphic course project. I also tried reusing my calculator logic (in C++) in my iOS calculator app (in Objective-C) when I was learning Objective-C. So I believe C++ Interoperability in Swift is a nice thing to have, since it allows developers to reuse existing libraries more easily.

It is my first time participating in open source events like GSoC, and I am new to open source projects. Thus, I really appreciate any guidance on the next steps or suggestions in general. I believe that with this opportunity, I can learn more about C++ and Swift, how open source project works, and how people cooperate.

Thanks for reading my post. I appreciate your time, and I hope you are all doing well.

Thanks,
Tongjie Wang

4 Likes

Hi @tongjiew, and welcome to the community! Thanks for voicing out your interest in this.

I can provide you with some additional insight into what this project entails. I am working on teaching the Swift compiler how to generate a C++ header that is able to represent Swift types , so that they can be used from C++. Swift enumerations will be represented using a C++ class type, with the underlying enum value being stored inline, or boxed up on the heap, depending on the layout of the Swift type. Enumerations without associated values will have a case value that's accessible from the class itself. For example, a Swift enum CompassDirection:

enum CompassDirection {
  case north
  case south
  case east
  case west
}

will be mapped to the following C++ class with an interface similar to this one:

class CompassDirection {
public:
  static const CompassDirection north;
  static const CompassDirection south;
  static const CompassDirection east;
  static const CompassDirection west;

  enum class cases { north, south, east, west };

  cases operator cases() const { ... }
};

which could then be used from C++ in a switch like this:

CompassDirection getOpposite(CompassDirection cd) {
  switch (cd) {                       // implicit conversion to CompassDirection::cases
  using enum CompassDirection::cases; // allow name lookup to find enum cases.
  case north:
    return CompassDirection::south;
  case south:
    return CompassDirection::north;
  case east:
    return CompassDirection::west;
  case west:
    return CompassDirection::east;
  }
}

This approach would need to be extended to work with enums that have associated values. For example, it would be reasonable to map a Swift enum like this:

enum Barcode {
  case upc(Int, Int, Int, Int)
  case qrCode(String)
}

To a C++ class like this one:

class Barcode {
public:
  Barcode() = delete;

  enum class cases { upc, qrCode };

  operator cases() const { ... }

  using UpcType = swift::Tuple<swift::Int, swift::Int, swift::Int, swift::Int>;

  // Returns true if the Swift enumeration is of case Barcode.upc
  bool isUpc() const;

  // Extracts the associated valus from Barcode.upc enum case
  UpcType getUpc() const;

  // Returns true if the Swift enumeration is of case Barcode.qrCode
  bool isQrCode() const;

  // Extracts an associated value from Barcode.qrCode enum case
  swift::String getQrCode() const;

  static Barcode initUpc(swift::Int, swift::Int, swift::Int, swift::Int);
  static Barcode initQrCode(swift::String);
};

The goal of this specific GSoC project then would be to extend the C++ header generator in Swift to emit C++ class declarations (with implementation) for enums with associated values, like in the Barcode example above.

If you're interested in this project, I think the next step that GSoC suggests is to start working on writing a project proposal based on this idea. Feel free to post your proposal draft on the forums, so that we can provide some feedback for you to help your proposal. In addition to that, I would also recommend reading through getting started docs for Swift, to get a sense of how you can setup a working environment for you to work on the Swift compiler:

Cheers,
Alex

4 Likes

Thanks for your detailed reply and for clarifying how this project works! I will start setting up the environment and later write the proposal's first draft. In the meantime, I have some small follow-up questions.

First, is this project only focused on "Swift to C++," or will it later let Swift code access these enums from C++ code? I ask this question because the project outcomes mention "enable C++ users to pass Swift enumerations with associated values to C++, and vice versa."

The second question is that since the functionality lives inside the Swift compiler, how familiar to the compiler should I get? I found this link on the Swift website talking about compiler architecture. Is there any component I should get familiar with?

Again thank you for your reply. It really helps me how to get started.

Tongjie

1 Like

I ask this question because the project outcomes mention "enable C++ users to pass Swift enumerations with associated values to C++, and vice versa ."

That's a very astute observation. This project is primarily focused on "Swift to C++", so we will need to allow C++ users to pass Swift enumerations to Swift functions that we're calling from C++. In the context of this project, the "vice-versa" refers to a Swift function/method returning an enum value that can then be used from C++.

In the future we will also need to teach Swift how to import a C++ function signature that receives such a type, and how to pass the enum to it correctly during a call in Swift. That is not something that needs to be done as part of this GSoC project though.

The second question is that since the functionality lives inside the Swift compiler, how familiar to the compiler should I get? I found this link on the Swift website talking about compiler architecture. Is there any component I should get familiar with?

For sure, getting familiar with the compiler would be useful. I think that getting familiar with how current Swift to Objective-C interoperability works is best for this project, as that model closely resembles the high level approach that will be adopted for C++. Apple has some high level documentation on this topic that could be useful here - Apple Developer Documentation . If you'd like to dig into the Swift codebase itself then you should checkout the libs/PrintAsClang library in the Swift codebase to see how it's implemented.

2 Likes

Hi, I managed to build the Swift compiler on my machine, and now I am working on the proposal. I have a quick question regarding the implementation detail.

If we want to emit a C++ class with implementation, how do we deal with init and init? initializers (if they exist)? Do we map them into C++ constructors or static functions? Or is this out of the scope for this GSoC project? I ask this because it will help me set up more reasonable implementation details and project timelines. I'm sorry if I bother you too much before the event start. I know you may be busy, and I appreciate your time and reply.

1 Like

Good question! The plan right now is to emit a static init member function in C++, that will return the constructed value. init? will map to an init static member function that will return an optional value. Also, you don't have to worry about any overload ambiguities between different inits in your GSoC as well, as issues related to overload ambiguities in C++ will be handled outside of this GSoC project.

2 Likes

Here's my proposal: Proposal for GSoC 2022 - Google Docs. Feel free to leave any comment or suggestion :slightly_smiling_face: Thanks for the reply in advance!

1 Like

Looks good! I did a quick editorial pass and it seems pretty good to me; Not commenting on the proposal contents though, that's up to @Alex_L to review :slight_smile:

Thanks for sharing the proposal for review early!
Please don't forget to submit it in the website before the deadline, with review or without :)

1 Like

Actually, I've sent my proposal to @Alex_L for review, and he gave me valuable feedback. At first, I was too nervous about posting it publicly, but now I think if this gets selected, a considerable number of users will use this feature, so it may be beneficial to post it publicly and listen to the community for feedback (since there are still some days before the deadline).

1 Like