5

estoy pasando por la programación en Scala 2ª edición por Odersky, cuchara, y Venners, y este ejemplo me tiró para un bucle ya que parecía ir en contra de lo que pensaba era cierto acerca de la programación funcional y inmutabilidad. En el ejemplo (y anteriormente en el libro en el cap. 18), los autores afirman que las operaciones sobre un objeto todavía puede ser "puramente funcional" incluso cuando esas operaciones podrían mutar el estado interno del objeto. El ejemplo, que está en la p.442, Cap. 19, es la siguiente:cola Funcional De Programación En Scala

class Queue[+T] private (
    private[this] var leading: List[T], 
    private[this] var trailing: List[T] 
) { 

    private def mirror() = 
    if (leading.isEmpty) { 
     while (!trailing.isEmpty) { 
     leading = trailing.head :: leading 
     trailing = trailing.tail 
     } 
    } 

    def head: T = { 
    mirror() 
    leading.head 
    } 

    def tail: Queue[T] = { 
    mirror() 
    new Queue(leading.tail, trailing) 
    } 

    def enqueue[U >: T](x: U) = 
    new Queue[U](leading, x :: trailing) 
} 

La justificación es que, con tal de que los efectos secundarios no son visibles para los clientes, algo como esto puede ser considerado funcional. Creo que puedo ir detrás de eso ... Es decir, estrictamente hablando, eso es lo que define una función. Pero es cierto (y no estoy realmente muy inteligente acerca de lo que las garantías de JVM modelo de memoria), pero no están ahí los problemas potenciales con que en este código?

Por ejemplo, si dos hilos se ejecutan las operaciones en esta cola, que se parece a esto para empezar:

Leading: Nil 
Trailing: List(1,2,3,4) 

¿No es posible que un hilo podría llamar a la cabeza() para llegar a este punto en el espejo() antes de ser descheduled:

private def mirror() = 
    if (leading.isEmpty) { 
     while (!trailing.isEmpty) { 
     leading = trailing.head :: leading 
     > trailing = trailing.tail 
     } 
    } 

momento en el que la cola se parece a esto:

Leading: List(1) 
Trailing: List(1,2,3,4) 

Y cuando un segundo subproceso llama a la cola(), mientras que el primero no se encuentra activo, esto sería devuelto:

Leading: Nil 
Trailing: List(1,2,3,4) 

Mientras que si la cabeza de la primera rosca() llamada fuera para terminar, este sería devuelto después de una cola posterior() llamar en esa lista:

Leading: List(2,3,4) 
Trailing: Nil 

que es cierto que no soy muy bueno para este tipo de cosas y programación concurrente que realmente está mindbending para mí, como estoy seguro de que es para mucha gente, estoy solo curiosidad por lo que me estoy perdiendo aquí.

+0

creo que estás en lo correcto. Supongo que se podría decir que la "sensación funcional" se rompe si la usa más de un hilo. ¿Se supone que los programas funcionales son simultáneos? No lo sé. – Owen

Respuesta

3

tiene usted razón: Código de aspecto funcional puede volverse no funcional cuando es utilizado por múltiples hilos si se utiliza el estado interno en el marco de su aplicación. Puede solucionar esto sincronizando cada método que toque las variables mutables (es decir, con un bloque synchronized). Desafortunadamente, esto no es ideal para el rendimiento, razón por la cual en una aplicación con subprocesos a menudo se prefieren las implementaciones funcionales.

+0

Muy bien, solo quería asegurarme de no estar loco. Con la concesión de que podría haber un poco de nebulosidad en estas definiciones, o al menos no un acuerdo total sobre lo que quieren decir ... ¿es justo llamar a esto "puramente funcional" o "inmutable" como lo hacen los autores? Parece funcional en las condiciones adecuadas, pero ciertamente no es inmutable ... quiero decir que muta estado bastante claridad, y el aspecto funcional se rompe con varios subprocesos. Lo pregunto porque estoy pensando en escribir a los autores y no quiero parecer una gran herramienta. –

+0

@Chris K - Creo que es justo llamarlo inmutable, pero también es aconsejable advertir sobre la seguridad de los hilos. Las computadoras son dispositivos inherentemente mutables; casi siempre hay una manera de hacer que una operación cause una mutación o fallar de otra manera, incluso si está diseñada para parecer inmutable. La pregunta es si realmente está proporcionando una interfaz que está _designed_ para mutar el estado y cuán frágil es.Dado que el multihilo no es tan inusual, esta fragilidad es decepcionante, pero no estoy seguro de que llamarlo "no puramente funcional" sea exacto. –

Cuestiones relacionadas