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

Fix NSCopying and NSMutableCopying #401

Closed
madsmtm opened this issue Jan 27, 2023 · 7 comments · Fixed by #419
Closed

Fix NSCopying and NSMutableCopying #401

madsmtm opened this issue Jan 27, 2023 · 7 comments · Fixed by #419
Labels
A-framework Affects the framework crates and the translator for them bug Something isn't working
Milestone

Comments

@madsmtm
Copy link
Owner

madsmtm commented Jan 27, 2023

In #293 / #291, I changed protocols to work like traits.

However, NSCopying and NSMutableCopying are still special-cased since they work a bit differently, they require the user to specify the output type and ownership. How can we make icrate do that for us? And what about protocols that "inherit" from these two (like DOMEventTarget)?

Perhaps this ties in with #399 somewhat?

In any case, I need to get a better understanding and research which types actually implement these two protocols, and just as importantly, which ones don't!

@madsmtm madsmtm added bug Something isn't working A-framework Affects the framework crates and the translator for them labels Jan 27, 2023
@madsmtm madsmtm mentioned this issue Jan 27, 2023
4 tasks
@madsmtm
Copy link
Owner Author

madsmtm commented Jan 27, 2023

Looking at the conforming types of NSMutableCopying to start with, it seems that the only classes that implement this while not having a Mutable class counterpart is:

Everything else works just like NSString vs. NSMutableString.

@madsmtm madsmtm added this to the icrate v0.1.0 milestone Jan 27, 2023
This was referenced Feb 2, 2023
@madsmtm
Copy link
Owner Author

madsmtm commented Feb 13, 2023

An example of using NSTextStorage, which is a subclass of NSMutableAttributedString:

Class copy return type mutableCopy return type
NSTextStorage NSAttributedString NSMutableAttributedString
NSMutableAttributedString NSAttributedString NSMutableAttributedString
NSAttributedString NSAttributedString NSMutableAttributedString

(Honestly, this behaviour seems more like a bug than the intended behaviour...)

@madsmtm
Copy link
Owner Author

madsmtm commented Feb 14, 2023

So in #419 I was considering getting rid of the Output parameter, but I think that might not be desirable after all?

The places where it is troublesome in the first place is in usage of ProtocolObject<dyn T> where T is a subtrait of NSCopying:

  • MTLFunctionStitchingFunctionNode::arguments
  • DOMEvent::target/currentTarget/srcElement + DOMMouseEvent::relatedTarget
  • ASAuthorizationPublicKeyCredentialAssertionRequest::allowedCredentials
  • ASAuthorization::credential
  • AXChartDescriptor::xAxis/additionalAxes

In all of these cases, the protocol is being used to do polymorphism, but we know that the type of Output is always Self. So perhaps we could do something like trait AXDataAxisDescriptor: NSCopying<Output = Self> { ... } and fn setXAxis(&self, x_axis: &impl AXDataAxisDescriptor);? Though that won't work in return type position, we'd still need some way of saying Id<ProtocolObject<dyn AXDataAxisDescriptor>> and have copy on that return the same.

Maybe having these as subtraits of NSCopying is really just too much work, and we should instead just do unsafe impl NSCopying for dyn AXDataAxisDescriptor { type Output = Self; }?


The other troublesome cases are when ProtocolObject<dyn NSCopying> is being used directly:

  • NSPathCell::setObjectValue
  • NSRulerMarker::representedObject
  • NSDictionary keys

Having just a bound of NSCopying on these is actually insufficient to make the functionality safe, so probably not really important. Though would be nice to be able to say ProtocolObject<dyn NSCopying<Output = Self>> here.

@madsmtm
Copy link
Owner Author

madsmtm commented Feb 14, 2023

Actually, the Output parameter might even be preferable for things like NSDictionary (using syntax ideas from #419):

trait AllowedKeyKinds {}
impl AllowedKeyKinds for Immutable {}
impl AllowedKeyKinds for ImmutableWithMutableSubclass {}

trait AllowedKeys {}
impl<T: PartialEq + Hash + ClassType> AllowedKey for T
where
    Self::Kind: AllowedKeyKinds,
{}

impl<K: AllowedKey, V: ...> for NSMutableDictionary<K, V> {
    pub fn insert(key: &impl NSCopying<Output = K>, val: Id<V>);
}

This would allow passing &NSMutableString as the string key, and have it automatically be converted to NSString (since NSMutableDictionary copies the keys internally)

@madsmtm
Copy link
Owner Author

madsmtm commented Feb 18, 2023

Okay, back to basics:

  1. What is most convenient for the user? How do they say which type NSCopying returns (which is most often Self on custom types):
    a) Specifying type Kind = Mutable<Self>; whenever they create a mutable type
    b) Specifying unsafe trait NSCopying { type Output = Self; }
    c) Somehow not having to worry about it (we make Self the default)

  2. Are there other places where the MyType/MyMutableType immutable/mutable relation might be useful to know?


I think the answer to these is:

  1. c) would be nice, but since I don't know how to do that, b) it is (it preserves code-locality of the parameter)
  2. Perhaps there are, but in those cases you can just use it from NSCopying, you don't need to know it from ClassType::Kind.

@madsmtm
Copy link
Owner Author

madsmtm commented Feb 18, 2023

Perhaps a solution could be something like:

// Implementation
extern_protocol!(
    pub unsafe trait NSCopying { ... }
    unsafe impl<T> ProtocolType for dyn NSCopying<Output = T> { ... }
);

// Type usage
ProtocolObject<dyn NSCopying<Output = DummySelf>>

(Or some kind of equivalent that still ensures you can't suddenly turn a dyn NSCopying<Output = A> into dyn NSCopying<Output = B>)

@madsmtm
Copy link
Owner Author

madsmtm commented Feb 26, 2023

Or for solution 1c, perhaps we could have classkinds Mutable, ImmutableWithMutableSubclass<T> and MutableWithImmutableSuperclass<T>? Then the user could just specify type Kind = Mutable;, and NSCopying/NSMutableCopying would otherwise work as usual (the copy/mutableCopy methods could even be made available to ProtocolObject<dyn NSCopying>, and would just return runtime::Object)

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 bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant