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

More natural derived properties #63

Closed
joshaber opened this issue Sep 24, 2012 · 10 comments
Closed

More natural derived properties #63

joshaber opened this issue Sep 24, 2012 · 10 comments

Comments

@joshaber
Copy link
Member

I've found when doing reactive UI stuff, I end up using -rac_deriveProperty:from: a lot. It's awesome for the most part, but it doesn't read very naturally. What I really want to write and read is something like:

self.titleLabel.textColor = someSubscribable;

I've come up with two different ways to write something more like that, both with tradeoffs, so I'd like to get some feedback.

Keyed subscripting:

rac(self.titleLabel.textColor) = someSubscribable;

That abuses keyed subscripting. It works for both object and non-object properties. The downside is that the class has to implement -setObject:forKeyedSubscript:. We can create a macro that does it for them, but it's an extra step users have to remember per-class.

Proxy bounce

self.titleLabel.rac.textColor = (id) someSubscribable;

// ooooh also:
[self.createButton.rac setTitleColor:(id) someSubscribable forState:UIControlStateNormal];

This uses a proxy to bounce message sends through. It's kinda awesome because you can use it with methods that aren't just plain setters, which happens to be the case a fair amount in UIKit land. But this approach has two downsides: (1) you have to cast the subscribable, (2) it won't work with non-object properties.

So I'd be curious to see if anyone has any other ideas or feels strongly about either of those two options.

@jwilling
Copy link
Contributor

The proxy looks fantastic. If I had a choice between the two, I'd rather go with the proxy and suffer the loss of not being able to use it with non-object properties.

However, would it be impractical to offer both? Subscripting primarily for scalars, and proxies for objects?

@jspahrsummers
Copy link
Member

I like the proxy much less now that I realize subscribables would always have to be cast. I think I would honestly rather see them wrapped in a dummy object made specifically for this purpose, like:

self.titleLabel.rac.textColor = someSubscribable.propertySomethingOrOther;

Where the subscribable's property would simply return id.

Can go you into more detail about how exactly the keyed subscripting works?

@joshaber
Copy link
Member Author

@jspahrsummers Yeah I agree the cast is weak sauce :(

The keyed subscripting works something like:

#define RAC(keypath) self[RAC_KEYPATH_SELF(keypath)]

- (void)setObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
    [self rac_deriveProperty:(NSString *) key from:obj];
}

RAC(self.blah.thing) = subscribable;

The really annoying bit is that the compiler has to be able to see the definition of -setObject:forKeyedSubscript: otherwise it won't compile. So we can't just inject it at runtime.

@jspahrsummers
Copy link
Member

@joshaber So that wouldn't work for objects that aren't relative to self? I don't know – the keyed subscripting seems pretty picky, and probably not worth it.

@joshaber
Copy link
Member Author

@jspahrsummers Well, you could imagine a version that does:

#define RAC_OBJ(obj, keypath) obj[RAC_KEYPATH(obj, keypath)]

But that object would need to to implement -setObject:forKeyedSubscript:.

Honestly, I don't really care much about that case. The case I'm specifically thinking of is UI where there are a lot of values derived from a few basic values, most/all of which are on the class itself.

@andymatuschak
Copy link
Contributor

Wait, couldn't you make the proxy-bounce situation way nicer by defining rac to return instancetype? Then you wouldn't have to cast. Also, you could totally make it work with non-object properties.

@andymatuschak
Copy link
Contributor

Ah, wait, totally misunderstood the problem; nevermind. I've got nothing.

@joshaber
Copy link
Member Author

Actually I think there's probably a way to make the keyed subscripting version more generic. I'll give a try.

The proxy bounce is really cool since it lets you pass in a subscribable in the place of a normal object but maybe there's a better / more specific way to surface that.

@jspahrsummers
Copy link
Member

Also, what happens if you proxy bounce on a RACSubscribable property? :trollface:

Does it have to be a subscribable of subscribables? How would it know?

@joshaber
Copy link
Member Author

That linked PR adds the subscripting-abusive assignment. It's a little more abusive but it works without needing the class to implement -setObject:forKeyedSubscript:.

@jspahrsummers I'm pretty sure the universe implodes. Pretty sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants