¿Los operadores son más claros de leer que las palabras clave o las funciones? [cerrado]

13

Es un poco subjetivo, pero espero obtener una comprensión más clara de qué factores hacen que un operador sea más fácil de usar, ya sea obtuso y difícil. He estado considerando los diseños de idiomas recientemente, y un problema que siempre vuelvo a dar vueltas es cuándo hacer una operación clave en el idioma como operador y cuándo usar una palabra clave o función.

Haskell es un poco conocido por esto, ya que los operadores personalizados son fáciles de crear y, a menudo, un nuevo tipo de datos vendrá empaquetado con varios operadores para su uso en él. La biblioteca Parsec, por ejemplo, viene con una tonelada de operadores para combinar analizadores juntos, con gemas como >. y .> . No puedo recordar lo que significan en este momento, pero sí recuerdo que son muy fáciles de trabajar. con una vez había memorizado lo que realmente significan. ¿Habría sido mejor una llamada de función como leftCompose(parser1, parser2) ? Ciertamente más detallado, pero más claro en algunos aspectos.

Las sobrecargas de operadores en lenguajes similares a C son un problema similar, pero se combinan con el problema adicional de sobrecargar el significado de operadores familiares como + con nuevos significados inusuales.

En cualquier idioma nuevo, esto parece un problema bastante difícil. En F #, por ejemplo, la conversión utiliza un operador de conversión de tipos matemáticamente derivado, en lugar de la sintaxis de conversión de estilo C # o el estilo verboso de VB. C #: (int32) x VB: CType(x, int32) F #: x :> int32

En teoría, un nuevo lenguaje podría tener operadores para la mayoría de las funciones integradas. En lugar de def o dec o var para la declaración de la variable, ¿por qué no ! name o @ name o algo similar. Ciertamente, acorta la declaración seguida por el enlace: @x := 5 en lugar de declare x = 5 o let x = 5 . La mayoría del código requerirá muchas definiciones de variables, ¿por qué no?

¿Cuándo un operador es claro y útil, y cuándo está ocultando?

    
pregunta CodexArcanum 15.03.2012 - 16:32

7 respuestas

16

Desde el punto de vista del diseño de lenguaje general, no es necesario que haya diferencias entre las funciones y los operadores. Uno podría describir las funciones como operaciones de prefijo con cualquier aridad (o incluso variable). Y las palabras clave se pueden ver simplemente como funciones u operadores con nombres reservados (lo cual es útil para diseñar una gramática).

Todas estas decisiones eventualmente se reducen a cómo desea que se lea la notación y que, como usted dice, es subjetivo, aunque se pueden hacer algunas racionalizaciones obvias, por ejemplo. use los operadores de infijo habituales para las matemáticas como todos los conocen

Por último, Dijkstra escribió una interesante justificación de las notaciones matemáticas que usó, que incluye una buena discusión de las compensaciones de infix vs notaciones de prefijo

    
respondido por el jk. 15.03.2012 - 17:04
8

Para mí, un operador deja de ser útil cuando ya no puede leer la línea de código en voz alta o en su cabeza, y tiene sentido.

Por ejemplo, declare x = 5 lee como "declare x equals 5" o let x = 5 puede leerse como "let x equal 5" , lo cual es muy comprensible cuando se lee en voz alta, sin embargo, leer @x := 5 se lee como "at x colon equals 5" (o% co_de) % si eres matemático), lo cual no tiene ningún sentido.

En mi opinión, use un operador si el código puede ser leído en voz alta y entendido por una persona razonablemente inteligente que no esté familiarizada con el idioma, pero use nombres de funciones si no.

    
respondido por el Rachel 15.03.2012 - 16:46
4

Un operador es claro y útil cuando está familiarizado. Y eso probablemente significa que los operadores de sobrecarga deben hacerse solo cuando el operador elegido está lo suficientemente cerca (como en forma, precedencia y asociatividad) como una práctica ya establecida.

Pero cavando un poco más, hay dos aspectos.

La sintaxis (infijo para operador en lugar de prefijo para sintaxis de llamada de función) y la denominación.

Para la sintaxis, hay otro caso en el que los infijos son lo suficientemente más claros que el prefijo como para justificar el esfuerzo de familiarizarse: cuando las llamadas están encadenadas y anidadas.

Compare a * b + c * d + e * f con +(+(*(a, b), *(c, d)), *(e, f)) o + + * a b * c d * e f (ambos se pueden analizar en la misma condición que la versión de infijo). El hecho de que + separe los términos en lugar de preceder a uno de ellos en gran medida hace que sea más fácil de leer (pero hay que recordar las reglas de precedencia que no son necesarias para la sintaxis de prefijo). Si necesita componer las cosas de esta manera, el beneficio a largo plazo valdrá el costo de aprendizaje. Y mantienes esta ventaja incluso si nombras a tus operadores con letras en lugar de usar símbolos.

Con respecto a la denominación de los operadores, veo pocas ventajas en el uso de algo más que los símbolos establecidos o el nombre claro. Sí, pueden ser más cortos, pero son realmente crípticos y se olvidarán rápidamente si no tienes una buena razón para conocerlos.

Un tercer aspecto si toma un POV de diseño de idioma, es si el conjunto de operadores debería estar abierto o cerrado, ¿puede agregar un operador o no, y si la prioridad y la asociatividad deben ser o no especificables por el usuario? Mi primer intento sería ser cuidadoso y no proporcionarle al usuario prioridad y asociatividad específicas, mientras que estaría más abierto al tener un conjunto abierto (aumentaría el impulso de usar la sobrecarga del operador, pero disminuiría el uso de uno malo). solo para beneficiarse de la sintaxis de infijo donde es útil).

    
respondido por el AProgrammer 15.03.2012 - 17:08
1

Los operadores-como-símbolos son útiles cuando intuitivamente tienen sentido. + y - son obviamente sumas y restas, por ejemplo, razón por la cual casi todos los idiomas los utilizan como operadores. Lo mismo ocurre con la comparación ( < y > se enseñan en la escuela primaria, y <= y >= son extensiones intuitivas de las comparaciones básicas cuando entiendes que no hay teclas de comparación subrayadas en el teclado estándar).

* y / son menos obvios de inmediato, pero se usan universalmente y su posición en el teclado numérico justo al lado de las teclas + y - ayuda a proporcionar contexto. Los << y >> de C están en la misma categoría: cuando entiendes lo que son un cambio a la izquierda y un cambio a la derecha, no es demasiado difícil entender las mnemotécnicas detrás de las flechas.

Luego se encuentra con algunos de los realmente extraños, cosas que pueden convertir el código C en una sopa de operador ilegible. (Marque aquí con C porque es un ejemplo muy pesado para el operador cuya sintaxis es muy parecida a todo el mundo, ya sea trabajando con C o con idiomas descendientes). Por ejemplo, entonces el operador % . Todo el mundo sabe lo que es: es un signo de porcentaje ... ¿verdad? Excepto en C, no tiene nada que ver con la división por 100; es el operador de módulo. Eso tiene sentido cero mnemónicamente, ¡pero ahí está!

Peor aún son los operadores booleanos. & como y tiene sentido, excepto que hay dos operadores & diferentes que hacen dos cosas diferentes, y ambos son sintácticamente válidos en cualquier caso donde uno de ellos es válido, aunque solo sea uno de ellos siempre en realidad tiene sentido en cualquier caso dado. ¡Eso es sólo una receta para la confusión! Los operadores o , xor y no son aún peores, ya que no usan símbolos de utilidad mnemónica y tampoco son consistentes. (No hay doble operador xor , y el lógico y en modo de bits no usa dos símbolos diferentes en lugar de un símbolo y una versión duplicada).

Y para empeorar las cosas, los operadores & y * se reutilizan para cosas completamente diferentes, lo que hace que el lenguaje sea más difícil de analizar para las personas y los compiladores. (¿Qué significa A * B ? Depende completamente del contexto: ¿ A es un tipo o una variable?)

Es cierto que nunca hablé con Dennis Ritchie y le pregunté sobre las decisiones de diseño que tomó en el lenguaje, pero se siente como si la filosofía de los operadores fuera "los símbolos por el bien de los símbolos".

Contraste esto con Pascal, que tiene los mismos operadores que C, pero una filosofía diferente para representarlos: los operadores deben ser intuitivos y fáciles de leer. Los operadores aritméticos son los mismos. El operador de módulo es la palabra mod , porque no hay un símbolo en el teclado que obviamente significa "módulo". Los operadores lógicos son and , or , xor y not , y solo hay uno de cada uno; el compilador sabe si necesita la versión booleana o bitwise en función de si está operando en números booleanos o números, eliminando toda una clase de errores. Esto hace que el código Pascal lejos sea más fácil de entender que el código C, especialmente en un editor moderno con resaltado de sintaxis para que los operadores y las palabras clave sean visualmente distintos de los identificadores.

    
respondido por el Mason Wheeler 15.03.2012 - 18:00
1

Creo que los operadores son mucho más legibles cuando su función refleja estrechamente su propósito matemático y familiar. Por ejemplo, los operadores estándar como +, -, etc. son más legibles que Agregar o Restar cuando se realizan sumas y restas. El comportamiento del operador debe estar claramente definido. Puedo tolerar una sobrecarga del significado de + para la concatenación de listas, por ejemplo. Idealmente, la operación no tendría efectos secundarios, devolviendo un valor en lugar de mutar.

Sin embargo, he luchado con operadores de acceso directo para funciones como fold. Obviamente, más experiencia con ellos facilitaría esto, pero encuentro foldRight más legible que /: .

    
respondido por el Matt H 15.03.2012 - 17:39
1

El problema con los operadores es que solo hay un pequeño número de ellos en comparación con el número de nombres de métodos sensuales (!) que podrían usarse en su lugar. Un efecto secundario es que los operadores definidos por el usuario tienden a introducir mucha sobrecarga.

Ciertamente, la línea C = A * x + b * c es más fácil de escribir y leer que C = A.multiplyVector(x).addVector(b.multiplyScalar(c)) .

O, bueno, ciertamente es más fácil de escribir, si tienes todas las versiones sobrecargadas de todos esos operadores en tu cabeza. Y puedes leerlo después, mientras arreglas el error segundo a último.

Ahora, para la mayoría de los códigos que se van a ejecutar allí, está bien. "El proyecto pasa todas las pruebas y se ejecuta": para muchos una parte del software es todo lo que podríamos desear.

Pero las cosas funcionan de manera diferente cuando estás haciendo un software que va a áreas críticas. Cosas críticas de seguridad. Seguridad. Software que mantiene los aviones en el aire, o que mantiene en funcionamiento las instalaciones nucleares. O software que encripta sus correos electrónicos altamente confidenciales.

Para los expertos en seguridad que se especializan en auditar códigos, esto puede ser una pesadilla. La combinación de una gran cantidad de operadores definidos por el usuario y la sobrecarga de operadores puede dejarlos en una situación desagradable, ya que les resulta difícil descubrir qué código se ejecutará con el tiempo.

Entonces, como se dijo en la pregunta original, este es un tema altamente subjetivo. Y aunque muchas sugerencias sobre cómo deben usarse los operadores pueden parecer perfectamente sensuales, la combinación de solo algunos de ellos puede crear muchos problemas a largo plazo.

    
respondido por el doppelfish 15.03.2012 - 22:41
0

Supongo que el ejemplo más extremo es APL, el siguiente programa es el "juego de la vida":

life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

¡Y si puede resolver lo que significa todo sin pasar un par de días con el manual de referencia, entonces buena suerte para usted!

El problema es que tienes un conjunto de símbolos que casi todos entienden intuitivamente: +,-,*,/,%,=,==,&

y el resto, que requieren alguna explicación antes de que puedan ser comprendidos, y, en general, son específicos del idioma en particular. Por ejemplo, no hay un símbolo obvio para especificar qué miembro de la matriz desea, [], () e incluso "." se han utilizado, pero igualmente no hay una palabra clave obvia que pueda usar fácilmente, por lo que hay un caso para el uso juicioso de los operadores. Pero no muchos de ellos.

    
respondido por el James Anderson 16.03.2012 - 10:57

Lea otras preguntas en las etiquetas