Rust: palabra clave var solo para locales mutables

Creado en 20 jun. 2012  ·  35Comentarios  ·  Fuente: rust-lang/rust

El número 1273 propuso let mut para locales mutables y mut para campos mutables. let mut es más detallado que una sola palabra clave y también rompe la alineación de las columnas. A la gente, con razón, no le gustó la idea de var para declaraciones de campo mutables. Pero creo que nadie sugirió la idea de usar var para declaraciones locales mutables y mut para declaraciones de campo mutables:

let x = 7; // declaration of immutable variable x
var y = 7; // declaration of mutable variable y
type point = { mut x: int, mut y: int }; // declaration of mutable record type

Dave

I-nominated

Todos 35 comentarios

Debo confesar que al principio pensé que deberíamos usar la misma palabra clave para variables mutables y campos mutables, pero var se lee un poco 'bien (aunque no me disgusta let mut )

Creo que es una característica que declarar una variable mutable es un poco más engorroso que una inmutable. Puedo ver a los programadores usando solo "var" para ser "consistente" o porque "var" sería más poderoso (no tienes que cambiarlo si decides mutar más tarde). Entonces terminas con un código menos legible en general.

No sugiero que Rust deba ser un lenguaje serio de esclavitud y disciplina, pero creo que un suave empujón en la dirección correcta es moralmente justificable (es decir, la regla sería "para un código seguro, las construcciones más seguras deben ser menos ruidosas que las más poderosas pero construcciones más fáciles de estropear ").

Por un lado me gusta esto, ya que eliminaría la ambigüedad visual de esta forma:

let mut x = 4,
    y = 8;  // is y mutable or not?

Pero me inclino a ponerme del lado de ssylvan. Declarar mutables no tiene por qué ser exactamente _feo_, pero creo que tiene sentido si son un poco menos convenientes de crear que los inmutables, aunque solo sea con una sola pulsación de tecla. La palabra clave de activación también debe ser distintiva, y (IMO) var se usa demasiado como una palabra clave de declaración de variable genérica para transmitir específicamente mutabilidad en un lenguaje que se enorgullece de la inmutabilidad por defecto. ¡Y piense en los pobres programadores de C #, para quienes var es nuestro let !

Todavía me gusta la idea de reemplazar let mut con una sola palabra clave, para abordar el fragmento de código anterior, pero ¿hay alguna razón para introducir una nueva palabra clave cuando mut sí sería suficiente, según la propuesta original en el # 1273?

@pcwalton señaló un problema con solo usar mut : existe una ambigüedad con los literales de registro y las expresiones de bloque que requiere una búsqueda anticipada arbitraria para resolver.

{ mut x: int ...

¿Grabar literal o bloquear con variable local?

Pude ver a muchos programadores aprendiendo que var es la forma de declarar variables en Rust, y no usar let en absoluto. Después de todo, var es cómo declaras variables locales en lenguajes como JavaScript. Me inclino a pensar que esta propuesta tiene algo de bueno.

Escuché a alguien señalar ayer que ahora let y var tendrían la misma longitud, lo que sería bueno para la alineación.

Soy algo indiferente, pero prefiero un poco var , porque es más corto. Hacer que la mutabilidad sea molesta no es un objetivo deseable como yo lo veo. (De hecho, tiendo a pensar que la función de un lenguaje de programación no debería ser hacer nada molesto, solo _claro_, que no es lo mismo).

Si bien todavía desconfío de usar let y var juntos (al igual que Javascript, pero 100% diferente), sería un problema mucho menor si hubiera un pase de pelusa para detectar variables que se declaran como mutables pero que en realidad nunca han mutado.

Hay un plan para hacer que la mutabilidad sea parte del tipo. ¿Eso afecta a los lugareños y hace que esto sea irrelevante?

Qué tal si:

val x = ... // immutable (val-ue)
var y = ... // mutable (var-iable)

Como en Scala.

Creo que @brson tiene razón y este problema desaparece una vez que movemos mut a un tipo, es decir, obtienes let x = mut 10;

Cerrando este tema por ahora; reabrir si crees que estoy equivocado!

No estoy seguro de esto. Me gusta la idea de mudar a mut en el tipo, pero no sé si es un "trato hecho" --- puede haber una rareza persistente allí. En cualquier caso, nunca consideré que se pudiera escribir let x = mut 5 , siempre asumí que escribirías let mut x = 5 igual que hoy; la "mutabilidad" del tipo de una variable provendría de la forma en que fue declarada, no del valor que se le asigna.

Hacer lo contrario parecería implicar que si tiene una matriz x del tipo [mut int] y escribe let y = x[0] entonces y es mutable? ¿O algo? Eso parece indeseable.

@Dretch No amo val / var porque no son lo suficientemente distintos, aunque el precedente de Scala es bueno.

Comparto la preocupación de var de forma predeterminada. La forma en que funciona ahora tiendo a declarar todo como inmutable, luego el compilador me recuerda que debería ser mutable, luego escribo mut . Podría decirse que este es un buen comportamiento al que estaría menos inclinado con una división de var/let : escribir var y let son igualmente difíciles, pero ni siquiera puede escribir let mut sin escribir let .

Pero no tengo ninguna preferencia y aprecio cuando puedo componer funciones enteramente de declaraciones que comienzan con palabras clave de tres caracteres.

@nikomatsakis En particular, para mí tiene sentido que las reglas sobre asignación única provengan de la mutabilidad de la declaración en lugar del tipo. Cambiar sutilmente las reglas de asignación según el tipo me huele raro.

Me inclino a estar de acuerdo con @pcwalton en que no deberíamos penalizar a los programadores por usar un enlace mutable si eso es lo que quieren. En cuanto a la preocupación de que las personas usen var innecesariamente, podríamos agregar una advertencia opcional que se queje si se asigna un enlace var forma individual. Pero también creo que podemos sentar precedentes para un buen estilo en rustc y la biblioteca estándar.

Dave

¿Es realmente tan terrible si los programadores declaran todas sus variables mutables? Parece que no es el fin del mundo si tenemos un conjunto de programadores de Rust que simplemente piensan que var es la forma en que declaras las variables, y otro conjunto que entiende usar let mayor parte del tiempo. y var cuando sea necesario. Como los primeros programadores de Rust, podemos sentar el precedente a favor de usar let y var correctamente.

En mi humilde opinión, un buen diseño de sintaxis no se trata solo de hacer que "todo" que pueda querer hacer sea conveniente, se trata de empujar suavemente a las personas hacia el "camino suave" de la semántica del lenguaje y los objetivos de diseño.

Por ejemplo, probablemente no agregaría soporte sintáctico especial para listas vinculadas en Rust (a la Haskell), porque uno de los principios fundamentales de Rust es ser eficiente, y el uso generalizado de listas vinculadas funcionará en contra de ese principio. Por la misma razón, compartir datos mutables entre subprocesos probablemente no debería ser demasiado conveniente (ya que la concurrencia segura es otro principio), ni debería ser muy conveniente lanzar un int arbitrario a un puntero (ya que la seguridad de la memoria es un gran principio).

Por no decir que debería ser imposible hacer cualquiera de estas cosas, mente, solo proporcionalmente inconveniente para que quede claro en la sintaxis cuál es la forma idiomática de escribir Rust.

Las variables mutables (locales) no son tan malas como cualquiera de estas, pero si Rust de hecho favorece los datos inmutables por razones de corrección y mantenimiento (algo con lo que personalmente estoy de acuerdo), entonces la sintaxis idealmente debería dar un suave empujón en esa dirección. Incluso un solo carácter adicional o un sigilo modificador adicional o lo que sea sería suficiente para dejar en claro que "dejar" es menos complicado que "dejar mut" o "dejar". o lo que sea, y por lo tanto debe ser el valor predeterminado preferido que debe intentar cuando no necesite que la variable sea mutable.

@ssylvan Oh, entiendo ese punto, es solo una cuestión de grado y el equilibrio de las compensaciones. Ya promovemos la inmutabilidad de las estructuras de datos, y la OMI local inmutable es menos importante de promover que los campos inmutables. (Especialmente porque, IINM, no permitimos que los locales mutables escapen en cierres de montón). Y la pérdida de la capacidad de refactorizar entre let y var sin cambiar el recuento de columnas supera el beneficio de promoviendo locales inmutables. Es difícil de cuantificar, así que supongo que es solo mi sentimiento.

Dave

Bueno, en ese caso, al menos "let foo = mut bar" o "let foo: = bar" en lugar de "let mut foo = bar" haría la primera alineación de fichas. Presumiblemente, el nombre de la variable será de longitud variable, por lo que no es tan importante evitar modificadores adicionales en el resto de la declaración.

Oh, oye, soy un poco parcial a la idea := .

Dave

Pensándolo bien, Pascal está permanentemente mal. Me retracto. :)

Dave

Además, let foo := bar evita algo como esto:

let mut foo;
foo = bar;

He encontrado ese patrón útil a veces, aunque parece que probablemente siempre haya otra forma de escribir el mismo patrón.

@eholk No creo que eso lo impida. Pero sigo pensando que les parecerá demasiado extraño a los programadores de casi cualquier lenguaje convencional.

Dave

Con respecto a := , Go lo usa para indicar una asignación de inferencia de tipo (aunque todavía no es un lenguaje convencional). Pero puedo prever dificultades para distinguir entre las dos formas de un vistazo:

let foo = "hello";
let foo := "hell";

El argumento de brson para la sintaxis actual (es decir, que la declaración mutable primero requiere la declaración inmutable) es convincente. Es totalmente genial si los lenguajes de programación son obstinados, siempre y cuando no sean idiotas al respecto. :)

No estoy interesado en = frente a := . Principalmente opuesto a val , var y variaciones de los mismos; simplemente no es _obvio_ que controle la mutabilidad. Quiero decir, no me rendiré disgustado si adoptamos uno de ellos, pero creo que "tener que explicar el mnemónico" es una mala señal. Estoy más bien con:

  • Dejar que el tipo lo dicte.
  • Dejar que mut solo funcione como un declarador local y requerir que el analizador demore la confirmación de la sintaxis de registro frente a la declaración local de un token adicional; todavía es LL (1) solo agrega un estado gramatical intermedio adicional, sin retroceso adicional (ambas formas de avance son válidas).
  • Dejándolo como let mut .

La principal razón para evitar a los locales mutables "accidentales" es que introdujimos la captura del entorno, para que se conviertan en una forma de acción a distancia, así como en peligros para una variedad de análisis como los préstamos.

(Todos los permisos eran inicialmente mutables, pero tampoco teníamos captura de entorno, solo enlace. Ahora no tenemos enlace, solo captura de entorno. Tomayto, tomahto).

Creo que las mutables no se pueden capturar implícitamente ahora.

@graydon tiene razón en que hubo dos motivaciones originales. Sin embargo, solo uno sigue siendo relevante. Las dos motivaciones fueron

  • captura implícita "por copia" de variables mutables en un fn@
  • comprender qué datos son mutables y cuáles no para pedir prestados

Resulta que esto último ya no es relevante. El uso de variables mutables / inmutables fue demasiado burdo en la práctica, por lo que el préstamo tiene la idea de tomar prestada una variable "temporalmente" --- una variable mutable se puede tomar prestada con un ptr inmutable siempre que la variable no se modifique mientras el puntero está en alcance.

Quizás podríamos simplemente eliminar la idea de locales mutables / inmutables y volver a la vieja regla: todo es mutable. Luego, podríamos emitir advertencias cuando una variable que se copia implícitamente en un cierre se modifica después de que se crea el cierre.

Hay una tercera motivación: las variables inmutables son más fáciles de razonar. Si todo es mutable, debe escanear toda la función para ver qué valores puede tener una variable durante su tiempo de vida. Cada variable tiene potencialmente un flujo de datos complicado (especialmente con bucles, ramas, parámetros de funciones mutables, etc.) y es difícil ver qué está sucediendo sin analizar cuidadosamente cada declaración. Si tiene sólo una o dos mutables en una función, actúa para "marcarlas" para que tenga más cuidado al leer el código que involucra hem.

@Dretch También me gusta el estilo Scala, con palabras clave "val" y "var".

Me gusta cómo la sintaxis actual hace que las mutables sobresalgan como un pulgar adolorido; facilita el escaneo del código. val y var parecen demasiado similares visualmente en ese sentido. Lo que no quiere decir que los mutables _deben_ sobresalir, pero mantener las palabras clave visualmente distintas es una faceta importante de la usabilidad.

Entiendo que los campos mutables se eliminarán del óxido. ¿Significa eso que mut podría usarse en lugar de let mut porque la ambigüedad de registro / variable en bloque desaparecería?

También creo que los registros estructurales están funcionando, lo que elimina la ambigüedad incluso si quedan campos mutables.

@Dretch , es cierto que los campos mutables están desapareciendo y los registros estructurales ya se han ido.

En general, soy indiferente al problema, aunque me gustaría señalar que _ podría_ tener sentido que mut sea ​​una palabra clave de declaración por derecho propio (como propone Dretch), en el caso de congelación / descongelación . Comparar hoy:

let foo = 1;  // immutable
/* 10,000 lines of code here */
let mut foo = foo;  // we're making foo mutable, totally understandable
/* 10,000 lines of code here */
let foo = foo;  // potential wtf

Con la propuesta:

let foo = 1;  // immutable
/* 10,000 lines of code here */
mut foo = foo;  // a mutable foo, no problems here
/* 10,000 lines of code here */
let foo = foo;  // slightly less of a potential for wtf, since we officially have two declaration forms

Aunque también siento que esto haría que el Rust-ism "la ausencia de mut implica inmutabilidad" sea menos consistente, porque todavía estaríamos escribiendo let foo = 1; lugar de solo foo = 1; (la última forma es obviamente indeseable para la declaración).

Kotlin también usa val y var .

No creo que vayamos a hacer este cambio, pero nominaré para el hito 1, bien definido, para que podamos resolverlo.

el consenso es no hacer esto, ya que es incompatible con mover mut a enlaces de patrón. clausura.

¿Fue útil esta página
0 / 5 - 0 calificaciones