2011-06-21 17 views
9

Acabo de asistir a una clase de Scala en una escuela de verano. El profesor recibió la siguiente pregunta:Decidir estáticamente si una clase de Scala es inmutable

- "¿Hay alguna forma de que el compilador diga si una clase es inmutable?"

El profesor respondió

- "No, no es Sería muy bonito si pudiera.".

me sorprendió. ¿No es solo para verificar si la clase contiene var-members?

Respuesta

7

¿Qué es inmutable?

La comprobación para ver si el objeto solo contiene val campos es una sobreproximación de inmutabilidad - el objeto puede muy bien contener var s, pero nunca asignar valores diferentes en ellos. O los segmentos del programa que asignan valores a var s pueden ser inalcanzables.

De acuerdo con la terminología Chris Okasaki, existen estructuras de datos inmutables y estructuras de datos funcionales.

Una estructura de datos inmutables (o una clase) es una estructura de datos que, una vez construida en memoria, nunca cambia sus componentes y valores - un ejemplo de esto es una tupla de Scala.

Sin embargo, si define la inmutabilidad de un objeto como la inmutabilidad de sí mismo y de todos los objetos accesibles a través de referencias del objeto, entonces una tupla puede no ser inmutable, depende de con qué lo instancia más adelante. A veces no hay suficiente información sobre el programa disponible en tiempo de compilación para decidir si una estructura de datos determinada es inmutable en el sentido de que contiene solo val s. Y la información falta debido al polimorfismo, ya sea paramétrico, subtipificación o ad-hoc (clases de tipo).

Este es el primer problema para decidir la inmutabilidad: falta de información estática.

Una estructura de datos funcional es una estructura de datos en la que puede realizar operaciones cuyas salidas dependen únicamente de las entradas para un estado dado. Un ejemplo de dicha estructura de datos es un árbol de búsqueda que almacena en caché el último elemento buscado almacenando en un campo mutable. Aunque cada búsqueda escribirá el último elemento buscado en el campo mutable, de modo que si el elemento se busca nuevamente, la búsqueda no tiene que repetirse, los resultados de la operación de búsqueda para dicha estructura de datos permanecen siempre iguales dado que nadie inserta nuevos elementos en él. Otro ejemplo de una estructura de datos funcional es splay trees.

En un modelo de programación imperativa general, para comprobar si una operación es pura, es decir, ¿las salidas dependen únicamente de las entradas, es undecidable. Nuevamente, se podría usar una técnica como la interpretación abstracta para proporcionar una respuesta conservadora, pero esta no es una respuesta exacta a la cuestión de la pureza.

Este es el segundo problema para decidir si algo que tiene var s es inmutable o funcional (observablemente inmutable): indecibilidad.

+0

Gracias. Esa es una publicación perspicaz. – aioobe

+1

Buena respuesta. El problema es realmente muy simple. La mutabilidad es una característica, que solo puede ocurrir en tiempo de ejecución. Lo que significa que ahora hay forma de decir en tiempo de compilación si su modelo estático es inmutable. Excepto por supuesto para cosas obvias que ni siquiera necesitarías verificar por inmutabilidad en primer lugar. – agilesteel

2

Si guarda un objeto mutable en un val, el objeto en sí mismo sigue siendo mutable. Entonces, debería verificar si cada clase que usa en un val es inmutable.

case class Mut(var mut:Int) 

val m = Mut(1) 
println(m.toString) 
m.mut = 3 
println(m.toString) 
5

Creo que el problema es que se necesita para asegurarse de que todos sus val s no tienen ningún var miembros tampoco. Y esto no puedes. Consideremos

class Base 
case class Immutable extends Base { val immutable: Int = 0 } 
case class Mutable extends Base { var mutable: Int = _ } 

case class Immutable_?(b: Base) 

Aunque Immutable_?(Immutable) es de hecho inmutable, Immutable_?(Mutable) no lo es.

+0

Claro, asumiendo esa definición, puedo ver por qué respondió como lo hizo. Luego 'scala.collection.immutable.List' no es inmutable si contiene referencias a objetos mutables. – aioobe

+0

Bueno, sí. Referencias a objetos potencialmente mutables. La * estructura * de una 'Lista' es inmutable, sin embargo. Pero para el compilador, no es posible ver qué es estructura y qué es contenido. – Debilski

1

No es tan fácil ya que podría tener vals que están vinculados a otras clases mutables o, incluso más difíciles de detectar, que llama a métodos en otras clases u objetos que son mutables.

Además, muy bien podría tener una clase inmutable que de hecho tiene vars (para ser más eficiente, por ejemplo ...).

Supongo que podría tener algo que compruebe si una clase parece como inmutable o no, pero parece que podría ser bastante confuso.

0

Puede tener una clase, que se puede instanciar a un objeto, y este objeto puede ser mutable o inmutable.

Ejemplo: una clase puede contener List[_], que, en tiempo de ejecución, puede ser List[Int] o List[StringBuffer]. Entonces, dos objetos diferentes de una clase pueden ser mutables o inmutables.

+0

Derecha. Con esa definición, ni siquiera una 'lista inmutable' es inmutable. Sin embargo, puedo ver cómo esa definición explica la respuesta del conferenciante. – aioobe

+0

Pero 'val list = List (1, 2, 3)' es un objeto inmutable de Type List (que por defecto es inmutable). Pero la semántica no está absolutamente clara. Puede llamar a una Lista de amigos inmutables, si la Lista no se cambia, y el número y los elementos no se cambian, pero uno de los amigos compra una bicicleta nueva, colocándola en su Lista de vehículos. O el amigo no cambia en absoluto, pero su método 'getAge'-return 29, mientras que ayer devolvió' 28 '. ¿Él cambió? ¿Cambió el calendario? ¿La edad es un atributo mutable, o un método, que toma el cumpleaños inmutable y la fecha actual? –

+0

@userunknown Por subprocesos de estado explícito o mónadas de lector/estado/escritor, esos dos son exactamente equivalentes. –

Cuestiones relacionadas