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

Consider adding support for Swift interop? #524

Open
silvanshade opened this issue Oct 14, 2023 · 1 comment
Open

Consider adding support for Swift interop? #524

silvanshade opened this issue Oct 14, 2023 · 1 comment

Comments

@silvanshade
Copy link
Contributor

Something I've been thinking about lately is that it might be interesting to start seriously considering Swift interop, or at the very least keep that possibility at the forefront with regard to any design decisions going forward.

Now that cxx-swift is starting to become usable, and I've managed to find a nice solution (which should be ready for testing next week) for distributing the Swift libraries on all the major platforms at build time, this means we should have access to basically the entire Swift compiler library tooling, not just ClangImporter.

Notably, one of the other Swift library components that looks quite interesting is PrintAsClang, which lets you dump a Swift module declaration as a clang header.

Theoretically, it seems like we should be able to use this functionality, along with the existing Objective-C to Rust translation semantics, to obtain a usable translation from pure Swift modules.

I haven't tried to use it at all yet so I don't know how well it works, but it's something to consider.

That also begs another question: if we have to rewrite a significant part of the header-translator in order to work with ClangImporter, would it maybe be a better idea to implement the new translation logic as a mapping from Swift to Rust (as much as possible anyway), rather than from Objective-C to Rust?

After all, ClangImporter is primarily meant to provide Swift modules, it just happens that (the way I understand how we would use it currently) we ignore that part and instead ask for the loaded Clang modules, so that we can iterate over those directly.

Reasons why it might be interesting to work with the Swift modules instead of the Clang modules:

  • it would provide a way for us to implement Swift interop for pure Swift frameworks
  • perhaps Swift is a cleaner target for mapping to Rust, and potentially already provides a lot of the semantic information (e.g., with regard to attributes, naming, derived declarations, etc.) we would have to reconstruct ourselves from the Clang modules
  • this might be a better approach for working toward Improve Xcode support #459, since we also have access to the Swift compiler IDE support, which is what Xcode uses internally

Any thoughts on this?

One thing I was just thinking might be a downside to this is that most of the existing major frameworks are still implemented in Objective-C even when they have Swift interfaces. But I'm not sure this is really a problem because, at least for now (though extern "crabi" may change that), we would still have to link using the C FFI, so it's not like there would be a performance overhead in that regard. What we would gain would still be potentially cleaner and more universal translation semantics and the ability to leverage the other compiler libraries like the IDE support.

@madsmtm
Copy link
Owner

madsmtm commented Oct 26, 2023

Theoretically, it seems like we should be able to use this functionality, along with the existing Objective-C to Rust translation semantics, to obtain a usable translation from pure Swift modules.

I think the main difficulty here is that interfacing with Swift requires interfacing with the Swift runtime as well, which is quite underspecified and objc2 is definitely not suited to handle it. Additionally, the Swift calling convention is... complex, to say the least.

We'd basically need to develop an entirely new library with a similar, if not greater, scope to objc2. This has already been worked on by others a bit, I'll link a few of the projects I know of that does some of this:

I'm not fundamentally opposed to doing all of this in this project, but I think we should focus our efforts on Objective-C, since there's still lots to do on that front.

That said, I do believe we could support Swift modules that expose an Objective-C interface, i.e. Swift classes and methods that use the @objc attribute. I suspect having just that will likely solve 80% of the use-case for Swift/Rust interop, the user would just have to add @objc to their Swift class, run header-translator, and boom, it'd be usable from Rust.

That also begs another question: if we have to rewrite a significant part of the header-translator in order to work with ClangImporter, would it maybe be a better idea to implement the new translation logic as a mapping from Swift to Rust (as much as possible anyway), rather than from Objective-C to Rust?

After all, ClangImporter is primarily meant to provide Swift modules, it just happens that (the way I understand how we would use it currently) we ignore that part and instead ask for the loaded Clang modules, so that we can iterate over those directly.

I'm not sure I understand the difference between a Clang and a Swift module? Are Clang modules more C-centric? Do Swift modules contain more information / are structured differently?

As long as we can confidently figure out "this method uses the Objective-C calling convention, and this uses the Swift calling convention", then I see no reason to not use the (presumably) more descriptive Swift modules.

Reasons why it might be interesting to work with the Swift modules instead of the Clang modules:

* it would provide a way for us to implement Swift interop for pure Swift frameworks

I agree that preparing for that future is a good idea.

It would also make sense to consider future C++ support in all of this, although definitely low priority.

* perhaps Swift is a cleaner target for mapping to Rust, and potentially already provides a lot of the semantic information (e.g., with regard to attributes, naming, derived declarations, etc.) we would have to reconstruct ourselves from the Clang modules

I agree that this is a good point, our naming should definitely follow Swift's naming instead of the Objective-C naming.

* this might be a better approach for working toward [Improve Xcode support #459](https://github.com/madsmtm/objc2/issues/459), since we also have access to the Swift compiler [IDE support](https://github.com/apple/swift/tree/main/lib/IDE), which is what Xcode uses internally

I'm too unsure of how better IDE support is going to work to really comment on if this would help us or not.

One thing I was just thinking might be a downside to this is that most of the existing major frameworks are still implemented in Objective-C even when they have Swift interfaces. But I'm not sure this is really a problem because, at least for now (though extern "crabi" may change that), we would still have to link using the C FFI, so it's not like there would be a performance overhead in that regard. What we would gain would still be potentially cleaner and more universal translation semantics and the ability to leverage the other compiler libraries like the IDE support.

I think my general point is that as long as we still emit the same objc2::extern_class! and objc2::extern_methods! macro calls, then I think using Swift modules as an intermediary is a great idea!

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