Why must the last part of an Objective-C method name take an argument (when there is more than one part)?

Objective CSelectorLanguage Design

Objective C Problem Overview


In Objective-C, you can't declare method names where the last component doesn't take an argument. For example, the following is illegal.

-(void)take:(id)theMoney andRun;
-(void)take:(id)yourMedicine andDontComplain;

Why was Objective-C designed this way? Was it just an artifact of Smalltalk that no one saw a need to be rid of?

This limitation makes sense in Smalltalk, since Smalltalk doesn't have delimiters around message invocation, so the final component would be interpreted as a unary message to the last argument. For example, BillyAndBobby take:'$100' andRun would be parsed as BillyAndBobby take:('$100' andRun). This doesn't matter in Objective-C where square brackets are required.

Supporting parameterless selector components wouldn't gain us much in all the usual ways a language is measured, as the method name a programmer picks (e.g. runWith: rather than take:andRun) doesn't affect the functional semantics of a program, nor the expressiveness of the language. Indeed, a program with parameterless components is alpha equivalent to one without. I'm thus not interested in answers that state such a feature isn't necessary (unless that was the stated reasons of the Objective-C designers; does anyone happen to know Brad Cox or Tom Love? Are they here?) or that say how to write method names so the feature isn't needed. The primary benefit is readability and writability (which is like readability, only... you know), as it would mean you could write method names that even more closely resemble natural language sentences. The likes of -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication (which Matt Gallagher points out on "Cocoa With Love" is a little bit confusing when you drop the formal parameter) could be named -(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed, thus placing the parameter immediately next to the appropriate noun.

Apple's Objective-C runtime (for example) is perfectly capable of handling these kind of selectors, so why not the compiler? Why not support them in method names as well?

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface Potrzebie : NSObject
-(void)take:(id)thing;
@end

@implementation Potrzebie
+(void)initialize {
    SEL take_andRun = NSSelectorFromString(@"take:andRun");
    IMP take_ = class_getMethodImplementation(self, @selector(take:));
    if (take_) {
        if (NO == class_addMethod(self, take_andRun, take_, "@@:@")) {
            NSLog(@"Couldn't add selector '%@' to class %s.", 
                  NSStringFromSelector(take_andRun), 
                  class_getName(self));
        }
    } else {
        NSLog(@"Couldn't find method 'take:'.");
    }
}

-(void)take:(id)thing {
    NSLog(@"-take: (actually %@) %@",NSStringFromSelector(_cmd), thing);
}
@end

int main() {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Potrzebie *axolotl=[[Potrzebie alloc] init];
    [axolotl take:@"paradichloroaminobenzaldehyde"];
    [axolotl performSelector:NSSelectorFromString(@"take:andRun")                   withObject:@"$100"];
    [axolotl release];

    [pool release];
    return 0;
}

Objective C Solutions


Solution 1 - Objective C

This is Brad Cox. My original answer misunderstood the question. I assumed reallyFast was a hardcoded extension to trigger faster messaging, not a kind of syntactic sugar. The real answer is that Smalltalk didn't support it, perhaps because its parser couldn't deal with the (assumed) ambiguity. Although OC's square brackets would remove any ambiguity, I simply didn't think of departing from Smalltalk's keyword structure.

Solution 2 - Objective C

21 years of programming Objective-C and this question has never crossed my mind. Given the language design, the compiler is right and the runtime functions are wrong ().

The notion of interleaved arguments with method names has always meant that, if there is at least one argument, the last argument is always the last part of the method invocation syntax.

Without thinking it through terribly much, I'd bet there are some syntactic bugaboos with not enforcing the current pattern. At the least, it would make the compiler harder to write in that any syntax which has optional elements interleaved with expressions is always harder to parse. There might even be an edge case that flat out prevents it. Certainly, Obj-C++ would make it more challenging, but that wasn't integrated with the language until years after the base syntax was already set in stone.

As far as why Objective-C was designed this way, I'd suspect the answer is that the original designers of the language just didn't consider allowing the interleaved syntax to go beyond that last argument.

That is a best guess. I'll ask one of 'em and update my answer when I find out more.


I asked Brad Cox about this and he was very generous in responding in detail (Thanks, Brad!!):

> > I was focused at that time on > duplicating as much of Smalltalk as > possible in C and doing that as > efficiently as possible. Any spare > cycles went into making ordinary > messaging fast. There was no thought > of a specialized messaging option > ("reallyFast?" [bbum: I asked using 'doSomething:withSomething:reallyFast' > as the example]) since ordinary > messages were already as fast as they > could be. This involved hand-tuning > the assembler output of the C > proto-messager, which was such a > portability nightmare that some if not > all of that was later taken out. I do > recall the hand-hacked messager was > very fast; about the cost of two > function calls; one to get into the > messager logic and the rest for doing > method lookups once there.
> Static typing enhancements were later > added on top of Smalltalk's pure > dynamic typing by Steve Naroff and > others. I had only limited involvement > in that.

>

Go read Brad's answer!

Solution 3 - Objective C

Just for your information, the runtime doesn't actually care about the selectors, any C string is valid, you could as well make a selector like that: "==+===+---__--¨¨¨¨¨^::::::" with no argument the runtime will accept it, the compiler just can't or else it's impossible to parse. There are absolutely no sanity check when it comes to selectors.

Solution 4 - Objective C

I assume they are not supported in Objective-C because they weren't available in Smalltalk, either. But that has a different reason than you think: they are not needed. What is needed is support for methods with 0, 1, 2, 3, ... arguments. For every number of arguments, there is already a working syntax to call them. Adding any other syntax would just cause unnecessary confusion.

If you wanted multi-word parameterless selectors, why stop with a single extra word? One might then ask that

 [axolotl perform selector: Y with object: Y]

also becomes supported (i.e. that a selector is a sequence of words, some with colon and a parameter, and others not). While this would have been possible, I assume that nobody considered it worthwhile.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionoutisView Question on Stackoverflow
Solution 1 - Objective CBrad CoxView Answer on Stackoverflow
Solution 2 - Objective CbbumView Answer on Stackoverflow
Solution 3 - Objective CPsychoView Answer on Stackoverflow
Solution 4 - Objective CMartin v. LöwisView Answer on Stackoverflow