From f61a1362c772d5fcdb3303d50dfc52765089a585 Mon Sep 17 00:00:00 2001 From: Seth Tisue Date: Wed, 29 Mar 2017 19:52:30 -0400 Subject: [PATCH] some DOS line endings had crept into the repo --- es/overviews/core/actors.md | 990 ++++++++-------- overviews/core/_posts/2010-11-30-actors.md | 1006 ++++++++--------- .../reflection/annotations-names-scopes.md | 896 +++++++-------- overviews/reflection/overview.md | 692 ++++++------ .../parallel-collections/architecture.md | 2 +- .../parallel-collections/configuration.md | 2 +- .../parallel-collections/conversions.md | 2 +- ru/overviews/parallel-collections/ctries.md | 2 +- .../custom-parallel-collections.md | 2 +- ru/overviews/parallel-collections/overview.md | 360 +++--- .../parallel-collections/performance.md | 2 +- 11 files changed, 1978 insertions(+), 1978 deletions(-) diff --git a/es/overviews/core/actors.md b/es/overviews/core/actors.md index 35fe834caa..498fd6abf6 100644 --- a/es/overviews/core/actors.md +++ b/es/overviews/core/actors.md @@ -1,495 +1,495 @@ ---- -layout: overview -title: API de actores en Scala -label-color: success -label-text: Available -language: es -overview: actors ---- - -**Philipp Haller and Stephen Tu** - -**Traducción e interpretación: Miguel Ángel Pastor Olivar** - -## Introducción - -La presente guía describe el API del paquete `scala.actors` de Scala 2.8/2.9. El documento se estructura en diferentes grupos lógicos. La jerarquía de "traits" es tenida en cuenta para llevar a cabo la estructuración de las secciones individuales. La atención se centra en el comportamiento exhibido en tiempo de ejecución por varios de los métodos presentes en los traits anteriores, complementando la documentación existente en el Scaladoc API. - -## Traits de actores: Reactor, ReplyReactor, y Actor - -### The Reactor trait - -`Reactor` es el padre de todos los traits relacionados con los actores. Heredando de este trait podremos definir actores con una funcionalidad básica de envío y recepción de mensajes. - -El comportamiento de un `Reactor` se define mediante la implementación de su método `act`. Este método es ejecutado una vez el `Reactor` haya sido iniciado mediante la invocación del método `start`, retornando el `Reactor`. El método `start`es *idempotente*, lo cual significa que la invocación del mismo sobre un actor que ya ha sido iniciado no surte ningún efecto. - -El trait `Reactor` tiene un parámetro de tipo `Msg` el cual determina el tipo de mensajes que un actor es capaz de recibir. - -La invocación del método `!` de un `Reactor` envía un mensaje al receptor. La operación de envío de un mensaje mediante el operador `!` es asíncrona por lo que el actor que envía el mensaje no se bloquea esperando a que el mensaje sea recibido sino que su ejecución continua de manera inmediata. Por ejemplo, `a ! msg` envia `msg` a `a`. Todos los actores disponen de un *buzón* encargado de regular los mensajes entrantes hasta que son procesados. - -El trait `Reactor` trait también define el método `forward`. Este método es heredado de `OutputChannel` y tiene el mismo efecto que el método `!`. Aquellos traits que hereden de `Reactor`, en particular el trait `ReplyActor`, sobreescriben este método para habilitar lo que comunmente se conocen como *"implicit reply destinations"* (ver a continuación) - -Un `Reactor` recibe mensajes utilizando el método `react`. Este método espera un argumento de tipo `PartialFunction[Msg, Unit]` el cual define cómo los mensajes de tipo `Msg` son tratados una vez llegan al buzón de un actor. En el siguiente ejemplo, el actor espera recibir la cadena "Hello", para posteriomente imprimir un saludo: - - react { - case "Hello" => println("Hi there") - } - -La invocación del método `react` nunca retorna. Por tanto, cualquier código que deba ejecutarse tras la recepción de un mensaje deberá ser incluido dentro de la función parcial pasada al método `react`. Por ejemplo, dos mensajes pueden ser recibidos secuencialmente mediante la anidación de dos llamadas a `react`: - - react { - case Get(from) => - react { - case Put(x) => from ! x - } - } - -El trait `Reactor` también ofrece una serie de estructuras de control que facilitan la programación utilizando el mecanismo de `react`. - -#### Terminación y estados de ejecución - -La ejecución de un `Reactor` finaliza cuando el cuerpo del método `act` ha sido completado. Un `Reactor` también pueden terminarse a si mismo de manera explícita mediante el uso del método `exit`. El tipo de retorno de `exit` es `Nothing`, dado que `exit` siempre dispara una excepción. Esta excepción únicamente se utiliza de manera interna y nunca debería ser capturada. - -Un `Reactor` finalizado pueden ser reiniciado mediante la invocación de su método `restart`. La invocación del método anterior sobre un `Reactor` que no ha terminado su ejecución lanza una excepción de tipo `IllegalStateException`. El reinicio de un actor que ya ha terminado provoca que el método `act` se ejecute nuevamente. - -El tipo `Reactor` define el método `getState`, el cual retorna, como un miembro de la enumeración `Actor.State`, el estado actual de la ejecución del actor. Un actor que todavía no ha sido iniciado se encuentra en el estado `Actor.State.New`. Si el actor se está ejecutando pero no está esperando por ningún mensaje su estado será `Actor.State.Runnable`. En caso de que el actor haya sido suspendido mientras espera por un mensaje estará en el estado `Actor.State.Suspended`. Por último, un actor ya terminado se encontrará en el estado `Actor.State.Terminated`. - -#### Manejo de excepciones - -El miembro `exceptionHandler` permite llevar a cabo la definición de un manejador de excepciones que estará habilitado durante toda la vida del `Reactor`: - - def exceptionHandler: PartialFunction[Exception, Unit] - -Este manejador de excepciones (`exceptionHandler`) retorna una función parcial que se utiliza para gestionar excepciones que no hayan sido tratadas de ninguna otra manera. Siempre que una excepción se propague fuera del método `act` de un `Reactor` el manejador anterior será aplicado a dicha excepción, permitiendo al actor ejecutar código de limpieza antes de que se termine. Nótese que la visibilidad de `exceptionHandler` es `protected`. - -El manejo de excepciones mediante el uso de `exceptionHandler` encaja a la perfección con las estructuras de control utilizadas para programas con el método `react`. Siempre que una excepción es manejada por la función parcial retornada por `excepctionHandler`, la ejecución continua con la "closure" actual: - - loop { - react { - case Msg(data) => - if (cond) // process data - else throw new Exception("cannot process data") - } - } - -Assumiendo que `Reactor` sobreescribe el atributo `exceptionHandler`, tras el lanzamiento de una excepción en el cuerpo del método `react`, y una vez ésta ha sido gestionada, la ejecución continua con la siguiente iteración del bucle. - -### The ReplyReactor trait - -El trait `ReplyReactor` extiende `Reactor[Any]` y sobrescribe y/o añade los siguientes métodos: - -- El método `!` es sobrescrito para obtener una referencia al actor - actual (el emisor). Junto al mensaje actual, la referencia a dicho - emisor es enviada al buzón del actor receptor. Este último dispone de - acceso al emisor del mensaje mediante el uso del método `sender` (véase más abajo). - -- El método `forward` es sobrescrito para obtener una referencia al emisor - del mensaje que actualmente está siendo procesado. Junto con el mensaje - actual, esta referencia es enviada como el emisor del mensaje actual. - Como consuencia de este hecho, `forward` nos permite reenviar mensajes - en nombre de actores diferentes al actual. - -- El método (añadido) `sender` retorna el emisor del mensaje que está siendo - actualmente procesado. Puesto que un mensaje puede haber sido reenviado, - `sender` podría retornar un actor diferente al que realmente envió el mensaje. - -- El método (añadido) `reply` envía una respuesta al emisor del último mensaje. - `reply` también es utilizado para responder a mensajes síncronos o a mensajes - que han sido enviados mediante un "future" (ver más adelante). - -- El método (añadido) `!?` ofrece un *mecanismo síncrono de envío de mensajes*. - La invocación de `!?` provoca que el actor emisor del mensaje se bloquee hasta - que se recibe una respuesta, momento en el cual retorna dicha respuesta. Existen - dos variantes sobrecargadas. La versión con dos parámetros recibe un argumento - adicional que representa el tiempo de espera (medido en milisegundos) y su tipo - de retorno es `Option[Any]` en lugar de `Any`. En caso de que el emisor no - reciba una respuesta en el periodo de espera establecido, el método `!?` retornará - `None`; en otro caso retornará la respuesta recibida recubierta con `Some`. - -- Los métodos (añadidos) `!!` son similares al envío síncrono de mensajes en el sentido de - que el receptor puede enviar una respuesta al emisor del mensaje. Sin embargo, en lugar - de bloquear el actor emisor hasta que una respuesta es recibida, retornan una instancia de - `Future`. Esta última puede ser utilizada para recuperar la respuesta del receptor una - vez se encuentre disponible; asimismo puede ser utilizada para comprobar si la respuesta - está disponible sin la necesidad de bloquear el emisor. Existen dos versiones sobrecargadas. - La versión que acepta dos parámetros recibe un argumento adicional de tipo - `PartialFunction[Any, A]`. Esta función parcial es utilizada para realizar el post-procesado de - la respuesta del receptor. Básicamente, `!!` retorna un "future" que aplicará la anterior - función parcial a la repuesta (una vez recibida). El resultado del "future" es el resultado - de este post-procesado. - -- El método (añadido) `reactWithin` permite llevar a cabo la recepción de mensajes en un periodo - determinado de tiempo. En comparación con el método `react`, recibe un parámetro adicional, - `msec`, el cual representa el periodo de tiempo, expresado en milisegundos, hasta que el patrón `TIMEOUT` - es satisfecho (`TIMEOUT` es un "case object" presente en el paquete `scala.actors`). Ejemplo: - - reactWithin(2000) { - case Answer(text) => // process text - case TIMEOUT => println("no answer within 2 seconds") - } - -- El método `reactWithin` también permite realizar accesos no bloqueantes al buzón. Si - especificamos un tiempo de espera de 0 milisegundos, primeramente el buzón será escaneado - en busca de un mensaje que concuerde. En caso de que no exista ningún mensaje concordante - tras el primer escaneo, el patrón `TIMEOUT` será satisfecho. Por ejemplo, esto nos permite - recibir determinado tipo de mensajes donde unos tienen una prioridad mayor que otros: - - reactWithin(0) { - case HighPriorityMsg => // ... - case TIMEOUT => - react { - case LowPriorityMsg => // ... - } - } - - En el ejemplo anterior, el actor procesa en primer lugar los mensajes `HighPriorityMsg` aunque - exista un mensaje `LowPriorityMsg` más antiguo en el buzón. El actor sólo procesará mensajes - `LowPriorityMsg` en primer lugar en aquella situación donde no exista ningún `HighProrityMsg` - en el buzón. - -Adicionalmente, el tipo `ReplyActor` añade el estado de ejecución `Actor.State.TimedSuspended`. Un actor suspendido, esperando la recepción de un mensaje mediante el uso de `reactWithin` se encuentra en dicho estado. - -### El trait Actor - -El trait `Actor` extiende de `ReplyReactor` añadiendo y/o sobrescribiendo los siguientes miembros: - -- El método (añadido) `receive` se comporta del mismo modo que `react`, con la excepción - de que puede retornar un resultado. Este hecho se ve reflejado en la definición del tipo, - que es polimórfico en el tipo del resultado: `def receive[R](f: PartialFunction[Any, R]): R`. - Sin embargo, la utilización de `receive` hace que el uso del actor - sea más pesado, puesto que el hilo subyacente es bloqueado mientras - el actor está esperando por la respuesta. El hilo bloqueado no está - disponible para ejecutar otros actores hasta que la invocación del - método `receive` haya retornado. - -- El método (añadido) `link` permite a un actor enlazarse y desenlazarse de otro - actor respectivamente. El proceso de enlazado puede utilizarse para monitorizar - y responder a la terminación de un actor. En particular, el proceso de enlazado - afecta al comportamiento mostrado en la ejecución del método `exit` tal y como - se escribe en el la documentación del API del trait `Actor`. - -- El atributo `trapExit` permite responder a la terminación de un actor enlazado, - independientemente de los motivos de su terminación (es decir, carece de importancia - si la terminación del actor es normal o no). Si `trapExit` toma el valor cierto en - un actor, este nunca terminará por culpa de los actores enlazados. En cambio, siempre - y cuando uno de sus actores enlazados finalice, recibirá un mensaje de tipo `Exit`. - `Exit` es una "case class" que presenta dos atributos: `from` referenciando al actor - que termina y `reason` conteniendo los motivos de la terminación. - -#### Terminación y estados de ejecución - -Cuando la ejecución de un actor finaliza, el motivo de dicha terminación puede ser -establecida de manera explícita mediante la invocación de la siguiente variante -del método `exit`: - - def exit(reason: AnyRef): Nothing - -Un actor cuyo estado de terminación es diferente del símbolo `'normal` propaga -los motivos de su terminación a todos aquellos actores que se encuentren enlazados -a él. Si el motivo de la terminación es una excepción no controlada, el motivo de -finalización será una instancia de la "case class" `UncaughtException`. - -El trait `Actor` incluye dos nuevos estados de ejecución. Un actor que se encuentra -esperando la recepción de un mensaje mediante la utilización del método `receive` se -encuentra en el método `Actor.State.Blocked`. Un actor esperado la recepción de un -mensaje mediante la utilización del método `receiveWithin` se encuentra en el estado -`Actor.State.TimeBlocked`. - -## Estructuras de control - -El trait `Reactor` define una serie de estructuras de control que simplifican el mecanismo -de programación con la función sin retorno `react`. Normalmente, una invocación al método -`react` no retorna nunca. Si el actor necesita ejecutar código a continuación de la invocación -anterior, tendrá que pasar, de manera explícita, dicho código al método `react` o utilizar -algunas de las estructuras que encapsulan este comportamiento. - -La estructura de control más basica es `andThen`. Permite registrar una `closure` que será -ejecutada una vez el actor haya terminado la ejecución de todo lo demas. - - actor { - { - react { - case "hello" => // processing "hello" - }: Unit - } andThen { - println("hi there") - } - } - -Por ejemplo, el actor anterior imprime un saludo tras realizar el procesado -del mensaje `hello`. Aunque la invocación del método `react` no retorna, -podemos utilizar `andThen` para registrar el código encargado de imprimir -el saludo a continuación de la ejecución del actor. - -Nótese que existe una *atribución de tipo* a continuación de la invocación -de `react` (`:Unit`). Básicamente, nos permite tratar el resultado de -`react` como si fuese de tipo `Unit`, lo cual es legal, puesto que el resultado -de una expresión siempre se puede eliminar. Es necesario llevar a cabo esta operación -dado que `andThen` no puede ser un miembro del tipo `Unit`, que es el tipo del resultado -retornado por `react`. Tratando el tipo de resultado retornado por `react` como -`Unit` permite llevar a cabo la aplicación de una conversión implícita la cual -hace que el miembro `andThen` esté disponible. - -El API ofrece unas cuantas estructuras de control adicionales: - -- `loop { ... }`. Itera de manera indefinidia, ejecutando el código entre -las llaves en cada una de las iteraciones. La invocación de `react` en el -cuerpo del bucle provoca que el actor se comporte de manera habitual ante -la llegada de un nuevo mensaje. Posteriormente a la recepción del mensaje, -la ejecución continua con la siguiente iteración del bucle actual. - -- `loopWhile (c) { ... }`. Ejecuta el código entre las llaves mientras la -condición `c` tome el valor `true`. La invocación de `react` en el cuerpo -del bucle ocasiona el mismo efecto que en el caso de `loop`. - -- `continue`. Continua con la ejecución de la closure actual. La invocación -de `continue` en el cuerpo de un `loop`o `loopWhile` ocasionará que el actor -termine la iteración en curso y continue con la siguiente. Si la iteración en -curso ha sido registrada utilizando `andThen`, la ejecución continua con la -segunda "closure" pasada como segundo argumento a `andThen`. - -Las estructuras de control pueden ser utilizadas en cualquier parte del cuerpo -del método `act` y en los cuerpos de los métodos que, transitivamente, son -llamados por `act`. Aquellos actores creados utilizando la sintáxis `actor { ... }` -pueden importar las estructuras de control desde el objeto `Actor`. - -#### Futures - -Los traits `RepyActor` y `Actor` soportan operaciones de envío de mensajes -(métodos `!!`) que, de manera inmediata, retornan un *future*. Un *future*, -es una instancia del trait `Future` y actúa como un manejador que puede -ser utilizado para recuperar la respuesta a un mensaje "send-with-future". - -El emisor de un mensaje "send-with-future" puede esperar por la respuesta del -future *aplicando* dicha future. Por ejemplo, el envío de un mensaje mediante -`val fut = a !! msg` permite al emisor esperar por el resultado del future -del siguiente modo: `val res = fut()`. - -Adicionalmente, utilizando el método `isSet`, un `Future` puede ser consultado -de manera no bloqueante para comprobar si el resultado está disponible. - -Un mensaje "send-with-future" no es el único modo de obtener una referencia a -un future. Estos pueden ser creados utilizando el método `future`. En el siguiente -ejemplo, `body` se ejecuta de manera concurrente, retornando un future como -resultado. - - val fut = Future { body } - // ... - fut() // wait for future - -Lo que hace especial a los futures en el contexto de los actores es la posibilidad -de recuperar su resultado utilizando las operaciones estándar de actores de -recepción de mensajes como `receive`, etc. Además, es posible utilizar las operaciones -basadas en eventos `react`y `reactWithin`. Esto permite a un actor esperar por el -resultado de un future sin la necesidad de bloquear el hilo subyacente. - -Las operaciones de recepción basadas en actores están disponibles a través del -atributo `inputChannel` del future. Dado un future de tipo `Future[T]`, el tipo -de `inputChannel` es `InputChannel[T]`. Por ejemplo: - - val fut = a !! msg - // ... - fut.inputChannel.react { - case Response => // ... - } - -## Canales - -Los canales pueden ser utilizados para simplificar el manejo de mensajes -que presentan tipos diferentes pero que son enviados al mismo actor. La -jerarquía de canales se divide en `OutputChannel` e `InputChannel`. - -Los `OutputChannel` pueden ser utilizados para enviar mensajes. Un -`OutputChannel` `out` soporta las siguientes operaciones: - -- `out ! msg`. Envía el mensaje `msg` a `out` de manera asíncrona. Cuando `msg` - es enviado directamente a un actor se incluye un referencia al actor emisor - del mensaje. - -- `out forward msg`. Reenvía el mensaje `msg` a `out` de manera asíncrona. - El actor emisor se determina en el caso en el que `msg` es reenviado a - un actor. - -- `out.receiver`. Retorna el único actor que está recibiendo mensajes que están - siendo enviados al canal `out`. - -- `out.send(msg, from)`. Envía el mensaje `msg` a `out` de manera asíncrona, - proporcionando a `from` como el emisor del mensaje. - -Nótese que el trait `OutputChannel` tiene un parámetro de tipo que especifica el -tipo de los mensajes que pueden ser enviados al canal (utilizando `!`, `forward`, -y `send`). Este parámetro de tipo es contra-variante: - - trait OutputChannel[-Msg] - -Los actores pueden recibir mensajes de un `InputChannel`. Del mismo modo que -`OutputChannel`, el trait `InputChannel` presenta un parámetro de tipo que -especifica el tipo de mensajes que pueden ser recibidos por el canal. En este caso, -el parámetro de tipo es covariante: - - trait InputChannel[+Msg] - -Un `InputChannel[Msg]` `in` soportal las siguientes operaciones. - -- `in.receive { case Pat1 => ... ; case Patn => ... }` (y de manera similar, - `in.receiveWithin`) recibe un mensaje proveniente de `in`. La invocación - del método `receive` en un canal de entrada presenta la misma semántica - que la operación estándar de actores `receive`. La única diferencia es que - la función parcial pasada como argumento tiene tipo `PartialFunction[Msg, R]` - donde `R` es el tipo de retorno de `receive`. - -- `in.react { case Pat1 => ... ; case Patn => ... }` (y de manera similar, - `in.reactWithin`). Recibe un mensaje de `in` utilizando la operación basada en - eventos `react`. Del mismo modo que la operación `react` en actores, el tipo - de retorno es `Nothing`, indicando que las invocaciones de este método nunca - retornan. Al igual que la operación `receive` anterior, la función parcial - que se pasa como argumento presenta un tipo más específico: - - PartialFunction[Msg, Unit] - -### Creando y compartiendo canales - -Los canales son creados utilizando la clase concreta `Channel`. Esta clase extiende -de `InputChannel` y `OutputChannel`. Un canal pueden ser compartido haciendo dicho -canal visible en el ámbito de múltiples actores o enviándolo como mensaje. - -El siguiente ejemplo muestra la compartición mediante publicación en ámbitos: - - actor { - var out: OutputChannel[String] = null - val child = actor { - react { - case "go" => out ! "hello" - } - } - val channel = new Channel[String] - out = channel - child ! "go" - channel.receive { - case msg => println(msg.length) - } - } - -La ejecución de este ejemplo imprime la cadena "5" en la consola. Nótese que el -actor `child` únicamente tiene acceso a `out`, que es un `OutputChannel[String]`. -La referencia al canal, la cual puede ser utilizada para llevar a cabo la recepción -de mensajes, se encuentra oculta. Sin embargo, se deben tomar precauciones y -asegurarse que el canal de salida es inicializado con un canal concreto antes de que -`child` le envíe ningún mensaje. En el ejemplo que nos ocupa, esto es llevado a cabo -mediante el mensaje "go". Cuando se está recibiendo de `channel` utilizando el método -`channel.receive` podemos hacer uso del hecho que `msg` es de tipo `String`, y por -lo tanto tiene un miembro `length`. - -Una alternativa a la compartición de canales es enviarlos a través de mensajes. -El siguiente fragmento de código muestra un sencillo ejemplo de aplicación: - - case class ReplyTo(out: OutputChannel[String]) - - val child = actor { - react { - case ReplyTo(out) => out ! "hello" - } - } - - actor { - val channel = new Channel[String] - child ! ReplyTo(channel) - channel.receive { - case msg => println(msg.length) - } - } - -La "case class" `ReplyTo` es un tipo de mensajes que utilizamos para distribuir -una referencia a un `OutputChannel[String]`. Cuando el actor `child` recibe un -mensaje de tipo `ReplyTo` éste envía una cadena a su canal de salida. El segundo -actor recibe en el canal del mismo modo que anteriormente. - -## Planificadores - -Un `Reactor`(o una instancia de uno de sus subtipos) es ejecutado utilizando un -*planificador*. El trait `Reactor` incluye el miembro `scheduler` el cual retorna el -planificador utilizado para ejecutar sus instancias: - - def scheduler: IScheduler - -La plataforma de ejecución ejecuta los actores enviando tareas al planificador mediante -el uso de los métodos `execute` definidos en el trait `IScheduler`. La mayor parte -del resto de métodos definidos en este trait únicamente adquieren cierto protagonismo -cuando se necesita implementar un nuevo planificador desde cero; algo que no es necesario -en muchas ocasiones. - -Los planificadores por defecto utilizados para ejecutar instancias de `Reactor` y -`Actor` detectan cuando los actores han finalizado su ejecución. En el momento que esto -ocurre, el planificador se termina a si mismo (terminando con cualquier hilo que estuviera -en uso por parte del planificador). Sin embargo, algunos planificadores como el -`SingleThreadedScheduler` (definido en el paquete `scheduler`) necesita ser terminado de -manera explícita mediante la invocación de su método `shutdown`). - -La manera más sencilla de crear un planificador personalizado consisten en extender la clase -`SchedulerAdapter`, implementando el siguiente método abstracto: - - def execute(fun: => Unit): Unit - -Por norma general, una implementación concreata utilizaría un pool de hilos para llevar a cabo -la ejecución del argumento por nombre `fun`. - -## Actores remotos - -Esta sección describe el API de los actores remotos. Su principal interfaz es el objecto -[`RemoteActor`](http://www.scala-lang.org/api/2.9.1/scala/actors/remote/RemoteActor$.html) definido -en el paquete `scala.actors.remote`. Este objeto facilita el conjunto de métodos necesarios para crear -y establecer conexiones a instancias de actores remotos. En los fragmentos de código que se muestran a -continuación se asume que todos los miembros de `RemoteActor` han sido importados; la lista completa -de importaciones utilizadas es la siguiente: - - import scala.actors._ - import scala.actors.Actor._ - import scala.actors.remote._ - import scala.actors.remote.RemoteActor._ - -### Iniciando actores remotos - -Un actore remot es identificado de manera unívoca por un -[`Symbol`](http://www.scala-lang.org/api/2.9.1/scala/Symbol.html). Este símbolo es único para la instancia -de la máquina virual en la que se está ejecutando un actor. Un actor remoto identificado con el nombre -`myActor` puede ser creado del siguiente modo. - - class MyActor extends Actor { - def act() { - alive(9000) - register('myActor, self) - // ... - } - } - -Nótese que el nombre únicamente puede ser registrado con un único actor al mismo tiempo. -Por ejemplo, para registrar el actor *A* como `'myActor` y posteriormente registrar otro -actor *B* como `'myActor`, debería esperar hasta que *A* haya finalizado. Este requisito -aplica a lo largo de todos los puertos, por lo que registrando a *B* en un puerto diferente -no sería suficiente. - -### Connecting to remote actors - -Establecer la conexión con un actor remoto es un proceso simple. Para obtener una referencia remota -a un actor remoto que está ejecutándose en la máquina `myMachine` en el puerto 8000 con el nombre -`'anActor`, tendremos que utilizar `select`del siguiente modo: - - val myRemoteActor = select(Node("myMachine", 8000), 'anActor) - -El actor retornado por `select` es de tipo `AbstractActor`, que proporciona esencialmente el mismo -interfaz que un actor normal, y por lo tanto es compatible con las habituales operaciones de envío -de mensajes: - - myRemoteActor ! "Hello!" - receive { - case response => println("Response: " + response) - } - myRemoteActor !? "What is the meaning of life?" match { - case 42 => println("Success") - case oops => println("Failed: " + oops) - } - val future = myRemoteActor !! "What is the last digit of PI?" - -Nótese que la operación `select` es perezosa; no inicializa ninguna conexión de red. Simplemente crea -una nueva instancia de `AbstractActor` que está preparada para iniciar una nueva conexión de red en el -momento en que sea necesario (por ejemplo cuando el método '!' es invocado). +--- +layout: overview +title: API de actores en Scala +label-color: success +label-text: Available +language: es +overview: actors +--- + +**Philipp Haller and Stephen Tu** + +**Traducción e interpretación: Miguel Ángel Pastor Olivar** + +## Introducción + +La presente guía describe el API del paquete `scala.actors` de Scala 2.8/2.9. El documento se estructura en diferentes grupos lógicos. La jerarquía de "traits" es tenida en cuenta para llevar a cabo la estructuración de las secciones individuales. La atención se centra en el comportamiento exhibido en tiempo de ejecución por varios de los métodos presentes en los traits anteriores, complementando la documentación existente en el Scaladoc API. + +## Traits de actores: Reactor, ReplyReactor, y Actor + +### The Reactor trait + +`Reactor` es el padre de todos los traits relacionados con los actores. Heredando de este trait podremos definir actores con una funcionalidad básica de envío y recepción de mensajes. + +El comportamiento de un `Reactor` se define mediante la implementación de su método `act`. Este método es ejecutado una vez el `Reactor` haya sido iniciado mediante la invocación del método `start`, retornando el `Reactor`. El método `start`es *idempotente*, lo cual significa que la invocación del mismo sobre un actor que ya ha sido iniciado no surte ningún efecto. + +El trait `Reactor` tiene un parámetro de tipo `Msg` el cual determina el tipo de mensajes que un actor es capaz de recibir. + +La invocación del método `!` de un `Reactor` envía un mensaje al receptor. La operación de envío de un mensaje mediante el operador `!` es asíncrona por lo que el actor que envía el mensaje no se bloquea esperando a que el mensaje sea recibido sino que su ejecución continua de manera inmediata. Por ejemplo, `a ! msg` envia `msg` a `a`. Todos los actores disponen de un *buzón* encargado de regular los mensajes entrantes hasta que son procesados. + +El trait `Reactor` trait también define el método `forward`. Este método es heredado de `OutputChannel` y tiene el mismo efecto que el método `!`. Aquellos traits que hereden de `Reactor`, en particular el trait `ReplyActor`, sobreescriben este método para habilitar lo que comunmente se conocen como *"implicit reply destinations"* (ver a continuación) + +Un `Reactor` recibe mensajes utilizando el método `react`. Este método espera un argumento de tipo `PartialFunction[Msg, Unit]` el cual define cómo los mensajes de tipo `Msg` son tratados una vez llegan al buzón de un actor. En el siguiente ejemplo, el actor espera recibir la cadena "Hello", para posteriomente imprimir un saludo: + + react { + case "Hello" => println("Hi there") + } + +La invocación del método `react` nunca retorna. Por tanto, cualquier código que deba ejecutarse tras la recepción de un mensaje deberá ser incluido dentro de la función parcial pasada al método `react`. Por ejemplo, dos mensajes pueden ser recibidos secuencialmente mediante la anidación de dos llamadas a `react`: + + react { + case Get(from) => + react { + case Put(x) => from ! x + } + } + +El trait `Reactor` también ofrece una serie de estructuras de control que facilitan la programación utilizando el mecanismo de `react`. + +#### Terminación y estados de ejecución + +La ejecución de un `Reactor` finaliza cuando el cuerpo del método `act` ha sido completado. Un `Reactor` también pueden terminarse a si mismo de manera explícita mediante el uso del método `exit`. El tipo de retorno de `exit` es `Nothing`, dado que `exit` siempre dispara una excepción. Esta excepción únicamente se utiliza de manera interna y nunca debería ser capturada. + +Un `Reactor` finalizado pueden ser reiniciado mediante la invocación de su método `restart`. La invocación del método anterior sobre un `Reactor` que no ha terminado su ejecución lanza una excepción de tipo `IllegalStateException`. El reinicio de un actor que ya ha terminado provoca que el método `act` se ejecute nuevamente. + +El tipo `Reactor` define el método `getState`, el cual retorna, como un miembro de la enumeración `Actor.State`, el estado actual de la ejecución del actor. Un actor que todavía no ha sido iniciado se encuentra en el estado `Actor.State.New`. Si el actor se está ejecutando pero no está esperando por ningún mensaje su estado será `Actor.State.Runnable`. En caso de que el actor haya sido suspendido mientras espera por un mensaje estará en el estado `Actor.State.Suspended`. Por último, un actor ya terminado se encontrará en el estado `Actor.State.Terminated`. + +#### Manejo de excepciones + +El miembro `exceptionHandler` permite llevar a cabo la definición de un manejador de excepciones que estará habilitado durante toda la vida del `Reactor`: + + def exceptionHandler: PartialFunction[Exception, Unit] + +Este manejador de excepciones (`exceptionHandler`) retorna una función parcial que se utiliza para gestionar excepciones que no hayan sido tratadas de ninguna otra manera. Siempre que una excepción se propague fuera del método `act` de un `Reactor` el manejador anterior será aplicado a dicha excepción, permitiendo al actor ejecutar código de limpieza antes de que se termine. Nótese que la visibilidad de `exceptionHandler` es `protected`. + +El manejo de excepciones mediante el uso de `exceptionHandler` encaja a la perfección con las estructuras de control utilizadas para programas con el método `react`. Siempre que una excepción es manejada por la función parcial retornada por `excepctionHandler`, la ejecución continua con la "closure" actual: + + loop { + react { + case Msg(data) => + if (cond) // process data + else throw new Exception("cannot process data") + } + } + +Assumiendo que `Reactor` sobreescribe el atributo `exceptionHandler`, tras el lanzamiento de una excepción en el cuerpo del método `react`, y una vez ésta ha sido gestionada, la ejecución continua con la siguiente iteración del bucle. + +### The ReplyReactor trait + +El trait `ReplyReactor` extiende `Reactor[Any]` y sobrescribe y/o añade los siguientes métodos: + +- El método `!` es sobrescrito para obtener una referencia al actor + actual (el emisor). Junto al mensaje actual, la referencia a dicho + emisor es enviada al buzón del actor receptor. Este último dispone de + acceso al emisor del mensaje mediante el uso del método `sender` (véase más abajo). + +- El método `forward` es sobrescrito para obtener una referencia al emisor + del mensaje que actualmente está siendo procesado. Junto con el mensaje + actual, esta referencia es enviada como el emisor del mensaje actual. + Como consuencia de este hecho, `forward` nos permite reenviar mensajes + en nombre de actores diferentes al actual. + +- El método (añadido) `sender` retorna el emisor del mensaje que está siendo + actualmente procesado. Puesto que un mensaje puede haber sido reenviado, + `sender` podría retornar un actor diferente al que realmente envió el mensaje. + +- El método (añadido) `reply` envía una respuesta al emisor del último mensaje. + `reply` también es utilizado para responder a mensajes síncronos o a mensajes + que han sido enviados mediante un "future" (ver más adelante). + +- El método (añadido) `!?` ofrece un *mecanismo síncrono de envío de mensajes*. + La invocación de `!?` provoca que el actor emisor del mensaje se bloquee hasta + que se recibe una respuesta, momento en el cual retorna dicha respuesta. Existen + dos variantes sobrecargadas. La versión con dos parámetros recibe un argumento + adicional que representa el tiempo de espera (medido en milisegundos) y su tipo + de retorno es `Option[Any]` en lugar de `Any`. En caso de que el emisor no + reciba una respuesta en el periodo de espera establecido, el método `!?` retornará + `None`; en otro caso retornará la respuesta recibida recubierta con `Some`. + +- Los métodos (añadidos) `!!` son similares al envío síncrono de mensajes en el sentido de + que el receptor puede enviar una respuesta al emisor del mensaje. Sin embargo, en lugar + de bloquear el actor emisor hasta que una respuesta es recibida, retornan una instancia de + `Future`. Esta última puede ser utilizada para recuperar la respuesta del receptor una + vez se encuentre disponible; asimismo puede ser utilizada para comprobar si la respuesta + está disponible sin la necesidad de bloquear el emisor. Existen dos versiones sobrecargadas. + La versión que acepta dos parámetros recibe un argumento adicional de tipo + `PartialFunction[Any, A]`. Esta función parcial es utilizada para realizar el post-procesado de + la respuesta del receptor. Básicamente, `!!` retorna un "future" que aplicará la anterior + función parcial a la repuesta (una vez recibida). El resultado del "future" es el resultado + de este post-procesado. + +- El método (añadido) `reactWithin` permite llevar a cabo la recepción de mensajes en un periodo + determinado de tiempo. En comparación con el método `react`, recibe un parámetro adicional, + `msec`, el cual representa el periodo de tiempo, expresado en milisegundos, hasta que el patrón `TIMEOUT` + es satisfecho (`TIMEOUT` es un "case object" presente en el paquete `scala.actors`). Ejemplo: + + reactWithin(2000) { + case Answer(text) => // process text + case TIMEOUT => println("no answer within 2 seconds") + } + +- El método `reactWithin` también permite realizar accesos no bloqueantes al buzón. Si + especificamos un tiempo de espera de 0 milisegundos, primeramente el buzón será escaneado + en busca de un mensaje que concuerde. En caso de que no exista ningún mensaje concordante + tras el primer escaneo, el patrón `TIMEOUT` será satisfecho. Por ejemplo, esto nos permite + recibir determinado tipo de mensajes donde unos tienen una prioridad mayor que otros: + + reactWithin(0) { + case HighPriorityMsg => // ... + case TIMEOUT => + react { + case LowPriorityMsg => // ... + } + } + + En el ejemplo anterior, el actor procesa en primer lugar los mensajes `HighPriorityMsg` aunque + exista un mensaje `LowPriorityMsg` más antiguo en el buzón. El actor sólo procesará mensajes + `LowPriorityMsg` en primer lugar en aquella situación donde no exista ningún `HighProrityMsg` + en el buzón. + +Adicionalmente, el tipo `ReplyActor` añade el estado de ejecución `Actor.State.TimedSuspended`. Un actor suspendido, esperando la recepción de un mensaje mediante el uso de `reactWithin` se encuentra en dicho estado. + +### El trait Actor + +El trait `Actor` extiende de `ReplyReactor` añadiendo y/o sobrescribiendo los siguientes miembros: + +- El método (añadido) `receive` se comporta del mismo modo que `react`, con la excepción + de que puede retornar un resultado. Este hecho se ve reflejado en la definición del tipo, + que es polimórfico en el tipo del resultado: `def receive[R](f: PartialFunction[Any, R]): R`. + Sin embargo, la utilización de `receive` hace que el uso del actor + sea más pesado, puesto que el hilo subyacente es bloqueado mientras + el actor está esperando por la respuesta. El hilo bloqueado no está + disponible para ejecutar otros actores hasta que la invocación del + método `receive` haya retornado. + +- El método (añadido) `link` permite a un actor enlazarse y desenlazarse de otro + actor respectivamente. El proceso de enlazado puede utilizarse para monitorizar + y responder a la terminación de un actor. En particular, el proceso de enlazado + afecta al comportamiento mostrado en la ejecución del método `exit` tal y como + se escribe en el la documentación del API del trait `Actor`. + +- El atributo `trapExit` permite responder a la terminación de un actor enlazado, + independientemente de los motivos de su terminación (es decir, carece de importancia + si la terminación del actor es normal o no). Si `trapExit` toma el valor cierto en + un actor, este nunca terminará por culpa de los actores enlazados. En cambio, siempre + y cuando uno de sus actores enlazados finalice, recibirá un mensaje de tipo `Exit`. + `Exit` es una "case class" que presenta dos atributos: `from` referenciando al actor + que termina y `reason` conteniendo los motivos de la terminación. + +#### Terminación y estados de ejecución + +Cuando la ejecución de un actor finaliza, el motivo de dicha terminación puede ser +establecida de manera explícita mediante la invocación de la siguiente variante +del método `exit`: + + def exit(reason: AnyRef): Nothing + +Un actor cuyo estado de terminación es diferente del símbolo `'normal` propaga +los motivos de su terminación a todos aquellos actores que se encuentren enlazados +a él. Si el motivo de la terminación es una excepción no controlada, el motivo de +finalización será una instancia de la "case class" `UncaughtException`. + +El trait `Actor` incluye dos nuevos estados de ejecución. Un actor que se encuentra +esperando la recepción de un mensaje mediante la utilización del método `receive` se +encuentra en el método `Actor.State.Blocked`. Un actor esperado la recepción de un +mensaje mediante la utilización del método `receiveWithin` se encuentra en el estado +`Actor.State.TimeBlocked`. + +## Estructuras de control + +El trait `Reactor` define una serie de estructuras de control que simplifican el mecanismo +de programación con la función sin retorno `react`. Normalmente, una invocación al método +`react` no retorna nunca. Si el actor necesita ejecutar código a continuación de la invocación +anterior, tendrá que pasar, de manera explícita, dicho código al método `react` o utilizar +algunas de las estructuras que encapsulan este comportamiento. + +La estructura de control más basica es `andThen`. Permite registrar una `closure` que será +ejecutada una vez el actor haya terminado la ejecución de todo lo demas. + + actor { + { + react { + case "hello" => // processing "hello" + }: Unit + } andThen { + println("hi there") + } + } + +Por ejemplo, el actor anterior imprime un saludo tras realizar el procesado +del mensaje `hello`. Aunque la invocación del método `react` no retorna, +podemos utilizar `andThen` para registrar el código encargado de imprimir +el saludo a continuación de la ejecución del actor. + +Nótese que existe una *atribución de tipo* a continuación de la invocación +de `react` (`:Unit`). Básicamente, nos permite tratar el resultado de +`react` como si fuese de tipo `Unit`, lo cual es legal, puesto que el resultado +de una expresión siempre se puede eliminar. Es necesario llevar a cabo esta operación +dado que `andThen` no puede ser un miembro del tipo `Unit`, que es el tipo del resultado +retornado por `react`. Tratando el tipo de resultado retornado por `react` como +`Unit` permite llevar a cabo la aplicación de una conversión implícita la cual +hace que el miembro `andThen` esté disponible. + +El API ofrece unas cuantas estructuras de control adicionales: + +- `loop { ... }`. Itera de manera indefinidia, ejecutando el código entre +las llaves en cada una de las iteraciones. La invocación de `react` en el +cuerpo del bucle provoca que el actor se comporte de manera habitual ante +la llegada de un nuevo mensaje. Posteriormente a la recepción del mensaje, +la ejecución continua con la siguiente iteración del bucle actual. + +- `loopWhile (c) { ... }`. Ejecuta el código entre las llaves mientras la +condición `c` tome el valor `true`. La invocación de `react` en el cuerpo +del bucle ocasiona el mismo efecto que en el caso de `loop`. + +- `continue`. Continua con la ejecución de la closure actual. La invocación +de `continue` en el cuerpo de un `loop`o `loopWhile` ocasionará que el actor +termine la iteración en curso y continue con la siguiente. Si la iteración en +curso ha sido registrada utilizando `andThen`, la ejecución continua con la +segunda "closure" pasada como segundo argumento a `andThen`. + +Las estructuras de control pueden ser utilizadas en cualquier parte del cuerpo +del método `act` y en los cuerpos de los métodos que, transitivamente, son +llamados por `act`. Aquellos actores creados utilizando la sintáxis `actor { ... }` +pueden importar las estructuras de control desde el objeto `Actor`. + +#### Futures + +Los traits `RepyActor` y `Actor` soportan operaciones de envío de mensajes +(métodos `!!`) que, de manera inmediata, retornan un *future*. Un *future*, +es una instancia del trait `Future` y actúa como un manejador que puede +ser utilizado para recuperar la respuesta a un mensaje "send-with-future". + +El emisor de un mensaje "send-with-future" puede esperar por la respuesta del +future *aplicando* dicha future. Por ejemplo, el envío de un mensaje mediante +`val fut = a !! msg` permite al emisor esperar por el resultado del future +del siguiente modo: `val res = fut()`. + +Adicionalmente, utilizando el método `isSet`, un `Future` puede ser consultado +de manera no bloqueante para comprobar si el resultado está disponible. + +Un mensaje "send-with-future" no es el único modo de obtener una referencia a +un future. Estos pueden ser creados utilizando el método `future`. En el siguiente +ejemplo, `body` se ejecuta de manera concurrente, retornando un future como +resultado. + + val fut = Future { body } + // ... + fut() // wait for future + +Lo que hace especial a los futures en el contexto de los actores es la posibilidad +de recuperar su resultado utilizando las operaciones estándar de actores de +recepción de mensajes como `receive`, etc. Además, es posible utilizar las operaciones +basadas en eventos `react`y `reactWithin`. Esto permite a un actor esperar por el +resultado de un future sin la necesidad de bloquear el hilo subyacente. + +Las operaciones de recepción basadas en actores están disponibles a través del +atributo `inputChannel` del future. Dado un future de tipo `Future[T]`, el tipo +de `inputChannel` es `InputChannel[T]`. Por ejemplo: + + val fut = a !! msg + // ... + fut.inputChannel.react { + case Response => // ... + } + +## Canales + +Los canales pueden ser utilizados para simplificar el manejo de mensajes +que presentan tipos diferentes pero que son enviados al mismo actor. La +jerarquía de canales se divide en `OutputChannel` e `InputChannel`. + +Los `OutputChannel` pueden ser utilizados para enviar mensajes. Un +`OutputChannel` `out` soporta las siguientes operaciones: + +- `out ! msg`. Envía el mensaje `msg` a `out` de manera asíncrona. Cuando `msg` + es enviado directamente a un actor se incluye un referencia al actor emisor + del mensaje. + +- `out forward msg`. Reenvía el mensaje `msg` a `out` de manera asíncrona. + El actor emisor se determina en el caso en el que `msg` es reenviado a + un actor. + +- `out.receiver`. Retorna el único actor que está recibiendo mensajes que están + siendo enviados al canal `out`. + +- `out.send(msg, from)`. Envía el mensaje `msg` a `out` de manera asíncrona, + proporcionando a `from` como el emisor del mensaje. + +Nótese que el trait `OutputChannel` tiene un parámetro de tipo que especifica el +tipo de los mensajes que pueden ser enviados al canal (utilizando `!`, `forward`, +y `send`). Este parámetro de tipo es contra-variante: + + trait OutputChannel[-Msg] + +Los actores pueden recibir mensajes de un `InputChannel`. Del mismo modo que +`OutputChannel`, el trait `InputChannel` presenta un parámetro de tipo que +especifica el tipo de mensajes que pueden ser recibidos por el canal. En este caso, +el parámetro de tipo es covariante: + + trait InputChannel[+Msg] + +Un `InputChannel[Msg]` `in` soportal las siguientes operaciones. + +- `in.receive { case Pat1 => ... ; case Patn => ... }` (y de manera similar, + `in.receiveWithin`) recibe un mensaje proveniente de `in`. La invocación + del método `receive` en un canal de entrada presenta la misma semántica + que la operación estándar de actores `receive`. La única diferencia es que + la función parcial pasada como argumento tiene tipo `PartialFunction[Msg, R]` + donde `R` es el tipo de retorno de `receive`. + +- `in.react { case Pat1 => ... ; case Patn => ... }` (y de manera similar, + `in.reactWithin`). Recibe un mensaje de `in` utilizando la operación basada en + eventos `react`. Del mismo modo que la operación `react` en actores, el tipo + de retorno es `Nothing`, indicando que las invocaciones de este método nunca + retornan. Al igual que la operación `receive` anterior, la función parcial + que se pasa como argumento presenta un tipo más específico: + + PartialFunction[Msg, Unit] + +### Creando y compartiendo canales + +Los canales son creados utilizando la clase concreta `Channel`. Esta clase extiende +de `InputChannel` y `OutputChannel`. Un canal pueden ser compartido haciendo dicho +canal visible en el ámbito de múltiples actores o enviándolo como mensaje. + +El siguiente ejemplo muestra la compartición mediante publicación en ámbitos: + + actor { + var out: OutputChannel[String] = null + val child = actor { + react { + case "go" => out ! "hello" + } + } + val channel = new Channel[String] + out = channel + child ! "go" + channel.receive { + case msg => println(msg.length) + } + } + +La ejecución de este ejemplo imprime la cadena "5" en la consola. Nótese que el +actor `child` únicamente tiene acceso a `out`, que es un `OutputChannel[String]`. +La referencia al canal, la cual puede ser utilizada para llevar a cabo la recepción +de mensajes, se encuentra oculta. Sin embargo, se deben tomar precauciones y +asegurarse que el canal de salida es inicializado con un canal concreto antes de que +`child` le envíe ningún mensaje. En el ejemplo que nos ocupa, esto es llevado a cabo +mediante el mensaje "go". Cuando se está recibiendo de `channel` utilizando el método +`channel.receive` podemos hacer uso del hecho que `msg` es de tipo `String`, y por +lo tanto tiene un miembro `length`. + +Una alternativa a la compartición de canales es enviarlos a través de mensajes. +El siguiente fragmento de código muestra un sencillo ejemplo de aplicación: + + case class ReplyTo(out: OutputChannel[String]) + + val child = actor { + react { + case ReplyTo(out) => out ! "hello" + } + } + + actor { + val channel = new Channel[String] + child ! ReplyTo(channel) + channel.receive { + case msg => println(msg.length) + } + } + +La "case class" `ReplyTo` es un tipo de mensajes que utilizamos para distribuir +una referencia a un `OutputChannel[String]`. Cuando el actor `child` recibe un +mensaje de tipo `ReplyTo` éste envía una cadena a su canal de salida. El segundo +actor recibe en el canal del mismo modo que anteriormente. + +## Planificadores + +Un `Reactor`(o una instancia de uno de sus subtipos) es ejecutado utilizando un +*planificador*. El trait `Reactor` incluye el miembro `scheduler` el cual retorna el +planificador utilizado para ejecutar sus instancias: + + def scheduler: IScheduler + +La plataforma de ejecución ejecuta los actores enviando tareas al planificador mediante +el uso de los métodos `execute` definidos en el trait `IScheduler`. La mayor parte +del resto de métodos definidos en este trait únicamente adquieren cierto protagonismo +cuando se necesita implementar un nuevo planificador desde cero; algo que no es necesario +en muchas ocasiones. + +Los planificadores por defecto utilizados para ejecutar instancias de `Reactor` y +`Actor` detectan cuando los actores han finalizado su ejecución. En el momento que esto +ocurre, el planificador se termina a si mismo (terminando con cualquier hilo que estuviera +en uso por parte del planificador). Sin embargo, algunos planificadores como el +`SingleThreadedScheduler` (definido en el paquete `scheduler`) necesita ser terminado de +manera explícita mediante la invocación de su método `shutdown`). + +La manera más sencilla de crear un planificador personalizado consisten en extender la clase +`SchedulerAdapter`, implementando el siguiente método abstracto: + + def execute(fun: => Unit): Unit + +Por norma general, una implementación concreata utilizaría un pool de hilos para llevar a cabo +la ejecución del argumento por nombre `fun`. + +## Actores remotos + +Esta sección describe el API de los actores remotos. Su principal interfaz es el objecto +[`RemoteActor`](http://www.scala-lang.org/api/2.9.1/scala/actors/remote/RemoteActor$.html) definido +en el paquete `scala.actors.remote`. Este objeto facilita el conjunto de métodos necesarios para crear +y establecer conexiones a instancias de actores remotos. En los fragmentos de código que se muestran a +continuación se asume que todos los miembros de `RemoteActor` han sido importados; la lista completa +de importaciones utilizadas es la siguiente: + + import scala.actors._ + import scala.actors.Actor._ + import scala.actors.remote._ + import scala.actors.remote.RemoteActor._ + +### Iniciando actores remotos + +Un actore remot es identificado de manera unívoca por un +[`Symbol`](http://www.scala-lang.org/api/2.9.1/scala/Symbol.html). Este símbolo es único para la instancia +de la máquina virual en la que se está ejecutando un actor. Un actor remoto identificado con el nombre +`myActor` puede ser creado del siguiente modo. + + class MyActor extends Actor { + def act() { + alive(9000) + register('myActor, self) + // ... + } + } + +Nótese que el nombre únicamente puede ser registrado con un único actor al mismo tiempo. +Por ejemplo, para registrar el actor *A* como `'myActor` y posteriormente registrar otro +actor *B* como `'myActor`, debería esperar hasta que *A* haya finalizado. Este requisito +aplica a lo largo de todos los puertos, por lo que registrando a *B* en un puerto diferente +no sería suficiente. + +### Connecting to remote actors + +Establecer la conexión con un actor remoto es un proceso simple. Para obtener una referencia remota +a un actor remoto que está ejecutándose en la máquina `myMachine` en el puerto 8000 con el nombre +`'anActor`, tendremos que utilizar `select`del siguiente modo: + + val myRemoteActor = select(Node("myMachine", 8000), 'anActor) + +El actor retornado por `select` es de tipo `AbstractActor`, que proporciona esencialmente el mismo +interfaz que un actor normal, y por lo tanto es compatible con las habituales operaciones de envío +de mensajes: + + myRemoteActor ! "Hello!" + receive { + case response => println("Response: " + response) + } + myRemoteActor !? "What is the meaning of life?" match { + case 42 => println("Success") + case oops => println("Failed: " + oops) + } + val future = myRemoteActor !! "What is the last digit of PI?" + +Nótese que la operación `select` es perezosa; no inicializa ninguna conexión de red. Simplemente crea +una nueva instancia de `AbstractActor` que está preparada para iniciar una nueva conexión de red en el +momento en que sea necesario (por ejemplo cuando el método '!' es invocado). diff --git a/overviews/core/_posts/2010-11-30-actors.md b/overviews/core/_posts/2010-11-30-actors.md index 0913d7f057..b4e8cf64d8 100644 --- a/overviews/core/_posts/2010-11-30-actors.md +++ b/overviews/core/_posts/2010-11-30-actors.md @@ -1,503 +1,503 @@ ---- -layout: overview -title: The Scala Actors API -overview: actors -languages: [zh-cn, es] ---- - -**Philipp Haller and Stephen Tu** - -## Introduction - -This guide describes the API of the `scala.actors` package of Scala 2.8/2.9. The organization follows groups of types that logically belong together. The trait hierarchy is taken into account to structure the individual sections. The focus is on the run-time behavior of the various methods that these traits define, thereby complementing the existing Scaladoc-based API documentation. - -NOTE: In Scala 2.10 the Actors library is deprecated and will be removed in future Scala releases. Users should use [Akka](http://akka.io) actors from the package `akka.actor`. For migration from Scala actors to Akka refer to the [Actors Migration Guide](actors-migration-guide.html). - -## The actor traits Reactor, ReplyReactor, and Actor - -### The Reactor trait - -`Reactor` is the super trait of all actor traits. Extending this trait allows defining actors with basic capabilities to send and receive messages. - -The behavior of a `Reactor` is defined by implementing its `act` method. The `act` method is executed once the `Reactor` is started by invoking `start`, which also returns the `Reactor`. The `start` method is *idempotent* which means that invoking it on an actor that has already been started has no effect. - -The `Reactor` trait has a type parameter `Msg` which indicates the type of messages that the actor can receive. - -Invoking the `Reactor`'s `!` method sends a message to the receiver. Sending a message using `!` is asynchronous which means that the sending actor does not wait until the message is received; its execution continues immediately. For example, `a ! msg` sends `msg` to `a`. All actors have a *mailbox* which buffers incoming messages until they are processed. - -The `Reactor` trait also defines a `forward` method. This method is inherited from `OutputChannel`. It has the same effect as the `!` method. Subtraits of `Reactor`, in particular the `ReplyReactor` trait, override this method to enable implicit reply destinations (see below). - -A `Reactor` receives messages using the `react` method. `react` expects an argument of type `PartialFunction[Msg, Unit]` which defines how messages of type `Msg` are handled once they arrive in the actor's mailbox. In the following example, the current actor waits to receive the string "Hello", and then prints a greeting: - - react { - case "Hello" => println("Hi there") - } - -Invoking `react` never returns. Therefore, any code that should run after a message has been received must be contained inside the partial function that is passed to `react`. For example, two messages can be received in sequence by nesting two invocations of `react`: - - react { - case Get(from) => - react { - case Put(x) => from ! x - } - } - -The `Reactor` trait also provides control structures which simplify programming with `react`. - -#### Termination and execution states - -The execution of a `Reactor` terminates when the body of its `act` method has run to completion. A `Reactor` can also terminate itself explicitly using the `exit` method. The return type of `exit` is `Nothing`, because `exit` always throws an exception. This exception is only used internally, and should never be caught. - -A terminated `Reactor` can be restarted by invoking its `restart` method. Invoking `restart` on a `Reactor` that has not terminated, yet, throws an `IllegalStateException`. Restarting a terminated actor causes its `act` method to be rerun. - -`Reactor` defines a method `getState` which returns the actor's current execution state as a member of the `Actor.State` enumeration. An actor that has not been started, yet, is in state `Actor.State.New`. An actor that can run without waiting for a message is in state `Actor.State.Runnable`. An actor that is suspended, waiting for a message is in state `Actor.State.Suspended`. A terminated actor is in state `Actor.State.Terminated`. - -#### Exception handling - -The `exceptionHandler` member allows defining an exception handler that is enabled throughout the entire lifetime of a `Reactor`: - - def exceptionHandler: PartialFunction[Exception, Unit] - -`exceptionHandler` returns a partial function which is used to handle exceptions that are not otherwise handled: whenever an exception propagates out of the body of a `Reactor`'s `act` method, the partial function is applied to that exception, allowing the actor to run clean-up code before it terminates. Note that the visibility of `exceptionHandler` is `protected`. - -Handling exceptions using `exceptionHandler` works well together with the control structures for programming with `react`. Whenever an exception has been handled using the partial function returned by `exceptionHandler`, execution continues with the current continuation closure. Example: - - loop { - react { - case Msg(data) => - if (cond) // process data - else throw new Exception("cannot process data") - } - } - -Assuming that the `Reactor` overrides `exceptionHandler`, after an exception thrown inside the body of `react` is handled, execution continues with the next loop iteration. - -### The ReplyReactor trait - -The `ReplyReactor` trait extends `Reactor[Any]` and adds or overrides the following methods: - -- The `!` method is overridden to obtain a reference to the current - actor (the sender); together with the actual message, the sender - reference is transferred to the mailbox of the receiving actor. The - receiver has access to the sender of a message through its `sender` - method (see below). - -- The `forward` method is overridden to obtain a reference to the - `sender` of the message that is currently being processed. Together - with the actual message, this reference is transferred as the sender - of the current message. As a consequence, `forward` allows - forwarding messages on behalf of actors different from the current - actor. - -- The added `sender` method returns the sender of the message that is - currently being processed. Given the fact that a message might have - been forwarded, `sender` may not return the actor that actually sent - the message. - -- The added `reply` method sends a message back to the sender of the - last message. `reply` is also used to reply to a synchronous message - send or a message send with future (see below). - -- The added `!?` methods provide *synchronous message sends*. Invoking - `!?` causes the sending actor to wait until a response is received - which is then returned. There are two overloaded variants. The - two-parameter variant takes in addition a timeout argument (in - milliseconds), and its return type is `Option[Any]` instead of - `Any`. If the sender does not receive a response within the - specified timeout period, `!?` returns `None`, otherwise it returns - the response wrapped in `Some`. - -- The added `!!` methods are similar to synchronous message sends in - that they allow transferring a response from the receiver. However, - instead of blocking the sending actor until a response is received, - they return `Future` instances. A `Future` can be used to retrieve - the response of the receiver once it is available; it can also be - used to find out whether the response is already available without - blocking the sender. There are two overloaded variants. The - two-parameter variant takes in addition an argument of type - `PartialFunction[Any, A]`. This partial function is used for - post-processing the receiver's response. Essentially, `!!` returns a - future which applies the partial function to the response once it is - received. The result of the future is the result of this - post-processing. - -- The added `reactWithin` method allows receiving messages within a - given period of time. Compared to `react` it takes an additional - parameter `msec` which indicates the time period in milliseconds - until the special `TIMEOUT` pattern matches (`TIMEOUT` is a case - object in package `scala.actors`). Example: - - reactWithin(2000) { - case Answer(text) => // process text - case TIMEOUT => println("no answer within 2 seconds") - } - - The `reactWithin` method also allows non-blocking access to the - mailbox. When specifying a time period of 0 milliseconds, the - mailbox is first scanned to find a matching message. If there is no - matching message after the first scan, the `TIMEOUT` pattern - matches. For example, this enables receiving certain messages with a - higher priority than others: - - reactWithin(0) { - case HighPriorityMsg => // ... - case TIMEOUT => - react { - case LowPriorityMsg => // ... - } - } - - In the above example, the actor first processes the next - `HighPriorityMsg`, even if there is a `LowPriorityMsg` that arrived - earlier in its mailbox. The actor only processes a `LowPriorityMsg` - *first* if there is no `HighPriorityMsg` in its mailbox. - -In addition, `ReplyReactor` adds the `Actor.State.TimedSuspended` execution state. A suspended actor, waiting to receive a message using `reactWithin` is in state `Actor.State.TimedSuspended`. - -### The Actor trait - -The `Actor` trait extends `ReplyReactor` and adds or overrides the following members: - -- The added `receive` method behaves like `react` except that it may - return a result. This is reflected in its type, which is polymorphic - in its result: `def receive[R](f: PartialFunction[Any, R]): R`. - However, using `receive` makes the actor more heavyweight, since - `receive` blocks the underlying thread while the actor is suspended - waiting for a message. The blocked thread is unavailable to execute - other actors until the invocation of `receive` returns. - -- The added `link` and `unlink` methods allow an actor to link and unlink - itself to and from another actor, respectively. Linking can be used - for monitoring and reacting to the termination of another actor. In - particular, linking affects the behavior of invoking `exit` as - explained in the API documentation of the `Actor` trait. - -- The `trapExit` member allows reacting to the termination of linked - actors independently of the exit reason (that is, it does not matter - whether the exit reason is `'normal` or not). If an actor's `trapExit` - member is set to `true`, this actor will never terminate because of - linked actors. Instead, whenever one of its linked actors terminates - it will receive a message of type `Exit`. The `Exit` case class has two - members: `from` refers to the actor that terminated; `reason` refers to - the exit reason. - -#### Termination and execution states - -When terminating the execution of an actor, the exit reason can be set -explicitly by invoking the following variant of `exit`: - - def exit(reason: AnyRef): Nothing - -An actor that terminates with an exit reason different from the symbol -`'normal` propagates its exit reason to all actors linked to it. If an -actor terminates because of an uncaught exception, its exit reason is -an instance of the `UncaughtException` case class. - -The `Actor` trait adds two new execution states. An actor waiting to -receive a message using `receive` is in state -`Actor.State.Blocked`. An actor waiting to receive a message using -`receiveWithin` is in state `Actor.State.TimedBlocked`. - -## Control structures - -The `Reactor` trait defines control structures that simplify programming -with the non-returning `react` operation. Normally, an invocation of -`react` does not return. If the actor should execute code subsequently, -then one can either pass the actor's continuation code explicitly to -`react`, or one can use one of the following control structures which -hide these continuations. - -The most basic control structure is `andThen`. It allows registering a -closure that is executed once the actor has finished executing -everything else. - - actor { - { - react { - case "hello" => // processing "hello" - }: Unit - } andThen { - println("hi there") - } - } - -For example, the above actor prints a greeting after it has processed -the `"hello"` message. Even though the invocation of `react` does not -return, we can use `andThen` to register the code which prints the -greeting as the actor's continuation. - -Note that there is a *type ascription* that follows the `react` -invocation (`: Unit`). Basically, it lets you treat the result of -`react` as having type `Unit`, which is legal, since the result of an -expression can always be dropped. This is necessary to do here, since -`andThen` cannot be a member of type `Nothing` which is the result -type of `react`. Treating the result type of `react` as `Unit` allows -the application of an implicit conversion which makes the `andThen` -member available. - -The API provides a few more control structures: - -- `loop { ... }`. Loops indefinitely, executing the code in braces in - each iteration. Invoking `react` inside the loop body causes the - actor to react to a message as usual. Subsequently, execution - continues with the next iteration of the same loop. - -- `loopWhile (c) { ... }`. Executes the code in braces while the - condition `c` returns `true`. Invoking `react` in the loop body has - the same effect as in the case of `loop`. - -- `continue`. Continues with the execution of the current continuation - closure. Invoking `continue` inside the body of a `loop` or - `loopWhile` will cause the actor to finish the current iteration and - continue with the next iteration. If the current continuation has - been registered using `andThen`, execution continues with the - closure passed as the second argument to `andThen`. - -The control structures can be used anywhere in the body of a `Reactor`'s -`act` method and in the bodies of methods (transitively) called by -`act`. For actors created using the `actor { ... }` shorthand the control -structures can be imported from the `Actor` object. - -#### Futures - -The `ReplyReactor` and `Actor` traits support result-bearing message -send operations (the `!!` methods) that immediately return a -*future*. A future, that is, an instance of the `Future` trait, is a -handle that can be used to retrieve the response to such a message -send-with-future. - -The sender of a message send-with-future can wait for the future's -response by *applying* the future. For example, sending a message using -`val fut = a !! msg` allows the sender to wait for the result of the -future as follows: `val res = fut()`. - -In addition, a `Future` can be queried to find out whether its result -is available without blocking using the `isSet` method. - -A message send-with-future is not the only way to obtain a -future. Futures can also be created from computations directly. -In the following example, the computation body is started to -run concurrently, returning a future for its result: - - val fut = Future { body } - // ... - fut() // wait for future - -What makes futures special in the context of actors is the possibility -to retrieve their result using the standard actor-based receive -operations, such as `receive` etc. Moreover, it is possible to use the -event-based operations `react` and `reactWithin`. This enables an actor to -wait for the result of a future without blocking its underlying -thread. - -The actor-based receive operations are made available through the -future's `inputChannel`. For a future of type `Future[T]`, its type is -`InputChannel[T]`. Example: - - val fut = a !! msg - // ... - fut.inputChannel.react { - case Response => // ... - } - -## Channels - -Channels can be used to simplify the handling of messages that have -different types but that are sent to the same actor. The hierarchy of -channels is divided into `OutputChannel`s and `InputChannel`s. - -`OutputChannel`s can be sent messages. An `OutputChannel` `out` -supports the following operations. - -- `out ! msg`. Asynchronously sends `msg` to `out`. A reference to the - sending actor is transferred as in the case where `msg` is sent - directly to an actor. - -- `out forward msg`. Asynchronously forwards `msg` to `out`. The - sending actor is determined as in the case where `msg` is forwarded - directly to an actor. - -- `out.receiver`. Returns the unique actor that is receiving messages - sent to the `out` channel. - -- `out.send(msg, from)`. Asynchronously sends `msg` to `out` supplying - `from` as the sender of the message. - -Note that the `OutputChannel` trait has a type parameter that specifies -the type of messages that can be sent to the channel (using `!`, -`forward`, and `send`). The type parameter is contravariant: - - trait OutputChannel[-Msg] - -Actors can receive messages from `InputChannel`s. Like `OutputChannel`, -the `InputChannel` trait has a type parameter that specifies the type of -messages that can be received from the channel. The type parameter is -covariant: - - trait InputChannel[+Msg] - -An `InputChannel[Msg]` `in` supports the following operations. - -- `in.receive { case Pat1 => ... ; case Patn => ... }` (and similarly, - `in.receiveWithin`). Receives a message from `in`. Invoking - `receive` on an input channel has the same semantics as the standard - `receive` operation for actors. The only difference is that the - partial function passed as an argument has type - `PartialFunction[Msg, R]` where `R` is the return type of `receive`. - -- `in.react { case Pat1 => ... ; case Patn => ... }` (and similarly, - `in.reactWithin`). Receives a message from `in` using the - event-based `react` operation. Like `react` for actors, the return - type is `Nothing`, indicating that invocations of this method never - return. Like the `receive` operation above, the partial function - passed as an argument has a more specific type: - - PartialFunction[Msg, Unit] - -### Creating and sharing channels - -Channels are created using the concrete `Channel` class. It extends both -`InputChannel` and `OutputChannel`. A channel can be shared either by -making the channel visible in the scopes of multiple actors, or by -sending it in a message. - -The following example demonstrates scope-based sharing. - - actor { - var out: OutputChannel[String] = null - val child = actor { - react { - case "go" => out ! "hello" - } - } - val channel = new Channel[String] - out = channel - child ! "go" - channel.receive { - case msg => println(msg.length) - } - } - -Running this example prints the string `"5"` to the console. Note that -the `child` actor has only access to `out` which is an -`OutputChannel[String]`. The `channel` reference, which can also be used -to receive messages, is hidden. However, care must be taken to ensure -the output channel is initialized to a concrete channel before the -`child` sends messages to it. This is done using the `"go"` message. When -receiving from `channel` using `channel.receive` we can make use of the -fact that `msg` is of type `String`; therefore, it provides a `length` -member. - -An alternative way to share channels is by sending them in -messages. The following example demonstrates this. - - case class ReplyTo(out: OutputChannel[String]) - - val child = actor { - react { - case ReplyTo(out) => out ! "hello" - } - } - - actor { - val channel = new Channel[String] - child ! ReplyTo(channel) - channel.receive { - case msg => println(msg.length) - } - } - -The `ReplyTo` case class is a message type that we use to distribute a -reference to an `OutputChannel[String]`. When the `child` actor receives a -`ReplyTo` message it sends a string to its output channel. The second -actor receives a message on that channel as before. - -## Schedulers - -A `Reactor` (or an instance of a subtype) is executed using a -*scheduler*. The `Reactor` trait introduces the `scheduler` member which -returns the scheduler used to execute its instances: - - def scheduler: IScheduler - -The run-time system executes actors by submitting tasks to the -scheduler using one of the `execute` methods defined in the `IScheduler` -trait. Most of the trait's other methods are only relevant when -implementing a new scheduler from scratch, which is rarely necessary. - -The default schedulers used to execute instances of `Reactor` and `Actor` -detect the situation when all actors have finished their -execution. When this happens, the scheduler shuts itself down -(terminating any threads used by the scheduler). However, some -schedulers, such as the `SingleThreadedScheduler` (in package `scheduler`) -have to be shut down explicitly by invoking their `shutdown` method. - -The easiest way to create a custom scheduler is by extending -`SchedulerAdapter`, implementing the following abstract member: - - def execute(fun: => Unit): Unit - -Typically, a concrete implementation would use a thread pool to -execute its by-name argument `fun`. - -## Remote Actors - -This section describes the remote actors API. Its main interface is -the [`RemoteActor`](http://www.scala-lang.org/api/2.9.1/scala/actors/remote/RemoteActor$.html) object in package `scala.actors.remote`. This object -provides methods to create and connect to remote actor instances. In -the code snippets shown below we assume that all members of -`RemoteActor` have been imported; the full list of imports that we use -is as follows: - - import scala.actors._ - import scala.actors.Actor._ - import scala.actors.remote._ - import scala.actors.remote.RemoteActor._ - -### Starting remote actors - -A remote actor is uniquely identified by a [`Symbol`](http://www.scala-lang.org/api/2.9.1/scala/Symbol.html). This symbol is -unique to the JVM instance on which the remote actor is executed. A -remote actor identified with name `'myActor` can be created as follows. - - class MyActor extends Actor { - def act() { - alive(9000) - register('myActor, self) - // ... - } - } - -Note that a name can only be registered with a single (alive) actor at -a time. For example, to register an actor *A* as `'myActor`, and then -register another actor *B* as `'myActor`, one would first have to wait -until *A* terminated. This requirement applies across all ports, so -simply registering *B* on a different port as *A* is not sufficient. - -### Connecting to remote actors - -Connecting to a remote actor is just as simple. To obtain a remote -reference to a remote actor running on machine `myMachine`, on port -8000, with name `'anActor`, use `select` in the following manner: - - val myRemoteActor = select(Node("myMachine", 8000), 'anActor) - -The actor returned from `select` has type `AbstractActor` which provides -essentially the same interface as a regular actor, and thus supports -the usual message send operations: - - myRemoteActor ! "Hello!" - receive { - case response => println("Response: " + response) - } - myRemoteActor !? "What is the meaning of life?" match { - case 42 => println("Success") - case oops => println("Failed: " + oops) - } - val future = myRemoteActor !! "What is the last digit of PI?" - -Note that `select` is lazy; it does not actually initiate any network -connections. It simply creates a new `AbstractActor` instance which is -ready to initiate a new network connection when needed (for instance, -when `!` is invoked). - +--- +layout: overview +title: The Scala Actors API +overview: actors +languages: [zh-cn, es] +--- + +**Philipp Haller and Stephen Tu** + +## Introduction + +This guide describes the API of the `scala.actors` package of Scala 2.8/2.9. The organization follows groups of types that logically belong together. The trait hierarchy is taken into account to structure the individual sections. The focus is on the run-time behavior of the various methods that these traits define, thereby complementing the existing Scaladoc-based API documentation. + +NOTE: In Scala 2.10 the Actors library is deprecated and will be removed in future Scala releases. Users should use [Akka](http://akka.io) actors from the package `akka.actor`. For migration from Scala actors to Akka refer to the [Actors Migration Guide](actors-migration-guide.html). + +## The actor traits Reactor, ReplyReactor, and Actor + +### The Reactor trait + +`Reactor` is the super trait of all actor traits. Extending this trait allows defining actors with basic capabilities to send and receive messages. + +The behavior of a `Reactor` is defined by implementing its `act` method. The `act` method is executed once the `Reactor` is started by invoking `start`, which also returns the `Reactor`. The `start` method is *idempotent* which means that invoking it on an actor that has already been started has no effect. + +The `Reactor` trait has a type parameter `Msg` which indicates the type of messages that the actor can receive. + +Invoking the `Reactor`'s `!` method sends a message to the receiver. Sending a message using `!` is asynchronous which means that the sending actor does not wait until the message is received; its execution continues immediately. For example, `a ! msg` sends `msg` to `a`. All actors have a *mailbox* which buffers incoming messages until they are processed. + +The `Reactor` trait also defines a `forward` method. This method is inherited from `OutputChannel`. It has the same effect as the `!` method. Subtraits of `Reactor`, in particular the `ReplyReactor` trait, override this method to enable implicit reply destinations (see below). + +A `Reactor` receives messages using the `react` method. `react` expects an argument of type `PartialFunction[Msg, Unit]` which defines how messages of type `Msg` are handled once they arrive in the actor's mailbox. In the following example, the current actor waits to receive the string "Hello", and then prints a greeting: + + react { + case "Hello" => println("Hi there") + } + +Invoking `react` never returns. Therefore, any code that should run after a message has been received must be contained inside the partial function that is passed to `react`. For example, two messages can be received in sequence by nesting two invocations of `react`: + + react { + case Get(from) => + react { + case Put(x) => from ! x + } + } + +The `Reactor` trait also provides control structures which simplify programming with `react`. + +#### Termination and execution states + +The execution of a `Reactor` terminates when the body of its `act` method has run to completion. A `Reactor` can also terminate itself explicitly using the `exit` method. The return type of `exit` is `Nothing`, because `exit` always throws an exception. This exception is only used internally, and should never be caught. + +A terminated `Reactor` can be restarted by invoking its `restart` method. Invoking `restart` on a `Reactor` that has not terminated, yet, throws an `IllegalStateException`. Restarting a terminated actor causes its `act` method to be rerun. + +`Reactor` defines a method `getState` which returns the actor's current execution state as a member of the `Actor.State` enumeration. An actor that has not been started, yet, is in state `Actor.State.New`. An actor that can run without waiting for a message is in state `Actor.State.Runnable`. An actor that is suspended, waiting for a message is in state `Actor.State.Suspended`. A terminated actor is in state `Actor.State.Terminated`. + +#### Exception handling + +The `exceptionHandler` member allows defining an exception handler that is enabled throughout the entire lifetime of a `Reactor`: + + def exceptionHandler: PartialFunction[Exception, Unit] + +`exceptionHandler` returns a partial function which is used to handle exceptions that are not otherwise handled: whenever an exception propagates out of the body of a `Reactor`'s `act` method, the partial function is applied to that exception, allowing the actor to run clean-up code before it terminates. Note that the visibility of `exceptionHandler` is `protected`. + +Handling exceptions using `exceptionHandler` works well together with the control structures for programming with `react`. Whenever an exception has been handled using the partial function returned by `exceptionHandler`, execution continues with the current continuation closure. Example: + + loop { + react { + case Msg(data) => + if (cond) // process data + else throw new Exception("cannot process data") + } + } + +Assuming that the `Reactor` overrides `exceptionHandler`, after an exception thrown inside the body of `react` is handled, execution continues with the next loop iteration. + +### The ReplyReactor trait + +The `ReplyReactor` trait extends `Reactor[Any]` and adds or overrides the following methods: + +- The `!` method is overridden to obtain a reference to the current + actor (the sender); together with the actual message, the sender + reference is transferred to the mailbox of the receiving actor. The + receiver has access to the sender of a message through its `sender` + method (see below). + +- The `forward` method is overridden to obtain a reference to the + `sender` of the message that is currently being processed. Together + with the actual message, this reference is transferred as the sender + of the current message. As a consequence, `forward` allows + forwarding messages on behalf of actors different from the current + actor. + +- The added `sender` method returns the sender of the message that is + currently being processed. Given the fact that a message might have + been forwarded, `sender` may not return the actor that actually sent + the message. + +- The added `reply` method sends a message back to the sender of the + last message. `reply` is also used to reply to a synchronous message + send or a message send with future (see below). + +- The added `!?` methods provide *synchronous message sends*. Invoking + `!?` causes the sending actor to wait until a response is received + which is then returned. There are two overloaded variants. The + two-parameter variant takes in addition a timeout argument (in + milliseconds), and its return type is `Option[Any]` instead of + `Any`. If the sender does not receive a response within the + specified timeout period, `!?` returns `None`, otherwise it returns + the response wrapped in `Some`. + +- The added `!!` methods are similar to synchronous message sends in + that they allow transferring a response from the receiver. However, + instead of blocking the sending actor until a response is received, + they return `Future` instances. A `Future` can be used to retrieve + the response of the receiver once it is available; it can also be + used to find out whether the response is already available without + blocking the sender. There are two overloaded variants. The + two-parameter variant takes in addition an argument of type + `PartialFunction[Any, A]`. This partial function is used for + post-processing the receiver's response. Essentially, `!!` returns a + future which applies the partial function to the response once it is + received. The result of the future is the result of this + post-processing. + +- The added `reactWithin` method allows receiving messages within a + given period of time. Compared to `react` it takes an additional + parameter `msec` which indicates the time period in milliseconds + until the special `TIMEOUT` pattern matches (`TIMEOUT` is a case + object in package `scala.actors`). Example: + + reactWithin(2000) { + case Answer(text) => // process text + case TIMEOUT => println("no answer within 2 seconds") + } + + The `reactWithin` method also allows non-blocking access to the + mailbox. When specifying a time period of 0 milliseconds, the + mailbox is first scanned to find a matching message. If there is no + matching message after the first scan, the `TIMEOUT` pattern + matches. For example, this enables receiving certain messages with a + higher priority than others: + + reactWithin(0) { + case HighPriorityMsg => // ... + case TIMEOUT => + react { + case LowPriorityMsg => // ... + } + } + + In the above example, the actor first processes the next + `HighPriorityMsg`, even if there is a `LowPriorityMsg` that arrived + earlier in its mailbox. The actor only processes a `LowPriorityMsg` + *first* if there is no `HighPriorityMsg` in its mailbox. + +In addition, `ReplyReactor` adds the `Actor.State.TimedSuspended` execution state. A suspended actor, waiting to receive a message using `reactWithin` is in state `Actor.State.TimedSuspended`. + +### The Actor trait + +The `Actor` trait extends `ReplyReactor` and adds or overrides the following members: + +- The added `receive` method behaves like `react` except that it may + return a result. This is reflected in its type, which is polymorphic + in its result: `def receive[R](f: PartialFunction[Any, R]): R`. + However, using `receive` makes the actor more heavyweight, since + `receive` blocks the underlying thread while the actor is suspended + waiting for a message. The blocked thread is unavailable to execute + other actors until the invocation of `receive` returns. + +- The added `link` and `unlink` methods allow an actor to link and unlink + itself to and from another actor, respectively. Linking can be used + for monitoring and reacting to the termination of another actor. In + particular, linking affects the behavior of invoking `exit` as + explained in the API documentation of the `Actor` trait. + +- The `trapExit` member allows reacting to the termination of linked + actors independently of the exit reason (that is, it does not matter + whether the exit reason is `'normal` or not). If an actor's `trapExit` + member is set to `true`, this actor will never terminate because of + linked actors. Instead, whenever one of its linked actors terminates + it will receive a message of type `Exit`. The `Exit` case class has two + members: `from` refers to the actor that terminated; `reason` refers to + the exit reason. + +#### Termination and execution states + +When terminating the execution of an actor, the exit reason can be set +explicitly by invoking the following variant of `exit`: + + def exit(reason: AnyRef): Nothing + +An actor that terminates with an exit reason different from the symbol +`'normal` propagates its exit reason to all actors linked to it. If an +actor terminates because of an uncaught exception, its exit reason is +an instance of the `UncaughtException` case class. + +The `Actor` trait adds two new execution states. An actor waiting to +receive a message using `receive` is in state +`Actor.State.Blocked`. An actor waiting to receive a message using +`receiveWithin` is in state `Actor.State.TimedBlocked`. + +## Control structures + +The `Reactor` trait defines control structures that simplify programming +with the non-returning `react` operation. Normally, an invocation of +`react` does not return. If the actor should execute code subsequently, +then one can either pass the actor's continuation code explicitly to +`react`, or one can use one of the following control structures which +hide these continuations. + +The most basic control structure is `andThen`. It allows registering a +closure that is executed once the actor has finished executing +everything else. + + actor { + { + react { + case "hello" => // processing "hello" + }: Unit + } andThen { + println("hi there") + } + } + +For example, the above actor prints a greeting after it has processed +the `"hello"` message. Even though the invocation of `react` does not +return, we can use `andThen` to register the code which prints the +greeting as the actor's continuation. + +Note that there is a *type ascription* that follows the `react` +invocation (`: Unit`). Basically, it lets you treat the result of +`react` as having type `Unit`, which is legal, since the result of an +expression can always be dropped. This is necessary to do here, since +`andThen` cannot be a member of type `Nothing` which is the result +type of `react`. Treating the result type of `react` as `Unit` allows +the application of an implicit conversion which makes the `andThen` +member available. + +The API provides a few more control structures: + +- `loop { ... }`. Loops indefinitely, executing the code in braces in + each iteration. Invoking `react` inside the loop body causes the + actor to react to a message as usual. Subsequently, execution + continues with the next iteration of the same loop. + +- `loopWhile (c) { ... }`. Executes the code in braces while the + condition `c` returns `true`. Invoking `react` in the loop body has + the same effect as in the case of `loop`. + +- `continue`. Continues with the execution of the current continuation + closure. Invoking `continue` inside the body of a `loop` or + `loopWhile` will cause the actor to finish the current iteration and + continue with the next iteration. If the current continuation has + been registered using `andThen`, execution continues with the + closure passed as the second argument to `andThen`. + +The control structures can be used anywhere in the body of a `Reactor`'s +`act` method and in the bodies of methods (transitively) called by +`act`. For actors created using the `actor { ... }` shorthand the control +structures can be imported from the `Actor` object. + +#### Futures + +The `ReplyReactor` and `Actor` traits support result-bearing message +send operations (the `!!` methods) that immediately return a +*future*. A future, that is, an instance of the `Future` trait, is a +handle that can be used to retrieve the response to such a message +send-with-future. + +The sender of a message send-with-future can wait for the future's +response by *applying* the future. For example, sending a message using +`val fut = a !! msg` allows the sender to wait for the result of the +future as follows: `val res = fut()`. + +In addition, a `Future` can be queried to find out whether its result +is available without blocking using the `isSet` method. + +A message send-with-future is not the only way to obtain a +future. Futures can also be created from computations directly. +In the following example, the computation body is started to +run concurrently, returning a future for its result: + + val fut = Future { body } + // ... + fut() // wait for future + +What makes futures special in the context of actors is the possibility +to retrieve their result using the standard actor-based receive +operations, such as `receive` etc. Moreover, it is possible to use the +event-based operations `react` and `reactWithin`. This enables an actor to +wait for the result of a future without blocking its underlying +thread. + +The actor-based receive operations are made available through the +future's `inputChannel`. For a future of type `Future[T]`, its type is +`InputChannel[T]`. Example: + + val fut = a !! msg + // ... + fut.inputChannel.react { + case Response => // ... + } + +## Channels + +Channels can be used to simplify the handling of messages that have +different types but that are sent to the same actor. The hierarchy of +channels is divided into `OutputChannel`s and `InputChannel`s. + +`OutputChannel`s can be sent messages. An `OutputChannel` `out` +supports the following operations. + +- `out ! msg`. Asynchronously sends `msg` to `out`. A reference to the + sending actor is transferred as in the case where `msg` is sent + directly to an actor. + +- `out forward msg`. Asynchronously forwards `msg` to `out`. The + sending actor is determined as in the case where `msg` is forwarded + directly to an actor. + +- `out.receiver`. Returns the unique actor that is receiving messages + sent to the `out` channel. + +- `out.send(msg, from)`. Asynchronously sends `msg` to `out` supplying + `from` as the sender of the message. + +Note that the `OutputChannel` trait has a type parameter that specifies +the type of messages that can be sent to the channel (using `!`, +`forward`, and `send`). The type parameter is contravariant: + + trait OutputChannel[-Msg] + +Actors can receive messages from `InputChannel`s. Like `OutputChannel`, +the `InputChannel` trait has a type parameter that specifies the type of +messages that can be received from the channel. The type parameter is +covariant: + + trait InputChannel[+Msg] + +An `InputChannel[Msg]` `in` supports the following operations. + +- `in.receive { case Pat1 => ... ; case Patn => ... }` (and similarly, + `in.receiveWithin`). Receives a message from `in`. Invoking + `receive` on an input channel has the same semantics as the standard + `receive` operation for actors. The only difference is that the + partial function passed as an argument has type + `PartialFunction[Msg, R]` where `R` is the return type of `receive`. + +- `in.react { case Pat1 => ... ; case Patn => ... }` (and similarly, + `in.reactWithin`). Receives a message from `in` using the + event-based `react` operation. Like `react` for actors, the return + type is `Nothing`, indicating that invocations of this method never + return. Like the `receive` operation above, the partial function + passed as an argument has a more specific type: + + PartialFunction[Msg, Unit] + +### Creating and sharing channels + +Channels are created using the concrete `Channel` class. It extends both +`InputChannel` and `OutputChannel`. A channel can be shared either by +making the channel visible in the scopes of multiple actors, or by +sending it in a message. + +The following example demonstrates scope-based sharing. + + actor { + var out: OutputChannel[String] = null + val child = actor { + react { + case "go" => out ! "hello" + } + } + val channel = new Channel[String] + out = channel + child ! "go" + channel.receive { + case msg => println(msg.length) + } + } + +Running this example prints the string `"5"` to the console. Note that +the `child` actor has only access to `out` which is an +`OutputChannel[String]`. The `channel` reference, which can also be used +to receive messages, is hidden. However, care must be taken to ensure +the output channel is initialized to a concrete channel before the +`child` sends messages to it. This is done using the `"go"` message. When +receiving from `channel` using `channel.receive` we can make use of the +fact that `msg` is of type `String`; therefore, it provides a `length` +member. + +An alternative way to share channels is by sending them in +messages. The following example demonstrates this. + + case class ReplyTo(out: OutputChannel[String]) + + val child = actor { + react { + case ReplyTo(out) => out ! "hello" + } + } + + actor { + val channel = new Channel[String] + child ! ReplyTo(channel) + channel.receive { + case msg => println(msg.length) + } + } + +The `ReplyTo` case class is a message type that we use to distribute a +reference to an `OutputChannel[String]`. When the `child` actor receives a +`ReplyTo` message it sends a string to its output channel. The second +actor receives a message on that channel as before. + +## Schedulers + +A `Reactor` (or an instance of a subtype) is executed using a +*scheduler*. The `Reactor` trait introduces the `scheduler` member which +returns the scheduler used to execute its instances: + + def scheduler: IScheduler + +The run-time system executes actors by submitting tasks to the +scheduler using one of the `execute` methods defined in the `IScheduler` +trait. Most of the trait's other methods are only relevant when +implementing a new scheduler from scratch, which is rarely necessary. + +The default schedulers used to execute instances of `Reactor` and `Actor` +detect the situation when all actors have finished their +execution. When this happens, the scheduler shuts itself down +(terminating any threads used by the scheduler). However, some +schedulers, such as the `SingleThreadedScheduler` (in package `scheduler`) +have to be shut down explicitly by invoking their `shutdown` method. + +The easiest way to create a custom scheduler is by extending +`SchedulerAdapter`, implementing the following abstract member: + + def execute(fun: => Unit): Unit + +Typically, a concrete implementation would use a thread pool to +execute its by-name argument `fun`. + +## Remote Actors + +This section describes the remote actors API. Its main interface is +the [`RemoteActor`](http://www.scala-lang.org/api/2.9.1/scala/actors/remote/RemoteActor$.html) object in package `scala.actors.remote`. This object +provides methods to create and connect to remote actor instances. In +the code snippets shown below we assume that all members of +`RemoteActor` have been imported; the full list of imports that we use +is as follows: + + import scala.actors._ + import scala.actors.Actor._ + import scala.actors.remote._ + import scala.actors.remote.RemoteActor._ + +### Starting remote actors + +A remote actor is uniquely identified by a [`Symbol`](http://www.scala-lang.org/api/2.9.1/scala/Symbol.html). This symbol is +unique to the JVM instance on which the remote actor is executed. A +remote actor identified with name `'myActor` can be created as follows. + + class MyActor extends Actor { + def act() { + alive(9000) + register('myActor, self) + // ... + } + } + +Note that a name can only be registered with a single (alive) actor at +a time. For example, to register an actor *A* as `'myActor`, and then +register another actor *B* as `'myActor`, one would first have to wait +until *A* terminated. This requirement applies across all ports, so +simply registering *B* on a different port as *A* is not sufficient. + +### Connecting to remote actors + +Connecting to a remote actor is just as simple. To obtain a remote +reference to a remote actor running on machine `myMachine`, on port +8000, with name `'anActor`, use `select` in the following manner: + + val myRemoteActor = select(Node("myMachine", 8000), 'anActor) + +The actor returned from `select` has type `AbstractActor` which provides +essentially the same interface as a regular actor, and thus supports +the usual message send operations: + + myRemoteActor ! "Hello!" + receive { + case response => println("Response: " + response) + } + myRemoteActor !? "What is the meaning of life?" match { + case 42 => println("Success") + case oops => println("Failed: " + oops) + } + val future = myRemoteActor !! "What is the last digit of PI?" + +Note that `select` is lazy; it does not actually initiate any network +connections. It simply creates a new `AbstractActor` instance which is +ready to initiate a new network connection when needed (for instance, +when `!` is invoked). + diff --git a/overviews/reflection/annotations-names-scopes.md b/overviews/reflection/annotations-names-scopes.md index 1531ea4a5c..71494d01c2 100644 --- a/overviews/reflection/annotations-names-scopes.md +++ b/overviews/reflection/annotations-names-scopes.md @@ -1,448 +1,448 @@ ---- -layout: overview-large -title: Annotations, Names, Scopes, and More - -disqus: true - -partof: reflection -num: 4 -outof: 7 -languages: [ja] ---- - -EXPERIMENTAL - -## Annotations - -In Scala, declarations can be annotated using subtypes of -`scala.annotation.Annotation`. Furthermore, since Scala integrates with -[Java's annotation system](http://docs.oracle.com/javase/7/docs/technotes/guides/language/annotations.html#_top), -it's possible to work with annotations produced by a -standard Java compiler. - -Annotations can be inspected reflectively if the corresponding annotations -have been persisted, so that they can be read from the classfile containing -the annotated declarations. A custom annotation type can be made persistent by -inheriting from `scala.annotation.StaticAnnotation` or -`scala.annotation.ClassfileAnnotation`. As a result, instances of the -annotation type are stored as special attributes in the corresponding -classfile. Note that subclassing just -`scala.annotation.Annotation` is not enough to have the corresponding metadata -persisted for runtime reflection. Moreover, subclassing -`scala.annotation.ClassfileAnnotation` does not make your annotation visible -as a Java annotation at runtime; that requires writing the annotation class -in Java. - -The API distinguishes between two kinds of annotations: - -- *Java annotations:* annotations on definitions produced by the Java compiler, _i.e.,_ subtypes of `java.lang.annotation.Annotation` attached to program definitions. When read by Scala reflection, the `scala.annotation.ClassfileAnnotation` trait is automatically added as a subclass to every Java annotation. -- *Scala annotations:* annotations on definitions or types produced by the Scala compiler. - -The distinction between Java and Scala annotations is manifested in the -contract of `scala.reflect.api.Annotations#Annotation`, which exposes both -`scalaArgs` and `javaArgs`. For Scala or Java annotations extending -`scala.annotation.ClassfileAnnotation` `scalaArgs` is empty and the arguments -(if any) are stored in `javaArgs`. For all other Scala annotations, the -arguments are stored in `scalaArgs` and `javaArgs` is empty. - -Arguments in `scalaArgs` are represented as typed trees. Note that these trees -are not transformed by any phases following the type-checker. Arguments in -`javaArgs` are represented as a map from `scala.reflect.api.Names#Name` to -`scala.reflect.api.Annotations#JavaArgument`. Instances of `JavaArgument` -represent different kinds of Java annotation arguments: - -- literals (primitive and string constants), -- arrays, and -- nested annotations. - -## Names - -Names are simple wrappers for strings. -[Name](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Names$NameApi) -has two subtypes `TermName` and `TypeName` which distinguish names of terms (like -objects or members) and types (like classes, traits, and type members). A term -and a type of the same name can co-exist in the same object. In other words, -types and terms have separate name spaces. - -Names are associated with a universe. Example: - - scala> import scala.reflect.runtime.universe._ - import scala.reflect.runtime.universe._ - - scala> val mapName = TermName("map") - mapName: scala.reflect.runtime.universe.TermName = map - -Above, we're creating a `Name` associated with the runtime reflection universe -(this is also visible in its path-dependent type -`reflect.runtime.universe.TermName`). - -Names are often used to look up members of types. For example, to search for -the `map` method (which is a term) declared in the `List` class, one can do: - - scala> val listTpe = typeOf[List[Int]] - listTpe: scala.reflect.runtime.universe.Type = scala.List[Int] - - scala> listTpe.member(mapName) - res1: scala.reflect.runtime.universe.Symbol = method map - -To search for a type member, one can follow the same procedure, using -`TypeName` instead. It is also possible to rely on implicit conversions to -convert between strings and term or type names: - - scala> listTpe.member("map": TermName) - res2: scala.reflect.runtime.universe.Symbol = method map - -### Standard Names - -Certain names, such as "`_root_`", have special meanings in Scala programs. As -such they are essential for reflectively accessing certain Scala constructs. -For example, reflectively invoking a constructor requires using the -*standard name* `universe.nme.CONSTRUCTOR`, the term name `` which represents the -constructor name on the JVM. - -There are both - -- *standard term names,* _e.g.,_ "``", "`package`", and "`_root_`", and -- *standard type names,* _e.g.,_ "``", "`_`", and "`_*`". - -Some names, such as "package", exist both as a type name and a term name. -Standard names are made available through the `nme` and `tpnme` members of -class `Universe`. For a complete specification of all standard names, see the -[API documentation](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.StandardNames). - -## Scopes - -A scope object generally maps names to symbols available in a corresponding -lexical scope. Scopes can be nested. The base type exposed in the reflection -API, however, only exposes a minimal interface, representing a scope as an -iterable of [Symbol](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Symbols$Symbol)s. - -Additional functionality is exposed in *member scopes* that are returned by -`members` and `declarations` defined in -[scala.reflect.api.Types#TypeApi](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Types$TypeApi). -[scala.reflect.api.Scopes#MemberScope](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Scopes$MemberScope) -supports the `sorted` method, which sorts members *in declaration order*. - -The following example returns a list of the symbols of all overridden members -of the `List` class, in declaration order: - - scala> val overridden = listTpe.declarations.sorted.filter(_.isOverride) - overridden: List[scala.reflect.runtime.universe.Symbol] = List(method companion, method ++, method +:, method toList, method take, method drop, method slice, method takeRight, method splitAt, method takeWhile, method dropWhile, method span, method reverse, method stringPrefix, method toStream, method foreach) - -## Exprs - -In addition to type `scala.reflect.api.Trees#Tree`, the base type of abstract -syntax trees, typed trees can also be represented as instances of type -[`scala.reflect.api.Exprs#Expr`](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Exprs$Expr). -An `Expr` wraps -an abstract syntax tree and an internal type tag to provide access to the type -of the tree. `Expr`s are mainly used to simply and conveniently create typed -abstract syntax trees for use in a macro. In most cases, this involves methods -`reify` and `splice` (see the -[macros guide](http://docs.scala-lang.org/overviews/macros/overview.html) for details). - -## Flags and flag sets - -Flags are used to provide modifiers for abstract syntax trees that represent -definitions via the `flags` field of `scala.reflect.api.Trees#Modifiers`. -Trees that accept modifiers are: - -- `scala.reflect.api.Trees#ClassDef`. Classes and traits. -- `scala.reflect.api.Trees#ModuleDef`. Objects. -- `scala.reflect.api.Trees#ValDef`. Vals, vars, parameters, and self type annotations. -- `scala.reflect.api.Trees#DefDef`. Methods and constructors. -- `scala.reflect.api.Trees#TypeDef`. Type aliases, abstract type members and type parameters. - -For example, to create a class named `C` one would write something like: - - ClassDef(Modifiers(NoFlags), TypeName("C"), Nil, ...) - -Here, the flag set is empty. To make `C` private, one would write something -like: - - ClassDef(Modifiers(PRIVATE), TypeName("C"), Nil, ...) - -Flags can also be combined with the vertical bar operator (`|`). For example, -a private final class is written something like: - - ClassDef(Modifiers(PRIVATE | FINAL), TypeName("C"), Nil, ...) - -The list of all available flags is defined in -`scala.reflect.api.FlagSets#FlagValues`, available via -`scala.reflect.api.FlagSets#Flag`. (Typically, one uses a wildcard import for -this, _e.g.,_ `import scala.reflect.runtime.universe.Flag._`.) - -Definition trees are compiled down to symbols, so that flags on modifiers of -these trees are transformed into flags on the resulting symbols. Unlike trees, -symbols don't expose flags, but rather provide test methods following the -`isXXX` pattern (_e.g.,_ `isFinal` can be used to test finality). In some -cases, these test methods require a conversion using `asTerm`, `asType`, or -`asClass`, as some flags only make sense for certain kinds of symbols. - -*Of note:* This part of the reflection API is being considered a candidate -for redesign. It is quite possible that in future releases of the reflection -API, flag sets could be replaced with something else. - -## Constants - -Certain expressions that the Scala specification calls *constant expressions* -can be evaluated by the Scala compiler at compile time. The following kinds of -expressions are compile-time constants (see [section 6.24 of the Scala language specification](http://scala-lang.org/files/archive/spec/2.11/06-expressions.html#constant-expressions)): - -1. Literals of primitive value classes ([Byte](http://www.scala-lang.org/api/current/index.html#scala.Byte), [Short](http://www.scala-lang.org/api/current/index.html#scala.Short), [Int](http://www.scala-lang.org/api/current/index.html#scala.Int), [Long](http://www.scala-lang.org/api/current/index.html#scala.Long), [Float](http://www.scala-lang.org/api/current/index.html#scala.Float), [Double](http://www.scala-lang.org/api/current/index.html#scala.Double), [Char](http://www.scala-lang.org/api/current/index.html#scala.Char), [Boolean](http://www.scala-lang.org/api/current/index.html#scala.Boolean) and [Unit](http://www.scala-lang.org/api/current/index.html#scala.Unit)) - represented directly as the corresponding type. - -2. String literals - represented as instances of the string. - -3. References to classes, typically constructed with [scala.Predef#classOf](http://www.scala-lang.org/api/current/index.html#scala.Predef$@classOf[T]:Class[T]) - represented as [types](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Types$Type). - -4. References to Java enumeration values - represented as [symbols](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Symbols$Symbol). - -Constant expressions are used to represent - -- literals in abstract syntax trees (see `scala.reflect.api.Trees#Literal`), and -- literal arguments for Java class file annotations (see `scala.reflect.api.Annotations#LiteralArgument`). - -Example: - - Literal(Constant(5)) - -The above expression creates an AST representing the integer literal `5` in -Scala source code. - -`Constant` is an example of a "virtual case class", _i.e.,_ a class whose -instances can be constructed and matched against as if it were a case class. -Both types `Literal` and `LiteralArgument` have a `value` method returning the -compile-time constant underlying the literal. - -Examples: - - Constant(true) match { - case Constant(s: String) => println("A string: " + s) - case Constant(b: Boolean) => println("A Boolean value: " + b) - case Constant(x) => println("Something else: " + x) - } - assert(Constant(true).value == true) - -Class references are represented as instances of -`scala.reflect.api.Types#Type`. Such a reference can be converted to a runtime -class using the `runtimeClass` method of a `RuntimeMirror` such as -`scala.reflect.runtime.currentMirror`. (This conversion from a type to a -runtime class is necessary, because when the Scala compiler processes a class -reference, the underlying runtime class might not yet have been compiled.) - -Java enumeration value references are represented as symbols (instances of -`scala.reflect.api.Symbols#Symbol`), which on the JVM point to methods that -return the underlying enumeration values. A `RuntimeMirror` can be used to -inspect an underlying enumeration or to get the runtime value of a reference -to an enumeration. - -Example: - - // Java source: - enum JavaSimpleEnumeration { FOO, BAR } - - import java.lang.annotation.*; - @Retention(RetentionPolicy.RUNTIME) - @Target({ElementType.TYPE}) - public @interface JavaSimpleAnnotation { - Class classRef(); - JavaSimpleEnumeration enumRef(); - } - - @JavaSimpleAnnotation( - classRef = JavaAnnottee.class, - enumRef = JavaSimpleEnumeration.BAR - ) - public class JavaAnnottee {} - - // Scala source: - import scala.reflect.runtime.universe._ - import scala.reflect.runtime.{currentMirror => cm} - - object Test extends App { - val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs - - def jarg(name: String) = jann(TermName(name)) match { - // Constant is always wrapped in a Literal or LiteralArgument tree node - case LiteralArgument(ct: Constant) => value - case _ => sys.error("Not a constant") - } - - val classRef = jarg("classRef").value.asInstanceOf[Type] - println(showRaw(classRef)) // TypeRef(ThisType(), JavaAnnottee, List()) - println(cm.runtimeClass(classRef)) // class JavaAnnottee - - val enumRef = jarg("enumRef").value.asInstanceOf[Symbol] - println(enumRef) // value BAR - - val siblings = enumRef.owner.typeSignature.declarations - val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) - println(enumValues) // Scope { - // final val FOO: JavaSimpleEnumeration; - // final val BAR: JavaSimpleEnumeration - // } - - val enumClass = cm.runtimeClass(enumRef.owner.asClass) - val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) - println(enumValue) // BAR - } - -## Printers - -Utilities for nicely printing -[`Trees`](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Trees) and -[`Types`](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Types). - -### Printing Trees - -The method `show` displays the "prettified" representation of reflection -artifacts. This representation provides one with the desugared Java -representation of Scala code. For example: - - scala> import scala.reflect.runtime.universe._ - import scala.reflect.runtime.universe._ - - scala> def tree = reify { final class C { def x = 2 } }.tree - tree: scala.reflect.runtime.universe.Tree - - scala> show(tree) - res0: String = - { - final class C extends AnyRef { - def () = { - super.(); - () - }; - def x = 2 - }; - () - } - -The method `showRaw` displays the internal structure of a given reflection -object as a Scala abstract syntax tree (AST), the representation that the -Scala typechecker operates on. - -Note that while this representation appears to generate correct trees that one -might think would be possible to use in a macro implementation, this is not -usually the case. Symbols aren't fully represented (only their names are). -Thus, this method is best-suited for use simply inspecting ASTs given some -valid Scala code. - - scala> showRaw(tree) - res1: String = Block(List( - ClassDef(Modifiers(FINAL), TypeName("C"), List(), Template( - List(Ident(TypeName("AnyRef"))), - emptyValDef, - List( - DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), - Block(List( - Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), - Literal(Constant(())))), - DefDef(Modifiers(), TermName("x"), List(), List(), TypeTree(), - Literal(Constant(2))))))), - Literal(Constant(()))) - -The method `showRaw` can also print `scala.reflect.api.Types` next to the artifacts being inspected. - - scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar - import scala.tools.reflect.ToolBox - - scala> import scala.reflect.runtime.{currentMirror => cm} - import scala.reflect.runtime.{currentMirror=>cm} - - scala> showRaw(cm.mkToolBox().typeCheck(tree), printTypes = true) - res2: String = Block[1](List( - ClassDef[2](Modifiers(FINAL), TypeName("C"), List(), Template[3]( - List(Ident[4](TypeName("AnyRef"))), - emptyValDef, - List( - DefDef[2](Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree[3](), - Block[1](List( - Apply[4](Select[5](Super[6](This[3](TypeName("C")), tpnme.EMPTY), ...))), - Literal[1](Constant(())))), - DefDef[2](Modifiers(), TermName("x"), List(), List(), TypeTree[7](), - Literal[8](Constant(2))))))), - Literal[1](Constant(()))) - [1] TypeRef(ThisType(scala), scala.Unit, List()) - [2] NoType - [3] TypeRef(NoPrefix, TypeName("C"), List()) - [4] TypeRef(ThisType(java.lang), java.lang.Object, List()) - [5] MethodType(List(), TypeRef(ThisType(java.lang), java.lang.Object, List())) - [6] SuperType(ThisType(TypeName("C")), TypeRef(... java.lang.Object ...)) - [7] TypeRef(ThisType(scala), scala.Int, List()) - [8] ConstantType(Constant(2)) - -### Printing Types - -The method `show` can be used to produce a *readable* string representation of a type: - - scala> import scala.reflect.runtime.universe._ - import scala.reflect.runtime.universe._ - - scala> def tpe = typeOf[{ def x: Int; val y: List[Int] }] - tpe: scala.reflect.runtime.universe.Type - - scala> show(tpe) - res0: String = scala.AnyRef{def x: Int; val y: scala.List[Int]} - -Like the method `showRaw` for `scala.reflect.api.Trees`, `showRaw` for -`scala.reflect.api.Types` provides a visualization of the Scala AST operated -on by the Scala typechecker. - - scala> showRaw(tpe) - res1: String = RefinedType( - List(TypeRef(ThisType(scala), TypeName("AnyRef"), List())), - Scope( - TermName("x"), - TermName("y"))) - -The `showRaw` method also has named parameters `printIds` and `printKinds`, -both with default argument `false`. When passing `true` to these, `showRaw` -additionally shows the unique identifiers of symbols, as well as their kind -(package, type, method, getter, etc.). - - scala> showRaw(tpe, printIds = true, printKinds = true) - res2: String = RefinedType( - List(TypeRef(ThisType(scala#2043#PK), TypeName("AnyRef")#691#TPE, List())), - Scope( - TermName("x")#2540#METH, - TermName("y")#2541#GET)) - -## Positions - -Positions (instances of the -[Position](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Position) trait) -are used to track the origin of symbols and tree nodes. They are commonly used when -displaying warnings and errors, to indicate the incorrect point in the -program. Positions indicate a column and line in a source file (the offset -from the beginning of the source file is called its "point", which is -sometimes less convenient to use). They also carry the content of the line -they refer to. Not all trees or symbols have a position; a missing position is -indicated using the `NoPosition` object. - -Positions can refer either to only a single character in a source file, or to -a *range*. In the latter case, a *range position* is used (positions that are -not range positions are also called *offset positions*). Range positions have -in addition `start` and `end` offsets. The `start` and `end` offsets can be -"focussed" on using the `focusStart` and `focusEnd` methods which return -positions (when called on a position which is not a range position, they just -return `this`). - -Positions can be compared using methods such as `precedes`, which holds if -both positions are defined (_i.e.,_ the position is not `NoPosition`) and the -end point of `this` position is not larger than the start point of the given -position. In addition, range positions can be tested for inclusion (using -method `includes`) and overlapping (using method `overlaps`). - -Range positions are either *transparent* or *opaque* (not transparent). The -fact whether a range position is opaque or not has an impact on its permitted -use, because trees containing range positions must satisfy the following -invariants: - -- A tree with an offset position never contains a child with a range position -- If the child of a tree with a range position also has a range position, then the child's range is contained in the parent's range. -- Opaque range positions of children of the same node are non-overlapping (this means their overlap is at most a single point). - -Using the `makeTransparent` method, an opaque range position can be converted -to a transparent one; all other positions are returned unchanged. - +--- +layout: overview-large +title: Annotations, Names, Scopes, and More + +disqus: true + +partof: reflection +num: 4 +outof: 7 +languages: [ja] +--- + +EXPERIMENTAL + +## Annotations + +In Scala, declarations can be annotated using subtypes of +`scala.annotation.Annotation`. Furthermore, since Scala integrates with +[Java's annotation system](http://docs.oracle.com/javase/7/docs/technotes/guides/language/annotations.html#_top), +it's possible to work with annotations produced by a +standard Java compiler. + +Annotations can be inspected reflectively if the corresponding annotations +have been persisted, so that they can be read from the classfile containing +the annotated declarations. A custom annotation type can be made persistent by +inheriting from `scala.annotation.StaticAnnotation` or +`scala.annotation.ClassfileAnnotation`. As a result, instances of the +annotation type are stored as special attributes in the corresponding +classfile. Note that subclassing just +`scala.annotation.Annotation` is not enough to have the corresponding metadata +persisted for runtime reflection. Moreover, subclassing +`scala.annotation.ClassfileAnnotation` does not make your annotation visible +as a Java annotation at runtime; that requires writing the annotation class +in Java. + +The API distinguishes between two kinds of annotations: + +- *Java annotations:* annotations on definitions produced by the Java compiler, _i.e.,_ subtypes of `java.lang.annotation.Annotation` attached to program definitions. When read by Scala reflection, the `scala.annotation.ClassfileAnnotation` trait is automatically added as a subclass to every Java annotation. +- *Scala annotations:* annotations on definitions or types produced by the Scala compiler. + +The distinction between Java and Scala annotations is manifested in the +contract of `scala.reflect.api.Annotations#Annotation`, which exposes both +`scalaArgs` and `javaArgs`. For Scala or Java annotations extending +`scala.annotation.ClassfileAnnotation` `scalaArgs` is empty and the arguments +(if any) are stored in `javaArgs`. For all other Scala annotations, the +arguments are stored in `scalaArgs` and `javaArgs` is empty. + +Arguments in `scalaArgs` are represented as typed trees. Note that these trees +are not transformed by any phases following the type-checker. Arguments in +`javaArgs` are represented as a map from `scala.reflect.api.Names#Name` to +`scala.reflect.api.Annotations#JavaArgument`. Instances of `JavaArgument` +represent different kinds of Java annotation arguments: + +- literals (primitive and string constants), +- arrays, and +- nested annotations. + +## Names + +Names are simple wrappers for strings. +[Name](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Names$NameApi) +has two subtypes `TermName` and `TypeName` which distinguish names of terms (like +objects or members) and types (like classes, traits, and type members). A term +and a type of the same name can co-exist in the same object. In other words, +types and terms have separate name spaces. + +Names are associated with a universe. Example: + + scala> import scala.reflect.runtime.universe._ + import scala.reflect.runtime.universe._ + + scala> val mapName = TermName("map") + mapName: scala.reflect.runtime.universe.TermName = map + +Above, we're creating a `Name` associated with the runtime reflection universe +(this is also visible in its path-dependent type +`reflect.runtime.universe.TermName`). + +Names are often used to look up members of types. For example, to search for +the `map` method (which is a term) declared in the `List` class, one can do: + + scala> val listTpe = typeOf[List[Int]] + listTpe: scala.reflect.runtime.universe.Type = scala.List[Int] + + scala> listTpe.member(mapName) + res1: scala.reflect.runtime.universe.Symbol = method map + +To search for a type member, one can follow the same procedure, using +`TypeName` instead. It is also possible to rely on implicit conversions to +convert between strings and term or type names: + + scala> listTpe.member("map": TermName) + res2: scala.reflect.runtime.universe.Symbol = method map + +### Standard Names + +Certain names, such as "`_root_`", have special meanings in Scala programs. As +such they are essential for reflectively accessing certain Scala constructs. +For example, reflectively invoking a constructor requires using the +*standard name* `universe.nme.CONSTRUCTOR`, the term name `` which represents the +constructor name on the JVM. + +There are both + +- *standard term names,* _e.g.,_ "``", "`package`", and "`_root_`", and +- *standard type names,* _e.g.,_ "``", "`_`", and "`_*`". + +Some names, such as "package", exist both as a type name and a term name. +Standard names are made available through the `nme` and `tpnme` members of +class `Universe`. For a complete specification of all standard names, see the +[API documentation](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.StandardNames). + +## Scopes + +A scope object generally maps names to symbols available in a corresponding +lexical scope. Scopes can be nested. The base type exposed in the reflection +API, however, only exposes a minimal interface, representing a scope as an +iterable of [Symbol](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Symbols$Symbol)s. + +Additional functionality is exposed in *member scopes* that are returned by +`members` and `declarations` defined in +[scala.reflect.api.Types#TypeApi](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Types$TypeApi). +[scala.reflect.api.Scopes#MemberScope](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Scopes$MemberScope) +supports the `sorted` method, which sorts members *in declaration order*. + +The following example returns a list of the symbols of all overridden members +of the `List` class, in declaration order: + + scala> val overridden = listTpe.declarations.sorted.filter(_.isOverride) + overridden: List[scala.reflect.runtime.universe.Symbol] = List(method companion, method ++, method +:, method toList, method take, method drop, method slice, method takeRight, method splitAt, method takeWhile, method dropWhile, method span, method reverse, method stringPrefix, method toStream, method foreach) + +## Exprs + +In addition to type `scala.reflect.api.Trees#Tree`, the base type of abstract +syntax trees, typed trees can also be represented as instances of type +[`scala.reflect.api.Exprs#Expr`](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Exprs$Expr). +An `Expr` wraps +an abstract syntax tree and an internal type tag to provide access to the type +of the tree. `Expr`s are mainly used to simply and conveniently create typed +abstract syntax trees for use in a macro. In most cases, this involves methods +`reify` and `splice` (see the +[macros guide](http://docs.scala-lang.org/overviews/macros/overview.html) for details). + +## Flags and flag sets + +Flags are used to provide modifiers for abstract syntax trees that represent +definitions via the `flags` field of `scala.reflect.api.Trees#Modifiers`. +Trees that accept modifiers are: + +- `scala.reflect.api.Trees#ClassDef`. Classes and traits. +- `scala.reflect.api.Trees#ModuleDef`. Objects. +- `scala.reflect.api.Trees#ValDef`. Vals, vars, parameters, and self type annotations. +- `scala.reflect.api.Trees#DefDef`. Methods and constructors. +- `scala.reflect.api.Trees#TypeDef`. Type aliases, abstract type members and type parameters. + +For example, to create a class named `C` one would write something like: + + ClassDef(Modifiers(NoFlags), TypeName("C"), Nil, ...) + +Here, the flag set is empty. To make `C` private, one would write something +like: + + ClassDef(Modifiers(PRIVATE), TypeName("C"), Nil, ...) + +Flags can also be combined with the vertical bar operator (`|`). For example, +a private final class is written something like: + + ClassDef(Modifiers(PRIVATE | FINAL), TypeName("C"), Nil, ...) + +The list of all available flags is defined in +`scala.reflect.api.FlagSets#FlagValues`, available via +`scala.reflect.api.FlagSets#Flag`. (Typically, one uses a wildcard import for +this, _e.g.,_ `import scala.reflect.runtime.universe.Flag._`.) + +Definition trees are compiled down to symbols, so that flags on modifiers of +these trees are transformed into flags on the resulting symbols. Unlike trees, +symbols don't expose flags, but rather provide test methods following the +`isXXX` pattern (_e.g.,_ `isFinal` can be used to test finality). In some +cases, these test methods require a conversion using `asTerm`, `asType`, or +`asClass`, as some flags only make sense for certain kinds of symbols. + +*Of note:* This part of the reflection API is being considered a candidate +for redesign. It is quite possible that in future releases of the reflection +API, flag sets could be replaced with something else. + +## Constants + +Certain expressions that the Scala specification calls *constant expressions* +can be evaluated by the Scala compiler at compile time. The following kinds of +expressions are compile-time constants (see [section 6.24 of the Scala language specification](http://scala-lang.org/files/archive/spec/2.11/06-expressions.html#constant-expressions)): + +1. Literals of primitive value classes ([Byte](http://www.scala-lang.org/api/current/index.html#scala.Byte), [Short](http://www.scala-lang.org/api/current/index.html#scala.Short), [Int](http://www.scala-lang.org/api/current/index.html#scala.Int), [Long](http://www.scala-lang.org/api/current/index.html#scala.Long), [Float](http://www.scala-lang.org/api/current/index.html#scala.Float), [Double](http://www.scala-lang.org/api/current/index.html#scala.Double), [Char](http://www.scala-lang.org/api/current/index.html#scala.Char), [Boolean](http://www.scala-lang.org/api/current/index.html#scala.Boolean) and [Unit](http://www.scala-lang.org/api/current/index.html#scala.Unit)) - represented directly as the corresponding type. + +2. String literals - represented as instances of the string. + +3. References to classes, typically constructed with [scala.Predef#classOf](http://www.scala-lang.org/api/current/index.html#scala.Predef$@classOf[T]:Class[T]) - represented as [types](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Types$Type). + +4. References to Java enumeration values - represented as [symbols](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Symbols$Symbol). + +Constant expressions are used to represent + +- literals in abstract syntax trees (see `scala.reflect.api.Trees#Literal`), and +- literal arguments for Java class file annotations (see `scala.reflect.api.Annotations#LiteralArgument`). + +Example: + + Literal(Constant(5)) + +The above expression creates an AST representing the integer literal `5` in +Scala source code. + +`Constant` is an example of a "virtual case class", _i.e.,_ a class whose +instances can be constructed and matched against as if it were a case class. +Both types `Literal` and `LiteralArgument` have a `value` method returning the +compile-time constant underlying the literal. + +Examples: + + Constant(true) match { + case Constant(s: String) => println("A string: " + s) + case Constant(b: Boolean) => println("A Boolean value: " + b) + case Constant(x) => println("Something else: " + x) + } + assert(Constant(true).value == true) + +Class references are represented as instances of +`scala.reflect.api.Types#Type`. Such a reference can be converted to a runtime +class using the `runtimeClass` method of a `RuntimeMirror` such as +`scala.reflect.runtime.currentMirror`. (This conversion from a type to a +runtime class is necessary, because when the Scala compiler processes a class +reference, the underlying runtime class might not yet have been compiled.) + +Java enumeration value references are represented as symbols (instances of +`scala.reflect.api.Symbols#Symbol`), which on the JVM point to methods that +return the underlying enumeration values. A `RuntimeMirror` can be used to +inspect an underlying enumeration or to get the runtime value of a reference +to an enumeration. + +Example: + + // Java source: + enum JavaSimpleEnumeration { FOO, BAR } + + import java.lang.annotation.*; + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE}) + public @interface JavaSimpleAnnotation { + Class classRef(); + JavaSimpleEnumeration enumRef(); + } + + @JavaSimpleAnnotation( + classRef = JavaAnnottee.class, + enumRef = JavaSimpleEnumeration.BAR + ) + public class JavaAnnottee {} + + // Scala source: + import scala.reflect.runtime.universe._ + import scala.reflect.runtime.{currentMirror => cm} + + object Test extends App { + val jann = typeOf[JavaAnnottee].typeSymbol.annotations(0).javaArgs + + def jarg(name: String) = jann(TermName(name)) match { + // Constant is always wrapped in a Literal or LiteralArgument tree node + case LiteralArgument(ct: Constant) => value + case _ => sys.error("Not a constant") + } + + val classRef = jarg("classRef").value.asInstanceOf[Type] + println(showRaw(classRef)) // TypeRef(ThisType(), JavaAnnottee, List()) + println(cm.runtimeClass(classRef)) // class JavaAnnottee + + val enumRef = jarg("enumRef").value.asInstanceOf[Symbol] + println(enumRef) // value BAR + + val siblings = enumRef.owner.typeSignature.declarations + val enumValues = siblings.filter(sym => sym.isVal && sym.isPublic) + println(enumValues) // Scope { + // final val FOO: JavaSimpleEnumeration; + // final val BAR: JavaSimpleEnumeration + // } + + val enumClass = cm.runtimeClass(enumRef.owner.asClass) + val enumValue = enumClass.getDeclaredField(enumRef.name.toString).get(null) + println(enumValue) // BAR + } + +## Printers + +Utilities for nicely printing +[`Trees`](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Trees) and +[`Types`](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Types). + +### Printing Trees + +The method `show` displays the "prettified" representation of reflection +artifacts. This representation provides one with the desugared Java +representation of Scala code. For example: + + scala> import scala.reflect.runtime.universe._ + import scala.reflect.runtime.universe._ + + scala> def tree = reify { final class C { def x = 2 } }.tree + tree: scala.reflect.runtime.universe.Tree + + scala> show(tree) + res0: String = + { + final class C extends AnyRef { + def () = { + super.(); + () + }; + def x = 2 + }; + () + } + +The method `showRaw` displays the internal structure of a given reflection +object as a Scala abstract syntax tree (AST), the representation that the +Scala typechecker operates on. + +Note that while this representation appears to generate correct trees that one +might think would be possible to use in a macro implementation, this is not +usually the case. Symbols aren't fully represented (only their names are). +Thus, this method is best-suited for use simply inspecting ASTs given some +valid Scala code. + + scala> showRaw(tree) + res1: String = Block(List( + ClassDef(Modifiers(FINAL), TypeName("C"), List(), Template( + List(Ident(TypeName("AnyRef"))), + emptyValDef, + List( + DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), + Block(List( + Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), + Literal(Constant(())))), + DefDef(Modifiers(), TermName("x"), List(), List(), TypeTree(), + Literal(Constant(2))))))), + Literal(Constant(()))) + +The method `showRaw` can also print `scala.reflect.api.Types` next to the artifacts being inspected. + + scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar + import scala.tools.reflect.ToolBox + + scala> import scala.reflect.runtime.{currentMirror => cm} + import scala.reflect.runtime.{currentMirror=>cm} + + scala> showRaw(cm.mkToolBox().typeCheck(tree), printTypes = true) + res2: String = Block[1](List( + ClassDef[2](Modifiers(FINAL), TypeName("C"), List(), Template[3]( + List(Ident[4](TypeName("AnyRef"))), + emptyValDef, + List( + DefDef[2](Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree[3](), + Block[1](List( + Apply[4](Select[5](Super[6](This[3](TypeName("C")), tpnme.EMPTY), ...))), + Literal[1](Constant(())))), + DefDef[2](Modifiers(), TermName("x"), List(), List(), TypeTree[7](), + Literal[8](Constant(2))))))), + Literal[1](Constant(()))) + [1] TypeRef(ThisType(scala), scala.Unit, List()) + [2] NoType + [3] TypeRef(NoPrefix, TypeName("C"), List()) + [4] TypeRef(ThisType(java.lang), java.lang.Object, List()) + [5] MethodType(List(), TypeRef(ThisType(java.lang), java.lang.Object, List())) + [6] SuperType(ThisType(TypeName("C")), TypeRef(... java.lang.Object ...)) + [7] TypeRef(ThisType(scala), scala.Int, List()) + [8] ConstantType(Constant(2)) + +### Printing Types + +The method `show` can be used to produce a *readable* string representation of a type: + + scala> import scala.reflect.runtime.universe._ + import scala.reflect.runtime.universe._ + + scala> def tpe = typeOf[{ def x: Int; val y: List[Int] }] + tpe: scala.reflect.runtime.universe.Type + + scala> show(tpe) + res0: String = scala.AnyRef{def x: Int; val y: scala.List[Int]} + +Like the method `showRaw` for `scala.reflect.api.Trees`, `showRaw` for +`scala.reflect.api.Types` provides a visualization of the Scala AST operated +on by the Scala typechecker. + + scala> showRaw(tpe) + res1: String = RefinedType( + List(TypeRef(ThisType(scala), TypeName("AnyRef"), List())), + Scope( + TermName("x"), + TermName("y"))) + +The `showRaw` method also has named parameters `printIds` and `printKinds`, +both with default argument `false`. When passing `true` to these, `showRaw` +additionally shows the unique identifiers of symbols, as well as their kind +(package, type, method, getter, etc.). + + scala> showRaw(tpe, printIds = true, printKinds = true) + res2: String = RefinedType( + List(TypeRef(ThisType(scala#2043#PK), TypeName("AnyRef")#691#TPE, List())), + Scope( + TermName("x")#2540#METH, + TermName("y")#2541#GET)) + +## Positions + +Positions (instances of the +[Position](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Position) trait) +are used to track the origin of symbols and tree nodes. They are commonly used when +displaying warnings and errors, to indicate the incorrect point in the +program. Positions indicate a column and line in a source file (the offset +from the beginning of the source file is called its "point", which is +sometimes less convenient to use). They also carry the content of the line +they refer to. Not all trees or symbols have a position; a missing position is +indicated using the `NoPosition` object. + +Positions can refer either to only a single character in a source file, or to +a *range*. In the latter case, a *range position* is used (positions that are +not range positions are also called *offset positions*). Range positions have +in addition `start` and `end` offsets. The `start` and `end` offsets can be +"focussed" on using the `focusStart` and `focusEnd` methods which return +positions (when called on a position which is not a range position, they just +return `this`). + +Positions can be compared using methods such as `precedes`, which holds if +both positions are defined (_i.e.,_ the position is not `NoPosition`) and the +end point of `this` position is not larger than the start point of the given +position. In addition, range positions can be tested for inclusion (using +method `includes`) and overlapping (using method `overlaps`). + +Range positions are either *transparent* or *opaque* (not transparent). The +fact whether a range position is opaque or not has an impact on its permitted +use, because trees containing range positions must satisfy the following +invariants: + +- A tree with an offset position never contains a child with a range position +- If the child of a tree with a range position also has a range position, then the child's range is contained in the parent's range. +- Opaque range positions of children of the same node are non-overlapping (this means their overlap is at most a single point). + +Using the `makeTransparent` method, an opaque range position can be converted +to a transparent one; all other positions are returned unchanged. + diff --git a/overviews/reflection/overview.md b/overviews/reflection/overview.md index e26b180c9d..f0ace068aa 100644 --- a/overviews/reflection/overview.md +++ b/overviews/reflection/overview.md @@ -1,346 +1,346 @@ ---- -layout: overview-large -title: Overview - -partof: reflection -num: 1 -outof: 7 -languages: [ja] ---- - -EXPERIMENTAL - -**Heather Miller, Eugene Burmako, Philipp Haller** - -*Reflection* is the ability of a program to inspect, and possibly even modify -itself. It has a long history across object-oriented, functional, -and logic programming paradigms. -While some languages are built around reflection as a guiding principle, many -languages progressively evolve their reflection abilities over time. - -Reflection involves the ability to **reify** (ie. make explicit) otherwise-implicit -elements of a program. These elements can be either static program elements -like classes, methods, or expressions, or dynamic elements like the current -continuation or execution events such as method invocations and field accesses. -One usually distinguishes between compile-time and runtime reflection depending -on when the reflection process is performed. **Compile-time reflection** -is a powerful way to develop program transformers and generators, while -**runtime reflection** is typically used to adapt the language semantics -or to support very late binding between software components. - -Until 2.10, Scala has not had any reflection capabilities of its own. Instead, -one could use part of the Java reflection API, namely that dealing with providing -the ability to dynamically inspect classes and objects and access their members. -However, many Scala-specific elements are unrecoverable under standalone Java reflection, -which only exposes Java elements (no functions, no traits) -and types (no existential, higher-kinded, path-dependent and abstract types). -In addition, Java reflection is also unable to recover runtime type info of Java types -that are generic at compile-time; a restriction that carried through to runtime -reflection on generic types in Scala. - -In Scala 2.10, a new reflection library was introduced not only to address the shortcomings -of Java’s runtime reflection on Scala-specific and generic types, but to also -add a more powerful toolkit of general reflective capabilities to Scala. Along -with full-featured runtime reflection for Scala types and generics, Scala 2.10 also -ships with compile-time reflection capabilities, in the form of -[macros]({{site.baseurl }}/overviews/macros/overview.html), as well as the -ability to *reify* Scala expressions into abstract syntax trees. - -## Runtime Reflection - -What is runtime reflection? Given a type or instance of some object at **runtime**, -reflection is the ability to: - -- inspect the type of that object, including generic types, -- to instantiate new objects, -- or to access or invoke members of that object. - -Let's jump in and see how to do each of the above with a few examples. - -### Examples - -#### Inspecting a Runtime Type (Including Generic Types at Runtime) - -As with other JVM languages, Scala's types are _erased_ at compile time. This -means that if you were to inspect the runtime type of some instance, that you -might not have access to all type information that the Scala compiler has -available at compile time. - -`TypeTags` can be thought of as objects which carry along all type information -available at compile time, to runtime. Though, it's important to note that -`TypeTag`s are always generated by the compiler. This generation is triggered -whenever an implicit parameter or context bound requiring a `TypeTag` is used. -This means that, typically, one can only obtain a `TypeTag` using implicit -parameters or context bounds. - -For example, using context bounds: - - scala> import scala.reflect.runtime.{universe => ru} - import scala.reflect.runtime.{universe=>ru} - - scala> val l = List(1,2,3) - l: List[Int] = List(1, 2, 3) - - scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T] - getTypeTag: [T](obj: T)(implicit evidence$1: ru.TypeTag[T])ru.TypeTag[T] - - scala> val theType = getTypeTag(l).tpe - theType: ru.Type = List[Int] - -In the above, we first import `scala.reflect.runtime.universe` (it must always -be imported in order to use `TypeTag`s), and we create a `List[Int]` called -`l`. Then, we define a method `getTypeTag` which has a type parameter `T` that -has a context bound (as the REPL shows, this is equivalent to defining an -implicit "evidence" parameter, which causes the compiler to generate a -`TypeTag` for `T`). Finally, we invoke our method with `l` as its parameter, -and call `tpe` which returns the type contained in the `TypeTag`. As we can -see, we get the correct, complete type (including `List`'s concrete type -argument), `List[Int]`. - -Once we have obtained the desired `Type` instance, we can inspect it, e.g.: - - scala> val decls = theType.declarations.take(10) - decls: Iterable[ru.Symbol] = List(constructor List, method companion, method isEmpty, method head, method tail, method ::, method :::, method reverse_:::, method mapConserve, method ++) - -#### Instantiating a Type at Runtime - -Types obtained through reflection can be instantiated by invoking their -constructor using an appropriate "invoker" mirror (mirrors are expanded upon -[below]({{ site.baseurl }}/overviews/reflection/overview.html#mirrors)). Let's -walk through an example using the REPL: - - scala> case class Person(name: String) - defined class Person - - scala> val m = ru.runtimeMirror(getClass.getClassLoader) - m: scala.reflect.runtime.universe.Mirror = JavaMirror with ... - -In the first step we obtain a mirror `m` which makes all classes and types -available that are loaded by the current classloader, including class -`Person`. - - scala> val classPerson = ru.typeOf[Person].typeSymbol.asClass - classPerson: scala.reflect.runtime.universe.ClassSymbol = class Person - - scala> val cm = m.reflectClass(classPerson) - cm: scala.reflect.runtime.universe.ClassMirror = class mirror for Person (bound to null) - -The second step involves obtaining a `ClassMirror` for class `Person` using -the `reflectClass` method. The `ClassMirror` provides access to the -constructor of class `Person`. - - scala> val ctor = ru.typeOf[Person].declaration(ru.nme.CONSTRUCTOR).asMethod - ctor: scala.reflect.runtime.universe.MethodSymbol = constructor Person - -The symbol for `Person`s constructor can be obtained using only the runtime -universe `ru` by looking it up in the declarations of type `Person`. - - scala> val ctorm = cm.reflectConstructor(ctor) - ctorm: scala.reflect.runtime.universe.MethodMirror = constructor mirror for Person.(name: String): Person (bound to null) - - scala> val p = ctorm("Mike") - p: Any = Person(Mike) - -#### Accessing and Invoking Members of Runtime Types - -In general, members of runtime types are accessed using an appropriate -"invoker" mirror (mirrors are expanded upon -[below]({{ site.baseurl}}/overviews/reflection/overview.html#mirrors)). -Let's walk through an example using the REPL: - - scala> case class Purchase(name: String, orderNumber: Int, var shipped: Boolean) - defined class Purchase - - scala> val p = Purchase("Jeff Lebowski", 23819, false) - p: Purchase = Purchase(Jeff Lebowski,23819,false) - -In this example, we will attempt to get and set the `shipped` field of -`Purchase` `p`, reflectively. - - scala> import scala.reflect.runtime.{universe => ru} - import scala.reflect.runtime.{universe=>ru} - - scala> val m = ru.runtimeMirror(p.getClass.getClassLoader) - m: scala.reflect.runtime.universe.Mirror = JavaMirror with ... - -As we did in the previous example, we'll begin by obtaining a mirror `m`, -which makes all classes and types available that are loaded by the classloader -that also loaded the class of `p` (`Purchase`), which we need in order to -access member `shipped`. - - scala> val shippingTermSymb = ru.typeOf[Purchase].declaration(ru.TermName("shipped")).asTerm - shippingTermSymb: scala.reflect.runtime.universe.TermSymbol = method shipped - -We now look up the declaration of the `shipped` field, which gives us a -`TermSymbol` (a type of `Symbol`). We'll need to use this `Symbol` later to -obtain a mirror that gives us access to the value of this field (for some -instance). - - scala> val im = m.reflect(p) - im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for Purchase(Jeff Lebowski,23819,false) - - scala> val shippingFieldMirror = im.reflectField(shippingTermSymb) - shippingFieldMirror: scala.reflect.runtime.universe.FieldMirror = field mirror for Purchase.shipped (bound to Purchase(Jeff Lebowski,23819,false)) - -In order to access a specific instance's `shipped` member, we need a mirror -for our specific instance, `p`'s instance mirror, `im`. Given our instance -mirror, we can obtain a `FieldMirror` for any `TermSymbol` representing a -field of `p`'s type. - -Now that we have a `FieldMirror` for our specific field, we can use methods -`get` and `set` to get/set our specific instance's `shipped` member. Let's -change the status of `shipped` to `true`. - - scala> shippingFieldMirror.get - res7: Any = false - - scala> shippingFieldMirror.set(true) - - scala> shippingFieldMirror.get - res9: Any = true - -### Runtime Classes in Java vs. Runtime Types in Scala - -Those who are comfortable using Java reflection to obtain Java _Class_ -instances at runtime might have noticed that, in Scala, we instead obtain -runtime _types_. - -The REPL-run below shows a very simple scenario where using Java reflection on -Scala classes might return surprising or incorrect results. - -First, we define a base class `E` with an abstract type member `T`, and from -it, we derive two subclasses, `C` and `D`. - - scala> class E { - | type T - | val x: Option[T] = None - | } - defined class E - - scala> class C extends E - defined class C - - scala> class D extends C - defined class D - -Then, we create an instance of both `C` and `D`, meanwhile making type member -`T` concrete (in both cases, `String`) - - scala> val c = new C { type T = String } - c: C{type T = String} = $anon$1@7113bc51 - - scala> val d = new D { type T = String } - d: D{type T = String} = $anon$1@46364879 - -Now, we use methods `getClass` and `isAssignableFrom` from Java Reflection to -obtain an instance of `java.lang.Class` representing the runtime classes of -`c` and `d`, and then we test to see that `d`'s runtime class is a subclass of -`c`'s runtime representation. - - scala> c.getClass.isAssignableFrom(d.getClass) - res6: Boolean = false - -Since above, we saw that `D` extends `C`, this result is a bit surprising. In -performing this simple runtime type check, one would expect the result of the -question "is the class of `d` a subclass of the class of `c`?" to be `true`. -However, as you might've noticed above, when `c` and `d` are instantiated, the -Scala compiler actually creates anonymous subclasses of `C` and `D`, -respectively. This is due to the fact that the Scala compiler must translate -Scala-specific (_i.e.,_ non-Java) language features into some equivalent in -Java bytecode in order to be able to run on the JVM. Thus, the Scala compiler -often creates synthetic classes (i.e. automatically-generated classes) that -are used at runtime in place of user-defined classes. This is quite -commonplace in Scala and can be observed when using Java reflection with a -number of Scala features, _e.g._ closures, type members, type refinements, -local classes, _etc_. - -In situations like these, we can instead use Scala reflection to obtain -precise runtime _types_ of these Scala objects. Scala runtime types carry -along all type info from compile-time, avoiding these types mismatches between -compile-time and run-time. - -Below, we use define a method which uses Scala reflection to get the runtime -types of its arguments, and then checks the subtyping relationship between the -two. If its first argument's type is a subtype of its second argument's type, -it returns `true`. - - scala> import scala.reflect.runtime.{universe => ru} - import scala.reflect.runtime.{universe=>ru} - - scala> def m[T: ru.TypeTag, S: ru.TypeTag](x: T, y: S): Boolean = { - | val leftTag = ru.typeTag[T] - | val rightTag = ru.typeTag[S] - | leftTag.tpe <:< rightTag.tpe - | } - m: [T, S](x: T, y: S)(implicit evidence$1: scala.reflect.runtime.universe.TypeTag[T], implicit evidence$2: scala.reflect.runtime.universe.TypeTag[S])Boolean - - scala> m(d, c) - res9: Boolean = true - -As we can see, we now get the expected result-- `d`'s runtime type is indeed a -subtype of `c`'s runtime type. - -## Compile-time Reflection - -Scala reflection enables a form of *metaprogramming* which makes it possible -for programs to modify *themselves* at compile time. This compile-time -reflection is realized in the form of macros, which provide the ability to -execute methods that manipulate abstract syntax trees at compile-time. - -A particularly interesting aspect of macros is that they are based on the same -API used also for Scala's runtime reflection, provided in package -`scala.reflect.api`. This enables the sharing of generic code between macros -and implementations that utilize runtime reflection. - -Note that -[the macros guide]({{ site.baseurl }}/overviews/macros/overview.html) -focuses on macro specifics, whereas this guide focuses on the general aspects -of the reflection API. Many concepts directly apply to macros, though, such -as abstract syntax trees which are discussed in greater detail in the section on -[Symbols, Trees, and Types]({{site.baseurl }}/overviews/reflection/symbols-trees-types.html). - -## Environment - -All reflection tasks require a proper environment to be set up. This -environment differs based on whether the reflective task is to be done at run -time or at compile time. The distinction between an environment to be used at -run time or compile time is encapsulated in a so-called *universe*. Another -important aspect of the reflective environment is the set of entities that we -have reflective access to. This set of entities is determined by a so-called -*mirror*. - -Mirrors not only determine the set of entities that can be accessed -reflectively. They also provide reflective operations to be performed on those -entities. For example, in runtime reflection an *invoker mirror* can be used -to invoke a method or constructor of a class. - -### Universes - -`Universe` is the entry point to Scala reflection. -A universe provides an interface to all the principal concepts used in -reflection, such as `Types`, `Trees`, and `Annotations`. For more details, see -the section of this guide on -[Universes]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html), -or the -[Universes API docs](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Universe) -in package `scala.reflect.api`. - -To use most aspects of Scala reflection, including most code examples provided -in this guide, you need to make sure you import a `Universe` or the members -of a `Universe`. Typically, to use runtime reflection, one can import all -members of `scala.reflect.runtime.universe`, using a wildcard import: - - import scala.reflect.runtime.universe._ - -### Mirrors - -`Mirror`s are a central part of Scala Reflection. All information provided by -reflection is made accessible through these so-called mirrors. Depending on -the type of information to be obtained, or the reflective action to be taken, -different flavors of mirrors must be used. - -For more details, see the section of this guide on -[Mirrors]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html), -or the -[Mirrors API docs](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Mirrors) -in package `scala.reflect.api`. +--- +layout: overview-large +title: Overview + +partof: reflection +num: 1 +outof: 7 +languages: [ja] +--- + +EXPERIMENTAL + +**Heather Miller, Eugene Burmako, Philipp Haller** + +*Reflection* is the ability of a program to inspect, and possibly even modify +itself. It has a long history across object-oriented, functional, +and logic programming paradigms. +While some languages are built around reflection as a guiding principle, many +languages progressively evolve their reflection abilities over time. + +Reflection involves the ability to **reify** (ie. make explicit) otherwise-implicit +elements of a program. These elements can be either static program elements +like classes, methods, or expressions, or dynamic elements like the current +continuation or execution events such as method invocations and field accesses. +One usually distinguishes between compile-time and runtime reflection depending +on when the reflection process is performed. **Compile-time reflection** +is a powerful way to develop program transformers and generators, while +**runtime reflection** is typically used to adapt the language semantics +or to support very late binding between software components. + +Until 2.10, Scala has not had any reflection capabilities of its own. Instead, +one could use part of the Java reflection API, namely that dealing with providing +the ability to dynamically inspect classes and objects and access their members. +However, many Scala-specific elements are unrecoverable under standalone Java reflection, +which only exposes Java elements (no functions, no traits) +and types (no existential, higher-kinded, path-dependent and abstract types). +In addition, Java reflection is also unable to recover runtime type info of Java types +that are generic at compile-time; a restriction that carried through to runtime +reflection on generic types in Scala. + +In Scala 2.10, a new reflection library was introduced not only to address the shortcomings +of Java’s runtime reflection on Scala-specific and generic types, but to also +add a more powerful toolkit of general reflective capabilities to Scala. Along +with full-featured runtime reflection for Scala types and generics, Scala 2.10 also +ships with compile-time reflection capabilities, in the form of +[macros]({{site.baseurl }}/overviews/macros/overview.html), as well as the +ability to *reify* Scala expressions into abstract syntax trees. + +## Runtime Reflection + +What is runtime reflection? Given a type or instance of some object at **runtime**, +reflection is the ability to: + +- inspect the type of that object, including generic types, +- to instantiate new objects, +- or to access or invoke members of that object. + +Let's jump in and see how to do each of the above with a few examples. + +### Examples + +#### Inspecting a Runtime Type (Including Generic Types at Runtime) + +As with other JVM languages, Scala's types are _erased_ at compile time. This +means that if you were to inspect the runtime type of some instance, that you +might not have access to all type information that the Scala compiler has +available at compile time. + +`TypeTags` can be thought of as objects which carry along all type information +available at compile time, to runtime. Though, it's important to note that +`TypeTag`s are always generated by the compiler. This generation is triggered +whenever an implicit parameter or context bound requiring a `TypeTag` is used. +This means that, typically, one can only obtain a `TypeTag` using implicit +parameters or context bounds. + +For example, using context bounds: + + scala> import scala.reflect.runtime.{universe => ru} + import scala.reflect.runtime.{universe=>ru} + + scala> val l = List(1,2,3) + l: List[Int] = List(1, 2, 3) + + scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T] + getTypeTag: [T](obj: T)(implicit evidence$1: ru.TypeTag[T])ru.TypeTag[T] + + scala> val theType = getTypeTag(l).tpe + theType: ru.Type = List[Int] + +In the above, we first import `scala.reflect.runtime.universe` (it must always +be imported in order to use `TypeTag`s), and we create a `List[Int]` called +`l`. Then, we define a method `getTypeTag` which has a type parameter `T` that +has a context bound (as the REPL shows, this is equivalent to defining an +implicit "evidence" parameter, which causes the compiler to generate a +`TypeTag` for `T`). Finally, we invoke our method with `l` as its parameter, +and call `tpe` which returns the type contained in the `TypeTag`. As we can +see, we get the correct, complete type (including `List`'s concrete type +argument), `List[Int]`. + +Once we have obtained the desired `Type` instance, we can inspect it, e.g.: + + scala> val decls = theType.declarations.take(10) + decls: Iterable[ru.Symbol] = List(constructor List, method companion, method isEmpty, method head, method tail, method ::, method :::, method reverse_:::, method mapConserve, method ++) + +#### Instantiating a Type at Runtime + +Types obtained through reflection can be instantiated by invoking their +constructor using an appropriate "invoker" mirror (mirrors are expanded upon +[below]({{ site.baseurl }}/overviews/reflection/overview.html#mirrors)). Let's +walk through an example using the REPL: + + scala> case class Person(name: String) + defined class Person + + scala> val m = ru.runtimeMirror(getClass.getClassLoader) + m: scala.reflect.runtime.universe.Mirror = JavaMirror with ... + +In the first step we obtain a mirror `m` which makes all classes and types +available that are loaded by the current classloader, including class +`Person`. + + scala> val classPerson = ru.typeOf[Person].typeSymbol.asClass + classPerson: scala.reflect.runtime.universe.ClassSymbol = class Person + + scala> val cm = m.reflectClass(classPerson) + cm: scala.reflect.runtime.universe.ClassMirror = class mirror for Person (bound to null) + +The second step involves obtaining a `ClassMirror` for class `Person` using +the `reflectClass` method. The `ClassMirror` provides access to the +constructor of class `Person`. + + scala> val ctor = ru.typeOf[Person].declaration(ru.nme.CONSTRUCTOR).asMethod + ctor: scala.reflect.runtime.universe.MethodSymbol = constructor Person + +The symbol for `Person`s constructor can be obtained using only the runtime +universe `ru` by looking it up in the declarations of type `Person`. + + scala> val ctorm = cm.reflectConstructor(ctor) + ctorm: scala.reflect.runtime.universe.MethodMirror = constructor mirror for Person.(name: String): Person (bound to null) + + scala> val p = ctorm("Mike") + p: Any = Person(Mike) + +#### Accessing and Invoking Members of Runtime Types + +In general, members of runtime types are accessed using an appropriate +"invoker" mirror (mirrors are expanded upon +[below]({{ site.baseurl}}/overviews/reflection/overview.html#mirrors)). +Let's walk through an example using the REPL: + + scala> case class Purchase(name: String, orderNumber: Int, var shipped: Boolean) + defined class Purchase + + scala> val p = Purchase("Jeff Lebowski", 23819, false) + p: Purchase = Purchase(Jeff Lebowski,23819,false) + +In this example, we will attempt to get and set the `shipped` field of +`Purchase` `p`, reflectively. + + scala> import scala.reflect.runtime.{universe => ru} + import scala.reflect.runtime.{universe=>ru} + + scala> val m = ru.runtimeMirror(p.getClass.getClassLoader) + m: scala.reflect.runtime.universe.Mirror = JavaMirror with ... + +As we did in the previous example, we'll begin by obtaining a mirror `m`, +which makes all classes and types available that are loaded by the classloader +that also loaded the class of `p` (`Purchase`), which we need in order to +access member `shipped`. + + scala> val shippingTermSymb = ru.typeOf[Purchase].declaration(ru.TermName("shipped")).asTerm + shippingTermSymb: scala.reflect.runtime.universe.TermSymbol = method shipped + +We now look up the declaration of the `shipped` field, which gives us a +`TermSymbol` (a type of `Symbol`). We'll need to use this `Symbol` later to +obtain a mirror that gives us access to the value of this field (for some +instance). + + scala> val im = m.reflect(p) + im: scala.reflect.runtime.universe.InstanceMirror = instance mirror for Purchase(Jeff Lebowski,23819,false) + + scala> val shippingFieldMirror = im.reflectField(shippingTermSymb) + shippingFieldMirror: scala.reflect.runtime.universe.FieldMirror = field mirror for Purchase.shipped (bound to Purchase(Jeff Lebowski,23819,false)) + +In order to access a specific instance's `shipped` member, we need a mirror +for our specific instance, `p`'s instance mirror, `im`. Given our instance +mirror, we can obtain a `FieldMirror` for any `TermSymbol` representing a +field of `p`'s type. + +Now that we have a `FieldMirror` for our specific field, we can use methods +`get` and `set` to get/set our specific instance's `shipped` member. Let's +change the status of `shipped` to `true`. + + scala> shippingFieldMirror.get + res7: Any = false + + scala> shippingFieldMirror.set(true) + + scala> shippingFieldMirror.get + res9: Any = true + +### Runtime Classes in Java vs. Runtime Types in Scala + +Those who are comfortable using Java reflection to obtain Java _Class_ +instances at runtime might have noticed that, in Scala, we instead obtain +runtime _types_. + +The REPL-run below shows a very simple scenario where using Java reflection on +Scala classes might return surprising or incorrect results. + +First, we define a base class `E` with an abstract type member `T`, and from +it, we derive two subclasses, `C` and `D`. + + scala> class E { + | type T + | val x: Option[T] = None + | } + defined class E + + scala> class C extends E + defined class C + + scala> class D extends C + defined class D + +Then, we create an instance of both `C` and `D`, meanwhile making type member +`T` concrete (in both cases, `String`) + + scala> val c = new C { type T = String } + c: C{type T = String} = $anon$1@7113bc51 + + scala> val d = new D { type T = String } + d: D{type T = String} = $anon$1@46364879 + +Now, we use methods `getClass` and `isAssignableFrom` from Java Reflection to +obtain an instance of `java.lang.Class` representing the runtime classes of +`c` and `d`, and then we test to see that `d`'s runtime class is a subclass of +`c`'s runtime representation. + + scala> c.getClass.isAssignableFrom(d.getClass) + res6: Boolean = false + +Since above, we saw that `D` extends `C`, this result is a bit surprising. In +performing this simple runtime type check, one would expect the result of the +question "is the class of `d` a subclass of the class of `c`?" to be `true`. +However, as you might've noticed above, when `c` and `d` are instantiated, the +Scala compiler actually creates anonymous subclasses of `C` and `D`, +respectively. This is due to the fact that the Scala compiler must translate +Scala-specific (_i.e.,_ non-Java) language features into some equivalent in +Java bytecode in order to be able to run on the JVM. Thus, the Scala compiler +often creates synthetic classes (i.e. automatically-generated classes) that +are used at runtime in place of user-defined classes. This is quite +commonplace in Scala and can be observed when using Java reflection with a +number of Scala features, _e.g._ closures, type members, type refinements, +local classes, _etc_. + +In situations like these, we can instead use Scala reflection to obtain +precise runtime _types_ of these Scala objects. Scala runtime types carry +along all type info from compile-time, avoiding these types mismatches between +compile-time and run-time. + +Below, we use define a method which uses Scala reflection to get the runtime +types of its arguments, and then checks the subtyping relationship between the +two. If its first argument's type is a subtype of its second argument's type, +it returns `true`. + + scala> import scala.reflect.runtime.{universe => ru} + import scala.reflect.runtime.{universe=>ru} + + scala> def m[T: ru.TypeTag, S: ru.TypeTag](x: T, y: S): Boolean = { + | val leftTag = ru.typeTag[T] + | val rightTag = ru.typeTag[S] + | leftTag.tpe <:< rightTag.tpe + | } + m: [T, S](x: T, y: S)(implicit evidence$1: scala.reflect.runtime.universe.TypeTag[T], implicit evidence$2: scala.reflect.runtime.universe.TypeTag[S])Boolean + + scala> m(d, c) + res9: Boolean = true + +As we can see, we now get the expected result-- `d`'s runtime type is indeed a +subtype of `c`'s runtime type. + +## Compile-time Reflection + +Scala reflection enables a form of *metaprogramming* which makes it possible +for programs to modify *themselves* at compile time. This compile-time +reflection is realized in the form of macros, which provide the ability to +execute methods that manipulate abstract syntax trees at compile-time. + +A particularly interesting aspect of macros is that they are based on the same +API used also for Scala's runtime reflection, provided in package +`scala.reflect.api`. This enables the sharing of generic code between macros +and implementations that utilize runtime reflection. + +Note that +[the macros guide]({{ site.baseurl }}/overviews/macros/overview.html) +focuses on macro specifics, whereas this guide focuses on the general aspects +of the reflection API. Many concepts directly apply to macros, though, such +as abstract syntax trees which are discussed in greater detail in the section on +[Symbols, Trees, and Types]({{site.baseurl }}/overviews/reflection/symbols-trees-types.html). + +## Environment + +All reflection tasks require a proper environment to be set up. This +environment differs based on whether the reflective task is to be done at run +time or at compile time. The distinction between an environment to be used at +run time or compile time is encapsulated in a so-called *universe*. Another +important aspect of the reflective environment is the set of entities that we +have reflective access to. This set of entities is determined by a so-called +*mirror*. + +Mirrors not only determine the set of entities that can be accessed +reflectively. They also provide reflective operations to be performed on those +entities. For example, in runtime reflection an *invoker mirror* can be used +to invoke a method or constructor of a class. + +### Universes + +`Universe` is the entry point to Scala reflection. +A universe provides an interface to all the principal concepts used in +reflection, such as `Types`, `Trees`, and `Annotations`. For more details, see +the section of this guide on +[Universes]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html), +or the +[Universes API docs](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Universe) +in package `scala.reflect.api`. + +To use most aspects of Scala reflection, including most code examples provided +in this guide, you need to make sure you import a `Universe` or the members +of a `Universe`. Typically, to use runtime reflection, one can import all +members of `scala.reflect.runtime.universe`, using a wildcard import: + + import scala.reflect.runtime.universe._ + +### Mirrors + +`Mirror`s are a central part of Scala Reflection. All information provided by +reflection is made accessible through these so-called mirrors. Depending on +the type of information to be obtained, or the reflective action to be taken, +different flavors of mirrors must be used. + +For more details, see the section of this guide on +[Mirrors]({{ site.baseurl}}/overviews/reflection/environment-universes-mirrors.html), +or the +[Mirrors API docs](http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.Mirrors) +in package `scala.reflect.api`. diff --git a/ru/overviews/parallel-collections/architecture.md b/ru/overviews/parallel-collections/architecture.md index 86e0bff59a..334daa6abd 100644 --- a/ru/overviews/parallel-collections/architecture.md +++ b/ru/overviews/parallel-collections/architecture.md @@ -1,4 +1,4 @@ ---- +--- layout: overview-large title: Архитектура библиотеки параллельных коллекций diff --git a/ru/overviews/parallel-collections/configuration.md b/ru/overviews/parallel-collections/configuration.md index fcf72c2f26..f397f6fa02 100644 --- a/ru/overviews/parallel-collections/configuration.md +++ b/ru/overviews/parallel-collections/configuration.md @@ -1,4 +1,4 @@ ---- +--- layout: overview-large title: Конфигурирование параллельных коллекций diff --git a/ru/overviews/parallel-collections/conversions.md b/ru/overviews/parallel-collections/conversions.md index dc50771e57..6fce397db5 100644 --- a/ru/overviews/parallel-collections/conversions.md +++ b/ru/overviews/parallel-collections/conversions.md @@ -1,4 +1,4 @@ ---- +--- layout: overview-large title: Преобразования параллельных коллекций diff --git a/ru/overviews/parallel-collections/ctries.md b/ru/overviews/parallel-collections/ctries.md index 8af10c87c3..6d0c8d4bd5 100644 --- a/ru/overviews/parallel-collections/ctries.md +++ b/ru/overviews/parallel-collections/ctries.md @@ -1,4 +1,4 @@ ---- +--- layout: overview-large title: Многопоточные префиксные деревья diff --git a/ru/overviews/parallel-collections/custom-parallel-collections.md b/ru/overviews/parallel-collections/custom-parallel-collections.md index b71a0c87b7..e1a73137b4 100644 --- a/ru/overviews/parallel-collections/custom-parallel-collections.md +++ b/ru/overviews/parallel-collections/custom-parallel-collections.md @@ -1,4 +1,4 @@ ---- +--- layout: overview-large title: Создание пользовательской параллельной коллекции diff --git a/ru/overviews/parallel-collections/overview.md b/ru/overviews/parallel-collections/overview.md index 5e04b1130a..c749ff2523 100644 --- a/ru/overviews/parallel-collections/overview.md +++ b/ru/overviews/parallel-collections/overview.md @@ -1,180 +1,180 @@ ---- -layout: overview-large -title: Обзор - -disqus: true - -partof: parallel-collections -num: 1 -language: ru ---- - -**Авторы оригинала: Aleksandar Prokopec, Heather Miller** - -**Перевод Анастасии Маркиной** - -## Мотивация - -Пока производители процессоров в последние годы дружно переходили от одноядерных к многоядерным архитектурам, научное и производственное сообщества не менее дружно признали, что многопоточное программирование по-прежнему трудно сделать популярным. - -Чтобы упростить написание многопоточных программ, в стандартную библиотеку Scala были включены параллельные коллекции, которые скрыли от пользователей низкоуровневые подробности параллелизации, дав им привычную высокоуровневую абстракцию. Надежда была (и остается) на то, что скрытая под уровнем абстракции параллельность позволит на шаг приблизиться к ситуации, когда среднестатистический разработчик будет повседневно использовать в работе надежно исполняемый параллельный код. - -Идея проста: коллекции -- хорошо понятная и часто используемая программистами абстракция. Упорядоченность коллекций позволяет эффективно и прозрачно (для пользователя) обрабатывать их параллельно. Позволив пользователю "подменить" последовательные коллекции на те, что обрабатываются параллельно, решение Scala делает большой шаг вперед к охвату большего количества кода возможностями параллельной обработки. - -Рассмотрим следующий пример, где мы исполняем монадическую операцию на некоторой большой последовательной коллекции: - - val list = (1 to 10000).toList - list.map(_ + 42) - -Чтобы выполнить ту же самую операцию параллельно, требуется просто вызвать метод `par` -на последовательной коллекции `list`. После этого можно работать с параллельной коллекцией так же, как и с последовательной. То есть, пример выше примет вид: - - list.par.map(_ + 42) - -Библиотека параллельных коллекций Scala тесно связана с "последовательной" библиотекой коллекций Scala (представлена в версии 2.8), во многом потому, что последняя служила вдохновением к ее дизайну. Он предоставляет параллельную альтернативу ряду важных структур данных из библиотеки (последовательных) коллекций Scala, в том числе: - -* `ParArray` -* `ParVector` -* `mutable.ParHashMap` -* `mutable.ParHashSet` -* `immutable.ParHashMap` -* `immutable.ParHashSet` -* `ParRange` -* `ParTrieMap` (`collection.concurrent.TrieMap` впервые в версии 2.10) - -Библиотека параллельных коллекций Scala _расширяема_ также как и последовательные коллекции, представленные в стандартной библиотеке. Другими словами, как и в случае с обычными последовательными коллекциями, пользователи могут внедрять свои собственные типы коллекций, автоматически наследуя все предопределенные (параллельные) операции, доступные для других параллельных коллекций в стандартной библиотеке. - -## Несколько примеров - -Попробуем изобразить всеобщность и полезность представленных коллекций на ряде простых примеров, для каждого из которых характерно прозрачно-параллельное выполнение. - -_Примечание:_ Некоторые из последующих примеров оперируют небольшими коллекциями, для которых такой подход не рекомендуется. Они должны рассматриваться только как иллюстрация. Эвристически, ускорение становится заметным, когда размер коллекции дорастает до нескольких тысяч элементов. (Более подробно о взаимосвязи между размером коллекции и производительностью, смотрите [соответствующий подраздел]({{ site.baseurl}}/overviews/parallel-collections/performance.html#how_big_should_a_collection_be_to_go_parallel) раздела, посвященного [производительности]({{ site.baseurl }}/ru/overviews/parallel-collections/performance.html) в данном руководстве.) - -#### map - -Используем параллельную `map` для преобразования набора строк `String` в верхний регистр: - - scala> val lastNames = List("Smith","Jones","Frankenstein","Bach","Jackson","Rodin").par - lastNames: scala.collection.parallel.immutable.ParSeq[String] = ParVector(Smith, Jones, Frankenstein, Bach, Jackson, Rodin) - - scala> lastNames.map(_.toUpperCase) - res0: scala.collection.parallel.immutable.ParSeq[String] = ParVector(SMITH, JONES, FRANKENSTEIN, BACH, JACKSON, RODIN) - -#### fold - -Суммируем через `fold` на `ParArray`: - - scala> val parArray = (1 to 10000).toArray.par - parArray: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3, ... - - scala> parArray.fold(0)(_ + _) - res0: Int = 50005000 - -#### filter - -Используем параллельный `filter` для отбора фамилий, которые начинаются с буквы "J" или стоящей дальше в алфавите: - - scala> val lastNames = List("Smith","Jones","Frankenstein","Bach","Jackson","Rodin").par - lastNames: scala.collection.parallel.immutable.ParSeq[String] = ParVector(Smith, Jones, Frankenstein, Bach, Jackson, Rodin) - - scala> lastNames.filter(_.head >= 'J') - res0: scala.collection.parallel.immutable.ParSeq[String] = ParVector(Smith, Jones, Jackson, Rodin) - -## Создание параллельной коллекции - -Параллельные коллекции предназначались для того, чтобы быть использованными таким же образом, как и последовательные; единственное значимое отличие -- в методе _получения_ параллельной коллекции. - -В общем виде, есть два варианта создания параллельной коллекции: - -Первый, с использованием ключевого слова `new` и подходящего оператора import: - - import scala.collection.parallel.immutable.ParVector - val pv = new ParVector[Int] - -Второй, _преобразованием_ последовательной коллекции: - - val pv = Vector(1,2,3,4,5,6,7,8,9).par - -Разовьем эту важную мысль -- последовательные коллекции можно конвертировать в параллельные вызовом метода `par` на последовательных, и, соответственно, параллельные коллекции также можно конвертировать в последовательные вызовом метода `seq` на параллельных. - -_На заметку:_ Коллекции, являющиеся последовательными в силу наследования (в том смысле, что доступ к их элементам требуется получать по порядку, один элемент за другим), такие, как списки, очереди и потоки (streams), преобразовываются в свои параллельные аналоги копированием элементов в соответствующие параллельные коллекции. Например, список `List` конвертируется в стандартную неизменяемую параллельную последовательность, то есть в `ParVector`. Естественно, что копирование, которое для этого требуется, вносит дополнительный расход производительности, которого не требуют другие типы коллекций, такие как `Array`, `Vector`, `HashMap` и т.д. - -Больше информации о конвертировании можно найти в разделах [преобразования]({{ site.baseurl }}/ru/overviews/parallel-collections/conversions.html) и [конкретные классы параллельных коллекций]({{ site.baseurl }}/ru/overviews/parallel-collections/concrete-parallel-collections.html) этого руководства. - -## Семантика - -В то время, как абстракция параллельной коллекции заставляет думать о ней так, как если бы речь шла о нормальной последовательной коллекции, важно помнить, что семантика различается, особенно в том, что касается побочных эффектов и неассоциативных операций. - -Для того, чтобы увидеть, что происходит, для начала представим, _как именно_ операции выполняются параллельно. В концепции, когда фреймворк параллельных коллекций Scala распараллеливает операцию на соответствующей коллекции, он рекурсивно "разбивает" данную коллекцию, параллельно выполняет операцию на каждом разделе коллекции, а затем "комбинирует" все полученные результаты. - -Эти многопоточные, "неупорядоченные" семантики параллельных коллекций приводят к следующим скрытым следствиям: - -1. **Операции, имеющие побочные эффекты, могут нарушать детерминизм** -2. **Неассоциативные операции могут нарушать детерминизм** - -### Операции, имеющие побочные эффекты. - -Вследствие использования фреймворком параллельных коллекций семантики _многопоточного_ выполнения, в большинстве случаев для соблюдения детерминизма требуется избегать выполнения на коллекциях операций, которые выполняют побочные действия. В качестве простого примера попробуем использовать метод доступа `foreach` для увеличения значения переменной `var`, объявленной вне замыкания, которое было передано `foreach`. - - scala> var sum = 0 - sum: Int = 0 - - scala> val list = (1 to 1000).toList.par - list: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(1, 2, 3,… - - scala> list.foreach(sum += _); sum - res01: Int = 467766 - - scala> var sum = 0 - sum: Int = 0 - - scala> list.foreach(sum += _); sum - res02: Int = 457073 - - scala> var sum = 0 - sum: Int = 0 - - scala> list.foreach(sum += _); sum - res03: Int = 468520 - -В примере видно, что несмотря на то, что каждый раз `sum` инициализируется в 0, при каждом новом вызове `foreach` на предложенном `list`, `sum` получает различное значение. Источником недетерминизма является так называемая _гонка_-- параллельное чтение/запись одной и той же изменяемой переменной. - -В примере выше возможен случай, когда два потока прочитают _одно и то же_ значение переменной `sum`, потратят некоторое время на выполнение операции над этим значением `sum`, а потом попытаются записать новое значение в `sum`, что может привести к перезаписи (а следовательно, к потере) значимого результата, как показано ниже: - - Поток A: читает значение sum, sum = 0 значение sum: 0 - Поток B: читает значение sum, sum = 0 значение sum: 0 - Поток A: увеличивает sum на 760, пишет sum = 760 значение sum: 760 - Поток B: увеличивает sum на 12, пишет sum = 12 значение sum: 12 - -Приведенный выше пример демонстрирует сценарий, где два потока успевают прочитать одно и то же значение, `0`, прежде чем один или другой из них успеет прибавить к этому `0` элемент из своего куска параллельной коллекции. В этом случае `Поток A` читает `0` и прибавляет к нему свой элемент, `0+760`, в то время, как `Поток B` прибавляет `0` к своему элементу, `0+12`. После того, как они вычислили свои суммы, каждый из них записывает свое значение в `sum`. Получилось так, что `Поток A` успевает записать значение первым, только для того, чтобы это помещенное в `sum` значение было практически сразу же перезаписано потоком `B`, тем самым полностью перезаписав (и потеряв) значение `760`. - -### Неассоциативные операции - -Из-за _"неупорядоченной"_ семантики, нелишней осторожностью становится требование выполнять только ассоциативные операции во избежание недетерминированности. То есть, если мы имеем параллельную коллекцию `pcoll`, нужно убедиться, что при вызове на `pcoll` функции более высокого уровня, такой как `pcoll.reduce(func)`, порядок, в котором `func` применяется к элементам `pcoll`, может быть произвольным. Простым и очевидным примером неассоциативной операции является вычитание: - - scala> val list = (1 to 1000).toList.par - list: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(1, 2, 3,… - - scala> list.reduce(_-_) - res01: Int = -228888 - - scala> list.reduce(_-_) - res02: Int = -61000 - - scala> list.reduce(_-_) - res03: Int = -331818 - -В примере выше, мы берем `ParVector[Int]`, вызываем функцию `reduce`, и передаем ей `_-_`, которая просто берет два неименованных элемента, и вычитает один из другого. Вследствие того, что фреймворк параллельных коллекций порождает потоки и независимо выполняет `reduce(_-_)` на разных частях коллекции, результат двух запусков `reduce(_-_)` на одной и той же коллекции не будет одним и тем же. - -_Примечание:_ Часто возникает мысль, что так же, как и в случае с неассоциативными, некоммутативные операции, переданные в более высокую уровнем функцию на параллельной коллекции, приводят к недетеминированному поведению. Это неверно, простой пример -- конкатенация строк -- ассоциативная, но некоммутативная операция: - - scala> val strings = List("abc","def","ghi","jk","lmnop","qrs","tuv","wx","yz").par - strings: scala.collection.parallel.immutable.ParSeq[java.lang.String] = ParVector(abc, def, ghi, jk, lmnop, qrs, tuv, wx, yz) - - scala> val alphabet = strings.reduce(_++_) - alphabet: java.lang.String = abcdefghijklmnopqrstuvwxyz - -_"Неупорядоченная"_ семантика параллельных коллекций означает только то, что операции будут выполнены не по порядку (во _временном_ отношении. То есть, не последовательно), она не означает, что результат будет "*перемешан*" относительно изначального порядка (в _пространственном_ отношении). Напротив, результат будет практически всегда пересобран _по-порядку_-- то есть, параллельная коллекция, разбитая на части в порядке A, B, C, будет снова объединена в том же порядке A, B, C, а не в каком-то произвольном, например, B, C, A. - -Если требуется больше информации о том, как разделяются и комбинируются операции на различных типах коллекций, посетите раздел [Архитектура]({{ site.baseurl }}/ru/overviews/parallel-collections/architecture.html) этого руководства. - +--- +layout: overview-large +title: Обзор + +disqus: true + +partof: parallel-collections +num: 1 +language: ru +--- + +**Авторы оригинала: Aleksandar Prokopec, Heather Miller** + +**Перевод Анастасии Маркиной** + +## Мотивация + +Пока производители процессоров в последние годы дружно переходили от одноядерных к многоядерным архитектурам, научное и производственное сообщества не менее дружно признали, что многопоточное программирование по-прежнему трудно сделать популярным. + +Чтобы упростить написание многопоточных программ, в стандартную библиотеку Scala были включены параллельные коллекции, которые скрыли от пользователей низкоуровневые подробности параллелизации, дав им привычную высокоуровневую абстракцию. Надежда была (и остается) на то, что скрытая под уровнем абстракции параллельность позволит на шаг приблизиться к ситуации, когда среднестатистический разработчик будет повседневно использовать в работе надежно исполняемый параллельный код. + +Идея проста: коллекции -- хорошо понятная и часто используемая программистами абстракция. Упорядоченность коллекций позволяет эффективно и прозрачно (для пользователя) обрабатывать их параллельно. Позволив пользователю "подменить" последовательные коллекции на те, что обрабатываются параллельно, решение Scala делает большой шаг вперед к охвату большего количества кода возможностями параллельной обработки. + +Рассмотрим следующий пример, где мы исполняем монадическую операцию на некоторой большой последовательной коллекции: + + val list = (1 to 10000).toList + list.map(_ + 42) + +Чтобы выполнить ту же самую операцию параллельно, требуется просто вызвать метод `par` +на последовательной коллекции `list`. После этого можно работать с параллельной коллекцией так же, как и с последовательной. То есть, пример выше примет вид: + + list.par.map(_ + 42) + +Библиотека параллельных коллекций Scala тесно связана с "последовательной" библиотекой коллекций Scala (представлена в версии 2.8), во многом потому, что последняя служила вдохновением к ее дизайну. Он предоставляет параллельную альтернативу ряду важных структур данных из библиотеки (последовательных) коллекций Scala, в том числе: + +* `ParArray` +* `ParVector` +* `mutable.ParHashMap` +* `mutable.ParHashSet` +* `immutable.ParHashMap` +* `immutable.ParHashSet` +* `ParRange` +* `ParTrieMap` (`collection.concurrent.TrieMap` впервые в версии 2.10) + +Библиотека параллельных коллекций Scala _расширяема_ также как и последовательные коллекции, представленные в стандартной библиотеке. Другими словами, как и в случае с обычными последовательными коллекциями, пользователи могут внедрять свои собственные типы коллекций, автоматически наследуя все предопределенные (параллельные) операции, доступные для других параллельных коллекций в стандартной библиотеке. + +## Несколько примеров + +Попробуем изобразить всеобщность и полезность представленных коллекций на ряде простых примеров, для каждого из которых характерно прозрачно-параллельное выполнение. + +_Примечание:_ Некоторые из последующих примеров оперируют небольшими коллекциями, для которых такой подход не рекомендуется. Они должны рассматриваться только как иллюстрация. Эвристически, ускорение становится заметным, когда размер коллекции дорастает до нескольких тысяч элементов. (Более подробно о взаимосвязи между размером коллекции и производительностью, смотрите [соответствующий подраздел]({{ site.baseurl}}/overviews/parallel-collections/performance.html#how_big_should_a_collection_be_to_go_parallel) раздела, посвященного [производительности]({{ site.baseurl }}/ru/overviews/parallel-collections/performance.html) в данном руководстве.) + +#### map + +Используем параллельную `map` для преобразования набора строк `String` в верхний регистр: + + scala> val lastNames = List("Smith","Jones","Frankenstein","Bach","Jackson","Rodin").par + lastNames: scala.collection.parallel.immutable.ParSeq[String] = ParVector(Smith, Jones, Frankenstein, Bach, Jackson, Rodin) + + scala> lastNames.map(_.toUpperCase) + res0: scala.collection.parallel.immutable.ParSeq[String] = ParVector(SMITH, JONES, FRANKENSTEIN, BACH, JACKSON, RODIN) + +#### fold + +Суммируем через `fold` на `ParArray`: + + scala> val parArray = (1 to 10000).toArray.par + parArray: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3, ... + + scala> parArray.fold(0)(_ + _) + res0: Int = 50005000 + +#### filter + +Используем параллельный `filter` для отбора фамилий, которые начинаются с буквы "J" или стоящей дальше в алфавите: + + scala> val lastNames = List("Smith","Jones","Frankenstein","Bach","Jackson","Rodin").par + lastNames: scala.collection.parallel.immutable.ParSeq[String] = ParVector(Smith, Jones, Frankenstein, Bach, Jackson, Rodin) + + scala> lastNames.filter(_.head >= 'J') + res0: scala.collection.parallel.immutable.ParSeq[String] = ParVector(Smith, Jones, Jackson, Rodin) + +## Создание параллельной коллекции + +Параллельные коллекции предназначались для того, чтобы быть использованными таким же образом, как и последовательные; единственное значимое отличие -- в методе _получения_ параллельной коллекции. + +В общем виде, есть два варианта создания параллельной коллекции: + +Первый, с использованием ключевого слова `new` и подходящего оператора import: + + import scala.collection.parallel.immutable.ParVector + val pv = new ParVector[Int] + +Второй, _преобразованием_ последовательной коллекции: + + val pv = Vector(1,2,3,4,5,6,7,8,9).par + +Разовьем эту важную мысль -- последовательные коллекции можно конвертировать в параллельные вызовом метода `par` на последовательных, и, соответственно, параллельные коллекции также можно конвертировать в последовательные вызовом метода `seq` на параллельных. + +_На заметку:_ Коллекции, являющиеся последовательными в силу наследования (в том смысле, что доступ к их элементам требуется получать по порядку, один элемент за другим), такие, как списки, очереди и потоки (streams), преобразовываются в свои параллельные аналоги копированием элементов в соответствующие параллельные коллекции. Например, список `List` конвертируется в стандартную неизменяемую параллельную последовательность, то есть в `ParVector`. Естественно, что копирование, которое для этого требуется, вносит дополнительный расход производительности, которого не требуют другие типы коллекций, такие как `Array`, `Vector`, `HashMap` и т.д. + +Больше информации о конвертировании можно найти в разделах [преобразования]({{ site.baseurl }}/ru/overviews/parallel-collections/conversions.html) и [конкретные классы параллельных коллекций]({{ site.baseurl }}/ru/overviews/parallel-collections/concrete-parallel-collections.html) этого руководства. + +## Семантика + +В то время, как абстракция параллельной коллекции заставляет думать о ней так, как если бы речь шла о нормальной последовательной коллекции, важно помнить, что семантика различается, особенно в том, что касается побочных эффектов и неассоциативных операций. + +Для того, чтобы увидеть, что происходит, для начала представим, _как именно_ операции выполняются параллельно. В концепции, когда фреймворк параллельных коллекций Scala распараллеливает операцию на соответствующей коллекции, он рекурсивно "разбивает" данную коллекцию, параллельно выполняет операцию на каждом разделе коллекции, а затем "комбинирует" все полученные результаты. + +Эти многопоточные, "неупорядоченные" семантики параллельных коллекций приводят к следующим скрытым следствиям: + +1. **Операции, имеющие побочные эффекты, могут нарушать детерминизм** +2. **Неассоциативные операции могут нарушать детерминизм** + +### Операции, имеющие побочные эффекты. + +Вследствие использования фреймворком параллельных коллекций семантики _многопоточного_ выполнения, в большинстве случаев для соблюдения детерминизма требуется избегать выполнения на коллекциях операций, которые выполняют побочные действия. В качестве простого примера попробуем использовать метод доступа `foreach` для увеличения значения переменной `var`, объявленной вне замыкания, которое было передано `foreach`. + + scala> var sum = 0 + sum: Int = 0 + + scala> val list = (1 to 1000).toList.par + list: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(1, 2, 3,… + + scala> list.foreach(sum += _); sum + res01: Int = 467766 + + scala> var sum = 0 + sum: Int = 0 + + scala> list.foreach(sum += _); sum + res02: Int = 457073 + + scala> var sum = 0 + sum: Int = 0 + + scala> list.foreach(sum += _); sum + res03: Int = 468520 + +В примере видно, что несмотря на то, что каждый раз `sum` инициализируется в 0, при каждом новом вызове `foreach` на предложенном `list`, `sum` получает различное значение. Источником недетерминизма является так называемая _гонка_-- параллельное чтение/запись одной и той же изменяемой переменной. + +В примере выше возможен случай, когда два потока прочитают _одно и то же_ значение переменной `sum`, потратят некоторое время на выполнение операции над этим значением `sum`, а потом попытаются записать новое значение в `sum`, что может привести к перезаписи (а следовательно, к потере) значимого результата, как показано ниже: + + Поток A: читает значение sum, sum = 0 значение sum: 0 + Поток B: читает значение sum, sum = 0 значение sum: 0 + Поток A: увеличивает sum на 760, пишет sum = 760 значение sum: 760 + Поток B: увеличивает sum на 12, пишет sum = 12 значение sum: 12 + +Приведенный выше пример демонстрирует сценарий, где два потока успевают прочитать одно и то же значение, `0`, прежде чем один или другой из них успеет прибавить к этому `0` элемент из своего куска параллельной коллекции. В этом случае `Поток A` читает `0` и прибавляет к нему свой элемент, `0+760`, в то время, как `Поток B` прибавляет `0` к своему элементу, `0+12`. После того, как они вычислили свои суммы, каждый из них записывает свое значение в `sum`. Получилось так, что `Поток A` успевает записать значение первым, только для того, чтобы это помещенное в `sum` значение было практически сразу же перезаписано потоком `B`, тем самым полностью перезаписав (и потеряв) значение `760`. + +### Неассоциативные операции + +Из-за _"неупорядоченной"_ семантики, нелишней осторожностью становится требование выполнять только ассоциативные операции во избежание недетерминированности. То есть, если мы имеем параллельную коллекцию `pcoll`, нужно убедиться, что при вызове на `pcoll` функции более высокого уровня, такой как `pcoll.reduce(func)`, порядок, в котором `func` применяется к элементам `pcoll`, может быть произвольным. Простым и очевидным примером неассоциативной операции является вычитание: + + scala> val list = (1 to 1000).toList.par + list: scala.collection.parallel.immutable.ParSeq[Int] = ParVector(1, 2, 3,… + + scala> list.reduce(_-_) + res01: Int = -228888 + + scala> list.reduce(_-_) + res02: Int = -61000 + + scala> list.reduce(_-_) + res03: Int = -331818 + +В примере выше, мы берем `ParVector[Int]`, вызываем функцию `reduce`, и передаем ей `_-_`, которая просто берет два неименованных элемента, и вычитает один из другого. Вследствие того, что фреймворк параллельных коллекций порождает потоки и независимо выполняет `reduce(_-_)` на разных частях коллекции, результат двух запусков `reduce(_-_)` на одной и той же коллекции не будет одним и тем же. + +_Примечание:_ Часто возникает мысль, что так же, как и в случае с неассоциативными, некоммутативные операции, переданные в более высокую уровнем функцию на параллельной коллекции, приводят к недетеминированному поведению. Это неверно, простой пример -- конкатенация строк -- ассоциативная, но некоммутативная операция: + + scala> val strings = List("abc","def","ghi","jk","lmnop","qrs","tuv","wx","yz").par + strings: scala.collection.parallel.immutable.ParSeq[java.lang.String] = ParVector(abc, def, ghi, jk, lmnop, qrs, tuv, wx, yz) + + scala> val alphabet = strings.reduce(_++_) + alphabet: java.lang.String = abcdefghijklmnopqrstuvwxyz + +_"Неупорядоченная"_ семантика параллельных коллекций означает только то, что операции будут выполнены не по порядку (во _временном_ отношении. То есть, не последовательно), она не означает, что результат будет "*перемешан*" относительно изначального порядка (в _пространственном_ отношении). Напротив, результат будет практически всегда пересобран _по-порядку_-- то есть, параллельная коллекция, разбитая на части в порядке A, B, C, будет снова объединена в том же порядке A, B, C, а не в каком-то произвольном, например, B, C, A. + +Если требуется больше информации о том, как разделяются и комбинируются операции на различных типах коллекций, посетите раздел [Архитектура]({{ site.baseurl }}/ru/overviews/parallel-collections/architecture.html) этого руководства. + diff --git a/ru/overviews/parallel-collections/performance.md b/ru/overviews/parallel-collections/performance.md index 973e2b049b..d5bb68811a 100644 --- a/ru/overviews/parallel-collections/performance.md +++ b/ru/overviews/parallel-collections/performance.md @@ -1,4 +1,4 @@ ---- +--- layout: overview-large title: Измерение производительности