Method Chaining in Objective-C

Member
Posts: 254
Joined: 2005.10
Post: #1
I've been thinking about a different way of coding methods that return void. If you returned self instead of void, then a second method could be applied after the first. This could lead to more sentence-like code. For example, say I have a class whose init method does nothing, but I have some variables I would like to set up immediately.

Code:
@interface SomeClass
- (id) setName:(NSString*)aName;
- (id) setInteger:(NSNumber*)anInteger;
@end

@implementation
- (id) setName:(NSString*)aName { name = aName; return self; }
- (id) setInteger:(NSNumber*)anInteger { integer = anInteger; return self; }
@end

Then when I want to setup those variables immediately after init, I could chain the messages.

Code:
id myclass = [[SomeClass alloc] init][setName:@"name"][setInteger: [NSNumber numberWithInt: 1];

I'm just wondering what people think about this coding style. Here are a couple of problems I came up with:

  1. Obviously, this would be a potential source of confusion, since the classes you wrote would return self but others wouldn't.
  2. Additionally, the interface declaration could be more confusing since the user of the class could think that you meant for them to do something with the returned object.

Maybe if you did a define, like "#define VOID_ID id" that could reduce the confusion of the second problem.
Quote this message in a reply
Sage
Posts: 1,066
Joined: 2004.07
Post: #2
I think it's a cool structure, but doesn't seem to be in the style of Objective-C. But I think setting things up like sentences is very cool.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #3
The syntax you have doesn't work, the square brackets need to be nested.

This is a very common thing to do in Java, where the syntax suits it better. I don't see any reason not to do it in ObjC if you like, though.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #4
This is ridiculous. Do not do this.
Code:
foo = [foo setShoeSize:42];
Only makes sense when the object foo is immutable.
What you are doing here is pointless obfuscation.

Instead of this provide an init method which takes the parameters you want, you can also supply an init which takes no parameters, and calls that one with defaults.

edit: To make this clearer
Code:
id myclass = [[SomeClass alloc] initWithName:@"name" integer:[NSNumber numberWithInt: 1]];

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
It makes sense when the object you're initializing has large numbers of properties, all of which have sane default values. The other option is passing a dictionary to the initializer, which seems to be the Apple-preferred way to do it.

It has a lot in common with http://martinfowler.com/bliki/FluentInterface.html
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #6
OneSadCookie Wrote:The syntax you have doesn't work, the square brackets need to be nested.

Right... I've been designing a language for fun on the side and I had swapped the receiver out of the method call so it looks more like array/dict access. (reciever[message] instead of [reciever message]) This language also includes java-style default value for instance variables (type var = default) making this style of code more attractive.

I didn't know about that fluent interface pattern before, but that seems to be in the same vane as what I was thinking.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #7
Blacktiger Wrote:Right... I've been designing a language for fun on the side and I had swapped the receiver out of the method call so it looks more like array/dict access. (reciever[message] instead of [reciever message]) This language also includes java-style default value for instance variables (type var = default) making this style of code more attractive.

I didn't know about that fluent interface pattern before, but that seems to be in the same vane as what I was thinking.

No need to design your own language, Learn Smalltalk instead Smile

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Member
Posts: 114
Joined: 2005.03
Post: #8
If it's only the problem of setting up lots of different things at start, Nu has a very interesting idea: There's a generic set: method on NSObject, taking a list of keys and values which will then be set using KVC. Something like this should be possible in plain Objective C, too, like:
Code:
[anObject set:@"name", @"name", @"integer", [NSNumber numberWithInt:42], nil]
Quote this message in a reply
Post Reply