Sei sulla pagina 1di 76

PDF generado usando el kit de herramientas de fuente abierta mwlib. Ver http://code.pediapress.com/ para mayor informacin.

PDF generated at: Sat, 10 Nov 2012 15:34:35 UTC


Programacin en Vala
Contenidos
Artculos
Programacin en Vala 1
Introduccin 3
Su primer programa en Vala 4
Conceptos bsicos del lenguaje 6
Programacin orientada a objetos en Vala 26
Funcionalidades avanzadas del lenguaje 41
Funcionalidades experimentales del lenguaje 63
Bibliotecas del lenguaje 65
Herramientas 66
Otras tcnicas 69
Referencias
Fuentes y contribuyentes del artculo 72
Fuentes de imagen, Licencias y contribuyentes 73
Licencias de artculos
Licencia 74
Programacin en Vala
1
Programacin en Vala
Prlogo
Este libro pretende ser un manual de iniciacin al lenguaje de programacin Vala
[1]
. Este documento es
principalmente una traduccin del documento original
[2]
, aunque tambin aportar material propio.
ndice
1. 1. Introduccin
1. 1. Qu es Vala?
2. 2. A quin va dirigido este libro?
3. 3. Convenciones del lenguaje
2. 2. Su primer programa en Vala
1. 1. Compilado y ejecucin del programa
3. 3. Conceptos bsicos del lenguaje
1. 1. Archivos de cdigo y compilacin
2. 2. Visin general de la sintaxis
3. 3. Comentarios
4. 4. Tipos de datos
1. 1. Constantes
2. 2. Tipos bsicos
3. 3. Cadenas
4. 4. Vectores
5. 5. Referencias
6. 6. Conversin esttica de tipos
7. 7. Conversin dinmica de tipos (Inferencia)
5. 5. Operadores
6. 6. Estructuras de control
1. 1. Bucles
2. 2. Estructuras de control condicionales
7. 7. Elementos del lenguaje
1. 1. Mtodos
2. 2. Mtodos delegados
3. 3. Mtodos annimos (Clausura/Closure)
4. 4. Espacios de nombres
5. 5. Estructuras
6. 6. Clases
7. 7. Interfaces
8. 8. Atributos del cdigo
4. 4. Programacin orientada a objetos en Vala
1. 1. Cdigo bsico
2. 2. Constructores
3. 3. Destructores
4. 4. Seales
5. 5. Propiedades
Programacin en Vala
2
6. 6. Herencia
7. 7. Clases abstractas
8. 8. Interfaces/Mixins
9. 9. Polimorfismo
10. 10. Informacin de tipos en tiempo de ejecucin
11. 11. Conversin de tipos dinmica
12. 12. Tipos genricos
13. 13. Esquema de construccin tipo GObject
5. 5. Funcionalidades avanzadas del lenguaje
1. 1. Aserciones y Diseo por contrato
2. 2. Manejo de errores
3. 3. Direccin de parmetros
4. 4. Colecciones
5. 5. Mtodos con soporte de sintaxis
6. 6. Multihilo
7. 7. El bucle principal
8. 8. Mtodos asncronos
9. 9. Referencias dbiles
10. 10. Propiedad de las referencias
11. 11. Listas de parmetros de longitud variable
12. 12. Punteros
13. 13. Clases que no heredan de GLib.Object
6. 6. Funcionalidades experimentales del lenguaje
7. 7. Bibliotecas del lenguaje
1. 1. Acceso a ficheros en Vala (biblioteca GIO)
2. 2. Funcionalidad de redes en Vala (biblioteca GIO y SOUP)
3. 3. Ficheros XML en Vala
4. 4. Pruebas unitarias en Vala
5. 5. Desarrollo de interfaces grficas de usuario en Vala (Gtk+)
8. 8. Herramientas
1. 1. El compilador de Vala (valac)
2. 2. Las herramientas para generar bibliotecas
3. 3. Depuracin de programas
9. 9. Otras tcnicas
1. 1. Usando toda la potencia de GLib
Programacin en Vala/Desarrollo
Referencias
[1] http:/ / live.gnome. org/ Vala
[2] http:/ / live.gnome. org/ Vala/ Tutorial
Introduccin
3
Introduccin
Introduccin
El lenguaje de programacin Vala
[1]
es un proyecto relativamente nuevo y por ello est sujeto a cambios. Este libro
intentar transmitir lo mejor posible cuales son los objetivos que persigue este lenguaje de programacin y los
convenios que se deben seguir cuando se desarrolla con este lenguaje de programacin.
Qu es Vala?
Vala es un nuevo lenguaje de programacin
[2]
que permite usar tcnicas de programacin modernas para desarrollar
aplicaciones que se ejecutan usando las bibliotecas de GNOME
[3]
, aunque tambin es posible ejecutarlo en otros
sistemas operativos y entornos grficos, debido a sus bajas dependencias (GLib
[4]
y GObject
[5]
). Esta plataforma de
desarrollo provee de un entorno completo de programacin; con funcionalidades como el sistema de tipos dinmicos
y el gestor de memoria asistida. Antes de la existencia de Vala, la nica forma de programar para la plataforma era
con la API nativa de C, o utilizando un lenguaje de programacin de alto nivel que usan mquinas virtuales, como
Python o C#, que necesitan un wrapper
[6]
para usar esa biblioteca.
Vala es un lenguaje totalmente diferente de otros lenguajes y otras tcnicas, ya que el compilador genera cdigo en
lenguaje C
[7]
, que puede ser compilado para ser ejecutado sin ninguna biblioteca extra ni wrapper intermedio. Esto
tiene una serie de consecuencias, pero entre las mas importantes se encuentran:
1. 1. Los programas escritos en Vala debera tener un desempeo similar al mismo programa directamente escrito en
lenguaje C. Siendo mucho ms fcil y rpido de escribir y mantener.
1. 1. Una aplicacin escrita en Vala no puede hacer nada que un programa equivalente escrito en lenguaje C no pueda
hacer. Sin embargo Vala introduce una serie de funcionalidades que no estn disponibles en C, las cuales se
mapean en construcciones escritas en C, siendo estas ltimas difciles y complejas de escribir directamente.
Vala es, por lo tanto, un lenguaje de programacin moderno con todas las funcionalidades que se puede esperar de
una plataforma actual (Python, .NET, etc).
A quin va dirigido este libro?
Este libro no est pensado para aprender los conceptos de programacin bsicas (para eso existen libros que puede
consultar
[8]
). Este libro va dirigido a aquellos que quieran aprender a usar este lenguaje de programacin y algunas
de las bibliotecas que existen para el sistema. Se aconseja conocer algn lenguaje de programacin y en concreto un
lenguaje de programacin orientado a objetos.
Vala comparte bastante sintaxis con C#, pero algunas otras no se corresponden con construcciones de este lenguaje,
por tanto no se entrar en comparacin a menos que sea necesario, para evitar que este libro est enfocado a
programadores de C#.
Tambin sera conveniente que el lector tuvieras nociones de C, aunque esto no es necesario en si mismo, es
importante darse cuenta que Vala realmente se ejecuta como un programa escrito en C compilado, y puede
interactuar con bibliotecas escritas en C. Por tanto un conocimiento de C puede hacer comprender el funcionamiento
de Vala.
Introduccin
4
Convenciones del lenguaje
El cdigo ir en formato wiki normal al igual que los comandos necesarios para compilar y ejecutar los programas.
El cdigo ir acompaado de comentarios explicativos siempre que sea necesario para entenderlo.
Referencias
[1] http:/ / es. wikipedia. org/ wiki/ Vala_(lenguaje_de_programacin)
[2] http:/ / es. wikipedia. org/ wiki/ Lenguaje_de_programacin
[3] http:/ / es. wikipedia. org/ wiki/ GNOME
[4] http:/ / es. wikipedia. org/ wiki/ GLib
[5] http:/ / es. wikipedia. org/ wiki/ GObject
[6] http:/ / en. wikipedia. org/ wiki/ Wrapper_library
[7] http:/ / es. wikibooks. org/ wiki/ Programacin_en_C
[8] http:/ / es. wikibooks. org/ wiki/ Fundamentos_de_programacin
Su primer programa en Vala
Su primer programa en Vala
Como no puede ser de otro modo el primer programa en Vala va a ser el conocido como "Hola Mundo" que es el
programa ms simple (sin contar con el programa vaco) que se puede escribir en un lenguaje de programacin.
El listado de cdigo sera algo como lo que sigue:
class Demo.HelloWorld : GLib.Object {
public static int main(string[] args) {
stdout.printf("Hola, mundo!\n");
return 0;
}
}
A continuacin se explicarn algunas de las caractersticas que contiene el cdigo, para entenderlas es necesario
conocer los fundamentos de la programacin orientada a objetos
[1]
. La primera lnea que se ve es:
class Demo.HelloWorld : GLib.Object {
Esta lnea de cdigo representa la definicin de una nueva clase
[2]
llamada HelloWorld. Se puede observar que antes
del nombre de la clase se encuentra la palabra "Demo" seguida de un punto. Bien, esto indica el espacio de nombres
[3]
en el que se mueve el programa. Asimismo, se puede observar que despus del nombre de la nueva clase le siguen
dos puntos y la cadena "Glib.Object". Esta cadena va en el mismo formato que la anterior, es decir, "espacio de
nombres"."nombre de la clase" e indica una clase de la que hereda
[4]
la clase anterior. La mayora de las nuevas
clases heredarn de la clase "GLib.Object" que puede ser considerada como la clase bsica en el lenguaje Vala, ya
que, una parte importante de las funcionalidades del lenguaje estn supeditadas a que la clase sobre las que se
aplican hereden de esta clase o de una clase descendiente de sta. Como se ha podido ver la sintaxis de definicin de
una clase es bastante similar a otros lenguajes de programacin como C++, Java o C#.
Siguiendo con el mismo listado de cdigo tenemos que la siguiente lnea de cdigo es la que sigue a continuacin:
public static int main(string[] args) {
Su primer programa en Vala
5
Esta lnea de cdigo define un mtodo
[5]
de la clase HelloWorld llamado "main". Este mtodo va precedido por la
palabra reservada "public" que indica que se trata de un mtodo pblico (es decir, puede ser llamado externamente a
la clase a la que pertenece). La palabra reservada "static" nos indica que se trata de un mtodo esttico (est asociado
a la clase y no a un objeto en concreto, es decir, puede ser llamado sin instanciar ningn objeto de esa clase).
Adems se indica que el tipo de datos que devuelve este mtodo es de tipo entero, lo que se hace mediante la palabra
reservada "int". Por ltimo, entre los parntesis se indican los parmetros (los datos que utilizar internamente el
mtodo para trabajar). El parmetro es una lista
[6]
de cadenas
[7]
que contendr los parmetros con los que fu
llamado el programa desde la lnea de comandos
[8]
. El hecho de que el mtodo definido se llame "main" no es
casual, ya que, Vala considera a este mtodo concreto como el punto de entrada del programa, es decir, que una vez
compilado un programa escrito en Vala ste ser el primer mtodo en ser ejecutado. Este mtodo es el que contiene
la correspondientes inicializaciones que requiere el programa que estemos desarrollando, por ejemplo la
inicializacin de la interfaz grfica de usuario
[9]
.
La siguiente lnea de cdigo es la que sigue:
stdout.printf("Hola, mundo!\n");
Esta lnea de cdigo imprime por la salida estndar (normalmente ser la pantalla del ordenador) el mensaje
encerrado entre comillas. Es una llamada al mtodo "printf" del objeto "stdout". En el lenguaje de programacin
Vala existen una serie de objetos predefinidos a los cuales tenemos acceso por que se encuentran definidos dentro
del espacio de nombres GLib que est definido por defecto en cualquier programa Vala. El objeto "stdout" nos
permite el acceso a la salida estndar de la mquina y entre otros mtodos contiene el mtodo "printf" que muestra
un mensaje formateado por dicha salida.
La ltima lnea importante del cdigo inicial es la siguiente:
return 0;
Esta lnea hace que el programa finalice y devuelva un valor de 0 al sistema. Este valor normalmente se usa para
indicar si un programa ha finalizado de forma correcta o no. Si estuviera definido en otro mtodo cualquiera (que no
fuera el punto de entrada del programa) devolvera el valor y se almacenara en una variable. Por ejemplo:
int valor = objeto.metodo();
Las ltimas lneas del listado nicamente cierran la definicin de la clase y el mtodo definido como en cualquier
otro lenguaje como por ejemplo C++ o Java.
Compilado y ejecucin del programa
Una vez que se entiende el funcionamiento del programa, el siguiente paso es compilar dicho programa. Vala al ser
un lenguaje de programacin compilado
[10]
y por lo tanto necesita de un compilador
[11]
. El lenguaje de
programacin Vala dispone de un compilador llamado "valac" y que es compilador al mismo tiempo del lenguaje de
programacin Genie
[12]
.
Asumiendo que tenemos el compilador de Vala instalado en nuestra mquina, para compilar el primer programa
"Hola mundo" suponiendo que est escrito en un fichero llamado "hola.vala" sera:
valac hola.vala
Esto generara un fichero ejecutable llamada "hola" (dependiendo del sistema operativo en el que nos encontremos el
fichero binario resultante tendr o no una extensin como por ejemplo la ".exe" en Windows). Para ejecutar dicho
programa habr que escribir en la lnea de comandos algo como:
./hola
Su primer programa en Vala
6
Y nos mostrar la salida:
Hola mundo!
Referencias
[1] http:/ / es. wikipedia. org/ wiki/ Programacin_orientada_a_objetos
[2] http:/ / es. wikipedia. org/ wiki/ Clase_(informtica)
[3] http:/ / es. wikipedia. org/ wiki/ C%2B%2B#Espacios_de_nombres
[4] http:/ / es. wikipedia. org/ wiki/ Herencia_(programacin_orientada_a_objetos)
[5] http:/ / es. wikipedia. org/ wiki/ Mtodo_(programacin_orientada_a_objetos)
[6] http:/ / es. wikipedia. org/ wiki/ Lista_(estructura_de_datos)
[7] http:/ / es. wikipedia. org/ wiki/ Cadena_(informtica)
[8] http:/ / es. wikipedia. org/ wiki/ Lnea_de_comandos
[9] http:/ / es. wikipedia. org/ wiki/ Interfaz_grfica_de_usuario
[10] http:/ / es. wikipedia.org/ wiki/ Lenguaje_compilado
[11] http:/ / es. wikipedia.org/ wiki/ Compilador
[12] http:/ / es. wikipedia.org/ wiki/ Genie_(lenguaje_de_programacin)
Conceptos bsicos del lenguaje
Conceptos bsicos del lenguaje
Archivos de cdigo y compilacin
Los archivos de cdigo fuente de vala tienen, normalmente, la extensin ".vala". El lenguaje de programacin Vala
no fuerza a que los proyectos tengan una determinada estructura, en cuanto a los paquetes o los nombres de los
archivos que contiene una clase, como hacen otros lenguajes como Java. En lugar de eso la estructura se define
dentro de los archivos de cdigo mediante texto, definiendo la localizacin y estructura lgica mediante elementos
como los espacios de nombres. Cuando se quiere compilar cdigo Vala, se le pasa al compilador una lista de los
archivos de cdigo fuente necesarios, y el compilador determina como ensamblarlos todos juntos.
La ventaja de todo esto es que se pueden definir tantas clases o funciones como se desee dentro de un nico archivo
de cdigo, incluso combinando distintos espacios de nombres todos dentro del mismo archivo (aunque no se
demasiado recomendable por cuestiones de legibilidad y estructura). Vala por lo tanto no exige de manera inherente
una determinada estructura para los proyectos que se desarrollan usando esta plataforma. Sin embargo, si existen
ciertas convenciones a la hora de estructurar un proyecto desarrollado en Vala. Un buen ejemplo sera como se
estructura el propio proyecto del compilador de Vala.
Todos los archivos de cdigo que pertenezcan al mismo proyecto son suministrados al compilador "valac" mediante
la lnea de comandos, junto con los correspondientes parmetros de compilacin. Esto funciona de forma similar a
como se hara con el cdigo fuente compilado en Java. Por ejemplo:
$ valac compiler.vala --pkg libvala
Esa lnea de cdigo producira un archivo binario llamado "compiler" que sera enlazado
[1]
con el paquete "libvala"
(cuando nos referimos a paquete lo estamos haciendo a un concepto similar a biblioteca de funciones o la mal
traducida librera). De hecho, as es como se genera el compilador de Vala en realidad.
Si se quiere que el archivo ejecutable producido tenga un nombre especfico (distinto al que el compilador le da) o si
se le pasan varios archivos al compilador, es posible especificar el nombre del fichero ejecutable mediante la opcin
"-o":
Conceptos bsicos del lenguaje
7
$ valac source1.vala source2.vala -o myprogram
$ ./myprogram
Como se ha comentado anteriormente el compilador de vala es capaz de generar cdigo en lenguaje C en lugar de un
archivo ejecutable. As para realizar esto existe la opcin "-C" que indicar al compilador que genere todo el cdigo
C necesario para crear el ejecutable del proyecto. El compilador crear un archivo con extensin ".c" por cada
archivo con extensin ".vala" que le pasemos. Si abrimos el contenido de esos archivos generados se puede ver el
cdigo C equivalente al programa que hemos desarrollado en Vala. Se puede observar como se crean las mismas
clases que en Vala pero mediante la biblioteca GObject y cmo se registran de forma dinmica en el sistema. Este es
un ejemplo del poder que tiene la plataforma de desarrollo de GNOME. Sin embargo, todo esto es a ttulo
informativo, ya que, por suerte no es necesario generar todos estos ficheros, ni entender como funcionan
internamente para poder programar en Vala. Si en lugar de generar el fichero de cdigo C slo necesitamos generar
la cabecera (por ejemplo si estamos generando una biblioteca de funciones ser necesario para poder usarla en C o en
otro lenguaje) existe la opcin "-H" con la que conseguiremos ese objetivo. A continuacin un ejemplo que genera
los dos ficheros (un fichero de cdigo C y su correspondiente cabecera ".h"):
$ valac hello.vala -C -H hello.h
Visin general de la sintaxis
La sintaxis de Vala est fuertemente inspirada en la sintaxis del lenguaje de programacin C#, por lo que la mayora
de lo explicado aqu ser muy familiar para los programadores de C# e incluso para los que sepan algn lenguaje con
un sintaxis similar a C. Independientemente de eso se intentar dar explicaciones breves de los conceptos que se
estimen oportunos, aunque no en demasiada profundidad por que no es el cometido del presente documento.
Al igual que en otros lenguaje de programacin, en Vala existe el concepto de visibilidad o mbito
[2]
de las
variables. Un objeto o referencia nicamente es vlida dentro del mbito definido mediante corchetes ({}) dnde se
defini dicho objeto. Estos delimitadores son los mismos que se usan para delimitar las definiciones de las clases, los
mtodos, los bloques de cdigos, etc; por lo que todos estos conceptos tienen su propio mbito. Por ejemplo:
int funcion1 (void) {
int a=0;
}
int funcion2 (void) {
int a=1;
stdout.printf("%d\n", a);
}
El cdigo anterior define dos funciones que tiene sendas variables "a" definidas con distintos valores. La funcin
"funcion2" mostrar el valor de "a", el cal ser de 1 ya que la variable que se encuentra definida en el mbito de la
funcin "funcion2" vale 1.
El lenguaje Vala, a diferencia de otros, no es estricto en la localizacin de la definicin de variables. As no existe
una localizacin fija para este propsito, si bien es cierto que se aconseja por temas de legibilidad y estructura
definirlas al inicio del mbito en el que van a ser usadas.
Una variable se define mediante un tipo y un nombre despus del tipo. Es decir si queremos definir un entero de
nombre edad sera algo as:
int edad;
En caso de que el tipo fuera una clase (en lugar de un tipo de datos bsico) se crea una instancia de una clase. Si se
crea una referencia que no se inicia esta no apunta a ningn objeto. El concepto de referencia aqu es el mismo que
Conceptos bsicos del lenguaje
8
en el lenguaje de programacin Java, es decir, un puntero
[3]
que apunta a un objeto. As para definir un nuevo objeto
de una clase se usar el operador new:
// Referencia no inicializada
Clase objeto;
// Referencia inicializada que apunta al nuevo objeto
Clase objeto = new Clase();
Comentarios
Los comentarios se definen mediante los mismos smbolos que en C#, es decir, "//" para los comentarios de 1 lnea y
"/**/" para los comentarios de ms lneas. As tenemos:
// Comentario de una lnea
/*
Comentario escrito en
ms de una lnea
*/
/*
* Comentario especial para sistema de documentacin
* automtica.
*/
En relacin al ltimo tipo de comentarios, el lenguaje de programacin Vala dispone de un sistema generador de
documentacin automtica
[4]
propio cuyo nombre es Valadoc
[5]
.
Tipos de datos
Hablando en general podemos separar los tipos de datos en Vala en dos grandes subgrupos, los tipos de referencia y
los de valor. As estos nombres nos indican la forma en la que estos valores son pasados en el sistema. De esta forma
un tipo de valor es copiado en todos los lugares en los que es asignado a otro identificador (otra variable), mientras
que un valor de referencia se copia la referencia pero apunta al mismo objeto.
Constantes
Las constantes no son propiamente un tipo de dato ya que una constante define un valor de cualquier tipo de dato que
no se modifica durante la ejecucin del programa. As una constante se define mediante la palabra reservada "const"
seguida del tipo de constante que se define. As una constante de tipo real se definira mediante:
const float PI = 3.1415926;
Conceptos bsicos del lenguaje
9
Tipos bsicos
Vala dispone de un conjunto amplio de datos bsicos entre los que se encuentran los siguientes:
Byte (char, uchar): Es un valor que ocupa el mnimo posible en memoria (1 byte) y que se utiliza para almacenar
1 carcter o valores enteros de 0 a 255.
Character (unichar): Es un carcter de tipo unicode
[6]
por lo que ocupar en memoria 2 bytes.
Integer (int, uint): Enteros positivos que van desde 0 a 65536 (o desde -32768 a 32767 si es con signo), ocupa 2
bytes en memoria.
Long Integer (long, ulong): Es un entero largo que ocupa 4 bytes en memoria y que puede representar desde 0 a
4294967296.
Short Integer (short, ushort): Es un entero que ocupa 2 bytes en memoria y que funciona como un Integer.
Enteros de tamao fijo garantizado: Estos tipos garantizan que independientemente de la plataforma de ejecucin
del programa el entero ocupa el mismo tamao en memoria y tiene por lo tanto los mismos lmites. Estos tipos de
datos son: int8, int16, int32 e int64 (para los enteros con signo) y uint8, uint16, uint32 y uint64 (para los enteros
sin signo).
Nmeros de coma flotante: Hay dos tipos de datos de coma flotante, float y double. Los nmeros float ocupan en
memoria 4 bytes y los double 8 bytes. La principal diferencia es la precisin del nmero. Un nmero double
permite representar nmeros con ms precisin que un float.
Boolean (bool): Tipo de dato booleano con dos valores posibles cierto (true) y falso (false).
Datos compuestos (struct): Permite definir datos compuestos mediante la palabra reservada struct. Ejemplo: struct
persona { int edad, String nombre };
Enumeraciones (enum): Conjunto de valores enteros enumerados, es decir, salvo que no se indique otra cosa se
incrementan los valores.
Normalmente los valores que se especifican ocupan lo establecida en la lista, sin embargo slo se garantiza para los
enteros de tamao fijo garantizado. Para determinar el tamao en memoria de una variable se usa la palabra
reservada "sizeof". Se puede ver el valor mximo y mnimo que pueden tener un tipo de dato se usan los valores
MIN y MAX definidos. Por ejemplo int.MIN y int.MAX.
Cadenas
Las cadenas de texto en Vala se definen mediante la palabra reservada string. Estas cadenas son de tipo UTF-8, es
decir, son cadenas de texto unicode que pueden representar cualquier texto.
string a = "Hola";
Adems de este tipo de cadenas existen las cadenas literales, es decir, que no se interpretan los caracteres de escape
como "\n". Estas cadenas se definen mediante una triple comillas. Cualquier carcter que se encuentre entre el par de
tres comillas se inserta dentro de la cadena literal, por ejemplo un tabulador. Ejemplo:
string literal = """Esto es una cadena "literal" y puede contener
cualquier carcter.\n\tTexto tabulado.\n""";
Las cadenas que empiezan mediante una @ son plantillas. Estas plantillas pueden evalan variables y/o expresiones
que estn definidas mediante $. Por ejemplo:
string plantilla = @"$a * $b = $(a*b)"; // Devolver una cadena como
"6 * 7 = 42"
Los operadores == y != se utilizan en las cadenas y su comportamiento es distinto a otros lenguajes. As en Vala los
operadores == y != compara el contenido de las cadenas y no la referencias de las mismas. Por ejemplo en Java:
Cdigo Java
Conceptos bsicos del lenguaje
10
String a = "hola";
String b = "hola";
if (a == b) {
} else {
}
Cdigo Vala
string a = "hola";
string b = "hola";
if (a == b) {
} else {
}
El cdigo Java indicar que las variables apuntes a dos objetos distintos (dos referencias distintas) mientras que en
Vala si se devolver el valor de cierto ya que ambas cadenas son iguales, aunque se encuentren almacenadas en dos
variables distintas.
Al igual que en otros lenguajes de programacin como Python, las cadenas se pueden partir en partes mediante los
operadores [inicio:fin]. As si queremos seleccionar desde el carcter 5 hasta el 9 podemos hacer lo siguiente:
string a = "hola mundo";
string b = a[5:9];
Se puede acceder a un determinado carcter mediante los corchetes indicando el ndice del carcter, teniendo en
cuenta que los vectores en Vala empiezan en el ndice 0.
string a = "hola mundo";
unichar c = a[0];
Sin embargo esta forma de acceso a las cadenas es de slo lectura, es decir, no se puedes escribir un carcter (o una
cadena) indicando la posicin en la que debe ser insertado. Por ejemplo el siguiente cdigo es invlido:
Cdigo INVALIDO en Vala
string a = "hola mundo";
a[0] = "a";
Existen, asimismo, diversos mtodos para poder realizar conversiones entre cadenas y otros tipos de datos bsicos y
viceversa. A continuacin se presentan algunos ejemplos:
Ejemplos de conversiones entre cadenas y otros datos bsicos y viceversa
bool b = "false".to_bool(); // => false
int i = "-52".to_int(); // => -52
double d = "6.67428E-11".to_double(); // => 6.67428E-11
string s1 = true.to_string(); // => "true"
string s2 = 21.to_string(); // => "21"
string s3 = 24.17.to_string(); // => "24.170000000000002"
Conceptos bsicos del lenguaje
11
Vectores
Los vectores se declaran en Vala mediante el tipo de vector (el tipo de dato) seguido de "[]" y un nombre al final.
Antes de usar el vector adems de declararlo lo debemos inicializar indicando el tamao del mismo o en su caso los
valores que lo componen. Por ejemplo si queremos declarar un vector de 100 nmeros enteros llamado
"lista_primos" sera algo as:
int[] lista_primos = new int[100];
// Para saber el tamao de un vector se usa la propiedad "length"
stdout.printf("%d\n", lista_primos.length);
Al igual que con las cadenas, los vectores tambin pueden ser divididos en varias partes usando los operadores "[]".
As teniendo definido un vector de enteros tal que "{ 2, 4, 6, 8 }" podemos trocearlo de la siguiente forma:
int[] lista = { 2, 4, 6, 8 };
int[] c = lista[1:3]; // => { 4, 6 }
El nuevo vector es un vector completamente independiente del original y los cambios realizados sobre el segundo no
afectan al primero.
Adems de vectores se pueden definir matrices multidimensionales posicionando una coma (o ms dependiendo del
nmero de dimensiones que se quiera) dentro de los corchetes. As por ejemplo para definir una matriz
bidimensional vaca de 3x3 se realizara de la siguiente forma:
int[,] c = new int[3,3];
// Si se quiere una matriz con los valores slo tenemos que
indicarlos despus del =
int[,] d = {{2, 4, 6},
{3, 5, 7},
{1, 3, 5}};
Este tipo de matrices se representa internamente en memoria como un bloque contiguo. Los vectores de vectores
"[][]" en los cuales cada fila tiene un tamao distinto no estn soportados an.
Se pueden aadir elementos al vector mediante el uso del operado "+=". Sin embargo, esto slo funciona para
vectores definidos como locales o privados. El vector ser redimensionado en caso de ser necesario. En caso de que
esto pase, internamente se incrementa en potencias de 2 por temas de eficiencia y velocidad. Sin embargo la
propiedad ".length" indicar el nmero actual de elementos y no el valor interno. Por ejemplo:
int[] e = {}
e += 12; // Ahora e tiene un tamao interno de 2 (Aunque la propiedad
length vale 1)
e += 5; // Ahora e tiene un tamao interno de 2 (La propiedad length
vale 2)
e += 37; // Se aade otro elemento y se vuelve a redimensionar
internamente. Ahora su tamao interno sera de 4 elementos (La propiedad
length valdr 3)
Si despus de los parntesis despus del identificador junto con un tamao se obtendr un vector de tamao fijo. Este
tipo de vectores se aloja en memoria en la pila
[7]
o mediante "in-line allocated" (si se usa como variable de una clase
y no puede ser redimensionado despus. Ejemplo:
Conceptos bsicos del lenguaje
12
int e[10]; // No necesita new. No se le pueden aadir ms elementos.
Vala no realiza comprobaciones de lmites en el acceso a los vectores en tiempo de ejecucin. Si se necesita ms
seguridad sobre esta temtica se recomienda el uso de estructuras de datos ms sofisticadas como por ejemplo los
"ArrayList". Ms adelante se tratarn ms en profundidad esta familia de estructuras de datos (colecciones, lista, etc).
As por ejemplo en el siguiente ejemplo se accede a una posicin inexistente del vector; en lugar de mostrarnos un
error mostrar el contenido de una posicin de memoria externa al vector y de contenido indeterminado (basura):
int[] vector = new int[10];
stdout.printf("%d\n", vector[300]); // Puede mostrar cualquier valor,
pero no mostrar errores
Referencias
El tipo de dato conocido como referencia
[8]
es un tipo de dato que contiene un valor que permite el acceso indirecto
al contenido de una variable. El termino referencia es muy similar al termino puntero que se usa en otros lenguajes
de programacin como C, sin embargo en este caso una referencia normalmente se usar para los objetos creados,
mientras que un puntero puede ser de cualquier tipo de variable (entero, coma flotante, cadena, etc). As cada vez
que dentro de un programa escrito en Vala pasemos un objeto a una funcin o mtodo de otra clase, en realidad
estaramos pasando una referencia. El sistema es capaz de tener un registro de cuantas referencias siguen en uso, con
el fin de que pueda realizar la gestin de memoria por nosotros. Entre otras cosas el sistema de gestin de memoria
de Vala se encarga de liberar la memoria que ocupa un objeto cuando todas las referencias que apuntan a l hayan
dejado de usarse. El valor de una referencia que no apunte a ninguna parte ser null. Ms informacin acerca de las
referencias en el captulo de Programacin orientada a objetos en Vala
[9]
.
Conversin esttica de tipos
Cuando nos encontramos desarrollando un programa en cualquier lenguaje de programacin fuertemente tipado
[10]
,
normalmente nos encontramos ante el problema de pasar de un tipo de datos a otro con bastante frecuencia. En una
conversin de datos esttica el compilador sabe cuales son los tipos de datos origen y destino antes de ejecutar el
programa compilado. As en Vala se puede realizar este tipo de conversin de datos estableciendo el tipo de datos
entre parntesis despus de una igualdad. En una conversin esttica de datos no se establece ningn tipo de
comprobacin de seguridad. Este tipo de conversiones son vlidas para todos los tipos de datos en Vala. Por
ejemplo:
int i = 10;
float j = (float) i;
Conversin dinmica de tipos (Inferencia)
Existe otro tipo de conversin de tipos de datos conocida como conversin dinmica o inferencia de tipos
[11]
que se
usa sobre todo en lenguajes de programacin funcionales
[12]
. As dado que Vala permite definir variables sin tipo
inicial usando para ello la palabra reservada var, es necesario que se pueda establecer el tipo de una variable con
posterioridad a su definicin, es decir, inferir ese tipo a partir de una expresin que se encuentra a la derecha de una
igualdad. Por ejemplo el siguiente cdigo sera legal en Vala:
var p = new Person(); // es lo mismo que: Person p = new Person();
var s = "hello"; // es lo mismo que: string s = "hello";
var l = new List<int>(); // es lo mismo que: List<int> l = new List<int>();
var i = 10; // es lo mismo que: int i = 10;
Conceptos bsicos del lenguaje
13
Este tipo de variables sin tipo slo estn permitidas como variables locales
[13]
. Este mecanismo es muy til para
usar en los parmetros de los mtodos genricos.
Operadores
Como otros lenguajes de programacin, Vala tiene a disposicin de los programadores una gran variedad de
operadores para usar con distintos propsitos. Podemos separar los operadores de Vala en varios tipos segn el tipo
de datos sobre el que operan.
Operadores aritmticos
Estos operadores se aplican a todos los tipos numricos definidos anteriormente. Estos operadores son los que
aparecen en la siguiente tabla:
Operadores aritmticos I (identificador = expresinA OPERADOR expresinB)
Operador Descripcin
= El operador de asignacin se utiliza para realizar asignaciones entre una variable y el resultado de una expresin o un valor (otra
variable). A la izquierda de este operador debe aparecer un identificador (una variable) y a la derecha del mismo puede aparecer un
valor, una expresin o otra variable.
+ El operador de suma realiza la adicin de las expresiones que tiene a su izquierda y a su derecha. Este operador es aplicable a las
cadenas de texto ("string").
- El operador de resta realiza la resta de la expresin que tiene a la derecha sobre la expresin que tiene a su izquierda.
* El operador de multiplicacin realiza el producto entre la expresin que tiene a su izquierda y a su derecha.
/ El operador de divisin realiza esta operacin usando como dividendo la expresin que tiene a su izquierda y como divisor la expresin
que tiene a su derecha.
% El operador de mdulo calcula el resto de una divisin siendo la expresin que tiene a su izquierda el cociente y la expresin que existe
a su derecha el divisor.
Operadores aritmticos II (identificador OPERADOR expresin)
Operador Descripcin
+= Este operador realiza la adicin de la expresin sobre el contenido que tenga el identificador a su izquierda.
-= Este operador realiza la resta de la expresin sobre el contenido que tenga el identificador a su izquierda.
*= Este operador realiza el producto entre el contenido del identificador a su izquierda y la expresin a su derecha. El resultado se
almacena en el identificador.
/= Este operador realiza la divisin tomando como dividendo el contenido del identificador y como divisor el resultado de la expresin de
la derecha. El resultado de la divisin se almacena en el identificador.
%= Este operador calcula el mdulo (resto) de la divisin, tomando como dividendo el contenido del identificador y como divisor el
resultado de la expresin de la derecha. El resultado de la divisin se almacena en el identificador.
Conceptos bsicos del lenguaje
14
Operadores aritmticos III (identificador OPERADOR o bien OPERADOR identificador)
Operador Descripcin
++ Este operador incrementa en uno el contenido del identificador.
-- Este operador decrementa en uno el contenido del identificador.
Los operadores "++" y "--" se pueden usar tanto en una posicin prefija al identificador como postfija al mismo. Sin
embargo existe una sutil diferencia entre ambos usos. Supongamos que tenemos este operador en una expresin
(variable++ o ++variable). As, si el operador est delante del identificador la expresin devolver el nuevo valor
(variable + 1) sin embargo, si tenemos el operador detrs del identificador entonces la expresin devolver el valor
antiguo (variable). Esto puede hacer que cometamos errores difciles de detectar. Por ejemplo:
Cdigo con operador prefijo
int a = 0;
int b = ++a; // Aqu b valdra 1 que sera el valor que devuelve la
expresin
Cdigo con operador postfijo
int a = 0;
int b = a++; // Aqu b valdra 0 que sera el valor que devuelve la
expresin
Operadores a nivel de bits
Un operador a nivel de bits es aquel que realiza una operacin sobre los bits que componen los parmetros que
recibe. Los operadores booleanos que se definen en Vala son los mismos que se definen en el lgebra de Boole
[14]
o
compuestos por varios bsicos. As tendremos los siguientes operadores:
Operadores a nivel de bits I (expresin_booleana_A OPERADOR_BOOLEANO
expresin_booleana_B)
Operador Descripcin
| Este operador realiza la operacin booleana OR de la expresin que tiene a su izquierda y la expresin que tiene a su derecha.
^ Este operador realiza la operacin booleana XOR de la expresin que tiene a su izquierda y la expresin que tiene a su derecha.
& Este operador realiza la operacin booleana AND de la expresin que tiene a su izquierda y la expresin que tiene a su derecha.
Conceptos bsicos del lenguaje
15
Operadores a nivel de bits II (OPERADOR_BOOLEANO expresin_booleana)
Operador Descripcin
~ Este operador realiza la operacin booleana NOT de la expresin que tiene a su derecha.
Operadores a nivel de bits III (identificador OPERADOR_BOOLEANO expresin
booleana)
Operador Descripcin
|= Este operador realiza la operacin booleana OR entre el identificador y el resultado de la expresin booleana. El resultado se almacena
dentro del identificador.
^= Este operador realiza la operacin booleana XOR entre el identificador y el resultado de la expresin booleana. El resultado se
almacena dentro del identificador.
&= Este operador realiza la operacin booleana AND entre el identificador y el resultado de la expresin booleana. El resultado se
almacena dentro del identificador.
Operadores a nivel de bits IV (identificador OPERADOR_BOOLEANO expresin entera)
Operador Descripcin
>> Este operador realiza el movimiento de los bits de izquierda a derecha un nmero de veces igual al valor devuelto por la expresin
entera. Se introducirn tantos 0 por la izquierda como indique la expresin entera.
<< Este operador realiza el movimiento de los bits de derecha a izquierda un nmero de veces igual al valor devuelto por la expresin
entera. Se introducirn tantos 0 por la derecha como indique la expresin entera.
Operadores a nivel de bits V (identificador OPERADOR_BOOLEANO expresin entera )
Operador Descripcin
>>= Este operador realiza el movimiento de los bits de izquierda a derecha un nmero de veces igual al valor devuelto por la expresin
entera. Se introducirn tantos 0 por la izquierda como indique la expresin entera. El resultado se almacena en el identificador.
<<= Este operador realiza el movimiento de los bits de derecha a izquierda un nmero de veces igual al valor devuelto por la expresin
entera. Se introducirn tantos 0 por la derecha como indique la expresin entera. El resultado se almacena en el identificador.
Operadores lgicos
Los operadores lgicos son aquellos que toman unos operandos y realizan alguna operacin de tipo lgico sobre
ellos. Estos operadores se utilizan para comprobar si se satisface una condicin todos ellos devuelven un valor
booleano (true o false) que determina si esa condicin es cierta o no.
Conceptos bsicos del lenguaje
16
Operadores lgicos I
Operador Descripcin
! El operador lgico NOT hace que la condicin tome el valor contrario al que tiene. Por ejemplo si una expresin lgica devuelve
true y aplicamos el operador NOT la expresin se convierte en false.
&& El operador lgico AND comprueba dos expresiones lgicas sean ciertas. En ese caso el resultado ser true, en cualquier otro caso
ser false.
|| El operador lgico OR comprueba al menos una de las expresiones lgicas sea cierta. En ese caso el resultado ser true, en caso de
ambas expresiones sean falsas el operador devolver false.
expresion_evaluacion
? expresion_A :
expresion_B
El operador ternario evala una expresin de evaluacin y comprueba que sea cierta. En ese caso devuelve como resultado el valor
de la expresin A, en caso contrario devuelve el contenido de la expresin B.
expresion_evaluacion
?? expresion
Este operador es equivalente a escribir la expresin "a != null ? a : b. Es decir, si la expresin es distinto de null devuelve el valor de
la expresin, en caso contrario devuelve el valor de expresin. Este operador es til para suministrar un valor por defecto cuando una
referencia en null. Ejemplo:
stdout.printf("Hola, %s!\n", nombre ?? "Desconocido");
expresion_A in
expresion_B
El operador in comprueba si la expresin B se encuentra dentro de la expresin A. Este operador se utiliza sobre conjuntos o listas de
elementos, as si un conjunto de elementos se encuentra dentro de otro entonces el operador devolver true; en caso contrario
devuelve false. Este operador es vlido para las cadenas, realizando una bsqueda de una cadena B dentro de la cadena A. Ejemplo:
bool a = "Hola" in "Hola mundo"; // La variable a tendr el valor true
Estructuras de control
Las estructuras de control
[15]
son las que nos permiten estructurar el programa y definir el flujo de trabajo necesario
para conseguir el resultado esperado. As todos los lenguajes de programacin cuentan con ms o menos estructuras
de control. El lenguaje Vala por su parte dispone de un amplio nmero de estructuras de control a disposicin de los
programadores.
Bucles
Los bucles
[16]
son estructuras de control cuya utilidad es la de repetir un cdigo un nmero de veces. Dependiendo
de si ese nmero de veces es conocido de antemano o no tenemos dos tipos de bucles.
En el primer grupo de bucles conocemos el nmero de repeticiones que va a realizar el bucle antes de que se ejecute
el programa. Dentro de este grupo Vala dispone de dos estructuras de control. La primera es la que se define
mediante la palabra reservada for. Este bucle tiene en su definicin tres partes que distribuyen as:
for ( inicializacin_contador; condicion_salida; codigo_contador ) {
// Cdigo que se repite dentro del bucle
...
}
La parte de inicializacion_contador se utiliza para definir la variable que tendr el valor del contador en cada pasada
del bucle. Despus tendremos la parte de condicin_salida que debe contener una expresin booleana que cuando
devuelva que es cierta saldr del bucle. Por ltimo se define la parte del codigo_contador dnde se define el
incremento del paso de cada iteracin, normalmente ser un incremento (de una unidad) sobre el contenido de una
variable. Veamos un ejemplo:
for ( int i = 0; i < 10; i++ ) {
// Este bucle se ejecutar 10 veces yendo los valores del contador
"i" desde 0 a 9, siendo el paso 1
Conceptos bsicos del lenguaje
17
stdout.printf("Iteracin %d\n", i);
}
El otro tipo de bucle es el que se define mediante la palabra reservada foreach. Este bloque se define en dos partes
como las que aparecen en el siguiente ejemplo:
foreach ( elemento in lista_elementos ) {
// Se ejecuta tantas veces como elementos haya en la lista.
}
As en la primera parte se define una variable del mismo tipo que los objetos que forma la lista, mientras que en la
segunda parte se especifica la lista de objeto a recorrer. Por ejemplo:
int[] lista_enteros = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach( int entero in lista_enteros ) {
// Mostramos el contenido
stdout.printf("Contenido del elemento: %d\n", entero);
}
Este cdigo recorre un vector de enteros y va almacenando el contenido de cada elemento del vector en la variable
entero definida slo para ese mbito. Hay que sealar que aunque cambiemos el contenido de la variable entero no
se almacenar en el vector lista_enteros el nuevo valor, ya que, se hace una copia de los valores.
El segundo grupo de bucles que se ha definido al principio de esta seccin es aquel en el que no conocemos a priori
el nmero de ejecuciones que va a tener. Dentro de este grupo Vala define dos estructuras de control distintas. La
primera de ellas es el bucle mientras o while
[17]
. Este tipo de bucle se ejecutar mientras la expresin booleana que
se especifica al inicio del bucle sea cierta. As el bucle tiene la siguiente estructura:
bool condicion_salida = true;
while ( condicion_salida ) {
// Acciones que hacen que llegado el momento "condicion_salida"
tenga un valor false y se salga del bucle
}
Este bucle evala la condicin de salida antes de ejecutar las acciones que tiene definidas dentro del cuerpo del
mismo. As este bucle puede llegar a no ejecutarse ninguna vez.
El otro bucle definido en Vala es el conocido como bucle "Hacer mientras que" o "Do ... While". Este bucle realiza
al menos una ejecucin de las sentencias que tiene definidas dentro su cuerpo. Despus llega a la parte de evaluacin
de la condicin, ejecutndose este proceso mientras la condicin que evala sea cierta. Ejemplo de definicin:
bool condicion_salida = true;

do {
// Acciones que hacen que la condicion evaluada sea falsa
} while ( condicion );
Todas estos bucle puede ser manipulados haciendo uso de las palabras reservadas break y continue. La palabra
reservada break se utiliza para salir incondicionalmente del cuerpo del bucle (independientemente de que la
condicin sea cierta o no). Por su parta la palabra reservada continue hace que el flujo del programa vaya al lugar
donde se realiza la evaluacin de la condicin de salida del bucle. Ejemplo:
Conceptos bsicos del lenguaje
18
bool condicion_salida = true;

do {
// Nos salimos del bucle
break;
// Operaciones que no llegaran ejecutarse
} while ( condicion );
// Este bucle se ejecutara siempre
while( condicion ) {
// No hacemos nada y nos vamos a la evaluacin
continue;
// Acciones que cambiaran el valor de la condicin a false
}
Estructuras de control condicionales
La estructuras de control condicionales son aquellas que permiten ejecutar un trozo de cdigo dependiendo de si una
condicin es cierta o no. Dentro de este tipo de estructuras de control Vala dispone de dos tipos que estn a
disposicin del programador para su uso.
La primera de ellas es la estructura que se define con las palabras reservadas if ... else if ... else. Esta estructura de
control permite definir una condicin que de cumplirse ejecuta el trozo de cdigo que tiene encerrado entre
parntesis. La definicin sera algo as:
int a = 1;
if ( a == 1 ) {
// Acciones para cuando la variable a valga 1
} else {
// Acciones para cuando la variable tenga un valor distinto a 1
}
Adicionalmente esta estructura permite definir ms condiciones distintas a la primera mediante las palabras
reservadas else if. As si ampliamos el ejemplo anterior tendramos algo as:
int a = 1;
if ( a == 1 ) {
// Acciones para cuando la variable a valga 1
} else if ( a == 2 ) {
// Acciones para cuando la variable a valga 2
} else if ( a == 3 ) {
// Acciones para cuando la variable a valga 3
} else {
// Acciones para cuando la variable tenga un valor distinto a 1, 2
o 3
}
Adems de esta estructura de control condicional, Vala dispone de otra estructura que es muy til cuando tenemos un
gran nmero de casos a tratar sobre una misma variable. Esta estructura de control es la llamada switch case
[18]
.
Conceptos bsicos del lenguaje
19
Esta estructura de control define una variable sobre la que se van a realizar varios casos mediante la palabra switch.
El cdigo a aplicar se encuentra definido mediante la palabra reservada case. Un ejemplo variando el anterior sera:
int a = 1;
switch (a) {
case 1:
// Acciones para cuando la variable a valga 1
break;
case 2:
// Acciones para cuando la variable a valga 2
break;
case 3:
// Acciones para cuando la variable a valga 3
break;
default:
// Acciones para cuando la variable tenga un valor distinto a 1,
2 o 3
break;
}
Esta definicin es anloga a la realizada mediante if ... else if ... else teniendo en cuenta que todos los casos no
contemplados y definidos mediante la palabra reservada case se definen mediante la palabra reservada default. Es
muy importante no olvidar poner la palabra reservada break al final del bloque de cdigo de cada caso, ya que en
caso contrario, no se sale de la estructura de control condicional.
Una nota para programadores de C y otros lenguajes similares: las condiciones deben devolver un valor booleano
explcitamente, es decir, si queremos evaluar que una variable sea null o tenga un valor de 0 hay que especificarlo
explcitamente. Por ejemplo:
if ( objeto == null ) // BIEN
if ( objeto ) // MAL
Elementos del lenguaje
Mtodos
En Vala llamaremos mtodos a todas las funciones
[19]
indepedendientemente de si son independientes o se
encuentran definidas dentro de una clase de objetos, tampoco se tendr en cuenta si devuelven un valor o no. A partir
de ahora a todas ellas nos referiremos con el nombre de mtodos. Ejemplo de definicin de un mtodo:
int nombre_del_metodo ( int argumento1, Object argumento2 ) {
// Algoritmo a ejecutar
return valor_devuelto;
}
El cdigo de arriba define un mtodo con el nombre nombre_del_metodo que toma dos argumentos y devuelve un
entero. Dentro del mtodo se colocarn las acciones que el mtodo debe ejecutar para obtener la funcionalidad
deseada.
Como se ha comentado ya en varias ocasiones todo el cdigo Vala se traduce a cdigo C, por lo que todos los
mtodos Vala se traducen en funciones escritas en C, por lo que pueden recibir un nmero arbitrario de argumentos y
Conceptos bsicos del lenguaje
20
devuelve un valor (o ninguno si se definen como void). Se podran devolver ms de un valor poniendo esos valores
extra en un lugar conocido por el cdigo que llama al mtodo. Ms informacin acerca de esta tcnica se darn en la
seccin Funcionalidades avanzadas del lenguaje.
La convencin para la nomenclatura de los mtodos en Vala es mediante palabras en minscula y separando las
palabras mediante guiones bajos "_". Esto puede resultar algo extrao para los programadores que sepan C# o Java y
estn acostumbrados a usar CamelCase
[20]
o CamelCasemixto. Pero se sigue esta nomenclatura para ser consistente
con otras bibliotecas ya desarrolladas en Vala y C/GObject que ya usan dicha nomenclatura.
A diferencia de otros lenguajes de programacin, Vala no soporta la sobrecarga de mtodos
[21]
por lo que no es
posible definir dos o ms funciones con el mismo nombre y distinto nmero y/o tipos de argumentos. Ejemplo de
sobrecarga:
void draw(string text) { }
void draw(Shape shape) { } // Esta definicin nos dar un error.
Esto es debido a que las bibliotecas desarrolladas en Vala estn diseadas para que puedan ser usadas por
programadores de C tambin sin ningn cambio (y en C no existe la sobrecarga de funciones). En lenguaje Vala se
puede realizar algo parecido a lo siguiente para solucionar este inconveniente:
void draw_text(string text) { }
void draw_shape(Shape shape) { }
Eligiendo nombres ligeramente distintos el desarrollador puede evitar este inconveniente. En lenguajes que si
soportan la sobrecarga de mtodos se usa esta tcnica para suministrar mtodos con menos parmetros que un
mtodo general.
En caso de querer desarrollar mtodos generales se puede usar una caracterstica de Vala que son los argumentos por
defecto de los mtodos para obtener un comportamiento similar. De esta forma no es necesario pasar todos los
parmetros a los mtodos que han sido definidos de esta forma:
void metodo(int x, string s = "hola", double z = 0.5) { }
Este mtodo definido podra ser llamado de alguna de las siguientes formas:
metodo(2);
metodo(2, "que tal?");
metodo(2, "que tal?", 0.75);
Es posible incluso definir mtodos con un nmero de parmetros indefinidos y variable usando varargs como el
mtodo stdout.printf. Esta tcnica se explicar ms adelante.
Vala realiza una comprobacin bsica para comprobar que los parmetros (y el valor de vuelta) son nulos o no. Los
parmetros (o valor de vuelta) que se definen con el smbolo ? postfijo al nombre de la variable se les permite que
sean nulos (null). Esta informacin ayuda al compilador a realizar comprobaciones estticas y a aadir
comprobaciones en tiempo de ejecucin en las precondiciones de los mtodos, los cules pueden ayudar a anular
errores relacionados con las referencias nulas.
string? method_name(string? text, Foo? foo, Bar bar) {
// ...
}
En este ejemplo, foo y el valor de vuelta puede ser null, sin embargo, bar no debe ser null.
Conceptos bsicos del lenguaje
21
Mtodos delegados
Los mtodos delegados, permiten pasar trozos de cdigo entre objetos y otros mtodos. As por ejemplo se podra
definir un mtodo delegado para pasar a otro mtodo de la siguiente forma:
delegate void DelegateType(int a);
void f1(int a) {
stdout.printf("%d\n", a);
}
void f2(DelegateType d, int a) {
d(a); // LLamada a un mtodo delegado
}
void main() {
f2(f1, 5); // Se pasa un mtodo como un parmetro delegado
}
El ejemplo de arriba define un nuevo tipo llamada DelegateType el cual, representa un mtodo que recibe un entero
y no devuelve ningn valor. Cualquier mtodo que tenga este nmero de parmetros puede ser asignado a una
variable de este tipo o pasado como un argumento de este tipo. El cdigo ejecutar el mtodo f2, pasado como una
referencia al mtodo f1 y el nmero 5. El mtodo f2 ejecutar el mtodo f1, pasndole a l el nmero.
Los mtodo delegados puede ser creados de forma local. Un mtodo miembro puede ser asignado tambin como
mtodo delegado. Por ejemplo:
class Foo {
public void f1(int a) {
stdout.printf("a = %d\n", a);
}
delegate void DelegateType(int a);
public static int main(string[] args) {
Foo foo = new Foo();
DelegateType d1 = foo.f1;
d1(10);
return 0;
}
}
En este ejemplo dentro de la clase Foo se define un mtodo llamado f1 y un tipo delegado. Dentro del mtodo main
se define un mtodo delegado y se asigna el mtodo f1 del objeto foo.
Conceptos bsicos del lenguaje
22
Mtodos annimos (Clausura/Closure)
Un mtodo annimo, tambin conocido como una expresin lambda, funcin literal o clausura
[22]
, puede ser
definido usando el operador =>. La lista de parmetros se encuentran definidos en la parte de la izquierda del
operador, mientras que el cuerpo del mtodo se define a la derecha del operador.
Un mtodo annimo por si slo no tiene sentido. Slo es til si se asignan directamente a una variable o a un tipo
delegado o se pasa como argumento a otro mtodo. Hay que darse cuenta de que ni los parmetros ni los tipos
devueltos se dan explcitamente. En lugar de eso los tipos son inferidos de los parmetros que se usan con el tipo
delegado. Ejemplo de asignacin del mtodo a una variable de tipo delegado:
delegate void PrintIntFunc(int a);
void main() {
PrintIntFunc p1 = (a) => { stdout.printf("%d\n", a); };
p1(10);
// Las llaves {} son opcionales si el cuerpo del mtodo annimo es
de una lnea
PrintIntFunc p2 = (a) => stdout.printf("%d\n", a);
p2(20):
}
Ejemplo de como se pasa un mtodo annimo a otro mtodo
delegate int Comparator(int a, int b);
void my_sorting_algorithm(int[] data, Comparator compare) {
// ... el mtodo 'compare' es llamado en alguna parte de este
mtodo ...
}
void main() {
int[] data = { 3, 9, 2, 7, 5 };
// Un mtodo annimo se pasa como segundo parmetro:
my_sorting_algorithm(data, (a, b) => {
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
}
Los mtodos annimos son autnticas clausuras. Esto significa que pueden acceder a las variables locales del mtodo
exterior dentro de la expresin lambda. Ejemplo:
delegate int IntOperation(int i);
IntOperation curried_add(int a) {
return (b) => a + b; // 'a' es una variable externa
}
Conceptos bsicos del lenguaje
23
void main() {
stdout.printf("2 + 4 = %d\n", curried_add(2)(4));
}
En este ejemplo el mtodo curried_add (ver Currificacin
[23]
) devuelve un mtodo nuevo creado que mantiene el
valor de a. Este mtodo devuelto se llama con 4 como argumento, resultado de la suma de los dos nmeros.
Espacios de nombres
En programacin orientada a objetos un espacio de nombres
[24]
se utiliza para agrupar un conjunto de funcionalidad
(clases, constantes, mtodos, etc) que deben tener un nombre nico. As un espacio de nombres nos va a servir para
desarrollar bibliotecas o mdulos.
Para definir un espacio de nombres se utiliza la palabra reservada namespace seguida del identificador nico que
dar nombre al espacio de nombres. As un ejemplo de espacio de nombres sera:
namespace EspacioNombres {
// Las clases, mtodos, constantes que pertenecen al espacio de
nombres
}
Todo lo que se defina dentro de los corchetes pertenecer la espacio de nombres. Todo aquello definido fuera del
espacio de nombres debe usar nombres cualificados (EspacioNombres.clase para definir un objeto de una clase por
ejemplo), o por otra parte si se encuentra dentro de un archivo que contenga la lnea con using EspacioNombres;
podr usar todos los identificadores dentro de ese espacio de nombres sin necesidad de anteponer el nombre del
espacio de nombres delante de aquello a lo que quiera acceder. Por ejemplo:
Cdigo con using
// Usamos el espacio de nombres GLib
using GLib;
o = Object;
Cdigo sin using
o = GLib.Object;
Hay una ocasin en la cual es inevitable el uso de los nombres cualificados (independientemente de los espacios de
nombres que estemos usando), y es cuando se produce una ambigedad, es decir, existen dos identificados iguales en
distintos espacios de nombres que estamos usando. Por ejemplo existen dos clases Object definidas una en el
espacio de nombres GLib y otra en Gtk, as si hemos incluido ambos y queremos asegurarnos que usamos una clase
y no otra debemos hacerlo mediante los identificadores cualificados; es decir, GLib.Object o bien Gtk.Object
dependiendo del identificador al que queramos acceder.
En todos los programas escritos en Vala el espacio de nombres GLib se importa por defecto por lo que tenemos que
tener en cuenta los identificadores que existen dentro de este espacio de nombres por si surgen casos de ambigedad
como el anteriormente descrito.
Todo aquello que no se define dentro de algn espacio de nombres concreto, se supone que est definido en un
espacio de nombres genrico. Para acceder a este espacio de nombres global se usa el prefijo global::identificador.
Conceptos bsicos del lenguaje
24
Los espacios de nombres pueden estar anidados, por lo que nos podremos encontrar cosas como
EspacioNombres1.EspacioNombres1A.identificador.
Por ltimo decir que la nomenclatura de los espacios de nombres sigue el estndar CamelCase y es muy conveniente
que los desarrolladores sigan la norma para conseguir uniformidad en el cdigo desarrollado por toda la comunidad.
Estructuras
Una estructura de datos
[25]
se puede definir como un conglomerado de datos bsicos del lenguaje de programacin,
con el objetivo de facilitar la manipulacin de la misma. As en Vala es posible definir una estructura mediante la
palabra reservada struct. A continuacin un ejemplo de una definicin de una estructura:
struct Persona {
public int edad;
public string nombre;
}
Una estructura en Vala puede tener miembros privados para lo cual se definen mediante la palabra reservada private.
Los miembros de una estructura se definen como pblicos por defecto si no se indica otra cosa. Para inicializar los
valores de una estructura se puede obrar de alguna de las siguientes formas:
Persona p1 = Persona(); // Inicializacion sin valores
Persona p2 = Persona(18, "Juan"); // Inicializacion con valores en una
nica lnea
// Inicializacion con valores definidos en varias lneas
Persona p3 = Persona() {
edad = 18,
nombre = "Juan"
};
Las estructuras se almacenan en la pila
[26]
del programa y cuando se realiza una asignacin de una estructura a otra
se realiza mediante la copia de los valores, es decir, se realiza copia por valor
[27]
.
Clases
Una clase
[2]
es un tipo de objetos definido para resolver una parte del problema definido. Se ver una definicin ms
en profundidad de este tipo de programacin en la seccin Programacin Orientada a Objetos en Vala. A
continuacin se define una clase de objetos simple:
class NombreClase : NombreSuperClase, NombreInterfaz {
// Definicin de la clase
}
Mediante este cdigo definiramos una nueva clase llamada NombreClase, que heredara
[28]
de una clase llamada
NombreSuperClase y que implementara la interfaz
[29]
NombreInterfaz. Todos estos terminos se tratarn en ms
profundidad en la seccin Programacin Orientada a Objetos en Vala.
Conceptos bsicos del lenguaje
25
Interfaces
Las interfaces en Vala son algo distintas a las definidas por Java o C# y es que pueden ser usadas como mixins
[30]
que tienen una serie de mtodos y propiedades que la clase hija hereda, aunque estos mixins no estn pensados para
ser autnomos. Se ofrecern ms detalles sobre las interfaces en Vala en la seccin Programacin orientada a objetos
en Vala. A continuacin un ejemplo simple de definicin de una interfaz en Vala:
interface NombreInterfaz : NombreInterfazPadre {
}
Como se ha visto en el ejemplo de arriba una interfaz puede heredar tambin de otra interfaz padre.
Atributos del cdigo
Los atributos del cdigo indican al compilador de Vala como se supone que debe funcionar el cdigo en la
plataforma destino. La sintaxis que usan estos atributos es [Atributo] o [Atributo(parametro1 = valor1,
parametro2 = valor2, ... )].
En la mayora de ocasiones se usan para definir los archivos vapi que usa el compilador de Vala para poder usar las
bibliotecas escritas en C desde el lenguaje de programacin Vala.
Referencias
[1] http:/ / es. wikipedia. org/ wiki/ Enlazar
[2] http:/ / es. wikipedia. org/ wiki/ mbito_(programacin)
[3] http:/ / es. wikipedia. org/ wiki/ Puntero_(informtica)
[4] http:/ / es. wikipedia. org/ wiki/ Generador_de_documentacin
[5] http:/ / live.gnome. org/ Valadoc
[6] http:/ / es. wikipedia. org/ wiki/ Unicode
[7] http:/ / es. wikipedia. org/ wiki/ Pila_(informtica)
[8] http:/ / en. wikipedia. org/ wiki/ Reference_(computer_science)
[9] http:/ / es. wikibooks. org/ Programacin_en_Vala/ Programacin_orientada_a_objetos_en_Vala
[10] http:/ / es. wikipedia.org/ wiki/ Lenguaje_de_programacin_fuertemente_tipado
[11] http:/ / es. wikipedia.org/ wiki/ Inferencia_de_tipos
[12] http:/ / es. wikipedia.org/ wiki/ Lenguaje_de_programaci%C3%B3n_funcional
[13] http:/ / es. wikipedia.org/ wiki/ Variable_local
[14] http:/ / es. wikipedia.org/ wiki/ lgebra_de_Boole
[15] http:/ / es. wikipedia.org/ wiki/ Estructuras_de_control
[16] http:/ / es. wikipedia.org/ wiki/ Bucle_%28programaci%C3%B3n%29
[17] http:/ / es. wikipedia.org/ wiki/ Bucle_while
[18] http:/ / es. wikipedia.org/ wiki/ Switch_case
[19] http:/ / es. wikipedia.org/ wiki/ Funcin_(programacin)
[20] http:/ / es. wikipedia.org/ wiki/ CamelCase
[21] http:/ / es. wikipedia.org/ wiki/ Sobrecarga
[22] http:/ / es. wikipedia.org/ wiki/ Clausura_%28inform%C3%A1tica%29
[23] http:/ / es. wikipedia.org/ wiki/ Currificaci%C3%B3n
[24] http:/ / es. wikipedia.org/ wiki/ Espacio_de_nombres
[25] http:/ / es. wikipedia.org/ wiki/ Estructura_de_datos
[26] http:/ / es. wikipedia.org/ wiki/ Pila_%28inform%C3%A1tica%29
[27] http:/ / es. wikipedia.org/ wiki/ Argumento_%28inform%C3%A1tica%29#Paso_por_valor
[28] http:/ / es. wikipedia.org/ wiki/ Herencia_(informtica)
[29] http:/ / es. wikipedia.org/ wiki/ Interfaz_(Java)
[30] http:/ / es. wikipedia.org/ wiki/ Mixin
Programacin orientada a objetos en Vala
26
Programacin orientada a objetos en Vala
Se podra definir brevemente la programacin orientada a objetos
[1]
como un paradigma de programacin en el que
los programas estn definidos como objetos que interaccionan entre ellos para llevar a cabo una tarea. Para aquellas
personas que no tengan una idea clara de en que consiste la programacin orientada objetos se recomienda leer el
enlace anterior.
El lenguaje de programacin Vala no obliga a usar el paradigma de programacin orientada a objetos (de hecho se
puede decir que Vala es un lenguaje multiparadigma
[1]
, es decir, soporta varios paradigmas de programacin), sin
embargo, algunas de sus caractersticas slo estn accesibles mediante la programacin orientada a objetos.
Una definicin de clase indica qu datos compone cada objeto dentro de un programa, que otros objetos referencia, y
que mtodos se pueden ejecutar en ese objeto. La definicin puede incluir un nombre de otra clase de la cual esta
clase heredara. Una instancia de una clase es a su vez una instancia de todas las clases antecesoras (clases padre,
abuelo, etc; de esa clase), y hereda todos sus datos y mtodos, aunque no sea posible acceder a ellos por si misma.
Una clase puede tambin implementar cualquier nmero de interfaces, las cuales son un conjunto de definiciones de
mtodos que deben ser implementadas en aquellas clases que las implementan (cuando se habla de que una clase
implementa una interfaz nos estamos refiriendo a que esa clase ha sido definida usando la interfaz y eso obliga a que
la clase tenga al menos los mismos mtodos que la interfaz). Una instancia de la clase es tambin una instancia de
cada interfaz que implemente esa clase o cualquier clase antecesora suya.
Las clases en Vala puede tener miembros estticos (usando la palabra reservada static). Este modificador permite
definir a los datos o mtodos como pertenecientes a la clase como un conjunto, en lugar de especficos de una
instancia suya. Este tipo de miembros de la clase se pueden acceder sin necesidad de definir una instancia suya.
Cdigo bsico
Una definicin simple de una clase podra ser como el cdigo siguiente:
Cdigo de definicin de una clase
public class Clase : GLib.Object {
/* Campos */
public int dato1 = 0;
private int dato2;
/* Constructor */
public Clase() {
this.dato2 = 5;
}
/* Metodos */
public int mmetodo_1() {
stdout.printf("Dato privado: %d", this.second_data);
return this.dato2;
}
}
Este cdigo definir un nuevo tipo (el cual es registrado de forma automtica junto a los dems tipos de la biblioteca
gobject) que contiene tres miembros. Hay dos miembros de tipo dato, los enteros definidos al principio de la clase, y
Programacin orientada a objetos en Vala
27
un mtodo llamada metodo_1, el cual devuelve un valor entero. La definicin de la clase indica que la misma es una
subclase de GLib.Object, y por lo tanto sus instancias lo son al mismo tiempo del tipo Object, y contienen todos los
miembros que este tipo primitivo tiene. El hecho de que esta clase herede de Object tambin significa que hay unas
funcionalidades especiales de Vala que pueden usarse para acceder fcilmente a algunas de las funcionalidades de
Object.
Esta clase ha sido definida mediante la palabra reservada public. Esto implica que puede ser referenciada
directamente por cdigo que se encuentre definido en otro archivo distinto donde est definida esta clase.
Los miembros de la clase pueden ser descritos tambin como pblicos o privados (public o private). El miembro
dato1 es pblico, por lo que es visible para cualquier usuario de la clase y puede ser modificado sin intermediarios,
es decir, sin control alguno. El segundo dato es privado, y por lo tanto slo es accesible por cdigo que pertenezca a
la clase. El lenguaje Vala dispone de cuatro modificadores de acceso que aparecen descritos en la siguiente tabla:
Modificadores de acceso a miembro y clases en Vala
Modificador Descripcin
public Sin ningn tipo de restriccin. Si una clase es definida mediante este modificador podr ser definida por cdigo definido en un
archivo distinto al de la definicin de la clase. Los miembros definidos as en una clase puede ser accedidos sin ningn tipo de
restriccin al respecto.
private El acceso est limitado al cdigo interno de la clase o estructura donde ha sido definido. Este es el acceso por defecto si no se
especifica otro.
protected El acceso est limitado al cdigo interno de la clase o a cualquier clase que herede de esta clase.
internal El acceso est restringido a clases que hayan sido definidas dentro del mismo paquete que la clase (o miembro de la clase) as
definido.
El mtodo identificado como constructor (el mtodo debe ser pblico y llamarse igual que la clase) inicializa nuevas
instancias de la clase. Este mtodo puede tomar cero o ms argumentos y no devuelve ningn valor.
La parte final de la definicin de la clase de arriba es la definicin de los mtodos de la misma. El mtodo se llama
metodo_1, y devuelve un entero. Puesto que el mtodo definido no es esttico (static), slo puede ser llamado sobre
una instancia de la clase, y puede por lo tanto acceder a miembros del objeto. Esto se puede realizar mediante la
referencia al propio objeto this, la cual siempre apunta a la instancia en la cual el mtodo se est ejecutando. A
menos que sea motivo de ambigedad el identificador this puede ser omitido si se desea.
Para usar instancias de la clase que hemos definido anteriormente podemos usar cdigo como el siguiente:
Clase c = new Clase(); // Inicializacin del objeto
c.dato1 = 5; // Acceso al miembro dato pblico
c.metodo_1(); // Ejecucin del mtodo pblico
Constructores
El lenguaje Vala permite dos esquemas de construccin: el esquema de construccin tipo Java/C# y el esquema de
construccin tipo GObject (el cual ser descrito al final del presente captulo). A continuacin nos centraremos sobre
el primero de los tipos.
Vala no permite la sobrecarga de constructores (no permite crear ms de un constructor por clase), por las mismas
razones que no permite sobrecarga de operadores, lo cual significa que una clase no puede tener mltiples
constructores con el mismo nombre. Sin embargo, esto no mayor problema, ya que Vala permite la definicin de los
constructores con nombre, es decir, constructores que no se llaman igual que la clase. Si se quieren ofrecer diversos
constructores al desarrollador se puede obrar como sigue:
Programacin orientada a objetos en Vala
28
class Clase() : GLib.Objecr {
public Clase() {
}
public Clase.constructor_con_cadena(string cadena) {
}
public Clase.constructor_con_entero(int entero) {
}
}
Para crear un objeto con estos constructores es anlogo a lo anterior:
Clase c1 = new Clase();
Clase c2 = new Clase.constructor_con_cadena("Hola");
Clase c3 = new Clase.constructor_con_entero(7);
Se puede tambin usar constructores dentro de otros constructores para ahorrar esfuerzo, si parte de la inicializacin
ya la tenemos definida. As un ejemplo sera:
public class Point : Object {
public double x;
public double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public Point.rectangular(double x, double y) {
this(x, y);
}
public Point.polar(double radius, double angle) {
this.rectangular(radius * Math.cos(angle), radius *
Math.sin(angle));
}
}
void main() {
var p1 = new Point.rectangular(5.7, 1.2);
var p2 = new Point.polar(5.7, 1.2);
}
Programacin orientada a objetos en Vala
29
Destructores
Aunque Vala dispone de un sistema de gestin de la memoria puede que necesite crear destructores si se decide
gestionar la memoria de forma manual, usando punteros (que se vern ms adelante) o si se tienen que liberar otro
tipo de recursos al dejar de usar un tipo de objetos. La forma de definir un destructor es similar a cmo se hace en
C++:
class Clase : Object {
~Clase() {
stdout.printf("Destruyendo el objeto\n");
}
}
Puesto que la gestin de memoria en Vala se hace mediante conteo de referencias
[2]
y no mediante un recolector de
basuras
[3]
, los destructores son deterministas
[4]
y puede ser usados para implementar el patrn de diseo
[5]
RAII
[6]
para la gestin de recursos (cerrar flujos de datos, conexiones a bases de datos, etc).
Seales
Una seal en Vala es equivalente a los eventos en otros lenguajes de programacin (como C#) o a los listeners en
otros lenguajes (como Java). Una definicin corta de una seal podra ser una forma de ejecutar un nmero arbitrario
de mtodo idnticos (por ejemplo mtodos con los mismos parmetros) aproximadamente mismo tiempo.
Una seal se define como un miembro interno de una clase, y parece un mtodo sin cuerpo. Los manejadores de
seales se aaden mediante el mtodo connect(). Para obtener una idea ms clara de cmo se definen y para que
sirven las seales se aade el siguiente ejemplo:
class Foo : Object {
public signal void some_event (); // Definicin de la seal
public void method () {
some_event (); // Se emite la seal
}
}
void callback_a () {
stdout.printf ("Mtodo A\n");
}
void callback_b () {
stdout.printf ("Mtodo B\n");
}
void main () {
var foo = new Foo ();
foo.some_event.connect (callback_a); // Se conectan los
mtodos a la seal
foo.some_event.connect (callback_b);
foo.method ();
}
Programacin orientada a objetos en Vala
30
En el cdigo anterior define una clase llamada Foo que tiene una seal que se lanza en un mtodo llamado method.
Cuando se emita la seal se ejecutarn todos los mtodos que hayan sido conectados a la misma. En el mtodo
principal main se crea una instancia de Foo y luego se conectan los dos mtodos callback_a y callback_b a la seal.
Por ltimo se ejecuta el mtodo method que emite la seal, ejecutndose a continuacin tanto callback_a como
callback_b.
Las seales slo pueden ser definidas como pblicas ya que todas las seales deben poder estar conectadas a y
emitirse desde cualquier lugar del cdigo.
Propiedades
Una buena prctica cuando se desarrolla en un lenguaje orientado a objetos es esconder los detalles de la
implementacin de los usuarios de la clase (principio de encapsulamiento
[7]
), de manera que se pueda modificar el
funcionamiento interno sin necesidad de romper la API pblica. Una prctica es definir los miembros datos de una
clase como privados y suministrar mtodos de acceso a sus valores (estos mtodos se conocen como geters y seters).
Un ejemplo de esto sera el siguiente ejemplo:
class Person : Object {
private string name;
private int age;
Person(string name, int age) {
this.set_name(name);
this.set_age(age);
}
public string get_name() { return this.name; }
public void set_name(string name) { this.name = name; }
public int get_age() { return this.age; }
public void set_age(int age) { this.age = age; }
}
Esto es totalmente vlido y funciona correctamente, sin embargo, en Vala podemos hacer algo ms elegante. El
problema principal de estos mtodos es que son muy engorrosos para trabajar con ellos. Supongamos que queremos
incrementar la edad de la persona en una unidad:
Person p = new Person("Pedro", 25);
// Pedro ha cumplido aos hoy por lo que queremos aumentar su edad en 1
p.set_edad( p.get_edad() + 1 );
Y es en este preciso momento cuando las propiedades hacen acto de presencia para ayudar en esta tarea. Las
propiedades son un mecanismo por el cual se puede acceder y modificar los valores sin necesidad de acceder a
mtodos como en el caso anterior. As una propiedad tiene la siguiente estructura:
class Person : Object {
private string _name;
private int _age;
Person(string name, int age) {
// Accedemos a los valores mediante las propiedades
Programacin orientada a objetos en Vala
31
this.name = name;
this.age = age;
}
public string name {
get { return this._name; }
set { this._name = name; }
}
public string age {
get { return this._age; }
set { this._age = age; }
}
}
Una propiedad tiene un bloque set (acceso de escritura de los datos) y bloque get (acceso de lectura de los datos). El
identificador value representa el nuevo valor que se debe asignar en el bloque set de la propiedad.
Ahora se puede acceder a la propiedad como si de un dato pblico se tratara. Pero detrs de las cmaras el cdigo de
los bloques get y set se ejecutar dependiendo del tipo de acceso que se est realizando.
Person p = new Person("Peter", 25);
// Pedro ha cumplido aos hoy por lo que queremos aumentar su edad en 1
p.age++;
Si slo se pretende hacer la implementacin estndar entonces se puede realizar una definicin ms corta que la
anterior:
class Person : Object {
private string _name;
private int _age;
Person(string name, int age) {
// Accedemos a los valores mediante las propiedades
this.name = name;
this.age = age;
}
public string name { get; set; default="Peter" }
public string age { get; set; default=18 }
}
}
Si se quiere se puede hacer que la propiedad sea de slo lectura mediante el modificador del bloque set private o
dejando en blanco ese bloque:
public string name { get; private set; default="Peter" }
// Otra definicion posible
public string name { get; default="Peter" }
Programacin orientada a objetos en Vala
32
Adems del nombre una propiedad puede tener una descripcin breve llamada nick y/o una descripcin larga
llamada blurb. La forma de establecer estos atributos de las propiedades es mediante un atributo del cdigo
Property:
[Property(nick = "Person's name", blurb = "This is a string
representing the person's name")]
public string name { get; set; default="Peter" }
Este tipo de informacin puede ser accedida en tiempo de ejecucin, lo cual permite que programas como Glade
[8]
hagan uso de este tipo de informacin, presentando por ejemplo descripciones de las propiedades de los widgets
[9]
de GTK+
[10]
.
Toda clase derivada de GLib.Object tiene por defecto una propiedad llamada notify. Esta seal se emite cuando una
propiedad de algn objeto se modifica. As que se puede conectar un mtodo a esta seal si se est interesado en los
cambios en general:
// Esto se conoce como una expresin lambda
obj.notify.connect((s, p) => {
stdout.printf("Property '%s' has changed!\n", p.name);
});
Para definir la funcin se ha usado una expresin lambda, en la que s es el origen de la seal, p es la informacin de
la propiedad para la propiedad que ha sido modificada. Si slo se est interesado en las notificaciones de una
propiedad simple se puede usar la siguiente sintaxis:
alice.notify["age"].connect((s, p) => {
stdout.printf("age has changed\n");
});
Ntese que este caso se debe usar la representacin del nombre de la propiedad dnde los guiones bajos se
reemplazan por guiones: nombre_propiedad pasa a ser nombre-propiedad en esta representacin, la cual es el
convenio de nombres de propiedades usado por GObject.
Las notificaciones se pueden deshabilitar mediante el atributo de cdigo CCode justo antes de la declaracin de la
propiedad:
public class MyObject : Object {
[CCode(notify = false)]
// En esta propiedad no se emite la seal
public int without_notification { get; set; }
// Aqu si se emite la seal.
public int with_notification { get; set; }
}
Existe otro tipo de propiedades que se llaman propiedades de constructor que se describen ms adelante en la
seccin Esquema de construccin tipo GObject.
Programacin orientada a objetos en Vala
33
Herencia
En Vala una clase puede derivarse (y heredar) de cero o una clase. En la prctica la mayora de las veces heredar de
una clase, puesto que no hay herenca implcita como en otros lenguajes de programacin.
Cuando se define una clase nueva que hereda de otra, se crea una relacin entre las clases dnde las instancias de la
subclase definida son a su vez intancias de la clase padre. Esto significa que la operacin sobre instancias de las clase
padre tambin se pueden aplicar sobre las instancias de la clase hija. De hecho, dnde se debe usar una instancia de
la clase padre, se podr sustituir por una instacia de la clase hija.
Cuande se escribe la definicin de una clase es posible definir de forma exacta quien va a poder acceder a los
mtodos y a los datos del objetos. El siguiente ejemplo demostrar la variedad de estas opciones:
class SuperClass : GLib.Object {
private int data;
public SuperClass(int data) {
this.data = data;
}
protected void protected_method() {
}
public static void public_static_method() {
}
}
class SubClass : SuperClass {
public SubClass() {
base(10);
}
}
El miembro dato data de la clase SuperClass es una instancia de datos de esa clase. Habr un miembro de ese tipo
en cada una de las instancias de la clase padre SuperClass, y puesto que ha sido declarada como privada (private)
slo puede ser accedida por el cdigo que forma parte de la definicin de la clase padre.
El mtodo protected_method es un mtodo de SuperClass. Este mtodo al haber sido definido como protegido
(protected) podr ser ejecutado por la clase SuperClass y por todas las clases descendientes de sta.
El mtodo public_static_method tiene dos modificadores. El modificador static significa que puede ser ejecutado
sin necesidad de crear una instancia de la clase o de alguna clase hija de sta. Como resultado de esto, este mtodo
no tendr acceso a la referencia cuando se ejecute. El modificado public significa que el mtodo puede ser llamado
desde cualquier parte del cdigo, sin importar la relacin que tenga con la clase padre o sus derivadas.
Dadas estas definicioes, cualquier instancia de la clase SubClass tendr los tres miembros de la clase padre
SuperClass, pero slo podr acceder a los miembros no privados (private). El cdigo externo a la clase hija slo
podr acceder a los miembros que hayan sido definidos como pblicos (public).
Con el identificador base se puede enlazar con el contructor de la clase base, en caso de que sea necesario inicializar
algunos datos a los que slo tenemos acceso mediante el constructor de la clase padre.
Programacin orientada a objetos en Vala
34
Clases abstractas
Hay otro modificador para los mtodos, denomidado abstract. Este modificador permite definir un mtodo que no
tiene implementacin en la clase dnde se define. En lugar de implementarse en la clase dnde es definido, se obliga
a que sean las clases hijas de esa las que definan ese mtodo antes de que puede ser llamado. Esto permite definir
operaciones que se pueden ejecutar en todas las instancias de un tipo, mientras que nos aseguramos de que todos los
tipos definen sus propias implementaciones de esa funcionalidad. Una clase que contiene mtodos abstractos debe
ser definida como una clase abstracta tambin. El resultado de esto es que no se permitir crear instancias de esa
clase. Ejemplo:
public abstract class Animal : Object {
public void eat() {
stdout.printf("*chomp chomp*\n");
}
public abstract void say_hello();
}
public class Tiger : Animal {
public override void say_hello() {
stdout.printf("*roar*\n");
}
}
public class Duck : Animal {
public override void say_hello() {
stdout.printf("*quack*\n");
}
}
La implementacin de un mtodo abstracto debe ser marcada con el modificador override. Como se ve en el
ejemplo se define una clase abstracta denomida Animal. Esta clase define dos mtodos, uno de ellos normal que
denomina eat y define como come un animal (se supone que todos comen igual); el otro mtodo say_hello define
como un animal dice hola, y se define como abstracto para que en cada clase que defina un animal tenga una
implementacin distinta. As tenemos una clase Tiger que representa a un tigre y dice hola escribiendo "*roar*", y
por otra parte tenemos la clase Duck que hereda tambin de Animal y que representa a un pato y que implementa
say_hello escribiendo "*quack*".
Como se puede adivinar este mecanismo es muy til para definir una interfaz comn para una familia de clases que
heredan de la clase abstracta y que no puede ser instanciada.
Programacin orientada a objetos en Vala
35
Interfaces/Mixins
Una clase Vala puede implementar un nmero arbitrario de interfaces. Cada una de ellas es un tipo, parecido a una
clase, aunque no puede ser instanciada. Cuando una clase implementa una interfaz, una instancia de una clase as
declarada tambin es una instancia de la interfaz, y por lo tanto puede ser usada en sustitucin dnde se espere una
instancia de la interfaz.
El procedimiento para implementar una interfaz es el mismo que para heredar de una clase abstracta. Una interfaz
simple puede ser como sigue:
public interface ITest : GLib.Object {
public abstract int data_1 { get; set; }
public abstract void method_1();
}
Este cdigo define una interfaz llamada ITest el cual requiere la clase GLib.Object como padre y contiene dos
miembros. El miembro data_1 es una propiedad que ha sido declarado como abstracto. Esto no quiere decir que la
interfaz albergue una propiedad realmente, sino que obliga a cualquier clase que implemente esta interfaz a que
contenga un miembro propiedad del mismo tipo y con el mismo nombre y que contenga asimismo los bloques get y
set. Es necesario que se defina como abstracto puesto que una interfaz no puede tener ningn miembro dato definido.
El segundo miembro de la interfaz se denomina method_1 y es un mtodo. Este mtodo a estar definido como
abstracto debe ser definido por la clase que implemente esta interfaz. La forma ms simple para una implementacin
completa de una interfaz es:
public class Test1 : GLib.Object, ITest {
public int data_1 { get; set; }
public void method_1() {
}
}
Y puede ser usado de la siguiente forma:
var t = new Test1();
t.method_1();
ITest i = t;
i.method_1();
En el cdigo se puede apreciar que se define un objeto de tipo Test1 que implementa la interfaz ITes. Se define as
una referencia de tipo ITets y la asignamos para que apunte al nuevo objeto de tipo Test1. Como hemos dicho se
podrn acceder a los mtodos que define la interfaz y que obliga a que sean implementados en la clase. Hay que
recalcar que no se crea una instancia de la interfaz (el cdigo var i = new ITest(); NO ES CORRECTO), sino que
se crea una referencia de la interfaz que no se inicializa y se usa para asignarla al nuevo objeto creado.
Las interfaces en Vala no puede heredar de otras interfaces, pero puede declarar como prerrequisito a otras
interfaces, lo cual en la prctica funciona de la misma forma. Por ejemplo, sera deseable que cualquier clase que
implementara la interfaz List tambin debiera implementar la interfaz Collection. La sintaxis para realizar esto es la
misma que la que permite definir las interfaces que implementa una clase:
public interface List : Collection { // Esto obligar a que la clase
que implemente la interfaz "List" deba implementar la interfaz
"Collection" tambin
}
Programacin orientada a objetos en Vala
36
Esta definicin de List no puede ser implementada sin que se implemente la interfaz Collection tambin, y Vala
obliga a que se especifique todas las interfaces que deben ser implementadas para aquellas clases que quieran
implementar la interfaz List. El siguiente cdigo muestra un ejemplo:
public class ListClass : GLib.Object, Collection, List {
}
Las interfaces de Vala pueden tener una clase como prerrequisito tambin, si el nombre de una clase se define en los
prerrequisitos de una interfaz entonces, la interfaz slo puede ser implementada en clases derivadas de la clase que se
especific. Esto es til para asegurar que una instancia de una interfaz es tambin una clase derivada de la clase
GLib.Object, y por lo tanto la interfaz puede ser usada, por ejemplo, como el tipo de una propiedad.
El hecho de que una interfaz no pueda ser heredada de otra interfaz es slo una distincin tcnica, ya que, en la
prctica el sistema de Vala funciona igual al de otros lenguajes en este rea, pero con la funcionalidad extra de los
prerrequisitos de las clases.
Hay otra diferencia importante entre las interfaces en Vala y las interfaces Java/C#: las interfaces en Vala puede
tener mtodos que no sean abstractos. De hecho Vala permite la implementacin de mtodos en las interfaces.
Debido a esto, las interfaces de Vala pueden actuar como Mixins
[30]
. Esto es una forma de restriccin de la herencia
mltiple.
Polimorfismo
El polimorfismo
[11]
describe la forma en la cual el mismo objeto puede ser usado como ms de un tipo de cosa.
Varias de las tcnicas ya descritas aqu sugieren cmo es posible esto en Vala: una instancia de una clase puede ser
usada como una instancia de una clase padre, o de cualquier implementacin de las interfaces, sin cualquier
conocimiento de su tipo actual. A continuacin se muestra un ejemplo:
class SuperClass : GLib.Object {
public void method_1() {
stdout.printf("SuperClass.method_1()\n");
}
}
class SubClass : SuperClass {
public void method_1() {
stdout.printf("SubClass.method_1()\n");
}
}
Estas dos clases implementan un mtodo llamado method_1, y la clase SubClass contiene por tanto dos mtodos
llamados method_1, uno heredado de SuperClass y otro propio. Cada uno de ellos se ejecuta como muestra el
siguiente cdigo:
SubClass o1 = new SubClass();
o1.method_1();
SuperClass o2 = o1;
o2.method_1();
Este cdigo llamar a los dos mtodos. La segunda lnea contiene la inicializacin de la clase SubClass y llamar a
la versin de esa clase del mtodo. La cuarta lnea contiene la inicializacin de una instancia o2 de la clase
SuperClass y ejecutar la versin del mtodo de esta clase.
Programacin orientada a objetos en Vala
37
El problema que muestra el cdigo, es que cualquiera que sea el cdigo si contiene una instancia de la clase
SuperClass, sta ejecutar el mtodo que se define en esa clase, independientemente de a que objeto apunte esa
referencia. Para cambiar ese comportamiento es usar los mtodos virtuales. El siguiente cdigo muestra una versin
modificada del ejemplo anterior usando los mtodos virtuales:
class SuperClass : GLib.Object {
public virtual void method_1() {
stdout.printf("SuperClass.method_1()\n");
}
}
class SubClass : SuperClass {
public override void method_1() {
stdout.printf("SubClass.method_1()\n");
}
}
Cuando este cdigo se use de la misma forma que el anterior, el mtodo method_1 de la clase SubClass ser el
ejecutado, en lugar del mtodo de la clase padre. Esto es debido a que le hemos indicado al sistema que el mtodo
method_1 es un mtodo virtual, lo cual significa que si es redefinido en una clase hija, ser esa nueva versin la se
ejecutar siempre en instancias de esa clase hija, independientemente del tipo y conocimientos de la instancia que lo
ejecute.
Esta distincin puede que sea familiar a los programadores de algunos lenguajes, como C++, pero es totalmente
diferente al estilo del lenguaje Java, en dnde se previene del uso de los mtodos virtuales.
El lector puede que se haya dado cuenta de que cuando un mtodo se declara como abstracto (abstract) debe ser
virtual tambin. De lo contrario, no sera posible ejecutar ese mtodo dada una instancia del tipo aparente en el cual
fue definido. Cuando se implementa un mtodo abstracto en una subclase, se puede elegir declararlo como
sobreescribible (overriden), estableciendo la naturaleza virtual de ese mtodo, y permitiendo a los subtipos que usen
la misma implementacin si lo desean.
Es posible implementar los mtodos de una interfaz de tal forma que las subclases puedan cambiar la
implementacin. El proceso en este caso es declarar la implementacin inicial como virtual, y de ese modo las
subclases pueden sobrescribir si as lo necesitan.
Cuando se escribe una clase, es muy comn querer usar la funcionalidad definida en la clase de la cual hereda. Esto
es complicado en los lugares dnde se usa el nombre del mtodo ms de una vez en el rbol de herencia de las
clases. Para este cometido Vala tiene la palabra reservada base. El caso ms comn para usar este mecanismo es
cuando se ha sobrescrito la funcionalidad de un mtodo virtual para suministrar funcionalidad extra, pero aun se
necesita la funcionalidad del mtodo de la clase padre. El siguiente ejemplo muestra como actuar en este caso:
public override void method_name() {
base.method_name();
extra_task();
}
El cdigo muestra como se ejecuta el mtodo de la clase padre mediante la palabra reservada base que hace
referencia a la clase padre. Despus de ejecutar dicho mtodo slo tendramos que ejecutar la funcionalidad extra que
necesitemos.
Programacin orientada a objetos en Vala
38
Informacin de tipos en tiempo de ejecucin
Puesto las clases en Vala se registran en el sistema en tiempo de ejecucin, cada instancia contiene informacin de
su tipo que se puede consultar de forma dinmica mediante el operador is:
bool b = object is AlgunTipo;
Se puede obtener el informacin acerca del tipo de una instancia usando el mtodo definido get_type(). Este mtodo
est definido en GLib.Object por lo que la clase del objeto desde la cual lo llamamos debe heredar de esta clase
base.
Type type = object.get_type(); // Se obtiene el tipo y se almacena en
una instancia del tipo "Type"
stdout.printf("%s\n", type.name()); // Se muestra el nombre del tipo
Con el operador typeof() se puede acceder a la informacin del tipo de forma directa. A partir de la informacin del
tipo obtenida se puede crear nuevas instancias con Object.new(). Ejemplo:
Type type = typeof(Foo); // Se obtiene la informacin del tipo de la
instancia "Foo"
Foo foo = (Foo) Object.new(type); // Se crea un nuevo objeto del tipo
"type" y se asigna a la referencia foo
En este caso el constructor que se utiliza para inicializar los objetos de esta forma ser el descrito en la seccin de los
constructores estilo GObject.
Conversin de tipos dinmica
Para la conversin dinmica entre tipos una variable se convierte mediante una expresin posfija as y el tipo al que
queremos convertir la referencia. Vala dispone de comprobacin de tipos dinmica para asegurarse de que la
conversin es factible. En caso de que la conversin sea imposible de realizar se devuelve null. Sin embargo, esto
requiere que se especifique tanto el tipo de la clase origen como el destino. Ejemplo:
Button b = widget as Button;
Si por alguna razn la clase de la instancia widget no es de tipo Button o una de las clase hijas de sta o no
implementa la interfaz Button, b ser null. Esta conversin es equivalente a la siguiente expresin:
Button b = (widget is Button) ? (Button) widget : null;
Tipos genricos
Vala incluye un sistema de tipos genrico, mediante el cual una instancia particular de una clase se puede restringir
con un tipo particular o un conjunto de tipos elegidos en la construccin de la clase. Esta restriccin se usa
normalmente para asegurarse que los datos almacenados en un objeto deben ser de un tipo particular, por ejemplo
para implementar una lista de objetos de un determinado tipo. En este ejemplo, Vala se asegura que slo los objetos
del tipo indicado puedan ser aadidos a la lista, y todos los objetos que sean devueltos sern tambin de ese tipo (o
convertidos a ese tipo).
En Vala, los tipos genricos (generics) se gestionan cuando el programa se encuentra en ejecucin. Cuando se define
una clase que puede ser restringida a un tipo de dato, existir slo una clase, cuyas instancias sern personalizadas
individualmente. Esto es diferente a C++, dnde se crea una nueva clase para cada tipo requerido. Vala es similar al
sistema usado por Java en este sentido. Esto tiene varias consecuencias, la ms importante de ellas es que los
miembros estticos (static) de un tipo se comparten como un todo, sin importar las restricciones que se encuentren
Programacin orientada a objetos en Vala
39
en cada instancia; y eso dado una clase o una subclase, un tipo genrico refinado por una subclase puede ser usado
como un tipo genrico refinado por la clase. Ejemplo:
public class Wrapper<G> : GLib.Object {
private G data;
public void set_data(G data) {
this.data = data;
}
public G get_data() {
return this.data;
}
}
La clase Wrapper debe ser restringida con un tipo para inicializarla, en este caso el tipo se identifica como G, y de
esta manera las instancias de esta clase almacenarn un objeto del tipo G, y tendrn mtodos para obtener o
modificar ese objeto. La razn de este ejemplo especfico es explicar que actualmente una clase de tipo genrico no
puede usar propiedades es su restriccin del tipo, por lo que debe usar mtodos para obtener y modificar este dato.
Para inicializar esta clase, se debe elegir un tipo de dato, por ejemplo el tipo cadena (en Vala no existe restriccin en
el tipo de dtos que puede usarse en una clase genrica). Para crear una instancia de la clase:
var wrapper = new Wrapper<string>();
wrapper.set_data("test");
var data = wrapper.get_data();
Como puede verse, cuando se obtiene los datos de la clase Wrapper, se asignan a un identificador con un tipo no
explcito (que se define mediante la palabra reservada var). Esto es posible por que Vala sabe que tipo de objetos se
encuentran en cada instancia de Wrapper, y por lo tanto puede realizar este trabajo por usted. El hecho de que Vala
no cree varias clases para una definicin genrica significa que se puede realizar un cdigo como el que sigue:
class TestClass : GLib.Object {
}
void accept_object_wrapper(Wrapper<Glib.Object> w) {
}
...
var test_wrapper = new Wrapper<TestClass>();
accept_object_wrapper(test_wrapper);
...
Puesto que todas las instancias de TestClass son tambin objetos GLib.Object, el mtodo accept_object_wrapper
aceptar el objeto que le sea pasado, y lo tratar como si fuera una instancia de un objeto GLib.Object.
Programacin orientada a objetos en Vala
40
Esquema de construccin tipo GObject
Como se coment anteriormente en este mismo captulo, Vala ofrece un estilo de construccin alternativo que es
diferente al anteriormente descrito, pero muy cercano a como se realiza la construccin de objetos con la biblioteca
GObject. El mtodo que el programador prefiere depende de si se procede del estilo de programacin de GObject o
de Java/C#. El estilo de construccin de objetos GObject introduce un nuevo elemento de sintaxis: las propiedades
del constructor, una llamada especial a Object(...) y un bloque de constructor. Vamos a ver como funciona este tipo
de constructor:
public class Person : Object {
/* Propiedades del constructor */
public string name { get; construct; }
public int age { get; construct set; }
public Person(string name) {
Object(name: name);
}
public Person.with_age(string name, int years) {
Object(name: name, age: years);
}
construct {
// Todo lo que tenga que hacer adicionalmente el constructor
stdout.printf("Welcome %s\n", this.name);
}
}
Con este esquema de construccin cada mtodo constructor contiene una llamada a GObject(...) para establecer las
propiedades del constructor. La llamada a GObject(...) toma un nmero variable de parmetros con nombre en la
forma propiedad : valor. Estas propiedades deben ser declaradas como una propiedad del constructor. Se
establecern dichas propiedades a los valores dados despus de que todos los bloques de constructores desde el
original GLib.Object hacia abajo hasta el de la clase actual se hayan ejecutado.
Se garantiza la ejecucin del bloque del constructor cada vez que una clase es creada, incluso si es creada como un
subtipo de la misma. No tiene ni un parmetro ni un valor de retorno. Dentro de este bloque se puede realizar
llamadas a otros mtodos y establecer el valor de miembros dato si es necesario.
Las propiedades de construccin se definen como propiedades con bloques get y set para obtener establecer sus
valores, y por lo tanto con cdigo arbitrario en la asignacin. Si se necesita realizar la inicializacin en una propiedad
de un constructor, es posible escribir un bloque para esa propiedad, la cual se ejecutar inmediatamente despus de la
asignacin, y antes de cualquier cdigo de construccin.
Si una propiedad de constructor se declara sin bloque set se denomina como una propiedad de construccin
exclusiva, lo cual significa que slo puede ser asignada en la fase de construccin, pero no despus de esa fase. En el
ejemplo de arriba la propiedad name es una propiedad de este tipo. A continuacin un resumen de los distintos tipos
de propiedades junto con la nomenclatura que se encuentra en la libreras de tipo GObject:
public int a { get; private set; } // Lectura
public int b { private get; set; } // Escritura
public int c { get; set; } // Lectura / Escritura
Programacin orientada a objetos en Vala
41
public int d { get; set construct; } // Lectura / Escritura /
Construccin
public int e { get; construct; } // Lectura / Escritura / Slo
Construccin
Referencias
[1] http:/ / es. wikipedia. org/ wiki/ Lenguaje_de_programacin_multiparadigma
[2] http:/ / es. wikipedia. org/ wiki/ Conteo_de_referencias
[3] http:/ / es. wikipedia. org/ wiki/ Recolector_de_basura
[4] http:/ / es. wikipedia. org/ wiki/ Algoritmo_determinista
[5] http:/ / es. wikipedia. org/ wiki/ Patr%C3%B3n_de_dise%C3%B1o
[6] http:/ / es. wikipedia. org/ wiki/ RAII
[7] http:/ / es. wikipedia. org/ wiki/ Encapsulamiento_%28inform%C3%A1tica%29
[8] http:/ / es. wikipedia. org/ wiki/ Glade
[9] http:/ / es. wikipedia. org/ wiki/ Widget#Los_widget_en_el_. C3. A1mbito_de_la_programaci. C3. B3n_gr. C3. A1fica
[10] http:/ / es. wikipedia.org/ wiki/ GTK%2B
[11] http:/ / es. wikipedia.org/ wiki/ Polimorfismo_%28inform%C3%A1tica%29
Funcionalidades avanzadas del lenguaje
Aserciones y Diseo por contrato
Con las aserciones un programador puede comprobar que un predicado se cumple en tiempo de ejecucin. La
sintaxis es assert( condicin ). Si la asercin falla el programa terminar su ejecucin con un mensaje de error que
mostrar tal circunstancia. Hay varios mtodos de aserciones definidos en la GLib y que el programador podr usar,
entre los que se encuentran:
Aserciones definidas en GLib
Asercin Descripcin
assert_not_reached() Esta asercin se ejecuta en el caso en el que se llegue a ejecutar la lnea en la que se ha definido.
return_if_fail(expresin_booleana) Si la expresin booleana es falsa, un mensaje de error crtico se muestra y se finaliza la ejecucin de la
funcin. Esto slo se puede usar en mtodos que no devuelven ningn valor.
return_if_reached(val) Si se ejecuta devuelve el valor val y cancela la ejecucin del mtodo.
warn_if_fail(expresin_booleana) Muestra un mensaje de aviso si la expresin booleana resulta ser falsa.
warn_if_reached() Si se ejecuta la lnea dnde se encuentra definido entonces se muestra un mensaje de error.
Puede que el lector quiera usar las aserciones para comprobar si los argumentos de un mtodo tienen valor o son
null, sin embargo, esto no es necesario, ya que, Vala realiza esto de forma implcita sobre todos los parmetros que
no estn marcados con ? (el indicador de que pueden ser de valor null).
void method_name(Foo foo, Bar bar) {
/* No es necesario por que Vala lo hace por t!:
return_if_fail(foo != null);
return_if_fail(bar != null);
*/
}
Funcionalidades avanzadas del lenguaje
42
Vala soporta las funcionalidades bsicas de el diseo por contrato
[1]
. Un mtodo puede tener precondiciones
(requires) y postcondiciones (ensures) que deben ser satisfechos al principio o al final de un mtodo
respectivamente:
double method_name(int x, double d)
requires (x > 0 && x < 10)
requires (d >= 0.0 && d <= 1.0)
ensures (result >= 0.0 && result <= 10.0)
{
return d * x;
}
La variable result es una variable especial que representa el valor de retorno de un mtodo.
Manejo de errores
GLib tiene un sistema para manejar las excepciones en tiempo de ejecucin llamado GError. Vala traduce este
sistema a una forma familiar a la forma en que lo hacen los lenguajes de programacin modernos, pero esto no
quiere decir que lo haga exactamente igual que Java o C#. Es importante considerar cuando usar este tipo de manejo
de errores, GError ha sido diseado para tratar con errores que no sean fatales, es decir, cosas que no son sabidas por
el programa hasta que se ejecuta en un sistema, y no son fatales para la ejecucin del programa. No se debera usar
GError para reportar problemas que pueden ser previstos, como mostrar que se ha pasado un valor invlido al
mtodo. Si un mtodo, por ejemplo, necesita un nmero mayor que como parmetro, debera realizarse la
comprobacin de los valores negativos usando para ello tcnicas de programacin de diseo por contrato como las
precondiciones o las aserciones como se ha descrito en la seccin anterior.
Los errores en Vala son denominadas como excepciones, las cuales significan que estos errores deben ser
controlados en algn punto del cdigo. Sin embargo, si no se controla una excepcin el compilador de Vala
informar de que no se ha hecho esta comprobacin, mediante un aviso, pero no parar la compilacin del cdigo.
El proceso de una excepcin (o error en la terminologa Vala) se compone de:
Declarar que un mtodo puede lanzar una excepcin:
void my_method() throws IOError {
// ...
}
Lanzar el error en el lugar adecuado:
if (something_went_wrong) {
throw new IOError.FILE_NOT_FOUND("Requested file could not be
found.");
}
Controlar el error en un punto del cdigo adecuado:
try {
my_method();
} catch (IOError e) {
stdout.printf("Error: %s\n", e.message);
}
Comparar el cdigo con el operador is:
Funcionalidades avanzadas del lenguaje
43
IOChannel channel;
try {
channel = new IOChannel.file("/tmp/my_lock", "w");
} catch (FileError e) {
if(e is FileError.EXIST) {
throw e;
}
GLib.error("", e.message);
}
Todo esto es similar ms o menos como se hace en otros lenguajes, pero definir los tipos de errores permitidos es
algo nico. Los errores o excepciones tienen tres componentes, conocidos como dominio, cdigo y mensaje. Los
mensajes se han visto anteriormente, y son cadenas de texto suministradas cuando el error es creado. Los dominios
del error describen el tipo del problema, y se asimilan a la subclase de la excepcin en Java o similares. En los
ejemplos anteriores se describe un dominio de error llamado IOError. La tercera parte, el cdigo es un refinamiento
describiendo la variedad exacta del problema encontrado. Cada dominio de error tiene uno o ms cdigos de error,
en el ejemplo se usa un cdigo de error llamado FILE_NOT_FOUND.
La forma de definir esta informacin acerca de los tipos de error est relacionado con la implementacin en la
biblioteca GLib. Para entenderlo mejor se necesita una definicin como la siguiente:
errordomain IOError {
FILE_NOT_FOUND
}
Cuando se controla un error, se da el dominio del error en el que se encuentra definido los errores a controlar, y si un
cdigo de error definido en ese dominio es lanzado, el cdigo fuente que define este bloque se ejecuta con el valor
del error lanzado. Del objeto error lanzado se puede extraer el cdigo de error y el mensaje si se necesita. Si se quiere
controlar errores de ms de un dominio, simplemente se utilizan ms bloques de control de errores. Tambin existe
un bloque opcional que se coloca despus de los bloques de errores definidos por las sentencias try y catch, llamado
finally. Este cdigo ser ejecutado siempre al final de la seccin, independientemente de si se ha lanzado un error o
si se ha ejecutado un bloque catch, incluso si el error no ha sido controlado y ser lanzado otra vez. Esto permite, por
ejemplo, que cualquier recurso reservado en el bloque try ser liberado sin importar cualquier error lanzado. Un
ejemplo completo de todas las funcionalidades descritas es el siguiente:
errordomain ErrorType1 {
CODE_1A
}
errordomain ErrorType2 {
CODE_2A
}
public class Test : GLib.Object {
public static void thrower() throws ErrorType1, ErrorType2 {
throw new ErrorType1.CODE_1A("Error");
}
public static void catcher() throws ErrorType2 {
Funcionalidades avanzadas del lenguaje
44
try {
thrower();
} catch (ErrorType1 e) {
// Se controlan los errores definidos en el dominio de
error ErrorType1
if (e is ErrorType1.CODE_1A) {
// Se controla especficamente el error CODE_1A
perteneciente al dominio de errores ErrorType1
}
} finally {
// Bloque finally para realizar las acciones necesario de
limpieza
}
}
public static int main(string[] args) {
try {
catcher();
} catch (ErrorType2 e) {
// Se controlan los errores definidos en el dominio de
error ErrorType2
}
return 0;
}
}
Este ejemplo tiene dos dominios de errores, ambos puede ser lanzados por el mtodo lanzador llamado thrower. El
mtodo llamado catcher slo puede lanzar el segundo tipo de errores, y por lo tanto debe manejar el primer tipo si
thrower lo lanza. Finalmente el mtodo main controlar cualquier tipo de error desde catcher (de los dominios de
errores que el mtodo catcher ha definido que puede lanzar y que no controla el mtodo).
Direccin de parmetros
Un mtodo en Vala puede recibir cero o ms parmetros. El comportamiento por defecto cuando se llama a un
mtodo es el siguiente:
Cualquier parmetro que sea un tipo pasado por valor se copia a una direccin local al mtodo cuando se ejecuta.
Cualquier parmetro de tipo referencia no se copia, en lugar de esto se pasa una referencia al mtodo que se
ejecuta.
Este comportamiento se puede modificar utilizando para ello los modificadores de parmetros ref y out. Hay cuatro
combinaciones posibles dependiendo de si el programador utiliza estos modificadores en la llamada al mtodo o en
la definicin del mismo:
out utilizado en la llamada al mtodo: se pasar una variable no inicializada al mtodo y se puede esperar que est
inicializada despus de que el mtodo finalice la ejecucin.
out utilizado en la definicin del mtodo: el parmetro se considera no inicializado y el programador tendr que
inicializarlo.
ref utilizado en la llamada al mtodo: la variable que se pasa al mtodo tiene que ser inicializada y puede ser
modificada dentro del mtodo.
Funcionalidades avanzadas del lenguaje
45
ref utilizado en la definicin del mtodo: el parmetro se considera que est inicializado y puede ser modificado
dentro del mtodo.
Ejemplo:
void method_1(int a, out int b, ref int c) { ... }
void method_2(Object o, out Object p, ref Object q) { ... }
Estos mtodos definidos en el ejemplo de arriba podrn ser llamados de las siguientes formas:
int a = 1;
int b;
int c = 3;
method_1(a, out b, ref c);
Object o = new Object();
Object p;
Object q = new Object();
method_2(o, out p, ref q);
El tratamiento que se les va a dar a las variables ser el siguiente:
La variable "a" es de tipo valor. El valor ser copiado a una posicin de memoria nueva y local al mtodo, y por
lo tanto los cambios realizados dentro del mtodo no afectarn al valor original de la misma.
La variable "b" es de tipo valor tambin, pero se ha pasado mediante el modificador out. En este caso, el valor no
es copiado, en lugar de esto se pasa una referencia (puntero) al valor original, y por lo tanto cualquier cambio de
la variable en el mtodo se reflejar en el valor original.
La variable "c" se trata de la misma forma que "b", con la nica salvedad de que se ha se ha sealado claramente
en el mtodo.
La variable "o" es de tipo referencia. El mtodo recibe una referencia con el mismo objeto que cuando se realiza
la llamada. El mtodo puede cambiar el objeto, pero el cambio no ser visible para el cdigo que ha llamado al
mtodo.
La variable "p" es de tipo referencia, pero pasada mediante el modificador out. Esto significa que el mtodo
recibir un puntero a la referencia del objeto. El mtodo puede reemplazar la referencia con otro referencia a otro
objeto distinto, y cuando el mtodo finalice su ejecucin el cdigo que ha llamado al mtodo obtendr un objeto
totalmente distinto. Cuando se use este tipo de parmetro si el mtodo no reasigna la referencia entonces se
establece a null al finalizar la ejecucin del mtodo.
La variable "q" es de nuevo del mismo tipo que la anterior. En este caso se maneja como "p" con una importante
diferencia, ya que el mtodo puede elegir modificarla o no la referencia, y puede acceder al objeto al que
referencia. Vala se asegurar que la instancia "q" apunte a cualquier objeto, y por lo tanto no sea null cuando se
entra en el mtodo.
Funcionalidades avanzadas del lenguaje
46
Colecciones
La biblioteca de funciones Gee
[2]
es una biblioteca de colecciones escrita en Vala. Las clases deberan resultar
familiares a los desarrolladores que han usado bibliotecas como la JFC (Java's Foundation Classes). Gee est
formado por un conjunto de interfaces y distintos tipos de datos que se implementan de distintas formas.
Si se desea usar Gee en una aplicacin, es necesario instalar la biblioteca en el sistema de forma separada. Se puede
obtener Gee desde el enlace
[2]
. Para usar la biblioteca es necesario compilar el programa usando la opcin
--pkggee-1.0.
Los tipos de datos ms tiles son:
Listas: Colecciones ordenadas de elementos, accesibles por un ndice numrico.
Conjuntos: Colecciones de elementos distintos desordenadas.
Mapas (Diccionarios): Colecciones de elementos desordenados, accesibles por un ndice de tipo arbitrario.
Todas las listas y conjuntos en la biblioteca implementan la interfaz Collection, y todos los mapas la interfaz Map.
Las listas implementan asmismo la interfaz List mientras que los conjuntos implementan la interfaz Set. Estas
interfaces comunes significan no slo que todas las colecciones son de un tipo similar y que pueden ser usadas de
manera intercambiable, sino que las colecciones nuevas pueden ser escritas usando las mismas interfaces, y por lo
tanto usando cdigo ya existente.
Tambin es comn a todas las colecciones la interfaz Iterable. Esto significa que cualquier objeto de esta categora
puede ser iterado mediante los mtodos estndar de la interfaz, o directamente mediante la sintxis de Vala, usando
foreach.
Todas las clases e interfaces usan tipos genricos. Esto significa que deben ser instanciadas con un tipo particular o
conjunto de tipos que van a contener. El sistema se asegurar de que slo los tipos especificados puedan aadirse a
una coleccin, y que cuando los objetos se extraigan desde una coleccin se devuelvan con ese tipo.
ArrayList<G>
Implementa: Iterable <G>, Collection <G>, List <G>.
Es una lista ordenada de elementos del tipo G implementada por un vector que crece de forma dinmica. Este tipo es
muy rpido para acceder a los datos, pero potencialmente lento cuando se insertan elementos en cualquier posicin
que no sea al final, o al insertar elementos cuando el vector ya est lleno (y hay por tanto que redimensionarlo).
Ejemplo:
using Gee;
static int main (string[] args) {
var list = new ArrayList<int> (); // Se crea un arraylist de enteros
list.add (1); // Se aade un elemento al final
list.add (2);
list.add (5);
list.add (4);
list.insert (2, 3); // Se inserta el elemento '2' en la posicin
'3'
list.remove_at (3); // Se elimina el elemento de la posicin '3'
// Se recorre todo el vector
foreach (int i in list) {
stdout.printf ("%d\n", i);
}
Funcionalidades avanzadas del lenguaje
47
list[2] = 10; // Se obtiene el mismo
resultado que con '''list.set (2, 10)'''
stdout.printf ("%d\n", list[2]); // Se obtiene el mismo
resultado que con '''list.get (2)'''
return 0;
}
Para compilar este programa se tiene que ejecutar algo similar a lo que aparece en la siguiente lnea de comandos:
valac programa_gee.vala --pkg gee-1.0
Como se puede ver en el cdigo de arriba lo primero que se hace es crear el objeto de tipo ArrayList de tipo entero
lo cual se especifica entre los smbolos de menor y mayor. Despus se usa el mtodo add para aadir un elemento al
final de la coleccin. Esta inserccin es rpido en comparacin con la inserccin de un elemento en una posicin
determinada de la lista; algo que se consigue mendiante el uso del mtodo insert, al que se le pasa el elemento y la
posicin. Se cuenta con el mtodo remove_at que se usa para eliminar un elemento en una posicin determinada,
indicando la posicin como parmetro. Se ve como se puede recorrer toda la lista mediante el uso de la construccin
foreach. Por ltimo se como es posible acceder a la lista mediante el uso de la sintaxis de vector indicando la
posicin entre corchetes. Esta sintxis se puede usar tanto para acceder como modificar el valor de una posicin
determinada. Para ms informacin sobre las listas se puede consultar la API de Vala al respecto en [3].
HashMap<K,V>
Implementa: Iterable <Entry<K,V>>, Map <K,V>
Es un mapa en relacin 1 a 1 de elementos de tipo K a elementos de tipo V. El mapeo se hace mediante el clculo de
un valor hash
[4]
para cada llave, esto puede ser modificado mediante el uso de punteros a funciones para el clculo
de funciones de hash y funciones que comprueben la igualdad de las claves de una forma concreta.
Se puede pasar opcionalmente una funcin de hash y un comparador al constructor de la siguiente forma:
var map = new Gee.HashMap<Foo, Object>(foo_hash, foo_equal);
Ejemplo:
using Gee;
static int main (string[] args) {
var map = new HashMap<string, int> ();
map.set ("one", 1);
map.set ("two", 2);
map.set ("three", 3);
map["four"] = 4; // same as map.set ("four", 4)
map["five"] = 5;
stdout.printf("%d\n", map['four']);
foreach (string key in map.keys) {
stdout.printf ("%d\n", map[key]); // same as map.get (key)
}
return 0;
Funcionalidades avanzadas del lenguaje
48
}
Este programa se compila de la misma forma que el anterior. El programa define inicialmente un mapa map que
tendrn claves de tipo cadena y valores de tipo entero. Estos mapas puede definir valores de tuplas mediante el
mtodo set de los objetos o mediante la sintxis de corchetes. As se puede usar tambin el mtodo get para obtener
un valor dado una clave o mediante la sintxis de los corchetes. Para ms informacin sobre este tipo de colecciones
se puede consultar la API en [5].
HashSet<G>
Implementa: Iterable <G>, Collection <G>, Set <G>
Un conjunto de elementos del tipo G que no estn repetidos. Los elementos duplicados se detectan calculando un
valor resumen (hash) para cada clave, esto puede modificarse pasando un mtodo que calcule el resumen y un
mtodo que compruebe la igualdad de una forma especfica. Esto se realiza de la misma forma que con un mapa de
tipo HashMap.
Ejemplo:
using Gee;
static int main (string[] args) {
var my_set = new HashSet<string> ();
my_set.add ("one");
my_set.add ("two");
my_set.add ("three");
my_set.add ("two"); // No se podr aadir por que ya est
en el conjunto
foreach (string s in my_set) {
stdout.printf ("%s\n", s);
}
return 0;
}
En el ejemplo de arriba se aaden elementos al conjunto mediante el mtodo add. Para recorrer todo el conjunto se
puede usar la construccin foreach de Vala. Para acceder se usa el mtodo contains que nos indica si un elemento se
encuentra dentro del conjunto o no.
Vista de slo lectura
Se puede obtener una vista de una coleccin de slo lectura mediante la propiedad read_only_view, por ejemplo,
mi_mapa.read_only_view. Esto devolver una vista que tiene la misma interfaz que la coleccin que contiene, pero
no permitir ninguna modificacin, o cualquier acceso a la coleccin que contiene.
Mtodos con soporte de sintaxis
Vala reconoce algunos mtodos que tienen un nombre determinado y un conjunto de parmetros y suministra soporte
para ellos. Por ejemplo, si una clase tiene un mtodo llamado contains() los objetos de este tipo se pueden utilizar
con el operador in. La siguiente tabla muestra unos mtodos especiales que Vala reconoce:
Funcionalidades avanzadas del lenguaje
49
Mtodos con reconocimiento de sintaxis
Mtodo Operador Descripcin
get(TIPO ndice) Acceso mediante objeto[ndice] Permite el acceso mediante un ndice (del tipo definido) a un
objeto indexado
void set(TIPO1 ndice,
TIPO2 item)
Acceso mediante objeto[ndice] = item Permite la insercin de un item en (del tipo definido) a un objeto
indexado
get(TIPO1 ndice1, TIPO2
ndice2)
Acceso mediante objeto[ndice1, ndice2] Permite el acceso mediante dos ndices (cada uno de un tipo que
puede ser distinto o no) a un objeto doblemente indexado (por
ejemplo una matriz)
void set(TIPO1 ndice1,
TIPO2 ndice2, TIPO2
item)
Acceso mediante objeto[ndice1, ndice2] =
item
Permite la insercin de un item en (del tipo definido) a un objeto
doblemente indexado (como por ejemplo una matriz)
slice(long start, long end) Trocea objetos mediante objeto[start:end] Permite trocear un objeto indexado mediante el operador por
defecto, indicando un inicio del troceo start, y un final end
bool contains(T needle) Comprueba que un subconjunto est dentro de
un conjunto mediante bool b = needle in object
Permite comprobar si un subconjunto needle se encuentra presente
dentro del conjunto object. En case de estar presente debe devolver
un valor true, en caso contrario false
string to_string(void) Convierte el objeto en una cadena y permite su
uso dentro de las plantillas de cadenas mediante
@"$object"
Permite convertir un objeto en cadena y por lo tanto se podr usar
en diversas situaciones entre ellas en las plantillas de cadenas.
Iterator iterator(void) Permite recorrer un objeto mediante la estructura
foreach"
Permite recorrer un objeto indexado de alguna forma mediante la
estructura foreach del lenguaje.
El siguiente ejemplo muestra algunos de los mtodos especificados:
public class EvenNumbers {
public int get(int index) {
return index * 2; // Devuelve el nmero par que ocupa la
posicin index del conjunto de los nmeros pares
}
public bool contains(int i) {
return i % 2 == 0; // Nos dice si el elemento i se
encuentra dentro del conjunto de nmeros pares
}
public string to_string() {
return "[This object enumerates even numbers]"; // La
representacin en cadena muestra ayuda de lo que representa la clase
}
public Iterator iterator() {
return new Iterator(this); // Permite que el conjunto de los
nmeros pares se recorra mediante foreach
}
public class Iterator {
private int index;
Funcionalidades avanzadas del lenguaje
50
private EvenNumbers even;
public Iterator(EvenNumbers even) {
this.even = even; // Constructor del iterador
}
public bool next() {
return true; // El mtodo nos indica si el conjunto tiene
o no un nmero par o no
}
public int get() {
this.index++; // Devuelve el siguiente nmero par del
iterador
return this.even[this.index - 1];
}
}
}
void main() {
var even = new EvenNumbers();
stdout.printf("%d\n", even[5]); // get()
if (4 in even) { // contains()
stdout.printf(@"$even\n"); // to_string()
}
foreach (int i in even) { // iterator()
stdout.printf("%d\n", i);
if (i == 20) break;
}
}
Multihilo
Hilos en Vala
Un programa escrito en Vala puede tener ms de un hilo en ejecucin, permitiendole hacer ms de una cosa al
mismo tiempo. Fuera del mbito de Vala los hilos comparten un mismo procesador o no, dependiendo del entorno de
ejecucin.
Un hilo en Vala no se define en el tiempo de compilacin, en lugar de eso se define una porcin del cdigo Vala para
que se ejecute como un nuevo hilo. Esto se realiza mediante el mtodo esttico de la clase Thread de la biblioteca
GLib, como puede verse en siguiente ejemplo:
void* thread_func() {
stdout.printf("Thread running.\n");
return null;
}
int main(string[] args) {
Funcionalidades avanzadas del lenguaje
51
if (!Thread.supported()) { // Se comprueba si se soportan la
ejecucin con hilos
stderr.printf("No puede ser ejecutado sin hilos.\n");
return 1;
}
try {
Thread.create(thread_func, false);
} catch (ThreadError e) {
return 1;
}
return 0;
}
Este programa pedir que un nuevo hilo se cree y ejecute. El cdigo a ejecutar est contenido en el mtodo
thread_func. Ntese tambin la comprobacin que se realiza al principio del mtodo principal, un programa en Vala
no podr usar hilos a no ser que sea compilado de una forma adecuada, de esta forma si se compila de la forma
habitual, mostrar un mensaje de error y parar la ejecucin. La posibilidad de comprobar el soporte de hilos en
tiempo de ejecucin permite al programa ser construido para ser ejecutado con o sin hilos si se quiere. Para compilar
con soporte de hilos, se debe ejecutar una lnea de comandos similar a la siguiente:
$ valac --thread threading-sample.vala
Esto incluir las bibliotecas necesarias e inicializar el sistema de hilos cuando sea posible. El programa se ejecutar
ahora sin producirse fallos de violacin de acceso
[6]
, pero no se comportar como se espera. Sin un conjunto de
bucles, el programa terminar cuando el hilo principal (el que ha sido creado con la funcin principal) finalice. Para
controlar este comportamiento, se puede permitir cooperar a los hilos entre s. Esto se puede realizar mediante los
bucles de eventos y las colas asncronas, pero en esta introduccin a los hilos se mostrar las posibilidades bsicas de
los hilos.
Es posible para un hilo comunicarle al sistema que ahora no necesita ejecutarse, y por lo tanto sugerir que sea otro
hilo el que debera ejecutarse en lugar del primero, esto se realiza mediante el mtodo esttico Thread.yield(). Si
esta sentencia se coloca al final del mtodo main definido arriba, el sistema de ejecucin pausar la ejecucin del
hilo principal por un instante y comprobar si hay otros hilos que pueden ejecutarse, encontrando el hilo creado
recientemente en un estado de pausa y a la espera de ejecucin, y ejecutar el nuevo hilo hasta la finalizacin del
mismo, y el programa tendr el comportamiento esperado. Sin embargo, no hay garanta de que esto pase as. El
sistema tiene potestad para decidir cuando ejecuta los hilos, y de esta forma podra no permitir que el nuevo hilo
termine antes de que el hilo principal es reiniciado y el programa finalice.
Para esperar a que un hilo finalice de forma completa hay un mtodo llamado join(). LLamando a este mtodo en un
objeto Thread causa que el hilo que ha realizado la llamada espere a que finalice el otro hilo antes de finalizar.
Tambin permite a un hilo recibir el valor de retorno de otro, si eso es til. Para implementar la unin de hilos se
realiza mediante un cdigo similar al siguiente:
try {
unowned Thread thread = Thread.create(thread_func, true);
thread.join();
} catch (ThreadError e) {
return 1;
}
Funcionalidades avanzadas del lenguaje
52
Esta vez, cuando se cree el hilo se le pasar true como ltimo argumento. Esto marca el hilo como que puede ser
unido (joinable). Se recuerda el valor devuelto desde la creacin, una referencia sin propietario al objeto Thread
(las referencias sin propietario se explicarn despus y no son vitales para esta seccin). Con esta referencia es
posible unir el nuevo hilo al hilo principal. Con esta versin del programa se garantiza que el nuevo hilo creado se
ejecutar al completo antes de que el primer hilo contine y finalice la ejecucin del programa.
Todos estos ejemplos tienen un problema potencial, en el cual el hilo creado no sabe en que contexto debera
ejecutarse. En el lenguaje C se suministrara a la creacin del hilo algunos datos ms, en Vala en cambio se pasara
una instancia del mtodo a Thread.create, en lugar de un mtodo esttico.
Control de recursos
Cuando ms de un hilo se est ejecutando al mismo tiempo, existe la posibilidad de que los datos sean accedidos de
forma simultanea. Esto puede hacer que el programa no sea determinista, ya que la salida depende de cuando el
sistema decide cambiar la ejecucin entre los hilos.
Para controlar esta situacin, se puede usar la palabra reservada lock para asegurarse de que un bloque de cdigo no
ser interrumpido por otros hilos que necesitan acceder al mismo dato. La mejor forma de mostrar esto es mediante
un ejemplo como el siguiente:
public class Test : GLib.Object {
private int a { get; set; }
public void action_1() {
lock (a) {
int tmp = a;
tmp++;
a = tmp;
}
}
public void action_2() {
lock (a) {
int tmp = a;
tmp--;
a = tmp;
}
}
}
Esta clase define dos mtodos, dnde ambos necesitan cambiar el valor de la variable a. Si no estuviera el bloque
definido por la palabra reservada lock, podra ser posible para las instrucciones de esos mtodos cambiaran el valor
de a y el resultado de las operaciones sera aleatorio. Como se ha establecido los bloques lock Vala garantizar que
si un hilo ha bloqueado la variable a, otro hilo que necesita la misma variable tenga que esperar su turno hasta que el
primero finalice de manipularla.
En Vala slo es posible bloquear miembros de un objeto que est ejecutando el cdigo. Esto podra parecer una
restriccin muy grande, pero de hecho el uso estndar de esta tcnica debera incluir clases que son responsables
individualmente de controlar un recurso, y por lo tanto todos los bloqueos deben ser internos a la clase. Del mismo
modo, en el ejemplo de arriba todos los accesos a la variable a se encapsulan en la clase.
Funcionalidades avanzadas del lenguaje
53
El bucle principal
La biblioteca GLib incluye un sistema para la ejecucin de un bucle de eventos, en las clases alrededor del bucle
principal MainLoop. El propsito de este sistema es permitir escribir programas que esperen a que sucedan eventos
para responder a dichos eventos, en lugar de tener que estar comprobando las condiciones continuamente hasta que
se cumplan. Este es el modelo que usa la biblioteca GTK+
[7]
, para que el programa espere hasta que se produzca la
interaccin con el usuario sin necesidad de tener cdigo ejecutndose en el momento que se produce la interaccin.
El siguiente programa crea e inicia el bucle MainLoop, y enlaza un conjunto de eventos a dicho bucle. En este caso
el cdigo es un simple temporizador, el cual ejecutar el mtodo despus de 2000ms. El mtodo de hecho parar el
bucle principal, el cual har que finalice el programa.
void main() {
var loop = new MainLoop();
var time = new TimeoutSource(2000);
time.set_callback(() => {
stdout.printf("Time!\n");
loop.quit();
return false;
});
time.attach(loop.get_context());
loop.run();
}
El cdigo crea un nuevo bucle principal (MainLoop) y despus inicializa un temporizador TimeoutSource.
Utilizando un mtodo annimo se aade el evento del temporizador al bucle principal. As cuando el temporizador
llegue a 0 lanzar un evento que har que se ejecute el mtodo annimo definido, el cual imprime por pantalla un
mensaje y despus sale de la ejecucin del bucle principal y finaliza la ejecucin del programa.
Cuando se usa GTK+, se crea un bucle principal automticamente, y se ejecutar cuando se lance el mtodo
Gtk.main(). Esto marca el punto dnde el programa est listo para ejecutarse y empezar a aceptar eventos del
usuario u otros eventos externos. El cdigo en GTK+ es equivalente al ejemplo de arriba, y por lo tanto se puede
aadir eventos de la misma forma, aunque se necesite usar los mtodos GTK+ para controlar el bucle principal.
void main(string[] args) {
Gtk.init(ref args);
var time = new TimeoutSource(2000);
time.set_callback(() => {
stdout.printf("Time!\n");
Gtk.main_quit();
return false;
});
time.attach(null);
Funcionalidades avanzadas del lenguaje
54
Gtk.main();
}
Un requisito comn en el desarrollo de interfaces de usuario es ejecutar el cdigo tan pronto como sea posible, pero
slo cuando no moleste al usuario. Para ello, se puede usar las instancias de tipo IdleSource. Estas mandan eventos
al bucle principal del programa, pero las peticiones slo sern tratadas cuando no hay nada ms importante que
hacer.
Para obtener ms informacin acerca de la biblioteca de funciones GTK+ se puede consultar la documentacin de
GTK+
[8]
o la documentacin de la API de Vala
[9]
.
Mtodos asncronos
Con los mtodos asncronos es posible programar sin realizar bloqueos de ninguna clase. Desde la versin 0.7.6 del
compilador de Vala, se suministra una sintaxis especial para la programacin asncrona.
Sintaxis y ejemplos
Un mtodo asncrono se define mediante el modificador async. Se puede llamar a un mtodo asncrono con la
sintaxis nombre_metodo.begin() desde un mtodo sncrono. Desde un mtodo asncrono se pueden llamar a otros
mtodos asncronos utilizando la palabra reservada yield. Esto har que el mtodo llamador se suspenda hasta que
otro mtodo devuelva el valor de retorno (y finalice por tanto su ejecucin). Todo esto se realiza implcitamente
mediante llamadas con AsyncResult. Todo lo relacionado con los mtodo asncronos en Vala depende de la
biblioteca GIO, por lo que se debe compilar los programas con la opcin --pkg gio-2.0. A continuacin se muestra
un ejemplo de este tipo de mtodos:
// Ejemplo con mtodos asncronos
async void list_dir() {
var dir = File.new_for_path (Environment.get_home_dir()); // Se
obtiene un objeto fichero del directorio HOME
try {
var e = yield
dir.enumerate_children_async(FILE_ATTRIBUTE_STANDARD_NAME,
0, Priority.DEFAULT,
null); // Se obtienen los ficheros/directorios que contiene el
directorio HOME
while (true) {
var files = yield e.next_files_async(10, Priority.DEFAULT,
null); // Se van obteniendo hasta que devuelve null y no hay ms
if (files == null) {
break;
}
foreach (var info in files) {
print("%s\n", info.get_name()); // Se muestran todos
los ficheros obtenidos
}
}
} catch (Error err) {
warning("Error: %s\n", err.message);
Funcionalidades avanzadas del lenguaje
55
}
}
void main() {
list_dir.begin();
new MainLoop().run();
}
El mtodo list_dir() no es bloqueante. Dentro de list_dir(), el mtodo asncrono enumerate_children_async() y
next_files_async() se llaman con la palabra reservada yield. El mtodo list_dir() continuar ejecutndose mientras
que se devuelvan los valores de retorno de los mtodo asncronos y finalicen su ejecucin.
Mtodos asncronos personalizados
El ejemplo anterior usaba mtodos de la biblioteca GIO para demostrar el uso del mtodo .begin() y de la palabra
reservada yield. Pero es posible escribir mtodos asncronos de manera personalizada. A continuacin se explicar la
manera de hacerlo.
// Ejemplo con mtodos asncronos personalizados:
class Test : Object {
public async string test_string(string s, out string t) {
assert(s == "hello");
Idle.add(test_string.callback);
yield;
t = "world";
return "vala";
}
}
async void run(Test test) {
string t, u;
u = yield test.test_string("hello", out t);
print("%s %s\n", u, t);
main_loop.quit();
}
MainLoop main_loop;
void main() {
var test = new Test();
run.begin(test);
main_loop = new MainLoop();
main_loop.run();
}
Funcionalidades avanzadas del lenguaje
56
La llamada .callback se usa para registrar de forma implcita un mtodo _finish para el mtodo asncrono. Esto se
usa con la palabra reservada yield.
// Se aada el callback al mtodo
Idle.add(async_method.callback);
yield;
// Se devuelve el resultado
return result;
Despus de la sentencia yield; el resultado se puede devolver. De manera implcita, se puede realizar con un
AsyncResult en el mtodo callback. El mtodo calback se parece mucho al concepto de continuacin
[10]
en ciertos
lenguajes de programacin (por ejemplo Scheme
[11]
) salvo que en Vala representa el contexto inmediatamente
posterior a la sentencia yield.
El mtodo end() es la sintaxis que se usa para el mtodo _finishi. Toma un AsyncResult y devuelve el resultado real
o lanza una excepcin (si el mtodo asncrono lo hace). La llamada se realiza en el callback del mtodo asncrono de
una forma similar a la siguiente:
async_method.end(result)
Referencias dbiles
La gestin de memoria en Vala se basa en el conteo automtico de referencias
[2]
. Cada vez que un objeto se asigna a
una variable su contador de referencias se incrementa en 1, cada vez que una variable, la cual referencia un objeto,
sale del mbito; su contador interno de referencias se decrementa en 1. Si el contador de referencias alcanza el valor
0 el objeto ser liberado (el bloque de memoria que contiene ese objeto ser liberado).
Sin embargo, es posible formar un ciclo de referencias con las estructuras de datos que el programador defina. Por
ejemplo, con una estructura de rbol
[12]
de datos dnde un nodo hijo mantiene una referencia a su padre y viceversa,
o una lista doblemente enlazada
[13]
dnde cada elemento mantiene una referencia a su predecesor y el predecesor
mantiene una referencia a su sucesor.
En estos casos los objetos podran mantenerse vivos simplemente referencindose unos a otros, a pesar de que
deberan ser liberados. Para romper este ciclo de referencias se pueden usar el modificador weak para una de las
referencias:
class Node : Object {
public Node prev;
public Node next;
public Node (Node? prev = null) {
this.prev = prev; // ref
if (prev != null) {
prev.next = this; // ref
}
}
}
void main () {
var n1 = new Node (); // ref
var n2 = new Node (n1); // ref
Funcionalidades avanzadas del lenguaje
57
// Imprime el conteo de referencias para los dos objetos
stdout.printf ("%u, %u\n", n1.ref_count, n2.ref_count);
} // unref, unref
Los lugares dnde se producen las referencias y los borrados de referencias se han comentado para una mejor
comprensin del ejemplo. La siguiente figura muestra la situacin despus de que los nodos A, B y C hayan sido
asignados y enlazados:
Cada flecha representa un enlace a un objeto de la lista doblemente enlazada. Se puede ver como en el ejemplo cada
vez que se asigna el objeto a un enlace se aumenta el contador de referencias. Al finalizar todos las asignaciones de
los objetos se deben obtener un contador de referencias de dos para cada nodo. Cuando se finalice el uso de los
nodos stos se eliminar la referencia a ellos, por lo que el contador de referencias se valdr 1 y no 0 por lo que la
memoria que ocupan no ser liberada. En este caso el programa finalizar y el trabajo que no ha realizado el
programa (liberar esos recursos) lo har el sistema operativo. Sin embargo que pasara si el programa fuera algo as:
void main () {
while (true) {
var a = new Node ();
var b = new Node (a);
var c = new Node (b);
Thread.usleep (1000);
}
}
Para comprobarlo slo tienes que abrir el gestor de tareas (por ejemplo gnome-system-monitor) e iniciar el
programa. Podrs ver que ese programa est devorando la memoria. Finaliza el proceso antes de que haga que tu
sistema no responda adecuadamente (la memoria ser liberada inmediatamente).
Un programa equivalente en C# o Java no tendra ningn problema, por que el recolector de basuras puede detectar
estos ciclos en las referencias en tiempo de ejecucin. Pero Vala esto no lo realiza (por que no hay recolector de
basuras) y el programador debe tener en cuenta este tipo de problemas.
La forma de romper el ciclo es mediante la definicin de alguna de las referencias como una referencia dbil (weak):
public weak Node prev;
public Node next;
Este modificador hace que la asignacin de esta variable no haga que su contador de referencias se incremente en 1.
De esta forma uno de los nodos tendr un contador de referencias de 1 en lugar de 2, por lo que cuando finalice el
programa se eliminar esa referencias y el contador de referencias alcanzar el valor de 0, por lo que se liberar la
memoria que ocupaba ese nodo. Esto al provocar que todas las referencias que contena el nodo se eliminen, har
que se produzca un efecto cascada liberando de memoria todos los nodos que haba.
Funcionalidades avanzadas del lenguaje
58
Propiedad de las referencias
Referencias sin propietario
Normalmente cuando se crea un objeto en Vala se devuelve una referencia que apunta a dicho objeto. Esto significa
que adems de haberse pasado un puntero al objeto a memoria, tambin se ha almacenado en el propio objeto que
ese puntero existe. De forma similar, cuando otra referencia al objeto se crea, tambin es almacenada. De la misma
forma que un objeto sabe cuantas referencias tiene, puede ser eliminado de ellas cuando lo necesite. Este es el
comportamiento bsico de la gestin de memoria.
Las referencias sin propietario no se almacenan en el objeto al que referencian. Esto permite al objeto ser eliminado
cuando deba serlo, sin importar el hecho de que an haya referencias que apunten hacia l. La forma usual de
alcanzar esto es con un mtodo definido con un valor de vuelta de una referencia sin propietario, como el siguiente
cdigo muestra:
class Test {
private Object o;
public unowned Object get_unowned_ref() {
this.o = new Object();
return this.o;
}
}
Cuando se llame a este mtodo, para recoger una referencia al objeto devuelto, se debe esperar recibir una referencia
dbil:
unowned Object o = get_unowned_ref();
La razn para este ejemplo tan complicado es debida al concepto de propiedad:
Si el objeto "o" no se almacena en la clase, entonces cuando el mtodo get_unowned_ref devuelve el valor,
"o" sera un objeto sin propietario (por ejemplo no habra referencias hacia l). Si este fuera el caso, el objeto
sera borrado y el mtodo jams devolvera una referencia vlida.
Si el valor de retorno no se define como unowned, la propiedad pasara al nodo que ha realizado la llamada. El
cdigo de llamada est, sin embargo, esperando una referencia sin propietario (unowned), la cual no puede
recibir la propiedad.
Si el cdigo de llamada se escribe de la siguiente forma:
Object o = get_unowned_ref();
Vala intentar o bien obtener una referencia del objeto o bien una instancia duplicada a dnde apunta la referencia.
En contraste a los mtodos normales, las propiedades siempre devuelven valores sin propietario. Esto significa que
no se puede devolver un objeto nuevo creado dentro de un mtodo get de una propiedad. Tambin significa que, no
se puede usar una referencia con propietario como valor de retorno de una llamada a un mtodo. Este hecho es
debido a que el valor de la propiedad est asignado (es propiedad de) al objeto que tiene la propiedad. Debido a esto
el siguiente cdigo devolver un error:
public Object property {
get {
return new Object(); // MAL: La propiedad devuelve una
Funcionalidades avanzadas del lenguaje
59
referencia sin dueo,
// el objeto nuevo ser borrado cuando
// el mbito del mtodo 'get' finalice,
finalizando el cdigo que
// ha llamada al mtodo 'get' obteniendo
una referencia a un
// objeto borrado.
}
}
Tampoco estara permitido realizar una cosa similar al siguiente cdigo:
public string property {
get {
return getter_method(); // MAL: Por la misma razn que
arriba.
}
}
public string getter_method() {
return "some text"; // "some text" se duplica y se devuelve en este
punto del cdigo.
}
Por el contrario, el siguiente cdigo es perfectamente legal y compila sin ningn problema:
public string property {
get {
return getter_method(); // BIEN: El mtodo 'getter_method'
devuelve una referencia sin propietario
}
}
public unowned string getter_method() {
return "some text";
// No se preocupe por que el texto no sea asignado a alguna
variable fuerte.
// las cadenas literales son propiedad del mdulo del programa en
Vala,
// y existen mientras el programa est cargado en memoria.
}
El modificador unowned se puede usar para hacer el almacenamiento de las propiedades sin propietario. Es decir:
public unowned Object property { get; private set; }
Es idntico al cdigo:
private unowned Object _property;
public Object property {
Funcionalidades avanzadas del lenguaje
60
get { return _property; }
}
La palabra reservada owned se puede usar para pedir que una propiedad devuelva especficamente una referencia al
valor con propietario, por lo tanto, causando que el valor de la referencia se copie del lado del objeto. Piense dos
veces antes de aadir la palabra reservada owned. Es una propiedad o simplemente un mtodo get_xxx? Puede que
tenga problemas en el diseo. De todas formas, el cdigo que sigue es correcto y compilar sin problemas:
public owned Object property { owned get { return new Object(); } }
Las referencias sin propietario juegan un papel similar a los punteros que sern descritos ms adelante. Sin embargo,
es ms simple usar punteros, ya que pueden ser convertidos en referencias normales de forma simple. Sin embargo,
no est aconsejado su uso en un programa a menos que el programador sepa lo que est haciendo.
Transferencia de la propiedad
La palabra reservada owned se usa para realizar una transferencia de la propiedad de una referencia de las siguientes
formas:
Como un prefijo del tipo del parmetro, lo cual indica que la propiedad del objeto se transfiere dentro del
contexto del cdigo.
Como un operador de conversin, se puede usar para evitar la duplicidad de clases sin conteo de referencia, lo
cual es imposible en Vala. Por ejemplo:
Foo foo = (owned) bar;
Este cdigo indica que bar ser inicializada a null y que foo heredar la propiedad del objeto al que bar apunta.
Listas de parmetros de longitud variable
Existe la posibilidad de usar las listas de argumentos de tamao variable para los mtodos en Vala, igual que en otros
lenguajes de programacin, como por ejemplo C. Se declaran mediante puntos suspensivos (...) en los parmetros del
mtodo. Un mtodo que tiene una lista de parmetros de longitud variable debe tener al menos un parmetro fijo:
void method_with_varargs(int x, ...) {
var l = va_list();
string s = l.arg();
int i = l.arg();
stdout.printf("%s: %d\n", s, i);
}
En este ejemplo x es un argumento fijo para cumplir con los requisitos. La lista de argumentos se obtiene con el
mtodo va_list(). Despus se puede ir obteniendo argumento tras argumento mediante el mtodo arg(T) de la lista
de argumentos, siendo T el tipo que debera ser el argumento. Si el tipo es evidente (como en el ejemplo anterior) se
infiere automticamente y se puede utilizar la llamada a arg() sin argumentos.
El siguiente ejemplo pasa un nmero indeterminado de cadenas de caracteres que se convierten en nmeros reales
(double):
void method_with_varargs(int fixed, ...) {
var l = va_list();
while (true) {
string? key = l.arg();
Funcionalidades avanzadas del lenguaje
61
if (key == null) {
break; // fin de la lista y se sale del bucle infinito
}
double val = l.arg();
stdout.printf("%s: %g\n", key, val);
}
}
void main() {
method_with_varargs(42, "foo", 0.75, "bar", 0.25, "baz", 0.32);
}
En el ejemplo se comprueba que la cadena sea null para reconocer el final de la lista de parmetros. Vala pasa
implcitamente el valor null como el ltimo argumento de la lista que reciben estos mtodos.
Este forma de recibir listas de parmetros de tamao indeterminado tiene un inconveniente que el programador debe
tener en cuenta. El compilador no puede decirle al programador cuando se estn pasando argumentos del tipo
correcto al mtodo y cuando no. Por este motivo el programador debe considerar el uso de estas listas slo si tiene
una buena razn para hacerlo y es imprescindible, por ejemplo: suministrar una funcin conveniente para los
programadores de C que usen una biblioteca desarrollada en Vala. A menudo un argumento del tipo vector es una
eleccin ms acertada y segura.
Un patrn comn para el uso de las listas de parmetros es esperar parejas de argumentos del tipo propiedad y valor
a menudo referidas a gobject. En este caso se puede escribir propiedad : valor, como en el siguiente ejemplo:
actor.animate (AnimationMode.EASE_OUT_BOUNCE, 3000, x: 100.0, y: 200.0,
rotation_angle_z: 500.0, opacity: 0);
Este cdigo de arriba sera equivalente al siguiente cdigo fuente:
actor.animate (AnimationMode.EASE_OUT_BOUNCE, 3000, "x", 100.0, "y",
200.0, "rotation-angle-z", 500.0, "opacity", 0);
Punteros
Los punteros de Vala son una forma de permitir la gestin manual de la memoria en los programas. Por regla
general, cuando el programador crea una instancia de un tipo se devuelve una referencia a ese objeto, y Vala se
encarga de destruir la instancia cuando no haya ms referencias a ese objeto, y por lo tanto no sea til. Si se pide un
puntero en lugar de una referencia, ser el programador el encargado de destruir la instancia cuando ya no se
necesite, y por lo tanto obtendr un mayor control sobre la memoria que est usando el programa en desarrollo.
Esta funcionalidad no se necesita en la mayora de las ocasiones, puesto que los ordenadores modernos son
suficientemente rpidos para manejar las referencias (y el conteo de referencias) y tienen suficiente memoria que las
pequeas problemas de eficiencia que genera la gestin de memoria automtica no son importantes. Sin embargo
pueden darse algunas situaciones en las cuales ser necesario usar la gestin manual de la memoria. Por ejemplo:
En caso de que el programador quiera optimizar un programa especficamente en el uso de memoria.
Cuando el programa trabaja con una biblioteca externa que no implementa el conteo de referencias para la
gestin de memoria (probablemente por que no est basada en g-object).
Para crear una instancia de un tipo y recibir un puntero a ese nuevo objeto (en lugar de una referencia) se procede de
la siguiente forma:
Object* o = new Object();
Funcionalidades avanzadas del lenguaje
62
Para acceder a los mtodos y los miembros en general del objeto se usa el operador ->:
o->method_1();
o->data_1;
Para liberar la memoria en la que se almacena el objeto (cuando ste ya no sea til):
delete o;
Vala tiene soporte para los operadores de punteros que se usan en C, es decir, el operador direccin de (&) y el
operador indireccin
[14]
(*). El primer operador obtiene la direccin de memoria de un objeto y el segundo obtiene
el propio objeto a partir de un puntero (se usa para acceder al contenido del objeto):
int i = 42; // Un entero con valor 42
int* i_ptr = &i; // Obtenemos un puntero que apunta al entero i
mediante el operador direccin de
int j = *i_ptr; // Mediante el operador indireccin se obtiene el
contenido del entero 'i'.
*i_ptr = 7; // Se modifica el valor del entero tambin mediante
el operador indireccin.
Cuando en lugar de valores primitivos (como en el caso anterior en el que se ha usado un entero) se usan referencia a
objetos se pueden omitir los operadores, ya que, en este caso se estn usando sobre referencias que apuntan a los
objetos.
Foo f = new Foo();
Foo* f_ptr = f; // Se obtiene la direccin del objeto que apunta la
referencia 'f'
Foo g = f_ptr; // Se obtiene el contenido del objeto y se apunta
mediante una nueva referencia llamada 'g'
unowned Foo f_weak = f; // Esto es equivalente a la segunda lnea de
cdigo
El uso de punteros es equivalente al uso de referencias sin propietario como se puede ver en el ejemplo de arriba en
la ltima lnea de cdigo.
Clases que no heredan de GLib.Object
Las clases que no hereden en ningn nivel de GLib.Object son tratadas como un caso especial. Estas clases derivan
directamente desde el sistema de tipos de GLib y por lo tanto son ms ligeras (en uso de recursos).
Un caso obvio de este tipo de clases son algunos de los Binding
[15]
a la biblioteca GLib. Puesto que la biblioteca
GLib hace un trabajo a ms bajo nivel que GObject, la mayora de las clases que se definen en el binding son de este
tipo. Como se ha comentado anteriormente, estas clases son ms ligeras, lo cual las haces tiles en algunos casos
(por ejemplo en el uso del propio compilador de Vala). Sin embargo, el uso de este tipo de clases no es muy habitual
por lo que no se tratar en este documento.
Funcionalidades avanzadas del lenguaje
63
Referencias
[1] http:/ / es. wikipedia. org/ wiki/ Dise%C3%B1o_por_Contrato
[2] http:/ / live.gnome. org/ Libgee
[3] http:/ / www. valadoc. org/ gee-1. 0/ Gee.ArrayList.html
[4] http:/ / es. wikipedia. org/ wiki/ Hash
[5] http:/ / www. valadoc. org/ gee-1. 0/ Gee.HashMap.html
[6] http:/ / es. wikipedia. org/ wiki/ Violacin_de_acceso
[7] http:/ / www. gtk. org/
[8] http:/ / library. gnome. org/ devel/ gtk/ stable/
[9] http:/ / valadoc. org/ gtk+ -2. 0/ index. html
[10] http:/ / en. wikipedia. org/ wiki/ Continuation
[11] http:/ / es. wikipedia.org/ wiki/ Scheme
[12] http:/ / es. wikipedia.org/ wiki/ %C3%81rbol_%28inform%C3%A1tica%29
[13] http:/ / es. wikipedia.org/ wiki/ Lista_%28inform%C3%A1tica%29#Lista_Doblemente_Enlazada
[14] http:/ / es. wikipedia.org/ wiki/ Indirecci%C3%B3n
[15] http:/ / es. wikipedia.org/ wiki/ Binding
Funcionalidades experimentales del lenguaje
Las funcionalidades que se presentan en este captulo han sido definidas como experimentales y por lo tanto no se
recomienda su uso hasta que se defina completamente el estndar del lenguaje, ya que podra cambiar su sintaxis e
incluso dejar de existir en una versin definitiva del compilador.
Expresiones relacionales encadenadas
Esta funcionalidad del lenguaje permite escribir expresiones relacionales complejas como la siguiente:
if (1 < a && a < 5) {}
if (0 < a && a < b && b < c && c < d && d < 255) {
// Acciones
}
De una forma ms simple como la siguiente:
if (1 < a < 5) {}
if (0 < a < b < c < d < 255) {
// Acciones
}
De esta forma se encadenan los valores y nos aseguramos que la condicin sea cierta antes de que se ejecuten las
acciones. Esta forma de escribir la expresin relacional es ms natural y semejante a como se define de forma
matemtica la expresin.
Funcionalidades experimentales del lenguaje
64
Expresiones regulares en literales
Las expresiones regulares
[1]
son una tcnica muy potente para tratar cadenas de texto y realizar operaciones de
bsqueda de patrones entre otros usos. Vala dispone de funcionalidad experimental con expresiones regulares en
literales de una forma similar a como lo hace el lenguaje de programacin Perl
[2]
. Vala utiliza el operador
/expresion-regular/ para definir un objeto de tipo Regex. Por ejemplo:
string email = "tux@kernel.org";
if (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.match(email)) {
stdout.printf("Direccin de correo vlida\n");
}
El modificador i que aparece despus de la definicin de la expresin regular y antes de la llamada al mtodo
match(email) hace que la expresin regular sea insensible a las maysculas. Se puede almacenar una expresin
regular en un objeto de tipo Regex:
Regex regex = /foo/;
Las expresiones regulares son una tcnica de una complejidad suficiente como para dedicarles un documento
separado del actual por lo que si el lector desea conocer ms sobre el uso de expresiones regulares en Vala puede
usar los siguientes enlaces para satisfaces su curiosidad:
Expresiones regulares con GLib
[3]
. (Esta es la sintaxis que se usa en Vala).
Expresiones regulares en Vala
[4]
. (Documentacin oficial de Vala).
Modo no-nulo estricto
Si se compilan programas con la opcin --enable-experimental-non-null el compilador de Vala ejecutar una serie
de comprobaciones estticas considerando todos los tipos como no nulos por defecto a menos que sean declarados
como posibles nulos con el modificador ?.
Object o1 = new Object(); // No puede ser nulo
Object? o2 = new Object(); // Puede ser nulo
El compilador realizar un anlisis en tiempo de compilacin para asegurarse de que las referencias se asigna a
referencias que no pueden se nulas. Por ejemplo, en este modo de compilacin, el siguiente cdigo no compilara y
dara un error:
Object o1 = new Object(); // No puede ser nulo
Object? o2 = new Object(); // Puede ser nulo
o1 = o2;
La referencia o2 ha sido marcada como una referencia que puede tener el valor nulo mientras que o1 no puede ser
nulo. Sin embargo se puede evitar este comportamiento por defecto del compilador mediante el uso de la conversin
a un tipo no nulo explcita, siempre que estemos seguros de que la referencia no sea nula:
o1 = (!) o2;
El modo no nulo estricto ayuda a evitar errores con referencias que tienen valores nulos. Esta caracterstica sera
complete si la posibilidad de valor nulo de todos los valores de retorno en las librerias estuviera marcada de forma
correcta, pero actualmente no siempre se hace.
Funcionalidades experimentales del lenguaje
65
Referencias
[1] http:/ / es. wikipedia. org/ wiki/ Expresi%C3%B3n_regular
[2] http:/ / es. wikipedia. org/ wiki/ Perl#Expresiones_regulares
[3] http:/ / library. gnome. org/ devel/ glib/ stable/ glib-regex-syntax. html
[4] http:/ / valadoc. org/ glib-2. 0/ GLib.Regex.html
Bibliotecas del lenguaje
Esta seccin se encargar de describir el uso de las principales bibliotecas que se necesitan en la mayora de los casos
a la hora de desarrollar una aplicacin. Sin embargo no se tratar la gran cantidad de bibliotecas que existen dentro
del lenguaje de programacin Vala, ya que existen diversas documentaciones sobre cada biblioteca especfica. As
para consultar todas las bibliotecas que son accesibles desde el lenguaje en la actualidad se puede consultar la pgina
de documentacin de vala
[1]
.
Acceso a ficheros en Vala (biblioteca GIO)
La biblioteca de funciones GIO
[2]
es similar en funcionalidad al framework IO de Java. Esta biblioteca contiene
objetos para el trabajo con ficheros, tanto para lectura como para escritura. Contiene dos clases base, una para lectura
y otra para escritura: InputStream y OutputStream. Cuando se abre un fichero para su lectura se obtiene una
referencia a un objeto de la clase InputStream.
Los flujos se pueden usar con el patrn de diseo decorador
[3]
para suministrar funcionalidad adicional. Por ejemplo
es posible leer el contenido de un fichero lnea a lnea mediante un DataInputStream. O se puede aplicar un
FileInputStream para realizar algn filtrado de datos.
Leer un fichero lnea a lnea
El siguiente ejemplo lee el contenido de un fichero de texto lnea a lnea y escribe el texto por pantalla.
static int main (string[] args) {
// Referencia a un fichero llamado 'data.txt'
var file = File.new_for_path ("data.txt");
if (!file.query_exists (null)) { // Se comprueba si el fichero
existe o no
stderr.printf ("File '%s' doesn't exist.\n", file.get_path ());
// No existe y se muestra un mensaje de error
return 1;
}
try {
// Se abre un fichero para lectura y se convierte el
FileInputStream en un
// DataInputStream, para que se pueda leer lnea a lnea
var in_stream = new DataInputStream (file.read (null));
string line;
// Se lee la lnea hasta que se devuelva un null que indica que
se ha llegado al final del fichero
while ((line = in_stream.read_line (null, null)) != null) {
Bibliotecas del lenguaje
66
stdout.printf ("%s\n", line);
}
} catch (Error e) { // Si se produce un error se muestra
error ("%s", e.message);
}
return 0;
}
Referencias
[1] http:/ / valadoc. org/
[2] http:/ / library. gnome. org/ devel/ gio/ stable/
[3] http:/ / es. wikipedia. org/ wiki/ Decorator_(patrn_de_diseo)
Herramientas
Las herramientas para compilar un programa escrito en Vala son muy sencillas: En primer lugar, y ante todo, el
compilador Valac, y en segundo lugar un editor de texto plano, no un procesador de palabras (como GEdit, no uses
programas parecidos a LibreOffice Writer).
Podemos usar un IDE como Geany para mayor comodidad. Esta es decisin del programador. Te mostraremos las
opciones a configurar y ser tu decisin la va que usars para desarrollar tus aplicaciones.
Instalando el compilador Valac
El compilador Valac se puede instalar de dos formas: Desde los repositorios de software de tu distribucin
GNU/Linux o bien desde el cdigo fuente descargado de la pgina oficial del proyecto Vala.
Desde los repositorios de software
El compilador se encuentra (a veces en versiones desactualizadas) en los repositorios de software de la mayora de
las distribuciones GNU/Linux. Lo puedes instalar si tienes Debian/Ubuntu o derivados con
apt-get install valac
O bien si tu distribucin es basada en RPM (Fedora) con el comando
yum install vala
Los usuarios de Arch Linux no tendrn problemas en tener el paquete actualizado, pues esta distribucin se
caracteriza por siempre ir al corriente en cuanto a las ltimas versiones de todos los paquetes de Software, basta
instalarlo con el comando
pacman -S vala
Herramientas
67
Desde el cdigo fuente
Si no deseas obtener el compilador como paquete de tu distribucin por alguna razn (como lo es que el paquete est
desactualizado) siempre lo puedes descargar y compilar por ti mismo. El compilador Valac puede ser descargado del
sitio web oficial de Vala
[1]
. Obtendrs un archivo nombrado como vala-x.x.x.tar.xz, donde las x representan el
nmero de la versin descargada, como puede ser vala-0.15.0.tar.xz.
Descomprime el archivo desde tu terminal:
tar -Jxf vala-0.15.0.tar.xz
Sustituye los nmeros de la versin por la versin del lanzamiento que hayas descargado.
Luego, una vez descomprimido el archivo, muvete a la ruta del directorio del compilador, en este caso a la carpeta
vala-0.15.0
cd vala-0.15.0
y ejecuta los comandos de construccin como los siguientes:
./configure --prefix=/usr
Si todo sale bien, se crearn los Makefiles para que puedas comenzar la compilacin (proceso que tarda de acuerdo a
la capacidad de tu computadora, variando al rededor de 3 minutos).
Pero si no tuviste xito, revisa que tengas los archivos de desarrollo de GLib, de tener Ubuntu/Debian o algn
derivado, instala el paquete libglib2.0-dev, si usas una distribucin basada en RPM, busca el paquete glib2-devel.
Cuando hayas completado lo anterior, contina el proceso simplemente ejecutando:
make
Y si la compilacin tuvo xito, puedes terminar el proceso de instalacin ejecutando -con privilegios
administrativos- el comando
make install
Y al finalizar, para asegurarte de que todo haya tenido xito, puedes revisar la versin del compilador que tienes
instalada en tu sistema, con el comando
valac --version
Y dicho comando deber devolver una salida con la versin que hemos instalado del compilador, en nuestro caso de
ejemplo, la salida ser
[root@machine vala-0.15.0]# valac --version
Vala 0.15.0
Y con esto nos hemos asegurado de instalar exitosamente el compilador Valac en nuestra computadora.
Herramientas
68
El editor de textos
El editor de textos que usaremos para crear nuestros programas ser un editor de texto plano, en el caso de la
plataforma GNOME y en casi todas las distribuciones GNU/Linux tenemos por defecto el editor de texto Gedit.
Gedit
Este editor nos da la caracterstica de resaltado de palabras clave del lenguaje, puede ser configurado para resaltar
parejas de corchetes (algo que es til cuando tenemos un programa muy jerarquizado) y nos puede mostrar los
nmeros de lnea en que nos encontramos.
Para usarlo, simplemente tenemos que abrirlo, crear un archivo de cdigo fuente y colocarle la extensin del archivo
.vala para que el editor automticamente detecte el tipo de lenguaje que manejamos y nos resalte las palabras clave.
La desventaja de usarlo es que tendremos que guardar los archivos de cdigo fuente cada vez que deseemos realizar
una compilacin y abrir una terminal para hacerla. Luego en la terminal teclear el comando para la construccin y, si
existieran errores, estos seran mostrados en pantalla, pero tendramos que buscar la lnea de cdigo errnea en el
archivo de cdigo fuente en Gedit, no en la terminal.
GNU Nano
No se recomienda el uso de este programa para usuarios novatos o sin experiencia en el uso extenso de la terminal,
pero es una opcin en caso de no disponer de alguna otra alternativa para editar textos, casi todas las distribuciones
GNU/Linux, independientemente del entorno del escritorio que tengamos (GNOME, KDE, XFCE, LXDE, etc) lo
traen incluido.
Este es un editor de texto en modo consola, es decir que para poder usarlo tendremos que abrir una terminal y teclear
el comando invocando al programa, de la forma
nano archivo.vala
donde archivo.vala es el nombre del archivo de cdigo fuente que deseamos editar, ya sea que exista o que deseemos
crearlo.
La lista de opciones que usaremos ser limitada, no existe un resaltado de sintaxis ni un conteo de nmeros de lnea
tal como lo tenemos en Gedit o en otros editores especializados.
Las opciones bsicas que usaremos sern
Ctrl + o para guardar el archivo actual.
Ctrl + x para salir del editor.
Ctrl + w para buscar una cadena de texto en el documento.
y Ctrl + g para ver la ayuda.
Y de la misma forma en que usamos Gedit para compilar un archivo de cdigo fuente, tendremos que guardar los
cambios antes de compilar, y debemos buscar manualmente las lneas que contengan errores y corregirlas, para
repetir el proceso hasta la finalizacin del desarrollo de nuestros programas.
Herramientas
69
Usar un IDE
IDE son siglas inglesas para un entorno integrado de desarollo, y es que precisamente en un programa como Geany
tenemos todas las opciones de configuracin que necesitamos para desarrollar (sin salir de ah) nuestros programas
escritos en varios lenguajes de programacin.
En primer lugar, debemos instalar Geany desde nuestros repositorios de Softwawe, y cuando est instalado
simplemente tenemos que abrir nuestros archivos de cdigo fuente en Vala y el editor integrado nos dar el resaltado
de sintaxis y la terminal incluida debajo o bien las opciones de compilacin rpida nos darn la ayuda que
necesitamos para desarrollar nuestros programas de forma eficiente.
Otras tcnicas
El compilador Valac est basado en el modelo de objetos de GLib y GObject. Todos los programas que escribimos
en lenguaje Vala son traducidos a lenguaje C y luego con el compilador GCC son compilados a cdigo de mquina.
Por esto mismo, los programas en Vala escritos de esta forma
void main () {
stdout.printf("Programa de prueba");
}
Tienen de forma oculta un namespace sin mostrarlo, ya que es agregado automticamente al compilador, de forma
que el programa anterior es equivalente al siguiente
using GLib; // Aunque esta lnea no es necesaria.

void main () {
stdout.printf("Programa de prueba");
}
Y es que la clase stdout es miembro de GLib, por tanto suceder que si escribimos o no el namespace este se usar.
Namespaces de GLib
Una lista de los namespaces de GLib
[1]
es:
Math
[2]
Definciones numricas, constantes matemticas y descomposicin de puntos flotantes
[3]
.
AtomicInt
[4]
Operaciones atmicas - Operaciones bsicas para enteros atmicos
[5]
.
AtomicPointer
[6]
Operaciones atmicas - Operaciones bsicas para punteros atmicos
[7]
Priority
[8]
Timeout
[9]
Idle
[10]
ChildWatch
[11]
Memory
[12]
Slice
[13]
Log
[14]
Filename
[15]
Base64
[16]
Codifica y decodifica datos en Base 64
[17]
.
Random
[18]
Generador de nmeros pseudo-aleatorios
[19]
.
Environment
[20]
KeyFileDesktop
[21]
Otras tcnicas
70
Bit
[22]
SpacedPrimes
[23]
CharacterSet
[24]
Process
[25]
FileUtils
[26]
Algunas funciones para manejo de archivos
[27]
.
DirUtils
[28]
Uri
[29]
Shell
[30]
Markup
[31]
KeyFileDesktop
[21]
Test
[32]
Intl
[33]
Win32
[34]
Y cabe decir que todos estos namespaces, cada uno con todas sus clases y funciones estn disponibles para su uso
con el compilador Valac sin agregar otra librera o namespace.
Ejemplo de uso de un Namespace de GLib
Como ya lo dijimos, los Namespaces de GLib pueden ser usados en cualquier momento en los programas escritos en
Vala que hagamos. Para ejemplificarlo veremos una ejemplo prctico y sencillo: Dado el valor de un ngulo,
deseamos conocer el valor del seno matemtico de ste. Para eso, recurriremos al Namespace Math de GLib, usando
la funcin Math.sin() para conocer el valor de dicha operacin (expresada en Radianes
[35]
). Dicho programa tendra
la siguiente forma:
void main () {
stdout.printf("Dame el valor de un ngulo: ");
string entrada = stdin.read_line();
double resultado = Math.sin( double.parse(angulo) );
stdout.printf("El seno de %s es %d radianes\n", entrada, resultado);
}
Explicando el programa, tenemos que en primer lugar, se imprime la lnea indicando la entrada de un ngulo. En la
siguiente lnea se crea una cadena de texto, llamada entrada, y el valor de esa cadena de texto se asigna mediante la
funcin stdin.read_line().
Luego, se crea un flotante de precisin doble, llamado resultado, y el valor de dicho resultado es la salida de la
funcin Math.sin(), y como parmetro a dicha funcin se asigna el valor de la cadena de texto entrada. Pero como se
trata de una cadena de texto (string), hacemos una conversin hacia un flotante de precisin doble con la funcin
double.parse().
Luego, se imprimen los resultados en pantalla. El indicador %s indica que se pasa una cadena de texto (string), y el
indicador %d indica que se pasa un flotante de precisin doble(double). Y a esos parmetros se pasan los parmetros
entrada y resultado.
Este ejemplo fue algo sencillo para explicar los Namespaces de GLib, y cada uno de ellos tiene su forma de uso, pero
bsicamente se utilizan de esa forma.
Otras tcnicas
71
Referencias
[1] http:/ / valadoc. org/ glib-2. 0/ GLib.html
[2] http:/ / valadoc. org/ glib-2. 0/ GLib.Math.html
[3] http:/ / developer. gnome. org/ glib/ 2. 28/ glib-Numerical-Definitions. html
[4] http:/ / valadoc. org/ glib-2. 0/ GLib.AtomicInt.html
[5] http:/ / developer. gnome. org/ glib/ 2. 28/ glib-Atomic-Operations. html
[6] http:/ / valadoc. org/ glib-2. 0/ GLib.AtomicPointer.html
[7] http:/ / developer. gnome. org/ glib/ 2. 28/ glib-Atomic-Operations. html
[8] http:/ / valadoc. org/ glib-2. 0/ GLib.Priority.html
[9] http:/ / valadoc. org/ glib-2. 0/ GLib.Timeout.html
[10] http:/ / valadoc. org/ glib-2. 0/ GLib.Idle.html
[11] http:/ / valadoc. org/ glib-2. 0/ GLib.ChildWatch.html
[12] http:/ / valadoc. org/ glib-2. 0/ GLib.Memory.html
[13] http:/ / valadoc. org/ glib-2. 0/ GLib.Slice. html
[14] http:/ / valadoc. org/ glib-2. 0/ GLib.Log.html
[15] http:/ / valadoc. org/ glib-2. 0/ GLib.Filename.html
[16] http:/ / valadoc. org/ glib-2. 0/ GLib.Base64.html
[17] http:/ / developer. gnome. org/ glib/ 2. 28/
[18] http:/ / valadoc. org/ glib-2. 0/ GLib.Random.html
[19] http:/ / developer. gnome. org/ glib/ 2. 28/ glib-Random-Numbers. html
[20] http:/ / valadoc. org/ glib-2. 0/ GLib.Environment.html
[21] http:/ / valadoc. org/ glib-2. 0/ GLib.KeyFileDesktop. html
[22] http:/ / valadoc. org/ glib-2. 0/ GLib.Bit. html
[23] http:/ / valadoc. org/ glib-2. 0/ GLib.SpacedPrimes.html
[24] http:/ / valadoc. org/ glib-2. 0/ GLib.CharacterSet.html
[25] http:/ / valadoc. org/ glib-2. 0/ GLib.Process.html
[26] http:/ / valadoc. org/ glib-2. 0/ GLib.FileUtils. html
[27] http:/ / developer. gnome. org/ glib/ 2. 28/
[28] http:/ / valadoc. org/ glib-2. 0/ GLib.DirUtils.html
[29] http:/ / valadoc. org/ glib-2. 0/ GLib.Uri.html
[30] http:/ / valadoc. org/ glib-2. 0/ GLib.Shell. html
[31] http:/ / valadoc. org/ glib-2. 0/ GLib.Markup.html
[32] http:/ / valadoc. org/ glib-2. 0/ GLib.Test.html
[33] http:/ / valadoc. org/ glib-2. 0/ GLib.Intl. html
[34] http:/ / valadoc. org/ glib-2. 0/ GLib.Win32.html
[35] http:/ / es. wikipedia.org/ wiki/ Radian
Fuentes y contribuyentes del artculo
72
Fuentes y contribuyentes del artculo
Programacin en Vala Fuente: http://es.wikibooks.org/w/index.php?oldid=192013 Contribuyentes: Sigmar, 9 ediciones annimas
Introduccin Fuente: http://es.wikibooks.org/w/index.php?oldid=182078 Contribuyentes: Sigmar, 11 ediciones annimas
Su primer programa en Vala Fuente: http://es.wikibooks.org/w/index.php?oldid=154216 Contribuyentes: Sigmar, 2 ediciones annimas
Conceptos bsicos del lenguaje Fuente: http://es.wikibooks.org/w/index.php?oldid=190592 Contribuyentes: Sigmar, 10 ediciones annimas
Programacin orientada a objetos en Vala Fuente: http://es.wikibooks.org/w/index.php?oldid=155147 Contribuyentes: Sigmar
Funcionalidades avanzadas del lenguaje Fuente: http://es.wikibooks.org/w/index.php?oldid=157213 Contribuyentes: Sigmar, 1 ediciones annimas
Funcionalidades experimentales del lenguaje Fuente: http://es.wikibooks.org/w/index.php?oldid=157203 Contribuyentes: Sigmar
Bibliotecas del lenguaje Fuente: http://es.wikibooks.org/w/index.php?oldid=157350 Contribuyentes: Sigmar
Herramientas Fuente: http://es.wikibooks.org/w/index.php?oldid=177967 Contribuyentes: TheOrlSan
Otras tcnicas Fuente: http://es.wikibooks.org/w/index.php?oldid=178070 Contribuyentes: TheOrlSan
Fuentes de imagen, Licencias y contribuyentes
73
Fuentes de imagen, Licencias y contribuyentes
Archivo:Doubly linked list insert after.png Fuente: http://es.wikibooks.org/w/index.php?title=Archivo:Doubly_linked_list_insert_after.png Licencia: Public Domain Contribuyentes: Original
uploader was Fripp at it.wikipedia
Licencia
74
Licencia
Creative Commons Attribution-Share Alike 3.0 Unported
//creativecommons.org/licenses/by-sa/3.0/

Potrebbero piacerti anche