-
Notifications
You must be signed in to change notification settings - Fork 14
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
Document findings for .ip. functionality #85
Comments
Quick SummaryThe
We might be able to work around these problems, but the extra complexity is probably not worth it. For more detail, read on. Motivation behind the original ideaRxSwift uses a "proxy" pattern for organizing Rx-provided extensions on existing classes. The result is that the API looks like this:
Rather than something like:
Instead of the extension methods and properties being added onto the UITextField class itself, they are added onto the "proxy" object, which is a property on the text field. The main motivation for using this pattern in Rx seems to be mostly aesthetic, as per the original github issue: How Rx implements thisThe Reactive proxyIn RxSwift, the proxy object is an instance of the
Note that Now in considering any generic, it is always useful to ask "what does this generic do?". The purpose of a generic is to capture some common logic that works the same way regardless of the specific types involved. In other words, beyond maybe conforming to some protocol (e.g. Equatable or Hashable) we don't need to know what our generic types are. The generic Adding a Reactive proxy to each objectConsider the example call:
As we can see, UITextField has been extended such that each instance has a
RxSwift injects this property like so:
There's a lot going on here so let's break it down: First we have a protocol called Next we extend Finally they extend Defining extension methods for a specific typeThe last step is actually using
Here we add a Why this doesn't work for SwiftWisdomSo far in trying to implement this syntax in wisdom, we've defined an However we run into some issues. This doesn't seem to work for structs or enumsWorking from inside the Reactive codebase, suppose I define the following four types:
Then I attempt to add some Reactive extensions like so:
As of Xcode 8.1, the last two lines cause a compiler error:
This seems to be because the
But this causes a different error:
It seems that the So here we come to obstacle number 1: Extending the Looking through the RxSwift codebase, it looks like all of their extensions are defined on classes. They do not, as far as I can see, have things like extensions on String (a struct), which is something that Swift Wisdom needs to support. This pattern does not work well with value typesLet's put aside for a minute the generics issue from above. After all, the end goal here is to have a syntax like
So in this case we have a concretely defined This will compile and work fine except for a pretty big caveat: The .ip proxy cannot easily implement mutating functions on the base object if that base is a value-type. Consider the following function:
The purpose of this function is to mutate the string by dropping the first character. Recall that this is a function on IntrepidStringExtension, not on String itself. That means that whenever we need to refer to a property or function of the string, we do so via So whereas before we'd have something like:
Now we'd have:
I do not know of any easy way around this. My opinion right now is that probably there is a way to allow Not all APIs make sense when transferred to the proxy styleFor an example of this take a look at String+Indexing.swift in current Swift Wisdom. There are a few custom subscipt functions in there. We would need to leave these on the base String type. Otherwise it doesn't make much visual sense, because you'd have calls like this:
That said, while this is ugly in my opinion, I'm not sure what the best practices are around adding custom subscript implementations to an extension and ensuring that they don't conflict. Also this is pretty subjective. In fact the originator of this pattern in RxSwift has a blog post specifically about using this to implement subscripts: https://medium.com/@JegnuX/safe-collection-subsripting-in-swift-3771f16f883#.jrr86qail I think the example there of implementing a safe subscript (like Final thoughtsOverall I don't think working around these problems is worth the switch from |
Excellent research findings @andrewdolce! I agree with your conclusion. |
Hi @andrewdolce, really awesome and I'm glad you wrote this up. I have some follow up questions on each of these blockers.
|
@brightredchilli Thanks for the comments. In response:
|
Just put another example that migrated to the dot syntax here for future reference. |
@andrewdolce can the findings from this be documented somewhere and this issue closed? |
@andrewdolce could you add the findings here.
The text was updated successfully, but these errors were encountered: