Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Idea] Use C++ instead of C for FFI #227

Closed
andre4ik3 opened this issue Jun 6, 2023 · 5 comments
Closed

[Idea] Use C++ instead of C for FFI #227

andre4ik3 opened this issue Jun 6, 2023 · 5 comments

Comments

@andre4ik3
Copy link

andre4ik3 commented Jun 6, 2023

At WWDC, Apple announced that Swift now has out-of-the-box C++ interop. There will be a session about it tomorrow:

efd92c91550d5169b4b8c577f6fb862e

So the idea is: can the C FFI be replaced with C++, and would it be beneficial? C++ is still a far cry from Swift, but it is closer. I believe replacing C exports with C++ can help ease implementation of new features in swift-bridge, bringing it closer to a seamless bridge. It can also simplify the generated Swift code.

Disclaimer: I'm not an FFI expert by any measure, the most FFI I have written myself is a basic one between Rust and C#, and it barely worked. So this may not be beneficial at all, but I still want to bring it up because it's a thing I immediately thought of when seeing the announcement in WWDC.

@andre4ik3 andre4ik3 changed the title [Idea/Suggestion] Swift's new C++ interop [Idea] Use C++ instead of C for FFI Jun 6, 2023
@chinedufn
Copy link
Owner

chinedufn commented Jun 6, 2023

Thanks for bringing this up and sharing your ideas and thoughts.

This reminded me of the cxx Rust library, which does something similar to swift-bridge, but for C++, and it is more stable and complete

In what sense is it more stable and complete? What criteria are you using? (not a challenge, I'm just trying to understand your use case better.)

I believe replacing C exports with C++ can help ease implementation of new features in swift-bridge

Do you have an example of what you mean by this?

@andre4ik3
Copy link
Author

In what sense is it more stable and complete? What criteria are you using? (not a challenge, I'm just trying to understand your use case better.)

CXX has stuff like slices, boxed values, arrays ([T; N]) implemented. Also it has more contributors and is more widely adopted, meaning naturally it will be more stable since there are more eyes on it. In the CXX documentation, it calls itself as "a replacement for extern "C" in a sense", maybe that explains what I mean better.

The new C++ Swift interop means that in most use cases (e.g. just passing strings, structs, enums, etc. across the language border), CXX can be used instead of swift-bridge altogether, and then Swift can interop with that. Although I can't really confirm it since I don't have access to the Xcode beta.

Do you have an example of what you mean by this?

For example, arrays can be implemented just by exposing them as a C++ API and then letting Swift interop with it.

BTW, the session is live, and there are some more details (although still not everything) about the new bridging layer they have. Here are some screenshots from it:

C++ -> Swift APIs
CleanShot 2023-06-07 at 18 48 02@2x

Some Swift APIs in C++ (not complete list)
CleanShot 2023-06-07 at 18 48 36@2x

Some C++ APIs in Swift (not complete list)
CleanShot 2023-06-07 at 18 48 46@2x

Again, this whole thing is an idea. It could make the package simpler, or it could make it more complicated. I just saw that the project has slowed down over the past few months and some stuff is still not implemented, so I am suggesting this as a way of implementing it. Not an FFI expert whatsoever so please correct me on anything that I got wrong :)

@chinedufn
Copy link
Owner

Thanks a lot for the additional context. I'll address your thoughts:

Also it has more contributors and is more widely adopted, meaning naturally it will be more stable since there are more eyes on it

If by stability you're referring to API churn, that isn't much of a concern I don't think since swift-bridge's APIs are fairly stable.

If you're referring to the likelihood of bugs, I'm also not weighing this highly since swift-bridge's test suite is fairly robust.'

CXX has stuff like slices, boxed values, arrays ([T; N]) implemented

cxx's type support is motivated by common C++/Rust interop use cases.

For example, cxx doesn't support Option<T>. I don't write C++, but I'm assuming that options can't be all that common if they aren't yet suppoted by cxx.
swift-bridge implemented support for Option<T> very early on since Swift/Rust both have a very commonly used Option{al} type.

Adding support for new types to swift-bridge is relatively easy. When it isn't it's almost always because of some Swift language
consideration ( example: #152 ). cxx won't have solved these Swift related considerations
since it isn't focused on Swift.

The new C++ Swift interop means that in most use cases (e.g. just passing strings, structs, enums, etc. across the language border), CXX can be used instead of swift-bridge altogether

If you're implying that we might be able to use cxx's bridge module macro, we'd lose the ability to have our own custom attribute such as https://github.com/chinedufn/swift-bridge/blob/master/book/src/bridge-module/opaque-types/README.md?plain=1#L210-L220

If you're implying that we might be able to use cxx's codegen machinery to power our codegen, that would just be adding an extra complex dependency to help with something that would be easier and better to keep in tree
(tighter control over the exact code that is generated).


So yeah, I don't think that cxx would help us in any meaningful way.

On the other hand, there may still be ways to take advantage of the new Swift and C++ interop directly ourselves. We should definitely research that.

Again, this whole thing is an idea. It could make the package simpler, or it could make it more complicated.

Gotcha.

I'm very interested in anything that you think might simplify our codegen or more easily support some kind of interop, without making the user experience more complex for end users.

Is there a specific example of a change that you would want to see made to some of our codegen? You can see a lot of our current codegen in here https://github.com/chinedufn/swift-bridge/blob/master/crates/swift-bridge-ir/src/codegen/codegen_tests.rs#L30-L53

I just saw that the project has slowed down over the past few months and some stuff is still not implemented

Thanks a lot for expressing the concern. My commits started to slow down when all of the features that I needed were implemented. (I maintain a mission-critical production application that uses swift-bridge on iOS)

It looks like Swift 5.9 has some useful stuff that I'm interested in taking advantage of (such as to solve #155), so I might have a spurt of commits around that.

Not an FFI expert whatsoever so please correct me on anything that I got wrong :)

Ha no worries, I guess it's hard to comment since there isn't an exact change that's being proposed. I appreciate you bringing up the idea. I've been monitoring some new Swift features that we might be able to take advantage of so this is timely.

I'll leave this issue open until I look through all of the new Swift/C++ interop and see if there is anything that we can use to solve real problems that we have. Feel free to suggest as well.

@andre4ik3
Copy link
Author

andre4ik3 commented Jun 7, 2023

Ok, sounds good. I agree, if swift-bridge is stable and it's already being used in production then there's no point overcomplicating it by adding another dependency that would actually limit what swift-bridge itself can do in codegen.

In terms of other features of Swift 5.9, maybe the ownership features are worth taking a look at? In this session they show that you can make a class not inherit from Copyable and have consuming funcs, which could more closely reflect what Rust has (e.g. &self vs self in methods). Actually I found something interesting about it, I'll make a second issue since it's not really related. Nevermind, I rediscovered #155 haha. But yes, in Swift 5.9 the consuming operator is stable, but it wouldn't be func __consuming, it'd be consuming func.

I'll try seeing if I can help in any way to implement some new types :) Feel free to close this issue if there's nothing in the new interop that can help you

@chinedufn
Copy link
Owner

Yup we totally want to explore Swift's new ownership features.

I'll add a link to that video to issue 155's body

I'll try seeing if I can help in any way to implement some new types

That would be awesome! This could be a good one to get your feet wet #187

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants