¿Por qué el operador de asignación asigna al lado izquierdo?

47

Hace poco comencé a enseñarle a una amiga a programar (estamos usando Python), y cuando comenzamos a hablar sobre la creación de variables y el operador de asignación, ella preguntó por qué el valor de la derecha está asignado al nombre de la izquierda, y no al revés .

No lo había pensado demasiado antes, porque me parecía natural, pero ella dijo que de izquierda a derecha le parecía más natural, ya que así es como la mayoría de nosotros leemos idiomas naturales.

Lo pensé y concluí que hace que el código sea mucho más fácil de leer, ya que los nombres asignados (que el programador deberá reutilizar) son fácilmente visibles, alineados a la izquierda.

aligned = 2
on = 'foo' + 'bar' + 'foobar'
the = 5.0 / 2
left = 2 + 5

Opuesto a:

2 = aligned 
'foo' + 'bar' + 'foobar' = on
5.0 / 2 = the 
2 + 5 = right 

# What were the names again...?

Ahora me pregunto si hay otras razones también para este estándar. ¿Hay una historia detrás de esto? ¿O hay alguna razón técnica por la que esta es una buena opción (no sé mucho sobre compiladores)? ¿Y hay algún lenguaje de programación que se asigne al lado derecho?

voithos
fuente
15
R puede asignar al lado derecho ( value -> variable).
Usted
¿Quizás esto se deba a nombres de variables incorrectos? ¿Qué hay de 'numAligned is 2' y 'chickensLeft is 2 + 5'?
Trabajo
18
¿Se llama tu amiga ... Yoda?
Adrian el
1
Si ella comienza a compararse sobre esto, me pregunto qué hará cuando vea C ++ & co.
BlackBear
3
Solo una nota al margen: Khan Academy tiene algunas lecciones sobre Python para programadores principiantes: khanacademy.org/#computer-science y Google tiene algunas más avanzadas: code.google.com/edu/languages/google-python-class/set- up.html
fox

Respuestas:

56

Lo mismo @paxdiablo. Los primeros lenguajes de programación fueron escritos por matemáticos, en realidad todos lo fueron. En matemáticas, por su propio principio, leer de izquierda a derecha, tiene sentido en la forma en que funciona.

x = 2y - 4.

En matemáticas, diría esto: Sea x igual a 2y -4.

Además, incluso en álgebra, haces esto. Cuando resuelve una ecuación para una variable, aísla la variable que está resolviendo para el lado izquierdo. es decir, y = mx + b;

Además, una vez que toda una familia de lenguajes, como la familia C, tiene una cierta sintaxis, es más costoso cambiarla.

Jonathan Henson
fuente
19
@FarmBoy: en matemáticas, la asignación y la igualdad SON lo mismo, ya que no hay una secuencia en una fórmula como en las computadoras. (a es igual a b y al mismo tiempo b es igual a)
Petruza
1
@FB excepto en algunos lenguajes funcionales de asignación única como, por ejemplo, Erlang. Asignación y Asegurar la igualdad son las mismas que en matemáticas
Peer Stritzinger
18
@Petruza No, en matemáticas, la asignación y la igualdad no son lo mismo. Si digo 'Let x = 2y - 3' es diferente de 'Así x = 2y - 3'. En matemáticas, típicamente el contexto los diferencia. Dado que el comentario que me cuestiona fue tan universalmente aclamado, mencionaré que tengo un Ph.D. en matemáticas, estoy bastante seguro de esto.
Eric Wilson
2
No conozco las matemáticas en ningún lugar cerca de un doctorado, lo que afirmo es que, como no hay secuencialidad, no hay un orden de ejecución en matemáticas tanto en una tarea como en una igualdad, a diferencia de la programación, en la que ambos lados de una tarea pueden ser diferentes en algún momento, y terminan siendo iguales en algún otro momento. Pero en matemáticas, en una tarea como let a be...cuando no hay tiempo, ambos lados de la tarea también son iguales, por lo que la tarea es de hecho una igualdad, no es de extrañar por qué ambos usan el mismo signo:=
Petruza,
55
@Petruzza - pero no es secuencialidad. Los documentos matemáticos se escriben de principio a fin, igual que cualquier otro documento. Si afirmo x = 1en el capítulo uno, pero afirmo x = 2en el capítulo dos, eso no es una contradicción terrible: cada afirmación se aplica solo dentro de un determinado contexto. La diferencia en la programación imperativa es, en parte, la eliminación de una barrera (no necesitamos un cambio de contexto) y, en parte, la implementación y la utilidad.
Steve314
26

BASIC, uno de los primeros lenguajes de computadora tenía la forma "adecuada" de:

10 LET AREA = HEIGHT * WIDTH

que coincide con la mentalidad matemática de especificar una variable, como "Sea H la altura del objeto".

COBOLTambién fue similar con su COMPUTEdeclaración. Al igual que con muchas formas de hacer las cosas, puede haber sido simplemente una decisión arbitraria que se llevó a cabo en muchos idiomas.


fuente
77
Supongo que este formulario es más natural cuando las líneas de programa se consideran "declaraciones" en lugar de "operaciones". Como en, en I declare that X must equal THISlugar del más linealEvaluate THIS and store it in X
voithos
Espera, ¿BASIC era un lenguaje informático "temprano"?
Alex Feinman
2
@Alex considerando que se remonta a la década de 1960, diría que es bastante temprano.
Ben Richards
1
Por otro lado, en COBOL podría escribir MULTIPLY HEIGHT BY WIDTH GIVING AREA, por lo que la variable que obtiene el resultado está en el lado derecho de la declaración.
user281377
25

En realidad, hay un lenguaje de programación que se asigna al lado derecho: TI-BASIC ! No solo eso, sino que tampoco usa '=' como operador de asignación, sino que usa una flecha conocida como el operador "STO".

ejemplos:

5→A
(A + 3)→B
(A - B)→C

En el ejemplo anterior, se declaran tres variables y se les dan valores. A sería 5, B sería 8 y C sería -3. La primera declaración / asignación se puede leer 'almacenar 5 como A'.

En cuanto a por qué TI-BASIC usa dicho sistema para la asignación, lo atribuyo a ser porque es un lenguaje de programación para una calculadora. El operador "STO" en las calculadoras TI se usaba con mayor frecuencia en las operaciones normales de la calculadora después de calcular un número. Si era un número que el usuario quería recordar, presionarían el botón "STO" y el caclulador les pediría un nombre (activando automáticamente el bloqueo alfa para que las pulsaciones de teclas produjeran letras en lugar de números):

Sin(7 + Cos(3))
                    -.26979276
Ans→{variable name}
                    -.26979276

y el usuario podría nombrar la variable lo que elijan. Tener que activar el bloqueo alfabético, escribir el nombre, luego presionar "STO", y presionar la tecla "Ans" habría sido demasiado engorroso para las operaciones normales. Dado que todas las funciones de la calculadora están disponibles en TI-BASIC, no se agregaron otros operadores de asignación ya que "STO" realizó la misma tarea, aunque al revés en comparación con la mayoría de los otros idiomas.

(Anécdota: TI-BASIC fue uno de los primeros idiomas que aprendí, así que cuando aprendí Java por primera vez en la universidad, ¡sentí que asignar a la IZQUIERDA era inusual y 'al revés'!)

diceguyd30
fuente
+1 ¡Lo olvidé por completo! TI Basic también fue mi primer idioma, pero no recuerdo este detalle.
barjak
En realidad, el operador STO está más cerca de cómo funciona la máquina y de cómo funciona cualquier lenguaje. El valor se calcula primero y luego se almacena en la memoria.
Kratz
15

Heurística 1: cuando se enfrente con más de una forma posible de hacer algo mientras diseña un idioma, elija el más común, el más intuitivo, o de lo contrario terminará con Perl +.

Ahora, ¿cómo es más natural (al menos para un hablante de inglés)? Veamos cómo escribimos / decimos cosas en inglés:

Steven ahora tiene 10 años (a diferencia de los 10 años, Steven ahora tiene). Yo peso más de 190 libras (a diferencia de más de 190 libras que peso).

En codigo:

steven = 10
i > 190

Lo siguiente también suena más natural:

"Si Mary tiene 18 años, entonces puede tener un dulce". "Si soy menor de 21 años, entonces le pediré a mi hermano que tome tequila".

if (mary == 18) { ... }
if (i < 21) { ... }

que:

"Si 18 años Mary es ..." "Si 21 es mayor que mi edad ..."

Ahora el código:

if (18 == mary) { ... }
if (21 > i) { ... }

Tenga en cuenta que esto no es natural ni para los programadores ni para los angloparlantes. Las oraciones suenan como yoda-speak, y el código se llama yoda-condition. Esto podría ser útil en C ++, pero estoy seguro de que la mayoría de la gente estaría de acuerdo: si un compilador pudiera hacer el trabajo pesado y aliviar la necesidad de las condiciones de yoda, la vida sería un poco más fácil.

Por supuesto, uno podría acostumbrarse a cualquier cosa. Por ejemplo, el número 81 se escribe como:

Ochenta y uno (inglés) Ochenta y uno (español) Uno y ochenta (alemán).

Finalmente, hay 4! = 24 formas válidas de decir "la manzana verde yace en la mesa" en ruso: el orden (casi) no importa, excepto que 'on' debe venir junto con 'table'. Entonces, si usted es un hablante nativo de ruso (por ejemplo), entonces no le importará si uno escribe a = 10o 10 = aporque ambos parecen igualmente naturales.

Si bien la lingüística es una asignatura fascinante, nunca la estudié formalmente y no conozco tantos idiomas. Sin embargo, espero haber proporcionado suficientes contraejemplos.

Trabajo
fuente
44
... y en francés, 81 se dice "cuatro veces veintiuno" ... :)
Martin Sojka
1
@ Martin, creo que el danés es muy similar.
un CVn
77
@ Martin Eso es realmente extraño, porque cuatro veces veintiuno son 84.
Peter Olson
66
@Peter: te has equivocado de paréntesis, es(four times twenty) one
SingleNegationElimination
44
@Job: Leyendo tu "Si Mary tiene 18 años ...", inevitablemente me acordé de Yoda diciendo "Cuando alcances los novecientos años, te ves tan bien que no, ¿hmm?" en El retorno del Jedi :-)
joriki
11

Comenzó con FORTRAN en la década de 1950. Donde FORTRAN era una abreviatura de FORmula TRANslation, las fórmulas en cuestión son ecuaciones algebraicas simples que por convención siempre se asignan a la izquierda.

Su COBOL casi contemporáneo, por otro lado, debía ser similar al inglés y asignado a la derecha (¡en su mayoría!).

MOVE 1 TO COUNTER.
ADD +1 TO LINE-CNT.
MULTIPLY QTY BY PRICE GIVING ITEM-PRICE.
James Anderson
fuente
Creo que este es el mejor ejemplo aquí porque ilustra perfectamente un contexto en un idioma donde es legible para un hablante de inglés común pero tiene la asignación correcta. Digo que es importante debido a la gran cantidad de personas que dicen en inglés que solo leería de izquierda a derecha para que la tarea tenga sentido, lo cual no es del todo cierto.
Joshua Hedges
5

Bueno, como señaló @ diceguyd30, hay dos anotaciones.

  • <Identifier> = <Value>significa "dejar que el identificador sea valor ". O para expandir eso: defina (o redefina) la variable Identificador a valor .
  • <Value> -> <Identifier>significa "almacenar valor para el identificador ". O para ampliar eso: ponga valor en la ubicación designada por el identificador .

Por supuesto, en general, el Identificador puede ser, de hecho, cualquier valor L.

El primer enfoque respeta el concepto abstracto de variables, el segundo enfoque trata más sobre el almacenamiento real.

Tenga en cuenta que el primer enfoque también es común en los idiomas, que no tienen asignaciones. También tenga en cuenta, que la definición de variables y asignación son relativamente cerca <Type> <Identifier> = <Value>vs <Identifier> = <Value>.

back2dos
fuente
3

Como ya se mencionó, todos los primeros lenguajes de computadora funcionaron de esa manera. Por ejemplo, FORTRAN, que apareció muchos años antes que BASIC.

En realidad, tiene mucho sentido tener la variable asignada a la izquierda de la expresión de asignación. En algunos idiomas, es posible que tenga varias rutinas sobrecargadas diferentes con el MISMO NOMBRE, devolviendo diferentes tipos de resultados. Al permitir que el compilador vea primero el tipo de la variable asignada, sabe a qué rutina sobrecargada llamar, o qué conversión implícita generar al convertir (por ejemplo) de un entero a un flotante. Esa es una explicación un poco simplista, pero espero que entiendas la idea.

Dave Jewell
fuente
2
Entiendo su explicación, pero ¿no podría el compilador mirar hacia adelante hasta el final de la declaración?
voithos
Eso podría hacer que el lexer sea más simple en los lenguajes actuales, pero ¿cuántos lenguajes de programación incluso admitían métodos con nombre, y mucho menos sobrecargas de métodos, cuando este tipo de sintaxis era nueva?
un CVn
2
Hola @voithos Sí, el compilador podría mirar hacia el futuro, pero eso probablemente habría sido un nivel inaceptable de complejidad en los primeros días de la escritura del compilador, ¡que a menudo era un ensamblador codificado a mano! Creo que poner la variable asignada a la izquierda es una opción pragmática: es más fácil de analizar tanto para el hombre como para la máquina.
Dave Jewell el
Creo que sería trivial que una tarea se asigne a la derecha. Cuando una expresión como 3 + 4 == 6 + 7, ambos lados se evalúan antes que el operador, porque el lenguaje se define de forma recursiva. El elemento de lenguaje 'variable = expresión' podría cambiarse fácilmente a 'expresión = variable'. Si eso causa o no situaciones ambiguas depende del resto del lenguaje.
Kratz
@Kratz: eso es cierto para los compiladores ahora, pero puede haber habido un problema menor para los idiomas interpretados muy antiguos que funcionaban con una fuente tokenizada. OTOH, eso podría haber favorecido la variable de la derecha en lugar de la variable de la izquierda.
Steve314
3

Podría ser un remanente de algoritmos de análisis tempranos. Recuerde que el análisis LR solo se inventó en 1965, y bien podría ser que los analizadores LL tuvieran problemas (dentro de las limitaciones de tiempo y espacio de las máquinas en ese momento) al revés. Considerar:

identifier = function();
function();

Los dos están claramente desambigados de la segunda ficha. Por otra parte,

function() = identifier;
function();

No es divertido. Esto empeora cuando comienza a anidar expresiones de asignación.

function(prev_identifier = expression) = identifier;
function(prev_identifier = expression);

Por supuesto, más fácil desambiguar para máquinas también significa más fácil desambiguar para humanos. Otro ejemplo fácil sería buscar la inicialización de cualquier identificador dado.

identifier1 = expressionOfAnArbitraryLength;
identifier2 = expressionOfAReallyReallyReallyArbitraryLength;
identifier3 = expression;
identifier4 = AlongLineExpressionWithAFunctionCallWithAssignment(
    identifier = expr);

Fácil, solo mira el lado izquierdo. Lado derecho, por otro lado

expressionOfAnArbitraryLength = identifier1;
expressionOfAReallyReallyReallyArbitraryLength = identifier2;
expression = identifier3;
AlongLineExpressionWithAFunctionCallWithAssignment(expr = identifier
    ) = identifier4;

Especialmente cuando no puedes grepperforar cartas, es mucho más difícil encontrar el identificador que deseas.

DeadMG
fuente
Precisamente el punto en el que había pensado, sí.
voithos
2

Los idiomas de ensamblaje tienen el destino como parte del código de operación de la izquierda. Los idiomas de nivel superior tienden a seguir las convenciones de los idiomas anteriores.

Cuando veas =(o :=para dialectos de Pascalish), podrías pronunciarlos como is assigned the value, entonces la naturaleza de izquierda a derecha tendrá sentido (porque también leemos de izquierda a derecha en la mayoría de los idiomas). Dado que los lenguajes de programación fueron desarrollados principalmente por personas que leen de izquierda a derecha, las convenciones se mantuvieron.

Es un tipo de dependencia del camino . Supongo que si las personas que hablaban hebreo o árabe (o algún otro idioma de derecha a izquierda) inventaron la programación de computadoras, sospecho que pondríamos el destino a la derecha.

Tangurena
fuente
Sí, pero sospecho que el texto en los editores también estaría alineado a la derecha ...
voithos
8
No se puede generalizar así sobre los lenguajes ensambladores. Varían en cuanto a dónde está el operando de destino.
rapid_now
2
@quickly_now: correcto; de hecho, la mayoría de los lenguajes de máquina primitivos (ni siquiera los ensambladores según los estándares actuales) ni siquiera tenían destino, ya que generalmente solo había uno o dos acumuladores de uso general. la mayoría de las operaciones implicaban el acumulador como destino, excepto los códigos de operación 'almacenar', que especificaban solo la dirección de memoria y no la fuente (que era el acumulador). Realmente no creo que haya influenciado en la sintaxis de asignación para lenguajes similares a ALGOL.
Javier
3
@Tangurena: algunos idiomas de ensamblador tienen la destilación a la izquierda. No del código de operación (ese es el código de objeto ensamblado), sino la izquierda de la lista de argumentos para la instrucción mnemónica. Sin embargo, otros tienen el destino a la derecha. En el ensamblador 68000, escribiría mov.b #255, d0, por ejemplo, dónde d0está el registro para asignar. Los ensambladores más antiguos solo tienen un único argumento por instrucción. En el 6502 LDA #255(Load Accumulator), podría argumentar que Aestá a la izquierda, pero también está a la izquierda en STA wherever(Store Accumulator).
Steve314
2
E incluso el Intel 4004 (el antepasado definitivo de 4 bits de la familia 8086, con los 8008 y 8080 en el medio) se desarrolló después de la asignación en idiomas de alto nivel. Si está asumiendo que la serie 8086 es representativa de lo que hicieron los ensambladores en los años 50 y anteriores, dudo mucho que sea cierto.
Steve314
2

Por si sirve de algo, la mayoría de las declaraciones de COBOL leen de izquierda a derecha, por lo que los dos operandos fueron nombrados en primer lugar, y el destino último, como: multiply salary by rate giving tax.

Sin embargo, no sugeriré que su estudiante prefiera COBOL, ¡por temor a que me marquen (con razón) por hacer un comentario tan bajo, grosero e insípido! :-)

Jerry Coffin
fuente
1

ella dijo que de izquierda a derecha le parecía más natural, ya que así es como la mayoría de nosotros leemos idiomas naturales.

Creo que esto es un error. Por un lado, puede decir "asignar 10 a x" o "mover 10 a x". Por otro lado, puede decir "establecer x en 10" o "x se convierte en 10".

En otras palabras, dependiendo de su elección de verbo, la variable asignada a puede o no ser el sujeto, y puede o no estar a la izquierda. Entonces, "lo que es natural" depende completamente de su elección habitual de redacción para representar la asignación.

Steve314
fuente
0

En pseudocódigo, el operador de asignación se escribe muy comúnmente a la derecha. Por ejemplo

2*sqrt(x)/(3+y) -> z

En las calculadoras Casio, incluso las variantes no programables, la variable de asignación también se muestra a la derecha

A+2B → C

En Forth la variable también está a la derecha

expression variable !

En x86, la sintaxis de Intel tiene el destino a la izquierda, pero la sintaxis de GAS invierte el orden, lo que confunde a muchas personas, especialmente en las instrucciones sobre el orden de los parámetros, como la resta o las comparaciones. Estas instrucciones son las mismas en 2 dialectos diferentes.

mov rax, rbx    ; Intel syntax
movq %rbx, %rax ; GAS syntax

Ambos mueven el valor en rbx a rax. Ningún otro lenguaje ensamblador que conozco escribe el destino a la derecha como GAS.

Algunas plataformas ponen la expresión a la izquierda y la variable a la derecha:

MOVE expression TO variable      COBOL
expression → variable            TI-BASIC, Casio BASIC
expression -> variable           BETA, R
put expression into variable     LiveCode

https://en.wikipedia.org/wiki/Assignment_%28computer_science%29#Notation

La mayoría de los idiomas asignan el valor a la izquierda, una de las razones es que es fácil alinear los operadores, más fácil de leer y reconocer la variable, ya que los operadores de asignación y las posiciones de las variables no variarán enormemente en las líneas, y es más fácil de leer como "dejar que la variable sea un valor".

Sin embargo, algunas personas prefieren decir "mover el valor x a y" y escribir la variable a la derecha.

phuclv
fuente
-1

Creo que sigue una forma lógica de pensar.
Tiene que haber una caja (variable) primero, luego pones un objeto (valor) dentro de ella.
No pones el objeto en el aire y luego pones una caja a su alrededor.

Petruza
fuente
2
Si tu puedes. En la mayoría de los idiomas, el lado derecho se evalúa antes que el izquierdo.
Javier
3
Es un tipo de "Conducir por el lado derecho de la carretera". Parece lógico, pero solo porque es la forma en que siempre lo has hecho. Todos los países superiores conducen por la izquierda.
James Anderson el
1
@JamesAnderson países superiores? : o
nawfal
Tienes razón, es lógico para un sistema de escritura de izquierda a derecha como el alfabeto romano, que supongo que es utilizado por casi todos los lenguajes de programación, si no todos.
Petruza