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

Replace objc with objc2? #28

Open
madsmtm opened this issue Jun 25, 2022 · 15 comments
Open

Replace objc with objc2? #28

madsmtm opened this issue Jun 25, 2022 · 15 comments
Labels
dependencies Pull requests that update a dependency file enhancement New feature or request

Comments

@madsmtm
Copy link
Contributor

madsmtm commented Jun 25, 2022

Hey, macOS maintainer of winit here. I've been working on a replacement for objc called objc2, and I think it could be interesting for this crate?

Some of the concrete improvements you'd reap benefit from, mainly in the category "improving correctness":

  • Helper macro msg_send_id! for following cocoa's memory management rules - as a quick example, NSString::new currently leaks because it uses Id::from_ptr instead of Id::from_retained_ptr.
  • Implementing Encode is now required for all types that go across msg_send! - this is great for catching bugs, for example this code in ListView::select_row_indexes is wrong, the type of index is &usize while it should be usize.
  • Soundness fixes concerning message sending, autoreleasepools and reference counting.

I have an implementation of Foundation that you may be interested in using, at the very least it can be useful as an example of how to use objc2 well.

See also my PR to the core-foundation-rs project.

Opening this issue to start the discussion, am a bit tired so sorry it's not more detailed. I would really like to work towards a completely safe interface over (the most commonly used parts of) Cocoa, but wanted to keep it out of the scope of objc2 itself - cacao seems like a nice work in that direction, would like to help out in this effort (other than just working on objc2).

@ryanmcgrath
Copy link
Owner

ryanmcgrath commented Jun 25, 2022 via email

@madsmtm
Copy link
Contributor Author

madsmtm commented Jun 25, 2022

Yeah well, I thought about it a year ago, and it took me a year... Anyhow, wonderful that you're on board! I might whip up a PR at some point, focusing on the soundness stuff at first, should I target the airyx-appkit-uikit-features branch when I get there?

Also, in objc2_foundation I went with exposing Id<NSString> and allowing direct control with impl Message for NSString, compared to NSString(Id<Object>) which allows access through objc fields, curious to know what you think about the two different approaches?

@ryanmcgrath
Copy link
Owner

If you get to it before I cut a 0.3, then yeah, airyx-appkit-uikit-features should be the one. It has a few bug fixes as it is so it's overdue to be merged. The issue is, as always, time. :(

Re: the format... I actually think impl Message for _ is potentially cleaner and is probably what I should do for the components in cacao for anyone who wants to just message the lower level component directly. My thought process for having the .objc escape hatch was that it made it really clear when you were in Rust vs ObjC territory, but in practice this is probably not a big problem... most who'd bother with this probably have a decent idea, and/or the Message barrier implies it anyway.

@ryanmcgrath
Copy link
Owner

Just to update - I haven't forgotten about these issues/PRs! Been incredibly busy the past week and a half, hoping to get to them soon.

@madsmtm
Copy link
Contributor Author

madsmtm commented Jul 30, 2022

I know how it is, don't stress, I don't mind if it takes a few months!

@madsmtm
Copy link
Contributor Author

madsmtm commented Sep 23, 2022

Just a heads up: I'm working on automatically generating bindings to all of AppKit and UIKit in madsmtm/objc2#264, which, combined with a few tricks to slowly carve out a safe subset (removing unsafe from a function is a semver-stable change), should make it possible to make cacao a lot simpler and safer.

In effect, you'll basically never have to do msg_send![obj, someMethod: arg1, withArg: arg2] again, instead you'll just do obj.someMethod_withArg(arg1, arg2) (and if we've reviewed it in objc2, and added it to a list of safe functions, you won't even have to use unsafe).

@ryanmcgrath
Copy link
Owner

Yeah, I'd seen mention of it before. :)

The real question for me actually becomes whether cacao is worth it - not because your work erases it or anything, but Apple-specific UI work is in an odd place because most of the people looking to natively write apps for the platform are going to do it with the core languages (Swift/far increasingly less ObjC). Hard to gauge whether anyone would consume this crate.

On the other hand, cacao does work around a lot of oddities... so there might still be a place for it.

@madsmtm
Copy link
Contributor Author

madsmtm commented Sep 23, 2022

Also, something that is almost possible now using declare_class! (still need a bit more work on the generics, but that should be doable):

pub trait WebViewDelegate {
    const NAME: &'static str;

    fn on_message(&self, _name: &str, _body: &str) {}
    // ...
}

declare_class!(
    pub struct WebViewDelegateObject<T: WebViewDelegate> {
        delegate: Ivarbox<Box<T>>,
    }

    unsafe impl<T: WebViewDelegate> ClassType for WebViewDelegateObject<T> {
        type Super = NSObject;
        const NAME: &'static str = <T as WebViewDelegate>::NAME;
    }

    unsafe impl<T: WebViewDelegate> Protocol<WKScriptMessageHandler> for WebViewDelegateObject {
        #[sel(userContentController:didReceiveScriptMessage:)]
        fn on_message(&self, _: &WKUserContentController, message: &WKScriptMessage) {
            autoreleasepool(|pool| {
                 self.delegate.on_message(message.name().to_str(pool), message.body().as_str(pool))
            })
        }

        // ...
    }
);

pub struct WebView<T = ()> {
    pub is_handle: bool,
    pub obj: Id<WKWebView>,
    pub layer: todo,
    pub delegate: Option<Id<WebViewDelegateObject<T>>>,

    // ... autolayout stuff
}

@madsmtm
Copy link
Contributor Author

madsmtm commented Sep 23, 2022

The real question for me actually becomes whether cacao is worth it - not because your work erases it or anything, but Apple-specific UI work is in an odd place because most of the people looking to natively write apps for the platform are going to do it with the core languages (Swift/far increasingly less ObjC). Hard to gauge whether anyone would consume this crate.

On the other hand, cacao does work around a lot of oddities... so there might still be a place for it.

I... Don't know about that - I guess it's hard for me to estimate what people actually want from Cocoa + Rust? What have you used it for yourself?

I think a completely safe interface would be nice though, and while objc2 will come close to some of it, there will probably always be some things (example: custom class declarations) that will always require a bit of unsafe.

@ryanmcgrath
Copy link
Owner

What have you used it for yourself?

Heh, cacao originally started after I got tired of writing a cocoa backend for alchemy. Since then I've used it for small tools on my own, but nothing I've released yet - from what I can tell, others are the same.

It's not something I'm deciding this instant anyway, and I'm mostly just openly musing on it. :)

@ryanmcgrath ryanmcgrath added enhancement New feature or request dependencies Pull requests that update a dependency file labels Apr 28, 2023
@madsmtm
Copy link
Contributor Author

madsmtm commented Aug 1, 2023

Following up on this: I've released objc2 v0.4, which I feel is at a pretty good point, I mostly expect things around declare_class! to change from now on - so I would say I'm ready to really get into using objc2 in this crate.

Also to those that don't know, the automatic generation of AppKit is coming along pretty nicely, it's called icrate.

@madsmtm
Copy link
Contributor Author

madsmtm commented Aug 1, 2023

I'm unsure what you think is the best way forward? In #30 (comment) you noted that you wanted to use icrate, which I'm all up for, but how do we get there?

The way I've been going about it was to slowly convert things to objc2, and then start using icrate after that, but do you think we should do it differently?

@agg23
Copy link
Contributor

agg23 commented Aug 1, 2023

With objc2 and the autogenerated API bindings, what role does Cacao serve? A Rust ergonomic interface to the underlying APIs?

@ryanmcgrath
Copy link
Owner

ryanmcgrath commented Aug 1, 2023 via email

@ryanmcgrath
Copy link
Owner

The way I've been going about it was to slowly convert things to objc2, and then start using icrate after that, but do you think we should do it differently?

@madsmtm this is totally fine with me, yeah - it's likely the path of least resistance, no sense in making our lives harder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants