Notación de puntos frente a notación de mensaje para propiedades declaradas


81

Ahora tenemos la notación "punto" para las propiedades. He visto varios vuelta y forths sobre los méritos de la notación de puntos frente a la notación mensaje. Para mantener las respuestas intactas, no voy a responder de ninguna manera en la pregunta.

¿Qué piensa acerca de la notación de puntos frente a la notación de mensajes para acceder a propiedades?

Intente mantenerlo enfocado en Objective-C; mi único sesgo que presentaré es que Objective-C es Objective-C, por lo que su preferencia de que sea como Java o JavaScript no es válida.

Los comentarios válidos tienen que ver con cuestiones técnicas (orden de las operaciones, precedencia del reparto, rendimiento, etc.), claridad (estructura frente a naturaleza del objeto, tanto a favor como en contra), concisión, etc.

Tenga en cuenta que soy de la escuela de calidad rigurosa y legibilidad en el código, habiendo trabajado en proyectos enormes donde la convención y la calidad del código son primordiales (el paradigma escribir una vez leído mil veces).


14
+1 esta es una gran pregunta y obtendrás muchas respuestas contradictorias. =)
Dave DeLong

1
El editor de código fuente debe ajustarse a las preferencias personales del programador, sin cambiar los caracteres del archivo en sí. De esa forma, todos obtendrían lo que quisieran.
Arne Evertsson

Respuestas:


64

No use el punto para el comportamiento. Utilice el punto para acceder o establecer atributos como cosas, normalmente atributos declarados como propiedades.

x = foo.name; // good
foo.age = 42; // good

y = x.retain; // bad

k.release; // compiler should warn, but some don't. Oops.

v.lockFocusIfCanDraw; /// ooh... no. bad bad bad

Para las personas nuevas en Objective-C, recomendaría no usar el punto para nada más que para cosas declaradas como @property. Una vez que tenga una idea del idioma, haga lo que le parezca correcto.

Por ejemplo, encuentro lo siguiente perfectamente natural:

k = anArray.count;
for (NSView *v in myView.subviews) { ... };

Puede esperar que el analizador estático de clang aumente la capacidad de permitirle verificar que el punto se esté usando solo para ciertos patrones o no para ciertos otros patrones.


18
Vaya, ni siquiera sabía que podía usar la sintaxis de puntos para cualquier otra cosa que no fueran propiedades. ¡Coloréame sorprendido! (Pero estoy de acuerdo, dot solo debe usarse para propiedades)
jbrennan

13
Eso es incorrecto. La notación de puntos es un sinónimo directo de una llamada de método equivalente; nada más y nada menos.
bbum

2
Me pregunto por qué la notación de puntos no se restringió a los descriptores de acceso declarados por @ propiedad. Parece que habría permitido a los autores de clases resolver áreas grises sobre qué métodos deberían permitirse en la notación de puntos, y no se sentiría tan ambiguo si usar o no métodos como .uppercaseStringsi la clase pudiera expresar su intención y tenerla ejecutado por el compilador. Quizás hay algo que me falta y que requiere la implementación actual de la notación de puntos.

4
Podría haberse limitado a @propertysolo, pero eso requeriría que el consumidor de una API aprenda otra dimensión booleana de información y que los diseñadores de API probablemente se ahoguen en argumentos sobre lo que debería y no debería ser un @property. Tenga en cuenta que Xcode prefiere los @propertymétodos implícitos al completar el código ... se recomienda, pero no se aplica.
bbum

1
@rodamn Sí responde eso; recomienda usar el punto con accesos @propertydeclarados solo cuando sea nuevo en el idioma. A medida que uno gana confianza con la codificación en Objective-C, haga lo que le parezca correcto. Interesante; muchos de nosotros hemos vuelto al uso muy limitado del punto.
bbum

22

Permítanme comenzar diciendo que comencé a programar en Visual / Real Basic, luego pasé a Java, así que estoy bastante acostumbrado a la sintaxis de puntos. Sin embargo, cuando finalmente me mudé a Objective-C y me acostumbré a los corchetes, luego vi la introducción de Objective-C 2.0 y su sintaxis de puntos, me di cuenta de que realmente no me gusta. (para otros idiomas está bien, porque así es como funcionan).

Tengo tres beefs principales con sintaxis de puntos en Objective-C:

Carne de res n. ° 1: No queda claro por qué podría estar recibiendo errores. Por ejemplo, si tengo la línea:

something.frame.origin.x = 42;

Entonces obtendré un error del compilador, porque somethinges un objeto, y no puede usar estructuras de un objeto como el lvalue de una expresión. Sin embargo, si tengo:

something.frame.origin.x = 42;

Entonces esto se compila bien, porque somethinges una estructura en sí misma que tiene un miembro NSRect, y puedo usarlo como un lvalue.

Si estuviera adoptando este código, necesitaría dedicar un tiempo a tratar de averiguar qué somethinges. ¿Es una estructura? ¿Es un objeto? Sin embargo, cuando usamos la sintaxis de corchetes, es mucho más claro:

[something setFrame:newFrame];

En este caso, no hay absolutamente ninguna ambigüedad si somethinges un objeto o no. La introducción de la ambigüedad es mi problema número uno.

Beef # 2: En C, la sintaxis de puntos se usa para acceder a miembros de estructuras, no a métodos de llamada. Los programadores pueden anular los métodos setFoo:y foode un objeto, pero aún así acceder a ellos a través de something.foo. En mi mente, cuando veo expresiones que usan la sintaxis de puntos, espero que sean una simple asignación en un ivar. Este no es siempre el caso. Considere un objeto controlador que media una matriz y una vista de tabla. Si llamo myController.contentArray = newArray;, esperaría que reemplazara la matriz anterior con la nueva matriz. Sin embargo, es posible que el programador original se haya anulado setContentArray:no solo para configurar la matriz, sino también para volver a cargar la vista de tabla. Desde la línea, no hay indicios de ese comportamiento. Si tuviera que ver[myController setContentArray:newArray];, entonces pensaba "Ajá, un método. Necesito ir a ver la definición de este método sólo para asegurarme de saber lo que está haciendo".

Así que creo que mi resumen de Beef # 2 es que puede anular el significado de la sintaxis de puntos con código personalizado.

Ternera # 3: Creo que se ve mal. Como programador de Objective-C, estoy totalmente acostumbrado a la sintaxis entre corchetes, por lo que leer y ver líneas y líneas de hermosos corchetes y luego romper repentinamente con, foo.name = newName; foo.size = newSize;etc., me distrae un poco. Me doy cuenta de que algunas cosas requieren sintaxis de puntos (estructuras C), pero esa es la única vez que las uso.

Por supuesto, si está escribiendo código para usted mismo, use lo que le resulte cómodo. Pero si está escribiendo un código que está planeando en código abierto, o está escribiendo algo que no espera mantener para siempre, le recomiendo encarecidamente que use la sintaxis de corchetes. Esta es, por supuesto, solo mi opinión.

Publicación de blog reciente contra la sintaxis de puntos: http://weblog.bignerdranch.com/?p=83

Refutación a la publicación anterior: http://eschatologist.net/blog/?p=226 (con artículo original a favor de la sintaxis de puntos: http://eschatologist.net/blog/?p=160 )


5
Beef # 1 me parece un poco engañoso. No veo cómo eso es una preocupación más de lo que podría intentar enviar un mensaje a una estructura y luego tener que darse cuenta de que la variable es en realidad una estructura. ¿De verdad ve a mucha gente que entiende cómo funciona confundirse con esto en la práctica? Esto parece ser el tipo de cosas que estropearías una vez, aprenderías sobre lvalue y luego lo harías bien en el futuro, como, digamos, no tratar de tratar NSNumbers como ints.
Chuck

2
@Chuck, es algo así como un caso marginal, pero yo hago bastante desarrollo de contratos, lo que implica heredar proyectos y tener que trabajar con ellos. Por something lo general, es un objeto, pero me he encontrado con un par de lugares donde los autores originales han creado estructuras (para velocidad, menor uso de memoria, etc.), y tengo que pasar un buen par de minutos tratando de averiguar por qué el código no lo hace. t compilar.
Dave DeLong

14

Soy un nuevo desarrollador de Cocoa / Objective-C, y mi opinión es la siguiente:

Me quedo con la notación de mensajería, aunque comencé con Obj-C 2.0, y aunque la notación de puntos me resulta más familiar (Java es mi primer idioma). Mi razón para esto es bastante simple: todavía no entiendo exactamente por qué agregaron la notación de puntos al idioma. A mí me parece una adición innecesaria, "impura". Aunque si alguien puede explicar cómo beneficia el idioma, me encantaría escucharlo.

Sin embargo, considero que esta es una elección estilística, y no creo que haya una forma correcta o incorrecta, siempre que sea coherente y legible , al igual que con cualquier otra opción estilística (como poner la llave de apertura en la misma línea que el encabezado del método o la siguiente línea).


2
+1 gran respuesta. Realmente me gustaría saber el "por qué" detrás de esto también. Quizás bbum o mmalc conocen la respuesta ... (ambos trabajan en )
Dave DeLong

11

La notación de puntos Objective-C es un azúcar sintáctico que se traduce al paso normal de mensajes, por lo que bajo el capó no cambia nada y no hace ninguna diferencia en tiempo de ejecución. La notación de puntos no es absolutamente más rápida que el paso de mensajes.

Después de este pequeño preámbulo necesario, he aquí los pros y los contras:

Pros y contras de la notación de puntos

  • pros

    • legibilidad: la notación de puntos es más fácil de leer que los corchetes anidados.
    • Simplifica la interacción con Atributos y Propiedades: utilizando la notación de puntos para las propiedades y la notación de mensajes para los métodos, puede lograr la separación de estado y comportamiento a nivel de Synthax
    • Es posible utilizar el operador de asignación compuesta (1) .
    • usando la @propertynotación de puntos y el compilador hace mucho trabajo por usted, puede generar código para una buena administración de memoria al obtener y configurar la propiedad; esta es la razón por la que las guías oficiales de Apple sugieren la notación de puntos.
  • contras

    • La notación de puntos solo se permite para acceder a un @property
    • Dado que Objective-C es una capa por encima del estándar C (extensión de lenguaje), la notación de puntos no deja en claro si la entidad a la que se accede es un objeto o una estructura. A menudo, parece que está accediendo a las propiedades de una estructura.
    • al llamar a un método con la notación de puntos, pierde los parámetros con nombre ventajas de legibilidad
    • cuando la notación de mensajes mixta y la notación de puntos parece que está codificando en dos idiomas diferentes

Ejemplos de código:

(1) Ejemplo de código de uso de operador compuesto:

//Use of compound operator on a property of an object
anObject.var += 1;
//This is not possible with standard message notation
[anObject setVar:[anObject var] + 1];

7

Usar el estilo de un idioma, de acuerdo con el idioma en sí, es el mejor consejo aquí. Sin embargo, este no es un caso de escribir código funcional en un sistema OO (o viceversa) y la notación de puntos es parte de la sintaxis en Objective-C 2.0.

Se puede hacer un mal uso de cualquier sistema. La existencia del preprocesador en todos los lenguajes basados ​​en C es suficiente para hacer cosas realmente bastante extrañas; solo mire el Concurso C ofuscado si necesita ver exactamente lo extraño que puede llegar a ser. ¿Significa eso que el preprocesador es automáticamente malo y que nunca debería usarlo?

El uso de la sintaxis de puntos para acceder a las propiedades, que se han definido como tales en la interfaz, está sujeto a abusos. La existencia de abuso in potentia no debería ser necesariamente un argumento en contra.

El acceso a la propiedad puede tener efectos secundarios. Esto es ortogonal a la sintaxis utilizada para adquirir esa propiedad. CoreData, delegación, propiedades dinámicas (primero + último = completo) necesariamente harán algún trabajo bajo las sábanas. Pero eso confundiría las 'variables de instancia' con las 'propiedades' de un objeto. No hay ninguna razón por la que las propiedades deban necesariamente almacenarse como están, especialmente si pueden calcularse (por ejemplo, la longitud de una cadena, por ejemplo). Entonces, ya sea que use foo.fullName o [foo fullName], todavía habrá una evaluación dinámica.

Por último, el comportamiento de la propiedad (cuando se usa como un valor l ) lo define el objeto mismo, como si se toma una copia o si se retiene. Esto hace que sea más fácil cambiar el comportamiento más adelante, en la propia definición de propiedad, en lugar de tener que volver a implementar los métodos. Eso se suma a la flexibilidad del enfoque, con la probabilidad resultante de que se produzcan menos errores (de implementación). Todavía existe la posibilidad de elegir el método incorrecto (es decir, copiar en lugar de retener) pero ese es un problema de arquitectura más que de implementación.

En última instancia, se reduce a la pregunta de '¿parece una estructura?'. Este es probablemente el principal diferenciador en los debates hasta ahora; si tiene una estructura, funciona de manera diferente que si tiene un objeto. Pero eso siempre ha sido cierto; no puede enviar una estructura a un mensaje, y necesita saber si está basado en pila o en referencia / malloc. Ya existen modelos mentales que difieren en términos de uso ([[CGRect alloc] init] o struct CGRect?). Nunca se han unificado en términos de comportamiento; necesita saber a qué se enfrenta en cada caso. Es muy poco probable que agregar denotaciones de propiedad para objetos confunda a cualquier programador que sepa cuáles son sus tipos de datos; y si no lo hacen, tienen problemas mayores.

En cuanto a consistencia; (Objetivo-) C es inconsistente en sí mismo. = se utiliza tanto para asignación como para igualdad, según la posición léxica en el código fuente. * se utiliza para punteros y multiplicaciones. Los BOOL son caracteres, no bytes (u otro valor entero), a pesar de que YES y NO son 1 y 0 respectivamente. La coherencia o la pureza no es para lo que se diseñó el lenguaje; se trataba de hacer las cosas.

Entonces, si no quiere usarlo, no lo use. Hágalo de una manera diferente. Si quiere usarlo y lo comprende, está bien si lo usa. Otros lenguajes tratan con los conceptos de estructuras de datos genéricas (mapas / estructuras) y tipos de objetos (con propiedades), a menudo usando la misma sintaxis para ambos a pesar de que uno es simplemente una estructura de datos y el otro es un objeto rico. Los programadores en Objective-C deben tener una capacidad equivalente para poder manejar todos los estilos de programación, incluso si no es el preferido.


6

Lo uso para propiedades porque

for ( Person *person in group.people){ ... }

es un poco más fácil de leer que

for ( Person *person in [group  people]){ ... }

en el segundo caso, la legibilidad se interrumpe al poner su cerebro en modo de envío de mensajes, mientras que en el primer caso está claro que está accediendo a la propiedad de personas del objeto de grupo.

También lo usaré al modificar una colección, por ejemplo:

[group.people addObject:another_person];

es un poco más legible que

[[group people] addObject:another_person];

El énfasis en este caso debería estar en la acción de agregar un objeto a la matriz en lugar de encadenar dos mensajes.


5

En su mayoría, me crié en la era de Objective-C 2.0 y prefiero la notación de puntos. Para mí, permite la simplificación del código, en lugar de tener corchetes adicionales, puedo usar un punto.

También me gusta la sintaxis de puntos porque me hace sentir que estoy accediendo a una propiedad del objeto, en lugar de simplemente enviarle un mensaje (por supuesto, la sintaxis de puntos realmente se traduce en el envío de mensajes, pero por el bien de las apariencias , el punto se siente diferente). En lugar de "llamar a un captador" con la sintaxis anterior, realmente se siente como si estuviera obteniendo algo útil directamente del objeto.

Parte del debate en torno a esto tiene que ver con "¡Pero ya tenemos sintaxis de puntos, y es para structs!". Y eso es cierto. Pero (y nuevamente, esto es solo psicológico) básicamente siento lo mismo para mí. Acceder a una propiedad de un objeto usando la sintaxis de puntos se siente igual que acceder a un miembro de una estructura, que es más o menos el efecto deseado (en mi opinión).

**** Editar: como señaló bbum, también puede usar la sintaxis de puntos para llamar a cualquier método en un objeto (no lo sabía). Entonces diré que mi opinión sobre la sintaxis de puntos es solo para tratar con las propiedades de un objeto, no el envío de mensajes cotidianos **


3

Prefiero la sintaxis de mensajería ... pero solo porque eso es lo que aprendí. Teniendo en cuenta que muchas de mis clases y las que no están en el estilo Objective-C 1.0, no me gustaría mezclarlas. No tengo ninguna razón real además de "a lo que estoy acostumbrado" para no usar la sintaxis de puntos ... EXCEPTO por esto, esto me vuelve loco

[myInstance.methodThatReturnsAnObject sendAMessageToIt]

No sé por qué, pero realmente me enfurece, sin una buena razón. Solo creo que haciendo

[[myInstance methodThatReturnsAnObject] sendAMessageToIt]

es más legible. ¡Pero a cada cual lo suyo!


3
Hago esto de vez en cuando, pero solo si accedo a una propiedad. Por ejemplo: [self.title lowercaseString]o algo. Pero puedo ver estilísticamente por qué es molesto mezclar y combinar la sintaxis. La única razón por la que lo hago es para aclarar qué es una propiedad y qué es un método que devuelve un objeto (sé que las propiedades son realmente solo eso, pero espero que entiendas lo que quiero decir).
jbrennan

3

Honestamente, creo que se trata de una cuestión de estilo. Personalmente, estoy en contra de la sintaxis de puntos (especialmente después de descubrir que puede usarla para llamadas a métodos y no solo para leer / escribir variables). Sin embargo, si lo va a usar, le recomiendo encarecidamente que no lo use para nada más que acceder y cambiar variables.


3

Una de las principales ventajas de la programación orientada a objetos es que no hay acceso directo al estado interno de los objetos.

La sintaxis de puntos me parece que es un intento de hacer que se vea y se sienta como si se estuviera accediendo directamente al estado. Pero en verdad, es solo azúcar sintáctico sobre los comportamientos -foo y -setFoo :. Yo prefiero llamar a las cosas por su nombre. La sintaxis de puntos ayuda a la legibilidad en la medida en que el código es más conciso, pero no ayuda a la comprensión porque no tener en cuenta que realmente está llamando -foo y -setFoo: podría significar problemas.

Los descriptores de acceso sintetizados me parecen un intento de facilitar la escritura de objetos en cuyo estado se accede directamente. Creo que esto fomenta exactamente el tipo de diseño de programa para el que se creó la programación orientada a objetos.

En general, preferiría que la sintaxis de puntos y las propiedades nunca se hayan introducido. Solía ​​poder decirle a la gente que ObjC son algunas extensiones limpias de C para que se parezca más a Smalltalk, y ya no creo que eso sea cierto.


2

En mi opinión, la sintaxis de puntos hace que Objective-C sea menos Smalltalk-esque. Puede hacer que el código parezca más simple, pero agrega ambigüedad. ¿Es una struct, uniono un objeto?


2

Mucha gente parece estar mezclando 'propiedades' con 'variables de instancia'. El objetivo de las propiedades es hacer posible modificar el objeto sin tener que conocer sus partes internas, creo. La variable de instancia es, la mayoría de las veces, la 'implementación' de una propiedad (que a su vez es la 'interfaz'), pero no siempre: a veces una propiedad no corresponde a un ivar, y en su lugar calcula un valor de retorno ' sobre la marcha'.

Por eso creo que la idea de que "la sintaxis de puntos te engaña haciéndote pensar que estás accediendo a la variable, por lo que es confuso" es incorrecta. Punto o corchete, no debe hacer suposiciones sobre los componentes internos: es una propiedad, no un ivar.


Como nota al margen, las referencias a objetos de Objective-C no son variables de estructuras de C directas, sino más bien "punteros a estructuras", por lo que la sintaxis de puntos no tendría sentido para acceder a los miembros directamente; es el operador de flecha el ->que cumple esa función (siempre que dichos ivars no tengan acceso restringido, por supuesto).
Nicolas Miari

1

Creo que podría cambiar a la mensajería en lugar de la notación de puntos porque en mi cabeza object.instanceVar es solo instanceVar que pertenece al objeto , para mí no se parece en nada a una llamada a un método , que es, así que podría haber cosas on en su descriptor de acceso y si usa instanceVar o self.instanceVar podría tener una diferencia mucho mayor que simplemente implícita versus explícita. Solo mis 2 ¢.


1

La notación de puntos intenta hacer que los mensajes parezcan accesos a un miembro de una estructura, lo que no es así. Podría funcionar bien en algunos casos. Pero pronto a alguien se le ocurrirá algo como esto:

NSView *myView = ...;
myView.frame.size.width = newWidth;

Se ve bien. Pero no es. Es lo mismo que

[myView frame].size.width = newWidth;

que no funciona. El compilador acepta el primero, pero legítimamente no el segundo. E incluso si emitió un error o advertencia para el primero, esto es confuso.


1

Llámame vago pero si tuviera que escribir un sencillo '.' vs. dos [] cada vez para obtener los mismos resultados, preferiría una sola. Odio los lenguajes prolijos. El () en ceceo me volvió loco. El lenguaje elegante como las matemáticas es conciso y efectivo, todos los demás se quedan cortos.


1
El problema es que las matemáticas, aunque concisas y efectivas, no son un lenguaje regular y, por lo tanto, no podemos analizarlas y compilarlas. Observe, por ejemplo, que en las funciones matemáticas es común escribirlas entre paréntesis, porque sería mucho más difícil seguirlas sin ellas.
jbrennan

1

Utilice la notación de puntos (siempre que pueda)

En los métodos de instancia que devuelven algún valor

No use notación de puntos

En los métodos de instancia que devuelven vacío, en los métodos init o en el método Class.

Y mi excepción favorita personal

NSMutableArray * array = @[].mutableCopy;

0

Personalmente, no uso la notación de puntos en el código. Solo lo uso en la expresión de enlace CoreData KVC cuando es necesario.

La razón para no usarlos en el código para mí es que la notación de puntos oculta la semántica del setter. Establecer una propiedad en notación de puntos siempre parece una asignación, independientemente de la semántica del establecedor (asignar / retener / copiar). El uso de la notación de mensaje hace visible que el objeto receptor tiene control sobre lo que sucede en el colocador y subraya el hecho de que esos efectos deben ser considerados.

Todavía estoy considerando si podría querer usar la notación de puntos al recuperar el valor de una propiedad declarada o compatible con KVC porque es cierto que es un poco más compacto y legible y no hay semántica oculta. En este momento me quedo con la notación de mensajes en aras de la coherencia.


1
Puede que todavía estén sucediendo cosas ocultas. Un captador puede hacer otras cosas además de devolver una variable de instancia. Incluso si es una propiedad declarada, el captador no tiene que ser sintetizado o podría haber sido anulado en una subclase.
Sven

-1

De acuerdo, la notación de puntos en Objective-C parece extraña, de hecho. Pero todavía no puedo hacer lo siguiente sin él:

int width = self.frame.size.width;

Funciona bien, pero:

int height = [[[self frame] size] height];

Me da "No se puede convertir a un tipo de puntero". Sin embargo, realmente me gustaría que mi código se viera consistente con la notación de mensajes.


5
-frame devuelve un NSRect, que es una estructura C, no un objeto Objective-C. Es por eso que el segundo ejemplo provoca un error del compilador. Debe ser: int height = [self frame] .size.height;

1
Convenido. ¡Pero el punto después del corchete se ve horrible! Por lo general, primero almaceno el rect en una variable local.
Nicolas Miari

-2

Esta es una gran pregunta y veo muchas respuestas diferentes. Aunque muchos han tocado los temas, intentaré responder esto desde un ángulo diferente (algunos podrían haberlo hecho implícitamente):

Si usamos la notación 'punto', la resolución del objetivo para el método se realiza en tiempo de compilación. Si usamos el paso de mensajes, la resolución del objetivo se pospone a la ejecución en tiempo de ejecución. Si los objetivos se resuelven en tiempo de compilación, la ejecución es más rápida, ya que resolver los objetivos en tiempo de ejecución incluye algunos gastos generales. (No es que la diferencia horaria importe mucho). Dado que ya hemos definido la propiedad en la interfaz del objeto, no tiene sentido diferenciar la resolución del objetivo para una propiedad en tiempo de ejecución y, por lo tanto, la notación de puntos es la notación que debemos usar para acceder a la propiedad.


¿Sabe que en ObjectiveC los selectores se evalúan, resuelven e invocan en cualquier caso en tiempo de ejecución? Por lo tanto, la notación de puntos es un sinónimo puro del antiguo estilo de corchetes. No existen diferencias técnicas de ningún tipo. Tus suposiciones de velocidad son completamente erróneas: pruébalo, usa Instrumentos y mírate a ti mismo.
Hasta el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.