¿Por qué la última parte del nombre de un método de Objective-C debe tomar un argumento (cuando hay más de una parte)?

90

En Objective-C, no puede declarar nombres de métodos donde el último componente no toma un argumento. Por ejemplo, lo siguiente es ilegal.

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

¿Por qué Objective-C fue diseñado de esta manera? ¿Era solo un artefacto de Smalltalk del que nadie vio la necesidad de deshacerse?

Esta limitación tiene sentido en Smalltalk, ya que Smalltalk no tiene delimitadores alrededor de la invocación de mensajes, por lo que el componente final se interpretaría como un mensaje unario para el último argumento. Por ejemplo, BillyAndBobby take:'$100' andRunse analizaría como BillyAndBobby take:('$100' andRun). Esto no importa en Objective-C, donde se requieren corchetes.

Admitir componentes de selector sin parámetros no nos beneficiaría mucho en todas las formas habituales en que se mide un lenguaje, ya que el nombre del método que elige un programador (por ejemplo, en runWith:lugar detake:andRun) no afecta la semántica funcional de un programa, ni la expresividad del lenguaje. De hecho, un programa con componentes sin parámetros es alfa equivalente a uno sin ellos. Por lo tanto, no me interesan las respuestas que indiquen que tal característica no es necesaria (a menos que esas fueran las razones declaradas por los diseñadores de Objective-C; ¿alguien conoce a Brad Cox o Tom Love? ¿Están aquí?) O que digan cómo escribir nombres de métodos para que la función no sea necesaria. El beneficio principal es la legibilidad y la capacidad de escritura (que es como la legibilidad, solo ... ya sabes), ya que significaría que podrías escribir nombres de métodos que se parezcan aún más a las oraciones del lenguaje natural. Los gustos de -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication(que Matt Gallagher señala en "Cocoa With Love"-(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed, colocando así el parámetro inmediatamente al lado del sustantivo apropiado.

El tiempo de ejecución Objective-C de Apple (por ejemplo) es perfectamente capaz de manejar este tipo de selectores, así que ¿por qué no el compilador? ¿Por qué no apoyarlos también en los nombres de los métodos?

#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
fuente
1
No puedo explicar la razón por la que no es posible, pero ¿por qué debería ser posible? Apple nombraría los métodos "takeAndRun:" y "takeAndDontComplain:";)
O takeAndRunWith:(id)theMoneyy takeAndDon'tComplainAbout:(id)yourMedicine. Gramaticalmente incómodo, sin duda.
Matthew Frederick
13
Gracias por hacer esto, es una pregunta muy interesante. Preguntaré por ahí.
bbum
5
Es la torpeza gramatical forzada ocasional lo que me hace querer la característica.
Salida
1
Gran pregunta. Como acotación al margen, el compilador no tiene ningún problema con métodos denominados así: - (void) :(id)theMoney;o - (void) :(id)obj1 :(id)obj2;. Por lo tanto, los selectores que solo contengan dos puntos están bien. ;-)
Ole Begemann

Respuestas:

111

Este es Brad Cox. Mi respuesta original entendió mal la pregunta. Asumí que realmenteFast era una extensión codificada para activar mensajes más rápidos, no una especie de azúcar sintáctico. La respuesta real es que Smalltalk no lo admitió, quizás porque su analizador no pudo lidiar con la ambigüedad (supuesta). Aunque los corchetes de OC eliminarían cualquier ambigüedad, simplemente no pensé en apartarme de la estructura de palabras clave de Smalltalk.

Brad Cox
fuente
Gracias, Brad. Mi interpretación de tu respuesta fue la misma; esa salida de SmallTalk no fue considerada.
bbum
42

21 años de programación de Objective-C y esta pregunta nunca se me ha pasado por la cabeza. Dado el diseño del lenguaje, el compilador tiene razón y las funciones en tiempo de ejecución son incorrectas ().

La noción de argumentos intercalados con nombres de métodos siempre ha significado que, si hay al menos un argumento, el último argumento es siempre la última parte de la sintaxis de invocación del método.

Sin pensarlo mucho, apuesto a que hay algunos errores sintácticos con no hacer cumplir el patrón actual. Al menos, haría que el compilador fuera más difícil de escribir, ya que cualquier sintaxis que tenga elementos opcionales intercalados con expresiones siempre es más difícil de analizar. Incluso podría haber un caso de borde que lo impida. Ciertamente, Obj-C ++ lo haría más desafiante, pero eso no se integró con el lenguaje hasta años después de que la sintaxis base ya estuviera escrita en piedra.

En cuanto a por qué Objective-C se diseñó de esta manera, sospecho que la respuesta es que los diseñadores originales del lenguaje simplemente no consideraron permitir que la sintaxis intercalada vaya más allá de ese último argumento.

Esa es la mejor suposición. Le preguntaré a uno de ellos y actualizaré mi respuesta cuando sepa más.


Le pregunté a Brad Cox sobre esto y fue muy generoso al responder en detalle (¡Gracias, Brad!):

En ese momento estaba concentrado en duplicar tanto Smalltalk como fuera posible en C y hacerlo de la manera más eficiente posible. Cualquier ciclo de repuesto se utilizó para acelerar la mensajería ordinaria. No se pensó en una opción de mensajería especializada ("¿Realmente Rápido?" [ Bbum: pregunté usando 'hacer algo: con algo: realmente Rápido' como ejemplo ]) ya que los mensajes ordinarios ya eran tan rápidos como podían ser. Esto implicó ajustar manualmente la salida del ensamblador del proto-messager de C, que fue una pesadilla de portabilidad tal que parte de eso, si no todo, se eliminó más tarde. Sí recuerdo que el mensajero pirateado a mano fue muy rápido; sobre el costo de dos llamadas a funciones; uno para entrar en la lógica del mensajero y el resto para realizar búsquedas de métodos una vez allí.
Más tarde, Steve Naroff y otros agregaron mejoras en la escritura estática además de la escritura dinámica pura de Smalltalk. Solo tuve una participación limitada en eso.

¡Ve a leer la respuesta de Brad!

bbum
fuente
Los bugaboos de sintaxis me interesan mucho.
Salida
1
Me parece que si tiene una parte del nombre del método sin dos puntos, tiene un problema de análisis porque no puede estar seguro de si está destinado a ser parte del nombre del método o no.
NSResponder
2
Se me pasó por la cabeza la primera vez que diseñé un protocolo para un delegado, mucho menos de 21 años después de comenzar con Objective-C. El patrón normal es suministrar el objeto que envía el mensaje de delegado como primer parámetro. ej -myObjectWithDelegate: (id) foo wantsYouToDoSomethingWith: (id) bar. Esto conduce a una discordancia discordante en los nombres de los métodos si tiene un método en el protocolo que no necesita otros parámetros. Consulte NSTableViewDataSource para ver un ejemplo. Un método no sigue el patrón ordenado y agradable de todos los demás.
JeremyP
21

Solo para su información, al tiempo de ejecución no le importan los selectores, cualquier cadena C es válida, también podría hacer un selector como ese: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "sin argumento, el tiempo de ejecución lo aceptará, el compilador simplemente no puede o es imposible analizarlo. No hay absolutamente ningún control de cordura cuando se trata de selectores.

Psicópata
fuente
7
+1 Pensé que estabas totalmente loco por sugerir esto, pero tienes razón. Para aquellos de ustedes que no creen: pastie.org/1388361
Dave DeLong
6

Supongo que no son compatibles con Objective-C porque tampoco estaban disponibles en Smalltalk. Pero eso tiene una razón diferente a la que cree: no son necesarios. Lo que se necesita es soporte para métodos con 0, 1, 2, 3, ... argumentos. Para cada número de argumentos, ya existe una sintaxis funcional para llamarlos. Agregar cualquier otra sintaxis solo causaría una confusión innecesaria.

Si deseaba selectores sin parámetros de varias palabras, ¿por qué detenerse con una sola palabra adicional? Entonces uno podría preguntar eso

 [axolotl perform selector: Y with object: Y]

también se admite (es decir, que un selector es una secuencia de palabras, algunas con dos puntos y un parámetro, y otras no). Si bien esto hubiera sido posible, supongo que nadie consideró que valiera la pena.

Martin contra Löwis
fuente
1
Había pensado en el argumento de "no son necesarios", pero no me interesaba. La pregunta actualizada aclara esto. Permitir que los componentes del selector arbitrario no tomen parámetros ofrece menos capacidad de escritura, ya que la diferencia entre los espacios y el caso camel es menor que la diferencia entre un componente final sin parámetros y la reescritura de declaraciones en lenguaje natural y los parámetros de reposicionamiento (ambos deben hacerse con ObjC, tal como está).
Salida
Además, permitir componentes arbitrarios sin parámetros aumenta la posibilidad de colisiones de palabras clave y complica la resolución de nombres, especialmente cuando se mezclan C ++ y ObjC ( andy orserían obstáculos particulares). Esto sucedería mucho menos si solo se permitiera que el componente final de un nombre de método no tuviera parámetro, ya que tendería a constar de varias palabras.
Salida