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

Adding support for Swift / Moving away from Obj-C on Apple platforms #747

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

TheRogue76
Copy link

@TheRogue76 TheRogue76 commented Dec 14, 2023

This proposal aims to define a possible design for how we can move away from Obj-C on Apple platforms, and what challenges we might face along the way and what needs to be done to get there. It is a continuation of the work setup by #253 and facebook/react-native#41896 .

Please feel free to leave comments, edits and thoughts on this proposal as well as any challenges that you feel might block such a change so we can define the scope of the work that might be needed and how / if we should go about doing this.

Special thanks to @cipolleschi for the instructions on how to setup this RFC

A rendered version of the proposal can be read here

Copy link

@cipolleschi cipolleschi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @TheRogue76 Thanks for opening this RFC. I left some comments with more context.

To set expectations, our plans for next year are to double down on the New Architecture work. The final goal is to remove the old architecture (we don't have an estimate yet of when this will happen) but we will not have capacity to work on Swift support unfortunately.

As soon as the New Arch is out of the door and the old arch is deprecated, I hope we will have more bandwidth. It will also be easier as we won't have to support both architecture but we will be able to only focus on the New one.

The motivation for this change is threefold:
- As of Swift 5.9, Swift is now capable of direct interop with C++, Which was one of the primary reasons Obj-C and Obj-C++ were still required within the repository. While the development [is still ongoing](https://www.swift.org/documentation/cxx-interop/status/) and there are [constraints that still exist](https://github.com/apple/swift/issues/66159), Apple's end goal is to reach the needed API parity to work seamlessly between Swift and C++
- Obj-C is relatively hard to write and maintain for, and it is reflected by the [community](https://github.com/react-native-community/discussions-and-proposals/issues/104). Having a modern language that is more readable, more performant(in some cases) and [safer from certain class of errors](https://developer.apple.com/swift/#safety) means that users and library maintainers alike can produce better quality code and take advantage of the underlying platforms easier if they need it
- As Swift evolves and becomes more feature rich, there is a possibility that Apple will begin to remove support for Obj-C in it's toolchain. The documentation for the various APIs that Apple provides may also be moved to simply having Swift as the supported language.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on top of it, more recent frameworks produced by Apple are Swift only (Swift Data, for example)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very true. Added a line to it under 21e7c3f


## Alternatives

### Leaving things as is

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another alternative: we can create a wrapper of Objective-C(++) around C++ pure code exposing APIs that are compatible with Swift.
This approach is a middle-ground that should:

  • avoid a complete rewrite of some internals
  • allow contributors to start using swift only
  • work around current Swift/C++ interop limitations
  • take much less time than the main approach

To achieve this, we should highlight which are all the APIs that could be useful for devs to be accessed in Swift (which is not a joke of a task)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added under d5c39ae. Could be a nice alternative. Wrote one con for it as well that comes to my mind regarding Toolchain depracation but perhaps it won't be that big of a problem


- What other parts of the infra need to be changed for this transition to work?
- How will this affect other targets such as React Native macOS, React Native visionOS, etc.?
- Is our current separation of internals from the OSS template enough that we can simply change the template directly without any of the first four steps needed? (I managed to get a [test repo](https://github.com/TheRogue76/React-Native-Template-With-Swift) to work as a proof of concept with these changes, but I am not sure if that means that the app will work for all situations (new arch, bridge-less, etc.). I also submitted [a PR](https://github.com/facebook/react-native/pull/41896) to test out the current tests we had and those passed, but that might not be enough). And what about Expo? Will it continue to function if this change is done to the base template, or would it interfere with any of the work done on their side

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is our current separation of internals from the OSS template enough that we can simply change the template directly without any of the first four steps needed?

No, as explained in the PR, that's not enough.
We had to make sure that all the configurations work and that the flags are passed properly.

Also, the AppDelegate is not the only API that users interface with. There are all the APIs related to create a Custom Module and a Custom Component.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed under 6a05439.


## Unresolved questions

- What other parts of the infra need to be changed for this transition to work?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely, we need to verify that

  • Native/TurboModule APIs are compatible with Swift
  • Native/Fabric Components APIs are compatible with Swift
  • Codegen (for the New Arch) is compatible with Swift (and can generate Swift code)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mentioned these as questions that need to be solved under 8ecb9db.

- Beginning the transition from Obj-C to Swift from the tests in the internals (**No effect on users or library maintainers**)
- Moving the rest of the modules one at a time from Obj-C to Swift (**Library maintainers may need to update, if they wish to take advantage of the newer APIs or if we break change an APIs signature, but ideally it should only be in the direction of making it easier to maintain libraries and better APIs**)
- Updating CocoaPods infra
- ? (Please add any more steps that come to mind, at the end or anywhere else in the list)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an important step missing.
The New Architecture main language is C++ and it is all conatined in the ReactCommon folder.
Most of the code exposed from ReactCommon is not configured as a Clang Module. This would make impossible for that code to be consumed by Swift, as documented here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that explains quite a bit. So would we need to configure them as Clang Modules? Is it even possible or would it have some other consequences on other parts of the code base?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is for sure possible.
It will require to write some modulemap files. If that's all it takes, it would not be breaking.
But my gut feeling tells me that we will have to also move some files around, specifically we should move the public headers to an include folder. And that would be breaking, unfortunately.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mentioned both the required action and the concern as steps we would need to take under 228b56d

@mrousavy
Copy link
Member

Not very constructive, but I just wanna say I really stand behind this RFC.

Objective-C (or actually Objective-C++) is really good when it comes to C++ interop, but that's about it. Swift is easier to read, much less code, simpler, memory is managed better, sometimes it's even faster (direct method call vs message send), and it ultimately invites more outside contributions.
I'm sure a lot of people are hesitant about reading RN Core code or contributing to it just because it's Objective-C. Swift is easier to understand for JS devs.

Expo uses Swift, VisionCamera uses Swift, and pretty much all modern iOS libs use Swift.

With that said, it's obviously a huge effort, and I fully agree that current efforts are best dedicated to new arch stuff. That's where it starts to get tricky though because everything is in C++ now and Swift <> C++ interop is still very limited - no templates, not all default headers will work, and stuff like folly, jsi, or react headers will probably require intermediate bridging headers.

Which is an okay workaround, but takes more time to write.

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

Successfully merging this pull request may close these issues.

None yet

3 participants