Skip to content

Comments

Better protocols#293

Merged
madsmtm merged 27 commits intomasterfrom
better-protocols
Jan 27, 2023
Merged

Better protocols#293
madsmtm merged 27 commits intomasterfrom
better-protocols

Conversation

@madsmtm
Copy link
Owner

@madsmtm madsmtm commented Nov 23, 2022

Fixes #291.

TODO:

  • Finish basic implementation
  • Update documentation
  • Use new implementation for NSCopying, NSMutableCopying, ... Deferred to Fix NSCopying and NSMutableCopying #401
  • Test assembly output to ensure that using dyn like this doesn't incur extra overhead

@madsmtm madsmtm added enhancement New feature or request A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates labels Nov 23, 2022
@madsmtm madsmtm added the A-framework Affects the framework crates and the translator for them label Dec 23, 2022
@madsmtm madsmtm added this to the objc2 v0.3 milestone Jan 18, 2023
@madsmtm
Copy link
Owner Author

madsmtm commented Jan 26, 2023

A somewhat end-goal is that we can use this in icrate for translating places that take/return something like id<NSMutableCopying + NSFastEnumeration> to:

ProtocolObject<dyn NSMutableCopying + NSFastEnumeration>

// where:
// trait NSMutableCopying: NSCopying { ... }
// trait NSFastEnumeration { ... }

To use such an object, we would like the following implementations to exist:

// Required to use the object at all
impl NSCopying for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}
impl NSMutableCopying for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}
impl NSFastEnumeration for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}

// Would be nice to have
impl ConformsTo<dyn NSCopying> for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}
impl ConformsTo<dyn NSMutableCopying> for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}
impl ConformsTo<dyn NSFastEnumeration> for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}

// Not really that important, but could be cool
impl ConformsTo<dyn NSCopying + NSFastEnumeration> for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}
impl ConformsTo<dyn NSMutableCopying + NSFastEnumeration> for ProtocolObject<dyn NSMutableCopying + NSFastEnumeration> {}

// For an object `MyClass` that implements the protocols, these are required
impl NSCopying for MyClass {}
impl NSMutableCopying for MyClass {}
impl NSFastEnumeration for MyClass {}

// And these would be expected
impl ConformsTo<dyn NSCopying> for MyClass {}
impl ConformsTo<dyn NSMutableCopying> for MyClass {}
impl ConformsTo<dyn NSFastEnumeration> for MyClass {}

// To properly handle the case above, these would be nice
impl ConformsTo<dyn NSCopying + NSFastEnumeration> for MyClass {}
impl ConformsTo<dyn NSMutableCopying + NSFastEnumeration> for MyClass {}

Note: dyn TraitA + TraitB + ... is not yet possible in Rust unless only one of them is a non-auto trait. But we still have to plan for the future!

@madsmtm madsmtm closed this Jan 26, 2023
@madsmtm madsmtm reopened this Jan 26, 2023
@madsmtm
Copy link
Owner Author

madsmtm commented Jan 26, 2023

I've been going about this a bit wrong; what we want is for users to specify this:

extern_protocol!(
    unsafe trait NSCopying {
        // ...
    }
);

extern_protocol!(
    unsafe trait NSMutableCopying: NSCopying {
        // ...
    }
);

extern_protocol!(
    unsafe trait NSFastEnumeration {
        // ...
    }
);

extern_class!(
    struct MyClass;
);

unsafe impl NSCopying for MyClass {}
unsafe impl NSMutableCopying for MyClass {}
unsafe impl NSFastEnumeration for MyClass {}

Notice how the protocol implementations for the class is not in the extern_class! macro? That's intentional, since the protocol may be specified in a "later"/"higher up" framework than the class is (which would work for Objectice-C, since they'd just define a category, but it won't work for us).

Additionally, the use of ConformsTo is entirely hidden, which is also really nice!

@madsmtm
Copy link
Owner Author

madsmtm commented Jan 26, 2023

Implementation-wise:

extern_protocol!(
    unsafe trait FooBar: Foo + Bar {}
);

// Generates

unsafe trait FooBar: ... {...}

unsafe impl<T: ?Sized + FooBar> FooBar for ProtocolObject<T> {}

// Note: Needs to be done a bit differently because of the orphan rule
impl<T: ?Sized + FooBar> ConformsTo<dyn FooBar> for T {}

// Maybe?
// impl<T: ?Sized + FooBar> ConformsTo<dyn Foo> for T {}
// impl<T: ?Sized + FooBar> ConformsTo<dyn Bar> for T {}

@madsmtm madsmtm linked an issue Jan 27, 2023 that may be closed by this pull request
@madsmtm madsmtm marked this pull request as ready for review January 27, 2023 08:15
@madsmtm madsmtm merged commit 1521cb0 into master Jan 27, 2023
@madsmtm madsmtm deleted the better-protocols branch January 27, 2023 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-framework Affects the framework crates and the translator for them A-objc2 Affects the `objc2`, `objc2-exception-helper` and/or `objc2-encode` crates enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improving how we map protocols

1 participant