Por que a última parte de um nome de método Objective-C deve ter um argumento (quando há mais de uma parte)?

90

Em Objective-C, você não pode declarar nomes de métodos onde o último componente não aceita um argumento. Por exemplo, o seguinte é ilegal.

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

Por que Objective-C foi projetado dessa forma? Era apenas um artefato de Smalltalk do qual ninguém viu necessidade de se livrar?

Essa limitação faz sentido em Smalltalk, uma vez que Smalltalk não tem delimitadores em torno da invocação da mensagem, então o componente final seria interpretado como uma mensagem unária para o último argumento. Por exemplo, BillyAndBobby take:'$100' andRunseria analisado como BillyAndBobby take:('$100' andRun). Isso não importa em Objective-C, onde colchetes são obrigatórios.

O suporte a componentes do seletor sem parâmetros não nos renderia muito em todas as formas usuais de uma linguagem é medida, como o nome do método que um programador escolhe (por exemplo, runWith:em veztake:andRun) não afeta a semântica funcional de um programa, nem a expressividade da linguagem. Na verdade, um programa com componentes sem parâmetros é alfa equivalente a um sem. Portanto, não estou interessado em respostas que afirmam que tal recurso não é necessário (a menos que seja essa a razão declarada dos designers de Objective-C; alguém conhece Brad Cox ou Tom Love? Eles estão aqui?) Ou que dizem como escrever nomes de métodos para que o recurso não seja necessário. O principal benefício é a legibilidade e a gravabilidade (que é como a legibilidade, só ... você sabe), pois isso significaria que você poderia escrever nomes de métodos que se assemelham ainda mais a sentenças de linguagem natural. Gostos de -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(que Matt Gallagher aponta em "Cocoa With Love"-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed, colocando assim o parâmetro imediatamente próximo ao substantivo apropriado.

O tempo de execução Objective-C da Apple (por exemplo) é perfeitamente capaz de lidar com esse tipo de seletores, então por que não o compilador? Por que não suportá-los em nomes de métodos também?

#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;
}
outis
fonte
1
não consigo explicar o motivo pelo qual não é possível, mas por que deveria ser possível? A Apple nomearia os métodos "takeAndRun:" e "takeAndDontComplain:";)
Ou takeAndRunWith:(id)theMoneye takeAndDon'tComplainAbout:(id)yourMedicine. Gramaticamente estranho, com certeza.
Matthew Frederick
13
Obrigado por perguntar isso - é uma pergunta muito interessante. Vou perguntar por aí.
bbum
5
É a estranheza gramatical forçada ocasional que me faz querer o recurso.
outis
1
Ótima pergunta. Apenas como um aparte, o compilador não tem problemas com métodos nomeados como este: - (void) :(id)theMoney;ou - (void) :(id)obj1 :(id)obj2;. Portanto, os seletores que consistem em nada além de dois pontos são adequados. ;-)
Ole Begemann

Respostas:

111

Este é o Brad Cox. Minha resposta original entendeu mal a pergunta. Eu presumi que realmenteFast fosse uma extensão codificada para acionar mensagens mais rápidas, não um tipo de açúcar sintático. A verdadeira resposta é que Smalltalk não o suportava, talvez porque seu analisador não pudesse lidar com a ambigüidade (assumida). Embora os colchetes do OC eliminassem qualquer ambigüidade, simplesmente não pensei em me afastar da estrutura de palavras-chave de Smalltalk.

Brad Cox
fonte
Obrigado, Brad. Minha interpretação de sua resposta foi a mesma; essa saída de SmallTalk não foi considerada.
bbum
42

21 anos programando Objective-C e essa questão nunca me passou pela cabeça. Dado o design da linguagem, o compilador está certo e as funções de tempo de execução estão erradas ().

A noção de argumentos intercalados com nomes de métodos sempre significou que, se houver pelo menos um argumento, o último argumento é sempre a última parte da sintaxe de invocação do método.

Sem pensar muito sobre isso, aposto que existem alguns problemas sintáticos em não impor o padrão atual. No mínimo, tornaria o compilador mais difícil de escrever, pois qualquer sintaxe que tenha elementos opcionais intercalados com expressões é sempre mais difícil de analisar. Pode até haver um caso extremo que evite isso. Certamente, Obj-C ++ o tornaria mais desafiador, mas ele não foi integrado à linguagem até anos depois que a sintaxe básica já estava gravada em pedra.

Quanto ao motivo pelo qual Objective-C foi projetado dessa forma, eu suspeito que a resposta é que os designers originais da linguagem simplesmente não consideraram permitir que a sintaxe intercalada fosse além do último argumento.

Esse é o melhor palpite. Vou perguntar a um deles e atualizar minha resposta quando descobrir mais.


Perguntei a Brad Cox sobre isso e ele foi muito generoso em responder detalhadamente (Obrigado, Brad !!):

Eu estava focado na época em duplicar o máximo possível de Smalltalk em C e fazer isso da maneira mais eficiente possível. Todos os ciclos sobressalentes eram usados ​​para tornar as mensagens comuns mais rápidas. Não foi pensado em uma opção de mensagem especializada ("reallyFast?" [ Bbum: Eu perguntei usando 'doSomething: withSomething: reallyFast' como exemplo ]), uma vez que as mensagens comuns já eram tão rápidas quanto poderiam ser. Isso envolvia o ajuste manual da saída do montador do proto-mensageiro C, que era um pesadelo de portabilidade que parte, senão tudo, foi removido posteriormente. Eu me lembro que o messager hackeado à mão era muito rápido; sobre o custo de duas chamadas de função; um para entrar na lógica do messager e o resto para fazer pesquisas de método uma vez lá.
Aprimoramentos de tipagem estática foram posteriormente adicionados no topo da tipagem dinâmica pura de Smalltalk por Steve Naroff e outros. Eu tinha um envolvimento limitado nisso.

Vá ler a resposta de Brad!

bbum
fonte
Bugaboos de sintaxe me interessam muito.
outis
1
Parece-me que, se você tiver um pedaço do nome do método sem dois-pontos, terá um problema de análise porque não pode ter certeza se a intenção é fazer parte do nome do método ou não.
NSResponder
2
Passou pela minha cabeça a primeira vez que desenhei um protocolo para um delegado, o que aconteceu muito menos de 21 anos depois de começar com Objective-C. O padrão normal é fornecer o objeto enviando a mensagem de delegado como o primeiro parâmetro. por exemplo -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Isso leva a uma inconsistência gritante nos nomes dos métodos se você tiver um método no protocolo que não precise de outros parâmetros. Veja NSTableViewDataSource para um exemplo. Um método não segue o padrão limpo e agradável de todos os outros.
JeremyP
21

Apenas para sua informação, o tempo de execução não se preocupa realmente com os seletores, qualquer string C é válida, você também pode fazer um seletor como este: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "sem nenhum argumento o tempo de execução irá aceitá-lo, o compilador simplesmente não pode ou então é impossível analisar. Não há absolutamente nenhuma verificação de sanidade quando se trata de seletores.

Psicopata
fonte
7
1 Achei que você estava totalmente louco por sugerir isso, mas você está certo. Para aqueles de vocês que não acreditam: pastie.org/1388361
Dave DeLong
6

Presumo que eles não sejam suportados em Objective-C porque também não estavam disponíveis em Smalltalk. Mas isso tem um motivo diferente do que você pensa: eles não são necessários. O que é necessário é o suporte para métodos com 0, 1, 2, 3, ... argumentos. Para cada número de argumentos, já existe uma sintaxe de trabalho para chamá-los. Adicionar qualquer outra sintaxe apenas causaria confusão desnecessária.

Se você queria seletores sem parâmetros com várias palavras, por que parar com uma única palavra extra? Pode-se então perguntar que

 [axolotl perform selector: Y with object: Y]

também se torna compatível (ou seja, um seletor é uma sequência de palavras, algumas com dois pontos e um parâmetro, e outras não). Embora isso tivesse sido possível, presumo que ninguém considerou que valesse a pena.

Martin v. Löwis
fonte
1
Eu tinha pensado no argumento "eles não são necessários", mas não estava interessado nele. A pergunta atualizada torna isso mais claro. Permitir que componentes do seletor arbitrário não recebam parâmetros oferece menos capacidade de escrita, pois a diferença entre espaços e caixa de camelo é menor do que a diferença entre um componente final sem parâmetros e reescrever declarações de linguagem natural e parâmetros de reposicionamento (ambos os quais devem ser feitos com ObjC, como é).
outis
Além disso, permitir componentes sem parâmetros arbitrários aumenta a possibilidade de colisões de palavras-chave e complica a resolução de nomes, especialmente ao misturar C ++ e ObjC ( ande orseriam obstáculos específicos). Isso aconteceria muito menos se apenas o componente final de um nome de método não tivesse nenhum parâmetro, pois tenderia a consistir em várias palavras.
outis