Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9:...

49
Tema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos (1) miércoles 11 de mayo de 2011 Referencias • Capítulo 9 PLP • Guia rápida sobre clases y objetos en la guía de Racket • Especificación del módulo de Classes and objects en el manual de Racket miércoles 11 de mayo de 2011

Transcript of Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9:...

Page 1: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Tema 9: Programación Orientada a Objetos

Sesión 26: Programación Orientada a Objetos (1)

miércoles 11 de mayo de 2011

Referencias

• Capítulo 9 PLP

• Guia rápida sobre clases y objetos en la guía de Racket

• Especificación del módulo de Classes and objects en el manual de Racket

miércoles 11 de mayo de 2011

Page 2: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Indice de hoy

• Ideas fundamentales de la POO

• POO en Racket

• Objetos y clases

• Herencia

• Interfaces

miércoles 11 de mayo de 2011

Programación Orientada a Objetos

• La Programación Orientada a Objetos es un paradigma de programación que explota en los 80 pero nace a partir de ideas a finales de los 60 y 70

• Smalltalk como lenguaje paradigmática de POO; desarrollado en Xerox Park a finales de los 70

• Alan Kay es el diseñador del Smalltalk y el creador el término “Object-Oriented”

• Artículo de Alan Kay:“The Early History of Smalltalk”,ACM SIGPLAN, March 1993

• Lenguajes POO: Smalltalk, Java, Ruby, Python, C#, C++ (si se usa con prudencia)

miércoles 11 de mayo de 2011

Page 3: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Alan Key

• “I invented the term Object-Oriented and I can tell you I did not have C++ in mind.”

• “Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term objects for this topic because it gets many people to focus on the lesser idea.The big idea is messaging.”

• “Smalltalk's design--and existence--is due to the insight that everything we can describe can be represented by the recursive composition of a single kind of behavioral building block that hides its combination of state and process inside itself and can be dealt with only through the exchange of messages.”

miércoles 11 de mayo de 2011

¿Interesados en SmallTalk?

• Visitar:

• http://www.squeak.org/

• http://swiki.agro.uba.ar/small_land

• http://www.squeakland.org

miércoles 11 de mayo de 2011

Page 4: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

El comienzo de la POO y de las interfaces de usuario: Ivan Sutherland y Sketchpad

• Vídeo en YouTube

miércoles 11 de mayo de 2011

Del paradigma imperativo al OO

• Programación procedural: estado abstracto (tipos de datos y barrera de abstracción) + funciones

• Siguiente paso: agrupar estado y funciones en una única entidad

• Los objetos son estas entidades

miércoles 11 de mayo de 2011

Page 5: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Algunas características POO

• Objetos (creados/instanciados en tiempo de ejecución) y clases (plantillas estáticas/tiempo de compilación)

• Los objetos agrupan estado y conducta (métodos) Los métodos se invocan mediante mensajes

• Dispatch dinámico: cuando una operación es invocada sobre un objeto, el propio objeto determina qué código se ejecuta. Dos objetos con la misma interfaz pueden tener implementaciones distintas.

• Herencia: las clases se pueden definir utilizando otras clases como plantillas y modificando sus métodos y/o variables de instancia.

miércoles 11 de mayo de 2011

Objeto

• Un objeto contiene un estado (atributos o variables de instancia) y un conjunto de funciones (métodos) que implementan las funcionalidades soportadas

• Al ejecutar un método, el objeto modifica su estado

• Pedimos a un objeto que ejecute un método lanzándole un mensaje

miércoles 11 de mayo de 2011

Page 6: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Clase

• Una clase es la plantilla que sirve para definir los objetos

• En una clase se define los elementos que componen el objeto (sus atributos o campos) y sus métodos

• En una clase también se pueden definir variables (variables de clase) compartidas por todos los objetos de esa clase

miércoles 11 de mayo de 2011

POO en Scheme

(require (lib "class.ss"))

(define persona% (class object% (init-field nombre nif) (field (apellidos null) (fecha-nacimiento null))

(define/public (di-hola) (printf "Hola, soy ~a~%" nombre))

(super-new)))

(define p1 (new persona% (nif '212121232) (nombre "Pepito")))(send p1 di-hola)

miércoles 11 de mayo de 2011

Page 7: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Sintaxis class

(class <super-clase> (init-field <var1> ... <varn>) (field (<var1> <valor1>) ... (<varn> <valorn>))

(define/public (<metodo> <args>) <cuerpo>)

(super-new <args>) <sentencias-inicializacion>)

miércoles 11 de mayo de 2011

Sintaxis new y paso de mensajes

(new <clase> (<arg1> <val1>) ... (<argn> <valn>))

(send <objeto> <metodo> <arg1> ... <argn>)

miércoles 11 de mayo de 2011

Page 8: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Herencia

• Al definir una clase hay que indicar la superclase que extiende

• La superclase por defecto es object%

• La clase hereda los métodos y atributos de la superclase: los objetos de la clase pueden ejecutar los métodos de la clase y los de la superclase

miércoles 11 de mayo de 2011

Invocación

• Todos los campos y métodos definidos en una clase pueden usarse directamente en los métodos de esa clase

• Los métodos de la superclase pueden invocarse desde el propio objeto utilizando (send this <metodo>)

• Los métodos y campos de la superclase pueden incluirse en el ámbito de la clase usando las palabras claves inherit y inherit-fields

miércoles 11 de mayo de 2011

Page 9: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo clase figura

• Definimos una clase figura% con el campo de inicialización nombre y los campos coord-inf-izq y coord-sup-der. Métodos: draw-bounding-box y los setters necesarios.

• Definimos una clase rectangulo% que extiende figura% con los campos de inicialización pos-xy, alto y ancho. Métodos: draw y area.

miércoles 11 de mayo de 2011

Ejemplo clase figura

(define figura% (class object% (init-field nombre) (field (coord-sup-izq null) (coord-inf-der null)) (define/public (get-nombre) nombre) (define/public (set-coords c1 c2) (set! coord-sup-izq c1) (set! coord-inf-der c2)) (define/public (draw-bounding-box) (let ((c1 coord-sup-izq) (c2 coord-inf-der)) (draw-solid-rect c1 (- (posn-x c2) (posn-x c1)) (- (posn-y c2) (posn-y c1))))) (super-new)))

miércoles 11 de mayo de 2011

Page 10: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

3 formas de definir la subclase rectangulo

• Ejemplo 1

(define rectangulo% (class figura% (init-field pos-xy alto ancho) (define/public (area) (* alto ancho)) (super-new) (send this set-coords pos-xy (make-posn (+ (posn-x pos-xy) ancho) (+ (posn-y pos-xy) alto)))))

miércoles 11 de mayo de 2011

3 formas de definir la subclase rectangulo

• Ejemplo 2

(define rectangulo% (class figura% (init-field pos-xy alto ancho) (inherit-field coord-sup-izq coord-inf-der) (define/public (area) (* alto ancho)) (super-new) (set! coord-sup-izq pos-xy) (set! coord-inf-der (make-posn (+ (posn-x pos-xy) ancho) (+ (posn-y pos-xy) alto)))))

miércoles 11 de mayo de 2011

Page 11: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

3 formas de definir la subclase rectangulo

• Ejemplo 3

(define rectangulo% (class figura% (init-field pos-xy alto ancho) (inherit set-coords) (define/public (area) (* alto ancho)) (super-new) (set-coords pos-xy (make-posn (+ (posn-x pos-xy) ancho) (+ (posn-y pos-xy) alto)))))

miércoles 11 de mayo de 2011

Relaciones entre objetos

• Las variables y parámetros guardan referencias a objetos

• Más de una variable puede referenciar al mismo objeto

• En la mayoría de lenguajes OO coexisten objetos y datos primitivos

• La semántica de la asignación en un dato primitivo es de copia y en objeto es de referencia

miércoles 11 de mayo de 2011

Page 12: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Relaciones entre objetos

(define persona% (class object% (init-field nombre) (field (apellidos null) (fecha-nacimiento null) (amigos null))

(define/public (es-amigo? otro) ;memq comprueba si otro está en amigos usando la igualdad eq? (if (memq otro amigos) #t #f))

(define/public (añade-amigo otro) (if (not (es-amigo? otro)) ; tambien es posible llamar a los métodos directamente (begin (set! amigos (cons otro amigos)) (send otro añade-amigo this))))

(define/public (saludan-amigos) (for-each (lambda (f) (send f di-hola)) amigos))

miércoles 11 de mayo de 2011

Relaciones entre objetos

(define/public (set-apellidos nuevos-apellidos) (set! apellidos nuevos-apellidos))

(define/public (set-fecha-nacimento fecha) (set! fecha-nacimiento fecha))

(define/public (get-nombre-completo) (if (not (null? apellidos)) (string-append nombre " " apellidos) nombre))

(define/public (di-hola) (define nombre-completo (send this get-nombre-completo)) (printf "hola, soy ~a~%" nombre-completo))

(super-new)))

(define nadal (new persona% (nombre "Rafa")))(define federer (new persona% (nombre "Roger")))(define djokovic (new persona% (nombre "Novak")))(send nadal añade-amigo federer)(send nadal añade-amigo djokovic)(send nadal saludan-amigos)(send federer saludan-amigos)

miércoles 11 de mayo de 2011

Page 13: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Herencia y polimorfismo

(define mago% (class persona% (init-field nombre-pila nivel-conjuro) (field (energia 100) (vida #t)) (inherit-field nombre)

(define/public (get-nivel-conjuro) nivel-conjuro)

(define/public (get-energia) energia)

(define/public (rayo) (set! energia (- energia 10)) (if (< 0 energia) (set! vida #f)))

(define/public (lanza-conjuro otro-mago) (define otro-nombre (send otro-mago get-nombre-completo)) (define nivel-otro (send otro-mago get-nivel-conjuro)) (printf "Yo, ~a, lanzo un conjuro a ~a~%" nombre otro-nombre) (if (< nivel-otro nivel-conjuro) (begin (send otro-mago rayo) (printf "Mi conjuro te ha alcanzado, ~a~%" otro-nombre)) (printf "~a, admito que eres más poderoso que yo" otro-nombre)))

(super-new (nombre (string-append "Mago " nombre-pila)))))

miércoles 11 de mayo de 2011

Herencia y polimorfismo

(define gandalf (new mago% (nombre-pila "Gandalf") (nivel-conjuro 100)))(define saruman (new mago% (nombre-pila "Saruman") (nivel-conjuro 90)))(send gandalf lanza-conjuro saruman)(send saruman lanza-conjuro gandalf)

(define enano% (class persona% (inherit-field nombre) ;; Reescritura de métodos (define/override (di-hola) (printf "Mmmm.. soy ~a y estoy hambriento!~%" nombre))

(super-new)))

(define frodo (new persona% (nombre "Frodo")))

(send frodo añade-amigo gandalf)(send frodo saludan-amigos)(send gandalf saludan-amigos)

(define gimli (new enano% (nombre "Gimli")))(send frodo añade-amigo gimli)(send frodo saludan-amigos)

miércoles 11 de mayo de 2011

Page 14: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Interfaz

• Una interfaz define un conjunto de métodos

• Cuando declaramos una clase que implementa una interfaz estamos obligados a implementar todos sus métodos

• Una interfaz no define una implementación (no podemos definir campos en una interfaz)

• Una clase puede implementar más de una interfaz, sin las ambiguedades de la herencia múltiple

miércoles 11 de mayo de 2011

Ejemplo clases geométricas

• Clase figura%:

(define figura% (class object% (init-field nombre) (field (coord-sup-izq null) (coord-inf-der null)) (define/public (get-nombre) nombre) (define/public (set-coords c1 c2) (set! coord-sup-izq c1) (set! coord-inf-der c2)) (define/public (print) (printf "[Figura ~a]\n" nombre)) (define/public (draw-bounding-box) (let ((c1 coord-sup-izq) (c2 coord-inf-der)) (draw-solid-rect c1 (- (posn-x c2) (posn-x c1)) (- (posn-y c2) (posn-y c1))))) (super-new)))

miércoles 11 de mayo de 2011

Page 15: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Tema 9: Programación Orientada a Objetos

Sesión 28: Programación Orientada a Objetos (2)

miércoles 18 de mayo de 2011

Referencias

• Programming in Scala, by Martin Odersky:

• Capítulo 4: Classes and Objects

• Capítulo 10: Composition and Inheritance

• Capítulo 12: Traits

• Capítulo 13, apartado 13.4: Access modifiers

miércoles 18 de mayo de 2011

Page 16: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Indice de hoy

• Objetos y clases en Scala

• Campos y métodos en Scala

• Herencia en Scala

• Modificadores

• Objetos Singleton

• Traits

miércoles 18 de mayo de 2011

Clases y objetos en Scala

• class para crear una clase y new para crear una instancia (objeto). Sintaxis:

• Ejemplo:

class Clase{ ... definición de la clase ... }

new Clase

class Pez{ def nadar() = println(“estoy nadando!”)}

var nemo = new Pez

nemo.nadarestoy nadando!

miércoles 18 de mayo de 2011

Page 17: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Campos y métodos en Scala

• Los campos (también llamados variables de instancia, porque cada instancia mantiene su propio conjunto de variables) mantienen el estado de los objetos. Se definen con val o var

• Los métodos modifican el estado de los objetos. Se definen con def

class Pez{ var nombre = “pez” def setNombre(n:String) = nombre = n def nadar() = println(“estoy nadando!”)}

var miPez = new PezmiPez.nombre --> String:pezmiPez.setNombre("Nemo")miPez.nombre --> String:Nemo

miércoles 18 de mayo de 2011

• ¿Qué pasa si defino la variable que contiene un objeto como val?¿Podré modificar el objeto al que referencia? ¿Por qué?

Clases y objetos en Scala

val otro = new Pez

otro.setNombre(“wanda”)

miércoles 18 de mayo de 2011

Page 18: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

• ¿Qué pasa si defino la variable que contiene un objeto como val?¿Podré modificar el objeto al que referencia? ¿Por qué?

Clases y objetos en Scala

val otro = new Pez

otro.setNombre(“wanda”)

nombre: ”pez”

otro“wanda”

miércoles 18 de mayo de 2011

Clases abstractas

• Como sabes, una clase abstracta puede tener alguno de sus miembros sin implementar. Además, es una clase que no se puede instanciar. Esto es coherente dado que una clase abstracta no tiene completa su implementación y encaja bien con la idea de que algo abstracto no puede materializarse.

• En Scala, se definen colocando el modificador abstract delante de class.

abstract class Figura{ var nombre: String var coordSupIzq : (Int,Int) var coordInfDer : (Int,Int) def print(): Unit def setCoords(c1:(Int,Int), c2:(Int,Int)) = { coordSupIzq = c1 coordInfDer = c2 }}

miércoles 18 de mayo de 2011

Page 19: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Métodos sin parámetros

• Ya hemos visto que en Scala se puede llamar a los métodos que no tienen parámetros de un objeto sin necesidad de los paréntesis de argumentos:

• A la hora de definir estos métodos también es posible hacerlo sin utilizar paréntesis de los argumentos:

nemo.nadarestoy nadando!

abstract class Figura{ ... def print(): Unit}

abstract class Figura{ ... def print: Unit}

miércoles 18 de mayo de 2011

Extendiendo clases

• En Scala se utiliza extends:

• La cláusula extends produce 2 efectos:

• Hace que la subclase herede todos los miembros (campos y métodos) no privados de la superclase

• Hace que la subclase sea un subtipo de la superclase.

• Si no se pone la cláusula extends, el compilador implícitamente asume que la clase extiende de scala.AnyRef (lo mismo que java.lang.object)

subClase extends superClase

miércoles 18 de mayo de 2011

Page 20: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Extendiendo clases (herencia). Ejemplo

class Rectangulo(name:String) extends Figura{ var nombre = name var coordSupIzq = (0,0) var coordInfDer = (0,0) def print():Unit = { println(“Coord 1: “ + coordSupIzq) println(“Coord 2: “ + coordInfDer) }}

var r1 = new Rectangulo("rec")r1: Rectangulo = Rectangulo@dd841

r1.setCoords((1,1),(20,20))

r1.printCoord 1: (1,1)Coord 2: (20,20)

Método implementado en la superclase

miércoles 18 de mayo de 2011

Extendiendo clases (jerarquía)

scalaAnyRef

“java.lang.object”

Figura“abstract”

Rectangulo

miércoles 18 de mayo de 2011

Page 21: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Más sobre métodos y campos: overriding de métodos y campos

• En Scala, los métodos y los campos se encuentran en el mismo namespace. Esto hace que sea posible que un campo sobreescriba un método sin parámetros:

• Por el mismo motivo, en Scala no está permitido definir un campo y un método con el mismo nombre en la misma clase (en Java sí que se puede):

abstract class Persona{ def misAmigos(): ListBuffer[String]}

//Javaclass Compila{ private int f = 0; public int f() { return 1; }}

//Scalaclass NoCompila{ private var f = 0 def f = 1}

class Mago(friends:ListBuffer[String]) extends Persona{ val misAmigos:ListBuffer[String] = friends}

miércoles 18 de mayo de 2011

Más sobre métodos y campos: namespaces

• Scala tiene dos namespaces mientras que Java tiene cuatro:

• Los namespaces de Java son: campos, métodos, tipos y paquetes

• Los namespaces de Scala son: valores (campos, métodos, paquetes y objetos singleton) y tipos (clases y traits)

• La razón de que Scala sólo tenga 2, es precisamente para que los métodos sin parámetro se puedan sobreescribir con un val.

miércoles 18 de mayo de 2011

Page 22: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Más sobre métodos y campos: definición de campos paramétricos

• Si volvemos a la definición de la clase Rectangulo, observamos que tiene un parámetro (name) cuyo único propósito es ser copiado al campo nombre:

• Podemos ahorrar código si combinamos el parámetro y el campo definiendo un campo paramétrico:

• De esta forma estamos definiendo al mismo tiempo un parámetro y un campo con el mismo nombre

class Rectangulo(name:String) extends Figura{ val nombre = name ... }

class Rectangulo(val nombre:String) extends Figura{ ... }

miércoles 18 de mayo de 2011

Modificadores

• override: es necesario en aquellos miembros que sobrescriben un miembro en concreto de la superclase. Es opcional si la superclase es abstracta y no tiene implementado ese miembro.

• private: funcionan como en Java, sólo son los miembros privados sólo son visibles dentro de la clase u objeto que contienen la definición del miembro. Por defecto todos los miembros son públicos.

• También se pueden añadir modificadores a los campos paramétricos:

class Gato{ val peligroso = false }

class Tigre( override val peligroso: Boolean, private var edad: Int ) extends Gato

miércoles 18 de mayo de 2011

Page 23: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Modificador final

• Funciona como en Java, cuando en una jerarquía de herencia, queremos asegurarnos que una subclase no pueda sobreescribir un miembro determinado. Se añade el modificador final delante del miembro.

• Por ejemplo, si no queremos que la subclase Rectangulo sobreescriba el método setCoords de Figura:

abstract class Figura{ var nombre: String var coordSupIzq : (Int,Int) var coordInfDer : (Int,Int) def print(): Unit final def setCoords(c1:(Int,Int), c2:(Int,Int)) = { coordSupIzq = c1 coordInfDer = c2 }}

miércoles 18 de mayo de 2011

Object

• La palabra object define un objeto singleton, una única instancia de una clase dada. Por si mismo, no define un tipo.

• Los objetos singleton no pueden tener argumentos ya que para crearlos no se llama a new (la propia definición de object lo crea).

• Se define igual que una clase, pero en lugar de la palabra clave class se usa object.

object Nombre{ ... definición ...}

object FiguraMath { val pi = 3.14159 def cuadrado(x: Int) = x * x def abs(x: Int) = if (x < 0) x * (-1)}

FiguraMath.abs(-4)def area (c:Circulo) = FiguraMath.cuadrado(c.radio) * (2 * FiguraMath.pi)

miércoles 18 de mayo de 2011

Page 24: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Objetos Singleton para crear aplicaciones

• Hasta el momento, en Scala hemos trabajado directamente en el intérprete o creando scripts (que no han dejado de ser expresiones evaluadas).

• Para ejecutar un programa en Scala, se debe definir un objeto singleton que contenga el método main.

• El método main toma un Array[String] como argumento y es de tipo Unit.

miércoles 18 de mayo de 2011

Objetos Singleton para crear aplicaciones

• Ejemplo, creamos el fichero Formas.scala (el nombre del fichero debe ser el mismo que el nombre de la aplicación, es decir, del objeto singleton):

abstract class Figura{ var nombre: String var coordSupIzq : (Int,Int) var coordInfDer : (Int,Int) def print(): Unit def setCoords(c1:(Int,Int), c2:(Int,Int)) = { coordSupIzq = c1 coordInfDer = c2 }}

class Rectangulo(name:String) extends Figura{ var nombre = name var coordSupIzq = (0,0) var coordInfDer = (0,0) def print():Unit = { println("Coord 1: " + coordSupIzq) println("Coord 2: " + coordInfDer) }}

object Formas{ def main (args: Array[String])={ val rec = new Rectangulo("rec1") rec.setCoords((5,5),(98,77)) rec.print } }

> scalac Formas.scala> scala FormasCoord 1: (5,5)Coord 2: (98,77)

miércoles 18 de mayo de 2011

Page 25: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

El trait Application

• Scala proporciona un trait llamado scala.Application. Este trait tiene declarado el método main, por lo que si lo extiende un objeto singleton, se puede usar como una aplicación de Scala directamente: se puede compilar y usar como cualquier otra aplicación donde se haya definido el método main dentro de un objeto singleton. Ejemplo:

object Formas extends Application{ val rec = new Rectangulo("rec1") rec.setCoords((5,5),(98,77)) rec.print}

> scalac Formas.scala> scala FormasCoord 1: (5,5)Coord 2: (98,77)

miércoles 18 de mayo de 2011

Traits

• Un trait encapsula definiciones de métodos y campos, que se pueden reutilizar mezclándolos dentro de clases. A diferencia de la herencia, donde una clase sólo puede heredar de una superclase, una clase puede mezclar cualquier número de traits.

• Se podría considerar que un trait es como una interfaz en Java con métodos concretos. Pero además los traits pueden declarar campos y mantener estado. Un trait define un nuevo tipo. Se consideran como interfaces de Java enriquecidas.

• Se definen como una clase sustituyendo la palabra clave class por trait.

trait Rectangular { def coordSupIzq: (Int,Int) def coordInfDer: (Int,Int) def izq = coordSupIzq._1 def der = coordInfDer._2 def ancho = der - izq }

miércoles 18 de mayo de 2011

Page 26: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Traits

• Para que una clase utilice (mezcle) un trait, se puede poner de dos formas:

• Si se utiliza extends, significa que hereda implícitamente de la superclase del trait (en el ejemplo, será AnyRef) y la mezcla con el trait, heredando sus métodos:

• Si se quiere mezclar un trait en un clase que explícitamente extiende una superclase, se usa extends para indicar la superclase y se utiliza with para mezclar en el trait.

class Rectangulo extends Rectangular{ ...}

class Rectangulo extends Figura with Rectangular{ ...}

miércoles 18 de mayo de 2011

Ejemplo completo figuras geométricas

abstract class Figura { val nombre: String def print(): Unit def DrawBoundingBox():Unit}

trait Rectangular { def coordSupIzq: (Int,Int) def coordInfDer: (Int,Int) def izq = coordSupIzq._1 def der = coordInfDer._2 def ancho = der - izq }class Rectangulo(val nombre:String, var coordSupIzq:(Int,Int), var coordInfDer:(Int,Int)) extends Figura with Rectangular { def print():Unit = { println("Rectangulo: "+ nombre) println("Coord 1: " + coordSupIzq) println("Coord 2: " + coordInfDer) } def DrawBoundingBox():Unit = { print println("BoundingBox: ") println("Punto Sup Izq: " + coordSupIzq) println("Punto Inf Der: " + coordInfDer) }}

class Circulo(val nombre:String, var centro:(Int,Int), var radio:Int) extends Figura { def print():Unit = { println("Circulo: " + nombre) println("Centro: " + centro) println("Radio: " + radio) } def DrawBoundingBox():Unit = { print println("BoundingBox: ") println("Punto Sup Izq:" + (centro._1-radio, centro._2-radio)) println("Punto Inf Der: "+ (centro._1+radio, centro._2+radio)) }}

object Geom extends Application { val rec = new Rectangulo("rec1",(5,5),(45,67)) val cir = new Circulo("cir1",(20,20),12) rec.izq rec.der rec.ancho rec.DrawBoundingBox cir.DrawBoundingBox}

miércoles 18 de mayo de 2011

Page 27: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo completo figuras geométricas

• Lo grabamos en el fichero Geom.scala y lo probamos:

>scalac Geom.scala>scala GeomRectangulo: rec1Coord 1: (5,5)Coord 2: (45,67)BoundingBox: Punto Sup Izq: (5,5)Punto Inf Der: (45,67)Circulo: cir1Centro: (20,20)Radio: 12BoundingBox: Punto Sup Izq:(8,8)Punto Inf Der: (32,32)

miércoles 18 de mayo de 2011

Ejemplo queue

• Lo probamos:

import scala.collection.mutable.ListBuffer

abstract class IntQueue{ def get(): Int def put(x: Int)}

class BasicIntQueue extends IntQueue { private val buf = new ListBuffer[Int] def get() = buf.remove(0) def put(x:Int) = buf += x}

scala> val cola = new BasicIntQueuescala> cola.put(10)scala> cola.put(20)scala> cola.get()res2: Int = 10scala> cola.get()res3: Int = 20

miércoles 18 de mayo de 2011

Page 28: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo queue con traits

• Ahora vamos a usar traits para modificar su comportamiento (vamos a hacer modificaciones apilables):

• El trait Doubling hace dos cosas muy interesantes:

• Declara como superclase IntQueue. Esta declaración hace que el trait sólo pueda ser mezclado en una clase que también extienda IntQueue.

• El trait tiene una llamada super a un método declarado abstracto. En una clase normal sería ilegal, pero es posible en un trait; los modificadores abstract override (sólo admitidos en los métodos de los traits) indican que el trait se debe mezclar en alguna clase que tenga la definición concreta del método.

trait Doubling extends IntQueue { abstract override def put(x:Int) = super.put(2 * x)}

miércoles 18 de mayo de 2011

Ejemplo queue con traits

• Lo probamos:

• Fíjate que la clase MiCola no define código nuevo, sólo mezcla una clase con un trait. En esta situación, se podría hacer el new directamente:

class MiCola extends BasicIntQueue with Doubling

scala> val cola = new MiColascala> cola.put(10)scala> cola.get()res2: Int = 20

scala> val cola = new BasicIntQueue with Doublingscala> cola.put(10)scala> cola.get()res2: Int = 20

miércoles 18 de mayo de 2011

Page 29: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo queue con traits

• Añadimos dos nuevos traits:

• Ahora, podemos elegir aquellas modificaciones que queramos para una determinada cola. Por ejemplo, definimos una cola que filtra números negativos y añade uno a todos los números que almacena:

trait Incrementing extends IntQueue { abstract override def put(x:Int) = super.put(x + 1)}trait Filtering extends IntQueue { abstract override def put(x:Int) = if (x >= 0) super.put(x)}

scala> val cola = new BasicIntQueue with Incrementing with Filteringscala> cola.put(-1)scala> cola.put(0)scala> cola.put(1)scala> cola.get()res2: Int = 1scala> cola.get()res3: Int = 2

miércoles 18 de mayo de 2011

Mixins

• El orden de los mixins (cuando un trait se mezcla con una clase, se le puede llamar mixin) es significante. Van de derecha a izquierda. Cuando se llama a un método de una clase con mixins, se llama primero al método del trait más a la derecha. Si ese método a su vez llama a super, invocará al método del siguiente trait a su izquierda.

• En el ejemplo anterior, primero se invoca al put de Filtering, de forma que se eliminan los enteros negativos y se añade uno a aquellos que no se han eliminado. Si invertimos el orden primero se incrementarán los enteros y entonces los enteros que todavía son negativos se descartarán:scala> val cola = new BasicIntQueue with Filtering with Incrementingscala> cola.put(-1)scala> cola.put(0)scala> cola.put(1)scala> cola.get()res2: Int = 0scala> cola.get()res3: Int = 1scala> cola.get()res3: Int = 2

miércoles 18 de mayo de 2011

Page 30: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo clases geométricas

• Interfaces dibujable% y printable%

(define dibujable% (interface () draw))(define printable% (interface () print))

(define circulo% (class* figura% (dibujable% printable%) ;; por que no da error? ;; dónde está la ;;implementación de print? (init-field centro radio) (inherit set-coords) (define/public (area) (* 3.14159 radio radio)) (define/public (draw) (draw-solid-disk centro radio 'red)) (super-new) (set-coords (make-posn (- (posn-x centro) radio) (- (posn-y centro) radio)) (make-posn (+ (posn-x centro) radio) (+ (posn-y centro) radio)))))

miércoles 11 de mayo de 2011

Ejemplo completo (herencia e interfaces): stack

miércoles 11 de mayo de 2011

Page 31: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo completo (herencia e interfaces): stack

(define i-stack% (interface () push! pop! is-empty?))

(define stack% (class* object% (i-stack%) (init-field (name 'stack)) (field (stack null))

(define/public (push! v) (set! stack (cons v stack)))

(define/public (pop!) (let ((v (car stack))) (set! stack (cdr stack)) v))

(define/public (is-empty?) (null? stack))

(define/public (print-name) (display name) (newline))

(super-new)))

miércoles 11 de mayo de 2011

Ejemplo completo (herencia e interfaces): stack

(define fancy-stack% (class stack% (inherit-field name)

(define/override (push! v) (super push! (cons 'fancy v)))

(super-new)))

(define double-stack% (class stack% (inherit push!)

(define/public (double-push! v) (push! v) (push! v))

(super-new (name 'double-stack))))

(define safe-stack% (class stack% (inherit is-empty?)

(define/override (pop!) (if (is-empty?) #f (super pop!)))

(super-new)))

miércoles 11 de mayo de 2011

Page 32: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo completo (herencia e interfaces): stack

(define i-extended-stack% (interface (i-stack%) size))

(define extended-stack% (class* safe-stack% (i-extended-stack%) (inherit-field stack)

(define/public (size) (length stack))

(super-new)))

miércoles 11 de mayo de 2011

Page 33: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Tema 9: Programación Orientada a Objetos

Sesión 29: Programación Orientada a Objetos (3)

martes 24 de mayo de 2011

Referencias

• Programming in Scala, by Martin Odersky: capítulo 30 (Actors and Concurrency)

martes 24 de mayo de 2011

Page 34: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Indice de hoy

• Ejemplo polimorfismo en tiempo de ejecución

• Traits

• Actores y paso de mensajes

martes 24 de mayo de 2011

Polimorfismo en tiempo de ejecución

abstract class Animal { def diAlgo(): Unit}

class Perro extends Animal { def diAlgo() = { println("Guau!!") }}

class Gato extends Animal { def diAlgo () = { println("Miau!!") }}

var animales: List[Animal] = List(new Perro, new Perro, new Gato)for (a <- animales) a.diAlgo

Guau!!Guau!!Miau!!

martes 24 de mayo de 2011

Page 35: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Especializando un objeto de una clase concreta

• Supongamos que la clase derivada añade algún comportamiento a la clase padre. Por ejemplo, definimos el método limpiate() en la clase Gato y el método traePalo() en la clase Perro:

class Perro extends Animal { def diAlgo() = { println("Guau!!") } def traePalo() = { println("Tírame el palo") }}

class Gato extends Animal { def diAlgo () = { println("Miau!!") } def limpiate() = { println("Me estoy acicalando") }}

martes 24 de mayo de 2011

Especializando un objeto de una clase concreta

• Los métodos sólo los podremos llamar en variables de cada clase

• Por ejemplo, supongamos que guardamos en una variable del tipo de la clase padre (Animal) un objeto de la clase derivada (Gato o Perro). Sería un error llamar al método definido en la clase derivada. También es un error asignarlo a una variable del tipo derivado:

var a: Animal = new Gato

// Error, método no definido en Animal:a.limpiate()// Error, type mismatch:var g: Gato = a

martes 24 de mayo de 2011

Page 36: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Especializando un objeto de una clase concreta

• Podemos hacerlo, sin embargo, si convertimos la variable en otra del tipo original. Scala define el método asInstanceOf para ello:

• También se puede utilizar una sentencia match para identificar el tipo de animal:

a.asInstanceOf[Gato].limpiate

var a: Animal = new Gatoa match { case g: Gato => g.limpiate() case p: Perro => p.traePalo()}me estoy acicalando

martes 24 de mayo de 2011

Traits

• Un trait encapsula definiciones de métodos y campos, que se pueden reutilizar mezclándolos dentro de clases. A diferencia de la herencia, donde una clase sólo puede heredar de una superclase, una clase puede mezclar cualquier número de traits.

• Se podría considerar que un trait es como una interfaz en Java con métodos concretos. Pero además los traits pueden declarar campos y mantener estado. Un trait define un nuevo tipo. Se consideran como interfaces de Java enriquecidas.

• Se definen como una clase sustituyendo la palabra clave class por trait.

trait Rectangular { def coordSupIzq: (Int,Int) def coordInfDer: (Int,Int) def izq = coordSupIzq._1 def der = coordInfDer._2 def ancho = der - izq }

martes 24 de mayo de 2011

Page 37: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Traits

• Para que una clase utilice (mezcle) un trait, se puede poner de dos formas:

• Si se utiliza extends, significa que la clase hereda implícitamente de la superclase AnyRef y la mezcla con el trait, heredando sus métodos.

• Si se quiere mezclar un trait en un clase que explícitamente extiende una superclase, se usa extends para indicar la superclase y se utiliza with para mezclar en el trait.

class Rectangulo extends Rectangular{ ...}

class Rectangulo extends Figura with Rectangular{ ...}

martes 24 de mayo de 2011

Ejemplo completo figuras geométricas

abstract class Figura { val nombre: String def print(): Unit def DrawBoundingBox():Unit}

trait Rectangular { def coordSupIzq: (Int,Int) def coordInfDer: (Int,Int) def izq = coordSupIzq._1 def der = coordInfDer._2 def ancho = der - izq }class Rectangulo(val nombre:String, var coordSupIzq:(Int,Int), var coordInfDer:(Int,Int)) extends Figura with Rectangular { def print():Unit = { println("Rectangulo: "+ nombre) println("Coord 1: " + coordSupIzq) println("Coord 2: " + coordInfDer) } def DrawBoundingBox():Unit = { print println("BoundingBox: ") println("Punto Sup Izq: " + coordSupIzq) println("Punto Inf Der: " + coordInfDer) }}

class Circulo(val nombre:String, var centro:(Int,Int), var radio:Int) extends Figura { def print():Unit = { println("Circulo: " + nombre) println("Centro: " + centro) println("Radio: " + radio) } def DrawBoundingBox():Unit = { print println("BoundingBox: ") println("Punto Sup Izq:" + (centro._1-radio, centro._2-radio)) println("Punto Inf Der: "+ (centro._1+radio, centro._2+radio)) }}

object Geom extends Application { val rec = new Rectangulo("rec1",(5,5),(45,67)) val cir = new Circulo("cir1",(20,20),12) rec.izq rec.der rec.ancho rec.DrawBoundingBox cir.DrawBoundingBox}

martes 24 de mayo de 2011

Page 38: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo completo figuras geométricas

• Lo grabamos en el fichero Geom.scala y lo probamos:

>scalac Geom.scala>scala GeomRectangulo: rec1Coord 1: (5,5)Coord 2: (45,67)BoundingBox: Punto Sup Izq: (5,5)Punto Inf Der: (45,67)Circulo: cir1Centro: (20,20)Radio: 12BoundingBox: Punto Sup Izq:(8,8)Punto Inf Der: (32,32)

martes 24 de mayo de 2011

Ejemplo queue

• Lo probamos:

import scala.collection.mutable.ListBuffer

abstract class IntQueue{ def get(): Int def put(x: Int)}

class BasicIntQueue extends IntQueue { private val buf = new ListBuffer[Int] def get() = buf.remove(0) def put(x:Int) = buf += x}

scala> val cola = new BasicIntQueuescala> cola.put(10)scala> cola.put(20)scala> cola.get()res2: Int = 10scala> cola.get()res3: Int = 20

martes 24 de mayo de 2011

Page 39: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo queue con traits

• Ahora vamos a usar traits para modificar su comportamiento (vamos a hacer modificaciones apilables):

• El trait Doubling hace dos cosas muy interesantes:

• Declara como superclase IntQueue. Esta declaración hace que el trait sólo pueda ser mezclado en una clase que también extienda IntQueue.

• El trait tiene una llamada super a un método declarado abstracto. En una clase normal sería ilegal, pero es posible en un trait; los modificadores abstract override (sólo admitidos en los métodos de los traits) indican que el trait se debe mezclar en alguna clase que tenga la definición concreta del método.

trait Doubling extends IntQueue { abstract override def put(x:Int) = super.put(2 * x)}

martes 24 de mayo de 2011

Ejemplo queue con traits

• Lo probamos:

• Fíjate que la clase MiCola no define código nuevo, sólo mezcla una clase con un trait. En esta situación, se podría hacer el new directamente:

class MiCola extends BasicIntQueue with Doubling

scala> val cola = new MiColascala> cola.put(10)scala> cola.get()res2: Int = 20

scala> val cola = new BasicIntQueue with Doublingscala> cola.put(10)scala> cola.get()res2: Int = 20

martes 24 de mayo de 2011

Page 40: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo queue con traits

• Añadimos dos nuevos traits:

• Ahora, podemos elegir aquellas modificaciones que queramos para una determinada cola. Por ejemplo, definimos una cola que filtra números negativos y añade uno a todos los números que almacena:

trait Incrementing extends IntQueue { abstract override def put(x:Int) = super.put(x + 1)}trait Filtering extends IntQueue { abstract override def put(x:Int) = if (x >= 0) super.put(x)}

scala> val cola = new BasicIntQueue with Incrementing with Filteringscala> cola.put(-1)scala> cola.put(0)scala> cola.put(1)scala> cola.get()res2: Int = 1scala> cola.get()res3: Int = 2

martes 24 de mayo de 2011

Mixins

• El orden de los mixins (cuando un trait se mezcla con una clase, se le puede llamar mixin) es significante. Van de derecha a izquierda. Cuando se llama a un método de una clase con mixins, se llama primero al método del trait más a la derecha. Si ese método a su vez llama a super, invocará al método del siguiente trait a su izquierda.

• En el ejemplo anterior, primero se invoca al put de Filtering, de forma que se eliminan los enteros negativos y se añade uno a aquellos que no se han eliminado. Si invertimos el orden primero se incrementarán los enteros y entonces los enteros que todavía son negativos se descartarán:scala> val cola = new BasicIntQueue with Filtering with Incrementingscala> cola.put(-1)scala> cola.put(0)scala> cola.put(1)scala> cola.get()res2: Int = 0scala> cola.get()res3: Int = 1scala> cola.get()res3: Int = 2

martes 24 de mayo de 2011

Page 41: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Modelo de concurrencia de Java

• Concurrencia: sucede cuando distintos procesos se ejecutan simultáneamente y pueden interactuar unos con otros.

• El modelo de Java para manejo de concurrencia está basado en threads (hilos de ejecución), mediante el bloqueo de datos compartidos.

• Para usar este modelo, el programador decide qué datos se compartirán por los threads y los marca como synchronized

• El mecanismo de bloqueo asegura que sólo un thread en un momento determinado entra en las secciones sincronizadas y tiene acceso a los datos compartidos.

• Complicado crear aplicaciones robustas multi-thread.

martes 24 de mayo de 2011

Problemas modelo de concurrencia de Java

• En cada punto del programa, se obliga a razonar qué datos se están modificando o pueden ser accedidos o modificados por otros threads, y qué bloqueos se deben mantener.

• Son muy complicadas también las pruebas de código multi-thread, ya que los threads son indeterministas.

• Java no controla los interbloqueos (sucede cuando 2 ó más threads no pueden ejecutarse porque están esperando la liberación de algún recurso compartido), por lo que es responsabilidad del diseñador el evitarlo.

• Java 5 introduce java.util.concurrent, una librería que proporciona abstracciones de alto nivel para manejar multi-threads, pero aún así también están basadas en el modelo de datos compartidos y bloqueos, por lo que no resuelve los problemas.

martes 24 de mayo de 2011

Page 42: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Actores y paso de mensajes

• Scala proporciona una alternativa basada en un modelo de paso de mensajes, más fácil de programar ya que no hay datos compartidos (y por tanto no tenemos el problema de los interbloqueos ni de las condiciones de carrera).

• Un actor es una entidad similar a un thread que dispone de un buzón para recibir mensajes.

• Para implementar un actor, se debe extender la clase scala.actors.Actor e implementar el método act.

martes 24 de mayo de 2011

Actores

• Ejemplo:

• Activamos un actor invocando al método start:

import scala.actors._

class SillyActor extends Actor { def act() { for (i <- 1 to 5) { println("Estoy actuando!") Thread.sleep(1000) } }}

scala>val actor = new SillyActorscala> actor.start() SillyActor.start()res1: scala.actors.Actor = SillyActor$@759f31descala> Estoy actuando!Estoy actuando!Estoy actuando!Estoy actuando!Estoy actuando!

martes 24 de mayo de 2011

Page 43: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Actores

• Fíjate que en el ejemplo anterior, la salida “Estoy actuando!” está intercalada con la salida del shell de Scala. Esto es debido a que la ejecución del actor SillyActor corre independientemente del thread del shell.

• La ejecución de los actores es independiente de unos a otros también. Ejemplo:

import scala.actors._

class SeriousActor extends Actor { def act() { for (i <- 1 to 5) { println("Ser o no ser.") Thread.sleep(1000) } }}

martes 24 de mayo de 2011

Actores

• Podemos ejecutar los dos actores al mismo tiempo:

var a = new SillyActorvar b = new SeriousActor

a.start; b.startscala> Estoy actuando!

scala> Ser o no ser.Estoy actuando!Ser o no ser.Estoy actuando!Ser o no ser.Estoy actuando!Ser o no ser.Estoy actuando!Ser o no ser.

martes 24 de mayo de 2011

Page 44: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Actores

• Otra manera de crear un actor es usando un método llamado actor en el objeto scala.actors.Actor:

• Esta definición crea un actor que ejecuta las acciones definidas en el bloque que sigue al método actor. El actor empieza inmediatamente cuando se define, no se necesita llamar al método start.

import scala.actors.Actor._

val seriousActor2 = actor { for (i <- 1 to 5) println(“Esa es la cuestión.”) Thread.sleep(1000)}

scala> Esa es la cuestión.Esa es la cuestión.Esa es la cuestión.Esa es la cuestión.Esa es la cuestión.

martes 24 de mayo de 2011

Comunicación entre actores: mensajes

• Ya hemos creado actores que se ejecutan independientemente unos de otros.

• ¿Cómo pueden trabajar juntos? ¿Cómo se pueden comunicar sin compartir memoria y sin bloqueos?

• Los actores se comunican enviándose mensajes.

• Se puede enviar un mensaje usando el método !

• Vemos que no sucede nada, porque SillyActor está ocupado “actuando”, por lo que sus mensajes quedan guardados en su buzón sin leer.

SillyActor ! “hola”

martes 24 de mayo de 2011

Page 45: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

receive

• Vamos a definir un actor que espere mensajes en su buzón e imprima lo que recibe.

• Se recibe un mensaje llamando a la función parcial receive (una función parcial es como una expresión match sin la palabra clave match):

import scala.actors.Actor._

val echoActor = actor { while(true) { receive { case msg => println(“Mensaje recibido: “+ msg) } }}

martes 24 de mayo de 2011

Recibiendo mensajes

• Cuando un actor envía un mensaje, no se bloquea, y cuando un actor recibe un mensaje, no se interrumpe.

• El mensaje enviado se queda en espera en el buzón del actor receptor hasta que el actor llame a receive.

scala> echoActor ! "hola"Mensaje recibido: hola

scala> echoActor ! 15Mensaje recibido: 15

martes 24 de mayo de 2011

Page 46: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Los mensajes son asíncronos

• Cuando un actor envía un mensaje no se queda esperando el resultado, sino que continúa su proceso

• Esto se denomina comunicación asíncrona

• Una invocación a una función o a un método es síncrona: el flujo de ejecución del objeto llamador se detiene hasta que la función devuelve un resultado

• Los mensajes se almacenan en una cola (buzón) en el actor receptor

• El receptor no interrumpe la ejecución de su proceso; sino que lee los mensajes cuando ejecuta un receive

martes 24 de mayo de 2011

Recibiendo mensajes: mensajes con tipo

• Un actor puede esperar mensajes de un tipo en concreto, especificándolo en el tipo del case.

• Por ejemplo, un actor que sólo espera mensajes de tipo Int:

• Si recibe mensajes de otro tipo, los ignora.

import scala.actors.Actor._

val intActor = actor { receive { case x: Int => println(“Tengo un Int: “+ x) }}

scala> intActor ! “hola”scala> intActor ! scala.math.Piscala> intActor ! 12scala> Tengo un Int: 12

martes 24 de mayo de 2011

Page 47: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Depurando actores

• Cuando llamamos al método Thread.sleep, fíjate que invocamos al método sleep de la clase Thread, eso es porque un actor no es más que un hilo de ejecución.

• Si quisiéramos ver el thread actual como un actor, deberíamos usar Actor.self. Es muy útil para depurar actores. Ejemplo:

• El método receive devuelve el valor computado por la función parcial. En este caso, devuelve el mensaje pasado.

scala> import scala.actors.Actor._import scala.actors.Actor._scala> self ! "hola"scala> self ! 3scala> self.receive { case x => x}res13: Any = hola

martes 24 de mayo de 2011

Depurando actores

• También se puede usar una variante de receive llamada receiveWithin, al que se le puede pasar un timeout en milisegundos.

• Si usas receive en el shell del intérprete, entonces receive bloqueará el shell hasta que llegue un mensaje. En el caso de self.receive, esa espera podría no terminar nunca. Con receiveWithin, se espera un determinado timeout.

scala> self.receiveWithin(1000) { case x => x } // espera 1 segundo!res7: Any = TIMEOUT

martes 24 de mayo de 2011

Page 48: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo completo

• Definimos dos actores que intercambian una serie de mensajes y luego finalizan. El primer actor envía mensajes “ping” al segundo actor, que como respuesta envía mensajes “pong” (por cada mensaje “ping” recibido, un mensaje “pong”).

• El actor ping comienza el intercambio de mensajes. Cuando el actor ping ha enviado un determinado número de mensajes, envía un mensaje Stop al actor pong.

• Ambos actores los definimos como subclases de Actor porque queremos pasarles argumentos a sus constructores.

• Para terminar la ejecución de un actor invocamos a exit().

martes 24 de mayo de 2011

Ejemplo completo

import scala.actors.Actorimport scala.actors.Actor._

class Ping(count: Int, pong: Actor) extends Actor { def act() { var pingsQuedan = count - 1 println("Ping envía Ping") pong ! "Ping" while (true) { receive { case "Pong" => if (pingsQuedan > 0) { println("Ping envía Ping") pong ! "Ping" pingsQuedan -= 1 } else { println("Ping envía Stop") pong ! "Stop" println("Ping stops") exit() } } } }}

class Pong extends Actor { def act() { while (true) { receive { case "Ping" => println("Pong envía Pong") sender ! "Pong" case "Stop" => println("Pong stops") exit() } } }}

object PingPong extends Application { val pong = new Pong val ping = new Ping(5, pong) ping.start pong.start}

martes 24 de mayo de 2011

Page 49: Tema 9: Programación Orientada a Objetosrua.ua.es/dspace/bitstream/10045/19672/10/tema9.pdfTema 9: Programación Orientada a Objetos Sesión 26: Programación Orientada a Objetos

Ejemplo completo

• Lo probamos:

> scalac PingPong.scala> scala PingPongPong: PongPing: PingPong: PongPing: PingPong: PongPing: PingPong: PongPing: PingPong: PongPing: stopPong: stop

martes 24 de mayo de 2011