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

Should async handover support Realm collections? #3863

Closed
JadenGeller opened this issue Jul 12, 2016 · 13 comments
Closed

Should async handover support Realm collections? #3863

JadenGeller opened this issue Jul 12, 2016 · 13 comments

Comments

@JadenGeller
Copy link
Contributor

Is there a compelling use case for supporting async handover of Realm collections? #3828 only pertains to handover of Realm objects, but a logical extension is to support collections as well. There isn't however an easy way to expose such functionality without majorly complicating the API, so maybe it isn't something we should add unless there's a compelling reason?

@JadenGeller
Copy link
Contributor Author

JadenGeller commented Jul 12, 2016

If we are to support it, we ought to decide on the API.

1. RealmBoundObject Protocol

My first thought was to introduce a protocol RLMRealmBoundObject (name pending) that RLMObject, RLMArray, RLMResults, and RLMLinkingObjects all conform to. This works well except in the Swift case of passing multiple objects that are not all RLMObjects.

func async<O: RealmBoundObject>(handingOver objects: [O], execute block: (Realm, [O]) -> ())

Here, a user cannot pass both an RLMArray and an RLMObject since O will not unify to the existential RealmBoundObject. We could have to introduce an additional (hopefully not ambiguous) overload.

func async(handingOver objects: [RealmBoundObject], execute block: (Realm, [RealmBoundObject]) -> ())

Note that we would not want to replace the former function with the latter since the latter will always require additional casting while the former will often not.

2. SequenceType Specializations

We could alternatively just introduce overloads that take in a single Realm collection. Though this would probably result in more overloads than the former solution, it would result in a reasonably simple API. The overloads would simply act as specializations of the SequenceType-accepting async variant that offer better performance characteristics, so it wouldn't be much extra cognitive overhead for users.

Unfortunately, users would be unable to pass multiple collections or a mixture of collections and objects, and there would be no way for them to implement this on top of what we've built. I'm unsure how significant we consider this limitation, but we definitely ought to consider use cases since there would be no reasonable workaround.

@JadenGeller
Copy link
Contributor Author

//cc @bigfish24

@bigfish24
Copy link
Contributor

bigfish24 commented Jul 13, 2016

I am in favor of option 1

@JadenGeller
Copy link
Contributor Author

JadenGeller commented Jul 13, 2016

I just checked, and it turns out the function overloads discussed in 1 are ambiguous… 😞 If we want 1 still, we need to give the existential method a different name… Thoughts @bigfish24?

For example, we could rename the latter to

func async(handingOverMixed objects: [RealmBoundObject], execute block: (Realm, [RealmBoundObject]) -> ())

and users would need to call

realm.async(handingOverMixed: [results, object]) {  }

only when they wanted to hand over RealmBoundObjects that don't share a common superclass.

I think this is pretty gross, but there's not a great alternative. We could only keep the existential method, but then excessive casting is necessary to use the API.

@JadenGeller
Copy link
Contributor Author

@austinzheng Do you have any clever workaround for the ambiguity here? If not, what do you suggest?

@austinzheng
Copy link
Contributor

What's wrong with just having the second API in option 1? (What's the use case for enforcing homogeneity again?)

@JadenGeller
Copy link
Contributor Author

JadenGeller commented Jul 13, 2016

@austinzheng With only the existential API, users will always have to cast from the existential to the correct type. With the protocol constrained generic API, users will often not need to cast.

realm.async(handingOver: [kim, tim]) { realm, people in
  // existential API: `people: [RealmBoundObject]`
  // constrained API: `people: [Person]`
}

@austinzheng
Copy link
Contributor

I see. I'll think about it. (I guess we don't want to go the cowards' route of just giving the methods slightly different names 😛.)

@JadenGeller
Copy link
Contributor Author

JadenGeller commented Jul 13, 2016

I don't think that it's necessarily a bad idea to do that.

@JadenGeller
Copy link
Contributor Author

JadenGeller commented Jul 13, 2016

Potential solution! 🎉 If we mark RealmBoundObject as @objc, it's existential will conform to RealmBoundObject. This means that two unrelated classes that conform to RealmBoundObject can be passed in the generic constraint API!

Unfortunately, you have to give the type checker needs some help in this case, but that's totally reasonable for the advanced use case of passing unrelated types. We should definitely document this though.

realm.async(handingOver: [results, person] as [RealmBoundObject]) { realm, objects in
    let results = objects[0] as! Results
    let person = objects[1] as! Person
    // do stuff async
}

The user simply must add an as [RealmBoundObject] to the parameter OR annotate the argument types in the closure. Again, in the case where everything in the array is of a common superclass, no type checker hints are necessary.

What're your thoughts, @austinzheng?

@austinzheng
Copy link
Contributor

Oh, that's clever. And given that RealmBoundObject is only supported for the NSObject-based classes we define, the @objc annotation shouldn't affect anything else.

@JadenGeller
Copy link
Contributor Author

Exactly! And hopefully by the time we get a pure Swift API (like a bazillion years from now), Swift will conform its existential to their relevant protocol.

@JadenGeller
Copy link
Contributor Author

Sounds like we'll go with the @objc protocol RealmBoundObject { } API.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants