Scala: var List vs val MutableList

En el libro Scala de Odersky et al, dicen usar listas. No he leído el libro de principio a fin, pero todos los ejemplos parecen usar val List. Según tengo entendido, también se recomienda usar vals sobre vars. Pero en la mayoría de las aplicaciones, ¿no hay un compromiso entre usar una lista var o una lista mutable val?. Obviamente, usamos una Lista val cuando podemos. Pero, ¿es una buena práctica usar muchas listas var (o vectores var, etc.)?

Soy bastante nuevo en Scala y vengo de C#. Allí tuve un montón de:

public List<T> myList {get; private set;}

colecciones que podrían haberse declarado fácilmente como vals si C# tuviera la inmutabilidad incorporada, porque la colección en sí nunca cambió después de la construcción, aunque los elementos se agregarían y restarían de la colección durante su vida útil. Así que declarar una colección var casi se siente como un paso lejos de la inmutabilidad.

En respuesta a las respuestas y comentarios, uno de los fuertes puntos de venta de Scala es que puede tener muchos beneficios sin tener que cambiar por completo la forma en que uno escribe el código como es el caso, por ejemplo, con Lisp o Haskell.

preguntado el 12 de junio de 12 a las 15:06

¿Qué compensación ve al no usar listas mutables? Puedo ver cómo ganas seguridad de subprocesos, pero ¿qué pierdes? -

@DonStewart, que accidentalmente podría establecer la variable de colección en el valor incorrecto. Aunque no son inmutables, la cultura de C# parece poner un mayor énfasis en lo privado siempre que sea posible, lo que reduce ese tipo de errores de tiempo de ejecución. Pero un val siempre tiene que ser preferible a un var para la clase consumidora, seguramente en igualdad de condiciones. -

@RichOliver Creo que lo que @DonStewart quiso decir es no usar listas mutables y no usando vars al mismo tiempo. -

@ErikAllik Mi pregunta no era un duplicado, ya que se hizo primero. La otra pregunta puede ser un duplicado de la mía. -

5 Respuestas

¿Es una buena práctica usar muchas Listas var (o Vectores var, etc.)?

Yo diría que es una mejor práctica usar var con colecciones inmutables de lo que es usar val con los mutables. Fuera de mi cabeza, porque

  • Tiene más garantías sobre el comportamiento: si su objeto tiene una lista mutable, nunca sabe si algún otro objeto externo lo actualizará

  • Limitas el alcance de la mutabilidad; los métodos que devuelven una colección producirán una inmutable, por lo que solo tiene mutabilidad dentro de su único objeto

  • Es fácil inmutar una var simplemente asignándola a un val, mientras que para hacer que una colección mutable sea inmutable, debe usar un tipo de colección diferente y reconstruirla.

En algunas circunstancias, como aplicaciones dependientes del tiempo con E/S extensas, la solución más simple es usar un estado mutable. Y en algo circunstancias, una solución mutable es simplemente más elegante. Sin embargo, en la mayoría de los códigos no necesita mutabilidad en absoluto. La clave es usar colecciones con funciones de orden superior en lugar de bucles o recursividad si no existe una función adecuada. Esto es más simple de lo que parece. Solo necesita dedicar un tiempo a conocer los métodos en List (y otras colecciones, que son en su mayoría iguales). Los más importantes son:

map: aplica la función proporcionada a cada elemento de la colección; utilícela en lugar de repetir y actualizar valores en una matriz

foldLeft: devuelve un solo resultado de una colección: use en lugar de hacer un bucle y actualizar una variable acumuladora

for-yield expresiones: simplifique su mapeo y filtrado, especialmente para problemas de tipo de bucle anidado

En última instancia, gran parte de la programación funcional es consecuencia de la inmutabilidad y realmente no se puede tener uno sin el otro; sin embargo, las variables locales son principalmente un detalle de implementación: no hay nada de malo en un poco de mutabilidad siempre que no pueda escapar del ámbito local. Por lo tanto, use vars con colecciones inmutables ya que las vars locales no son las que se exportarán.

Respondido el 20 de junio de 20 a las 10:06

Ah, sí parece una buena respuesta. No estoy buscando la solución definitiva, sino una práctica predeterminada que funcione. Ahorra importar las colecciones mutables. Así que parece ir con la corriente del idioma. Estoy preparado para hacer una refactorización importante más tarde cuando tenga una mejor vista general. - rico oliver

Usted está asumiendo que el List debe ser mutable, o lo que sea que apunte a él debe ser mutable. En otras palabras, debe elegir una de las dos opciones a continuación:

val list: collection.mutable.LinkedList[T]
var list: List[T]

Esa es una falsa dicotomía. Puedes tener ambos:

val list: List[T]

Entonces, la pregunta que deberías hacerte es ¿Cómo puedo hacer eso?, pero solo podemos responder eso cuando lo prueba y enfrenta un problema específico. No hay una respuesta genérica que resuelva todos sus problemas (bueno, la hay -- mónadas y recursividad -- pero eso es muy genérico).

Así que... inténtalo. Usted podría estar interesado en mirar Revisión de código, donde la mayoría de las preguntas de Scala se refieren precisamente a cómo hacer que un código sea más funcional. Pero, en última instancia, creo que la mejor manera de hacerlo es tratany recurra a Stack Overflow cuando no pueda resolver algún problema específico.

Respondido el 12 de junio de 12 a las 16:06

Me parece una dicotomía genuina en este momento, porque aunque estoy interesado en explorar enfoques funcionales con el tiempo, en el futuro inmediato quiero centrarme en una comprensión más completa de la sintaxis de Scala. Por el momento, solo quiero la fruta funcional madura. Las limitaciones del sistema tipo C# fueron el motivo por el que me mudé a Scala, no una falta de funcionalidad. Todavía estoy muy mal informado, pero mirar algunas de las cosas de Eric Meijer ha reforzado mi cautela instintiva del fundamentalismo funcional. - rico oliver

@RichOliver En ese caso, la fruta más baja por la que luchar es transparencia referencial. Eso significa que un observador externo sería incapaz de observar el estado, lo que generalmente es más fácil de lograr con var como variables locales de método que contienen colecciones inmutables. - Daniel C Sobral

Así es como veo este problema de mutabilidad en la programación funcional.

Mejor solución: Los valores son los mejores, por lo que lo mejor en el uso de la programación funcional son los valores y las funciones recursivas:

val myList = func(4); 
def func(n) = if (n>0) n::func(n) else Nil

Necesita cosas mutables: A veces se necesitan cosas mutables o hace que todo sea mucho más fácil. Mi impresión cuando nos enfrentamos a esta situación es usar las estructuras mutables, así que usar val list: collection.mutable.LinkedList[T] en lugar de var list: List[T], esto no se debe a una mejora real en el rendimiento, sino a las funciones mutables que ya están definidas en la colección mutable.

Este consejo es personal y tal vez no se recomienda cuando desea rendimiento, pero es una guía que utilizo para la programación diaria en scala.

Respondido el 12 de junio de 12 a las 17:06

Creo que no puedes separar la cuestión de mutable val / inmutable var del caso de uso específico. Déjame profundizar un poco: hay dos preguntas que quieres hacerte:

  1. ¿Cómo expongo mi colección al exterior?
    1. quiero una instantánea del estado actual, y esta instantánea no debe cambiar independientemente de los cambios que se realicen en la entidad que aloja la colección. En tal caso, debe preferir inmutable var. La razón es que la única manera de hacerlo con un mutable val es a través de una copia defensiva.
    2. quiero una vista en el estado, que debe cambiar para reflejar los cambios en el estado del objeto original. En este caso, debe optar por un inmutable val, y devolverlo envuelto a través de un envoltorio no modificable (muy parecido a lo que Collections.unmodifiableList() hace en Java, aquí es una pregunta donde se pregunta cómo hacerlo en Scala). No veo forma de lograr esto con una var inmutable, por lo que creo que su elección aquí es obligatoria.
    3. Solo me importa la ausencia de efectos secundarios.. En este caso, los dos enfoques son muy similares. con un inmutable var puede devolver directamente la representación interna, por lo que tal vez sea un poco más claro.
  2. ¿Cómo modifico mi colección?
    1. Suelo hacer cambios masivos, es decir, configuro toda la colección a la vez. Esto hace inmutable var una mejor opción: puede asignar lo que está en la entrada a su estado actual, y ya está bien. con un inmutable val, primero debe borrar su colección, luego copiar los nuevos contenidos. Definitivamente peor.
    2. Usualmente hago cambios puntuales, es decir, agrego/elimino un solo elemento (o algunos de ellos) a/de la colección. Esto es lo que en realidad veo la mayor parte del tiempo, la colección es solo un detalle de implementación y el trait sólo exponiendo métodos para la manipulación puntual de su estado. En este caso, un mutable val puede ser generalmente mejor en cuanto a rendimiento, pero en caso de que esto sea un problema, recomendaría echar un vistazo a Rendimiento de las colecciones de Scala.

contestado el 23 de mayo de 17 a las 13:05

Si es necesario usar listas var, ¿por qué no? Para evitar problemas, podría, por ejemplo, limitar el alcance de la variable. Hubo una pregunta similar hace un tiempo con una respuesta bastante buena: El conjunto mutable e inmutable de scala cuándo usar val y var.

contestado el 23 de mayo de 17 a las 12:05

Eso tendría sentido como una respuesta "generalmente la mejor opción". Sin embargo, eso es muy diferente de decir que no es necesario ningún compromiso o que, de hecho, es prudente, solo en términos de tiempo de los desarrolladores. - rico oliver

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.