Clases
Las clases comparten algunas características con los objetos literales: definen variables de instancia y métodos. Pero no son expresiones (no pueden asignarse a variables), sino definiciones.
Veamos un ejemplo:
Instanciacion
Para crear un Ave instanciamos un objeto de esa clase con la palabra reservada new, la cual retorna un objeto de la clase Ave:
Al crear un objeto, se le puede dar valores iniciales a cada uno de sus atributos, para que el objeto que se obtiene quede completo y consistente. Entre los ( ) se indica el identificador de cada una de las referencias y su valor inicial. Como se indica el nombre de cada atributo, no es necesario mantener un orden en particular en el envío de parámetros.
Hace que pepita quede inicializada con 100 de energía.
Para las referencias de la clase que tienen un valor seteado por defecto es opcional enviar por parámetro el valor, en cambio para las referencias sin inicializar en la definición de la clase es obligatorio enviar por parámetro el valor inicial.
Herencia
Al definir una clase, se puede especificar que hereda de otra clase. A la nueva clase se la llama subclase y a la de cual se hereda, superclase. Esto permite que los objetos que se instancien de la subclase, además de tener los atributos y métodos definidos en ella, también cuenta con los definidos en la superclase.
Ejemplos:
Las subclases pueden agregar nuevos métodos y variables y pueden redefinir métodos existentes (para más información ver Redefinición y super).
Clases abstractas
Un método abstracto declara su nombre y sus parámetros, sin implementarse. Es tarea de cada subclase proveer una implementación del método mediante la redefinición
Para definir un método abstract en Wollok, simplemente no se escribe el cuerpo del método, sin ninguna palabra reservada.
Una clase con al menos un método abstracto se considera una clase abstracta. De nuevo, no hay ninguna palabra para indicar que una clase es abstracta, ya que es información que se puede inferir de la definición misma de la clase.
Redefinicion y super
Las subclases pueden redefinir métodos ya implementados por su superclase. Para ello, debe explícitamente usar la palabra “override” antes de la definición del método.
Si al redefinir un método necesitamos invocar al método original, lo podemos hacer mediante la palabra reservada super:
Como puede verse, no es necesario especificar el nombre del método. En Wollok solo puede invocarse al método sobreescrito usando super. No es posible usar super para llamar a cualquier otro método en la superclase (porque además conceptualmente no es correcto).
Esto mantiene simple el lenguaje.
De la misma manera, super solo puede utilizarse en el contexto de un método que redefine otro.
Herencia de Objetos
Los objetos autodefinidos pueden definirse en base a una clase existente.
Esto permite la migración natural de objetos a clases de un programa que inicialmente comienza con objetos y luego parte del comportamiento se muda a definiciones de clase para reutilizar código. A veces no es necesario convertir todos los objetos a clases, Wollok permite combinar ambos en conjunto.
Si la instanciación de la clase Dog requiere de parámetros, estos se inician en la definición del objeto, similar al new.
Polimorfismo
Wollok combina objetos y clases en un solo lenguaje. El polimorfismo con objetos que se instancian a partir de clases funciona de la misma manera que con los objetos autodefinidos. No importa si un objeto es instancia de una clase, está definido por si mismo o incluso si es un objeto anónimo, todos pueden ser potencialmente usados en forma polimórfica.
Dos o más objetos pueden usarse en forma polimórfica si todos entienden un conjunto común de mensajes
Entonces:
No es necesario tener una superclase común para objetos para ser tratados polimórficamente. Como se dijo antes, lo único importante son los mensajes que entienden los objetos. Olvídense de la clase, ¡podría ni siquiera tenerla!
Tanto las clases Avion como Ave son parte de diferentes jerarquías, pero sus instancias siguen siendo polimórficas para cualquier otro objeto que las quiera hacer volar.
De todas maneras, el compilador es capaz de chequear si el mensaje que enviamos es válido.
Como ya se dijo, puede haber polimorfismo entre objetos definidos de diferente manera:
Modularizacion
Wollok provee una serie de reglas y construcciones del lenguaje para fomentar programas modulares: separar clases y programas para ser usado por otros programas / bibliotecas.
Packages
Un package es una unidad lógica que agrupa varias clases y objetos.
Cuando se crea un archivo .wlk, el nombre del archivo define el nombre del package por defecto. Ejemplo: si creo un archivo aves.wlk, esto implica definir un package aves…
Un archivo Wollok puede definir más de un package
Cada package tiene un nombre (“aves”, “entrenadores”, etc.). Cada clase definida dentro toma el nombre del package como prefijo, lo que introduce el fully qualified name (FQN) de una clase.
Ejemplo:
El FQN de la clase es: aves.AveQueNada
Al codificar dentro de un package, podemos referirnos a las clases por su nombre corto (en el ejemplo, AveQueNada). Esto es válido mientras estemos dentro del mismo paquete.
Para referirnos a una clase que está fuera del package DEBEMOS usar su FQN. Para evitar escribir una y otra vez los FQN de la clase, podemos usar los imports, como se describe a continuación.
Imports
Para poder acceder a las definiciones de distintas clases, es necesario decirle a Wollok dónde encontrarlas mediante el mecanismo de imports. Por defecto cada archivo Wollok (.wlk) define un package, por lo que al importar definiciones de un archivo tenemos acceso a todos los packages contenidos en él.
Ejemplo: tenemos un archivo definiciones.wlk
En otro archivo objects.wlk podemos acceder a pepita mediante un import:
En el caso de tener varios packages en el mismo archivo, debemos hacer el import de cada uno de los packages involucrados. Si nuestro archivo definiciones.wlk tiene estos packages:
Entonces debemos cambiar nuestro import del archivo objects.wlk de la siguiente manera: