dirkwhoffmann / virtualc64

VirtualC64 is a cycle-accurate C64 emulator for macOS
https://dirkwhoffmann.github.io/virtualc64
Other
342 stars 33 forks source link

Remove the ObjC proxy layer #790

Closed dirkwhoffmann closed 4 months ago

dirkwhoffmann commented 4 months ago

During WWDC 2023, Apple announced that Swift can interact directly with C++:

https://developer.apple.com/videos/play/wwdc2023/10172 https://www.swift.org/documentation/cxx-interop/

This is an excellent opportunity to trash the ObjC layer. The layer is a large portion of code, with the sole purpose of bridging the gap between Swift and C++ (originally, Swift could only talk to C).

As always, it's not as simple as they propose in the video, but I finally reached the point where I think I know what has to be done.

Here is the plan:

A lot of preliminary work has already been done:

dirkwhoffmann commented 4 months ago

Proof-of-concept. Old code:

    @IBAction func pauseAction(_ sender: Any!) {
        if c64.running { c64.pause() }
    }

    @IBAction func continueAction(_ sender: Any!) {
        if c64.paused { try? c64.run() }
    }

    @IBAction func stopAndGoAction(_ sender: Any!) {
        c64.stopAndGo()
    }

c64 is the existing ObjC proxy. The Swift GUI now contains a variable v64 which links directly to the C++ core (reference copied from the existing proxy).

Now, the old code can be replaced by this one, which proves the concept working:

    @IBAction func pauseAction(_ sender: Any!) {        
        if v64.isRunning() { v64.pause() }
    }

    @IBAction func continueAction(_ sender: Any!) {
         if v64.isPaused() { v64.run() }
    }

    @IBAction func stopAndGoAction(_ sender: Any!) {
        v64.stopAndGo()
    }

It's also possible to expose some C++ functions as properties to Swift (one could then write v64.isPaused instead of v64.isPaused() etc.), but I haven't looked into this yet.

dirkwhoffmann commented 4 months ago

Bummer! This makes the new feature useless for me.

Swift can interoperate with C++ code that throws exceptions. However, Swift does not support catching C++ exceptions. Instead, the running program terminates with a fatal error when a C++ exception that’s not caught by C++ code reaches Swift code.

dirkwhoffmann commented 4 months ago

Update: Because Swift cannot communicate with the C++ core directly due to the lack of exception support, I tried to port the ObjC proxy to Swift, utilizing the same exception passing trick as I did in the ObjC proxy. At the beginning, this worked well. However, after adding more and more functions, Swift build times were skyrocketing, reaching several minutes to compile.

Bottom line: Swift / C++ interop still seems to be in an early beta state, which makes it pretty unusable in larger real-life projects. Apple's marketing videos are brilliant, though. Good job there, as usual.