tags:

views:

1049

answers:

6

I understand that it marks the end of a set of varargs, but why can't it be implemented in such a way that doesn't require the nil?

+2  A: 

Any varargs function requires someway to know how many parameters are present -- if you don't nil terminate, you would just need something else. In this case the obvious alternative is a length, but then you'd need to update the length argument everytime you changed how many items were in the array, and that could be cumbersome, or worse broken.

I am guessing you have an array that may contain nil?

olliej
NSArray can't contain nil — you have to use NSNull to represent it. I'm guessing he's just been bitten by the annoying bugs that can result from forgetting the nil terminator.
Chuck
It's not as much being bit by forgetting the nil terminator, it's just that I'm used to other languages like Java and Ruby that allow for varargs without a nil terminator. Maybe what I'm asking is why does Obj-C require a nil terminator for varargs? Why can't the compiler just "do the right thing" for [NSArray arrayWithObjects: @"foo", @"bar"]? My question is more of a question of curiosity of why the language requires this. It's an obvious wart when coming from other languages. It's it because that's how varargs for in C functions?
pjb3
I _believe_ objective-c varargs are built on the standard C varargs which doesn't pass argument counts. Conceivably obj-c could have done that back in its original implementation, but now it is bound by ABI compatibility.
olliej
Yep, there are no special Objective-C varargs. This is just plain vanilla varargs, with all the annoyances that come along with it.
Chuck
A: 

OllieJ is correct. Keep in mind that obj-C is a proper superset of C. What you're suggesting is introducing a special case in the compiler where it has to care what class and selector you're using.

NSResponder
+7  A: 

It all has to do with the C calling ABI.

Consider these methods:

- (id)initWithFormat:(NSString *)format, ...;
+ (id)arrayWithObjects:(id)firstObj, ...;
+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;

The ... tells the compiler that a variable number of arguments of any type may be present. There is no way for the compiler to know what those types are required to be (the real definitions have markers that help with that).

Now, consider the three methods. All three have vastly different requirements for what might be present in the variable argument list. An array must be a bunch of objects followed by a nil. The dictionary requires a bunch of pairs of objects followed by a nil. Finally, the string method requires a bunch of arguments that match the types in the format string.

All of these behaviors are directly tied to the method being invoked and, if the author of an API decided to go for "hard to use", the behavior of decoding the variable arguments could be modified at runtime, just to make life difficult.

Bottom line: The C ABI doesn't have a syntax that allows for specifying that a method or function takes a variable number of arguments with any kind of set of constraints on the arguments or their termination.

Objective-C could change the rules just for method declarations & invocations, but that wouldn't help with C functions or C++, both of which Objective-C must remain compatible with.

bbum
It seems like the compiler could transparently add a final nil to [NSArray arrayWithObjects:a, b, c]. That would leave a gotcha that nil would not be permitted as an argument.We could even do this now. People who already include the nil would just get [NSArray arrayWithObjects:a, b, c, nil, nil], which I think is not fatal.
Ken
Ken, putting special cases in the compiler for particular classes like NSArray opens a huge can of worms. What if you subclass NSArray?
NSResponder
@Ken: You can't add `nil` to an `NSArray` anyway (you have to use `NSNull` instead).
mipadi
+1  A: 

@bbum gives some great technical details. Here are some thoughts on the practical "why don't they fix it?"

Remember: C is just assembler and Obj-C is just C... It could be redesigned of course, but there's almost no pressure to do so. You still couldn't put nil in an array (that would require a huge change). The compiler now warns you if you forget the nil, so it's not something developers complain a lot about. The trade-off is keeping the language much (much!) simpler than its kin, getting the benefits of decades of C-compiler optimizations and guaranteed compatibility with C code.

One thing that should become clear from @bbum's discussion: NSArray is not a language feature of Objective-C. C-arrays are a language feature, but NSArrays are just another object, no different than the objects you write.

Rob Napier
A: 

I just wonder how [NSString stringWithFormat:(NSString *)format, ...] works? I never put nil as a last argument in it! May be it counts argument placeholders in format string?

HARDWARRIOR
A: 

Objective c actually passes hidden arguments after your arguments like "self", so the nil terminator really shouldn't technically be required for most applications, as proven by NSString's +stringWithFormat:format,... method. As for how to implement something like stringWithFormat, I hope that someone posts an answer. There are various workarounds, but my current favorite is good for apps more than for released frameworks. Accept an NSArray in your method instead of "...", and then fill it with the convenience macro below, which is placed in your prefix file or utility header.

#define $array(objs...) [NSArray arrayWithObjects: objs, nil]

It'll allow for multiple well labeled variable length arguments and you'll free yourself from the archaic pattern of having to use the first argument and then va_list and its brothers in favor of a for-in loop or the many other collection tools available.

[self findMatchingSetAndAlert:@"title" ties:$array(tie1, tie2, tie3) shirts:$array(shirt1, shirt2, shirt3, shirt4)];

If someone knows how to implement a non-nil-delimited list such as stringWithFormat, please let us know! It uses attributes and macros or something designed specifically for formatting, but those are implemented somehow.

Peter DeWeese