objective c - tutorial - ¿Por qué la última parte de un nombre de método de Objective-C toma un argumento(cuando hay más de una parte)?
objective c vs swift (4)
En Objective-C, no puede declarar nombres de método 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? ¿Fue solo un artefacto de Smalltalk que nadie vio la necesidad de deshacerse de él?
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 único al último argumento. Por ejemplo, BillyAndBobby take:''$100'' andRun
se analizará como BillyAndBobby take:(''$100'' andRun)
. Esto no importa en Objective-C donde se requieren corchetes.
El soporte de componentes selector sin parámetros no nos ganaría mucho en todas las formas habituales en que se mide un idioma, ya que el nombre del método runWith:
por el programador (por ejemplo, runWith:
lugar de take:andRun
) no afecta la semántica funcional de un programa, ni expresividad del lenguaje. De hecho, un programa con componentes sin parámetros es equivalente alfa a uno sin. Por lo tanto, no estoy interesado en respuestas que indiquen que tal característica no es necesaria (a menos que fueran las razones indicadas por los diseñadores de Objective-C, ¿alguien conoce a Brad Cox o Tom Love? ¿Están aquí?) O que dicen cómo escribir nombres de métodos para que la característica no sea necesaria. El principal beneficio es la legibilidad y la escritura (que es como la legibilidad, solo ... ya sabes), ya que significa que podrías escribir nombres de métodos que se asemejan aún más a las oraciones en el lenguaje natural. Los gustos de -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
(que Matt Gallagher señala en "Cocoa With Love" es un poco confuso cuando sueltas el parámetro formal) podría llamarse -(BOOL)application:(NSApplication*)theApplication shouldTerminateAfterLastWindowClosed
, colocando el parámetro inmediatamente al lado del nombre apropiado.
El tiempo de ejecución Objective-C de Apple (por ejemplo) es perfectamente capaz de manejar este tipo de selectores, ¿por qué no el compilador? ¿Por qué no apoyarlos en los nombres de métodos también?
#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;
}
21 años de programación Objective-C y esta pregunta nunca se me pasó por la cabeza. Dado el diseño del lenguaje, el compilador tiene razón y las funciones del 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, apostaría a que hay algunos obstáculos sintácticos que no imponen el patrón actual. Al menos, dificultaría la escritura del compilador, ya que cualquier sintaxis que tenga elementos opcionales intercalados con expresiones es siempre más difícil de analizar. Incluso podría haber una caja de borde que lo evite a toda máquina. Ciertamente, Obj-C ++ lo haría más desafiante, pero eso no fue integrado con el lenguaje hasta años después de que la sintaxis básica 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 fuera más allá de ese último argumento.
Esa es una mejor suposición. Preguntaré a uno de ellos y actualizaré mi respuesta cuando descubra 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 la mayor cantidad posible de Smalltalk en C y hacerlo de la manera más eficiente posible.Todos los ciclos de repuesto entraron para hacer que la mensajería ordinaria sea rápida.No se pensó en una opción de mensajería especializada ("reallyFast?" [ Bbum: pregunté usando ''doSomething: withSomething: really Fast'' como el ejemplo ]) ya que los mensajes normales ya eran lo más rápidos posible.Esto implicó el ajuste manual de la salida del ensamblador del proto-mensajero C, que era una pesadilla de portabilidad tal que algo si no todo eso se eliminó más tarde.Recuerdo que el mensajero hackeado 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 hacer búsquedas de métodos una vez allí.Las mejoras de tipado estáticas se agregaron luego de la tipada dinámica pura de Smalltalk por Steve Naroff y otros.Solo tuve una participación limitada en eso.
¡Ve a leer la respuesta de Brad!
Este es Brad Cox. Mi respuesta original no entendió la pregunta. Supuse que realmente Fast era una extensión codificada para activar mensajes más rápidos, no un tipo de azúcar sintáctico. La verdadera respuesta es que Smalltalk no lo soportaba, tal vez porque su analizador no podía manejar la (supuesta) ambigüedad. Aunque los corchetes de OC eliminarían cualquier ambigüedad, simplemente no pensé en apartarme de la estructura de palabras clave de Smalltalk.
Solo para su información, el tiempo de ejecución realmente no se preocupa por los selectores, cualquier cadena C es válida, también podría hacer un selector como ese: "== + === + ---__-- ¨¨¨¨ ¨ ^ :::::: "sin argumentos, el tiempo de ejecución lo aceptará, el compilador simplemente no puede o, de lo contrario, es imposible de analizar. No hay absolutamente ningún control de cordura cuando se trata de selectores.
Supongo que no son compatibles con Objective-C porque tampoco estaban disponibles en Smalltalk. Pero eso tiene una razón diferente de la que piensas: 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 hay una sintaxis funcional para llamarlos. Agregar cualquier otra sintaxis solo causaría una confusión innecesaria.
Si quería selectores sin palabras de palabras múltiples, ¿por qué detenerse con una sola palabra extra? Uno podría entonces preguntar eso
[axolotl perform selector: Y with object: Y]
también se vuelve compatible (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 lo consideró valioso.