Este documento presenta una introducción al lenguaje de programación Vala. Explica brevemente qué es Vala, a quién va dirigido el documento y algunas convenciones del lenguaje. Luego muestra un programa "Hola Mundo" de ejemplo en Vala y explica sus características principales como la definición de clases, métodos y parámetros. Finalmente, proporciona referencias a otros documentos sobre conceptos de programación orientada a objetos relevantes para comprender el código de ejemplo.
Este documento presenta una introducción al lenguaje de programación Vala. Explica brevemente qué es Vala, a quién va dirigido el documento y algunas convenciones del lenguaje. Luego muestra un programa "Hola Mundo" de ejemplo en Vala y explica sus características principales como la definición de clases, métodos y parámetros. Finalmente, proporciona referencias a otros documentos sobre conceptos de programación orientada a objetos relevantes para comprender el código de ejemplo.
Este documento presenta una introducción al lenguaje de programación Vala. Explica brevemente qué es Vala, a quién va dirigido el documento y algunas convenciones del lenguaje. Luego muestra un programa "Hola Mundo" de ejemplo en Vala y explica sus características principales como la definición de clases, métodos y parámetros. Finalmente, proporciona referencias a otros documentos sobre conceptos de programación orientada a objetos relevantes para comprender el código de ejemplo.
Este documento presenta una introducción al lenguaje de programación Vala. Explica brevemente qué es Vala, a quién va dirigido el documento y algunas convenciones del lenguaje. Luego muestra un programa "Hola Mundo" de ejemplo en Vala y explica sus características principales como la definición de clases, métodos y parámetros. Finalmente, proporciona referencias a otros documentos sobre conceptos de programación orientada a objetos relevantes para comprender el código de ejemplo.
Descargue como PDF, TXT o lea en línea desde Scribd
Descargar como pdf o txt
Está en la página 1de 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 = "[email protected]"; 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/