Empezando

Instalaciones previas y algunos conceptos básicos.

Requisitos

Instalamos desde los repositorios de cualquier distribución linux:

  • valac (compilador). Esto puede requerir o recomendar libglib2.0-dev y gcc.
  • librerías: en principio no es necesario nada más, pero son recomendables libgee-0.8-2 y libgee-0.8-dev. Más adelante podemos necesitar alguna más, por ejemplo libgtk-3-0 y libgtk-3-dev para la interfaz gráfica y librerías SDL para juegos.
  • Un editor, en mi caso Gedit y Geany.

Nota:

valac es el compilador del lenguaje de programación Vala que compilará el programa Genie en C para producir el binario, por lo que instalando Vala instalamos su compilador.

En febrero de 2020 se ha publicado la versión Vala 0.47.4.

Por ejemplo, en una distribución linux como Manjaro puedes empezar a utilizar Genie instalando el paquete vala desde los repositorios oficiales (todavía la versión 0.46.5-1 a fecha 05/02/2020).

Visita Overview of Installing Vala para ver la instalación en otras distribuciones linux y en otros sistemas operativos.

Identado

Como un lenguaje que toma a Python como referencia, Genie utiliza espacios en blanco o tabuladores en lugar de llaves para delimitar bloques.

Aunque por defecto Genie utiliza la tabulación, también se pueden utilizar espacios para el sangrado pero en ese caso se debe especificar en la primera línea del programa, por ejemplo:

[indent = 4]

En este ejemplo, ese atributo le dice a Genie que ignore las tabulaciones y use 4 espacios para significar una sangría de bloque (indent = 0 significa usar una tabulación, pero no es necesario indicarlo).

En mi caso, prefiero utilizar la tabulación, por lo que los ejemplos de código que utilizo en esta wiki no hacen ninguna declaración explícita sobre ello. Según he leído, el uso de tabuladores o espacios para la sangría de código ha sido un tema recurrente de discusión en Python durante mucho tiempo, y finalmente el consenso general es usar espacios. Sin embargo, el creador de Genie decidió usar la tabulación por defecto, y en mi opinión es un acierto.

Info!

Los ejemplos de código de esta Wiki utilizan el identado por defecto basado en tabulaciones, y por tanto, salvo excepciones puntuales, no se utiliza ninguna declaración explícita sobre ello. No obstante, ten en cuenta que, en algunas aplicaciones, al copiar y pegar el código, las tabulaciones se pueden transformar en espacios. En esos casos, para usar el código tal cual, los espacios se deben reconvertir a tabulaciones.

Si utilizas Geany, puedes configurarlo desde Preferencias, en la pestaña Editor, y luego en Sangría para especificar un ancho de 4 y tipo Tabulaciones y marcar la opción de 'Usar la tecla Tabulador para realizar la sangría'. También tienes que tener en cuenta que si pegas en Geany un código identado con espacios y lo vas a editar, antes puedes cambiarlos todos en lote por tabuladores desde Documento, en 'Reemplazar espacios por tabulaciones'. Esto mismo también lo puedes hacer con SpacesToTab, una pequeña aplicación que he desarrollado (con Genie, por supuesto) y que permite sustituir a la vez todos los bloques de 4 espacios por tabuladores. La puedes encontrar en los ejemplos de Gtk.

Comentarios

Genie permite introducir comentarios dentro del código de dos maneras:

  • Comentarios de una línea (al inicio o al final de una línea) con //
  • Comentarios de varias líneas con el texto comentado entre /* y */
// Iniciamos el programa
init
	print "Hola mundo"  // Escribe en consola 'Hola mundo'
 
/* Fin de mi primer
 programa con Genie 
 ¡soy un genio de la programación! */

Bloque init

En el ejemplo de código anterior observamos un bloque init que incluye el código print.

init declarado fuera de una clase o estructura es equivalente a una función “principal” (main) en C, y hay que tener en cuenta dos cosas:

  1. Solo puede haber presente un init en el código (fuera de una clase o estructura).
  2. Cualquier código que deba ejecutarse al arrancar debe estar contenido o llamado desde ahí.

Condiciones y convenciones sobre los nombres

En el ejemplo anterior hablamos de init pero no de Init, puesto que Genie es sensible a mayúsculas y minúsculas.

Para definir las variables, funciones y demás identificadores recuerda no salirte de los caracteres imprimibles ASCII, esto es, olvídate de letras acentuadas y también de la ñ.

La convención sobre los nombres aboga porque:

  • las variables y las funciones (métodos) se escriban con minúsculas separadas por un guión bajo si se componen de dos palabras (var nombre, var contacto_nombre, def funcion_calculo),
  • las clases, los datos enum y los namespacesse se nombren con la primera letra en mayúsculas y si se componen de dos palabras, se unen ambas: class ClaseEjemplo, y
  • los valores de los enum se escriban con mayúsculas separados por un guión bajo si son dos palabras (DIA_LUNES).

Aunque ya lo iremos viendo, y según veamos más código bien escrito, finalmente lo haremos por costumbre. Por ahora mejor no agobiarse con algunos de estos palabros que veremos más adelante.

Guardar, compilar y ejecutar

Los archivos se guardan con la extensión .gs (“hola.gs”), se compilan con valac ($valac hola.gs) y se ejecutan desde la consola con: $./hola

Si trabajas con un IDE, como Geany o cualquier otro, puedes compilar y ejecutar directamente desde allí (F9 para compilar y F5 para ejecutar en Geany), aunque hay que tener en cuenta que a veces el comando valac utiliza ciertos parámetros y habrá que configurar el IDE para que los utilice.

Compilador valac

Ya hemos visto que utilizamos valac para compilar nuestro código escrito con Genie.

Puede resultar útil tener una visión general de lo que está sucediendo en segundo plano cuando se ejecuta valac, aunque solo sea por comprender los mensajes de retroalimentación del compilador, especialmente cuando devuelve algún mensaje de error o advertencia.

genie_and_valac
Fuente imagen: The Genie Programming Language Tutorial

De modo muy resumido (a lo bestia), el proceso que ejecuta valac se desarrolla en tres fases:

  1. En la primera etapa, valac convierte el archivo hola.gs en una representación interna.
  2. En una segunda etapa, valac verifica el código de esa representación interna comprobando que no existan errores (por ejemplo, en los tipos de datos).
  3. Finalmente, valac llama a un compilador C (por defecto gcc) que produce el binario desde código C (normalmente después de producir el binario, valac borra los archivos C temporales, pero se pueden salvar con el modificador --save-temps; y para producir solo un archivo C utilizamos --ccode que devuelve hola.c).

Uso de bibliotecas C

Genie tiene la poderosa propiedad de mantener un alto nivel de compatibilidad con los programas y bibliotecas C. Para usar una librería C específica, valac utiliza un archivo de traducción que traslada la sintaxis de Genie a un correcto código C. Ese archivo de traducción se conoce como archivo VAPI (Vala Application Programming Interface).

De forma predeterminada, valac incluye dos archivos VAPI cuando compila un programa Genie: GLib y GObject./p>

Para usar otras bibliotecas C en Genie, además de tenerlas instaladas, hay que utilizar el modificador --pkg seguido del nombre que llama a esa librería. Es la manera de indicar al compilador que el código requiere de otras dependencias y que debe organizarse en consecuencia.

Como hemos comentado y veremos en detalle a la hora de trabajar con listas y diccionarios, necesitamos una biblioteca adicional denominada libgee (libgee-0.8-2 y libgee-0.8-dev) y especificarlo en el compilador:

$ valac --pkg gee-0.8 hola.gs

Y para conseguir una interfaz gráfica Gtk hay que tener instaladas sus librerías (libgtk-3-0 y libgtk-3-dev) y definirlo en valac:

$ valac --pkg gtk+-3.0 hola.gs

Cada librería se debe indicar con un modificador --pkg independiente:

$ valac --pkg gtk+-3.0 --pkg gee-0.8 hola.gs

Esto se detalla al principio del código. Por ejemplo:

uses Gee
uses
	Gee 
	Gtk

Combinando archivos

Otra posibilidad que ofrece valac, especialmente útil en casos de códigos muy extensos para ofrecer un código más limpio y organizado, es la de subdividir nuestro código en distintos archivos e indicarle al compilador que importe los archivos necesarios (como si fueran librerías) para que el binario se ejecute correctamente.

init
	var mi_tirada = new Ruleta()
 
	print "%s",mi_tirada.apuestas()
	mi_tirada.jugar()
	stdout.printf ("%s",mi_tirada.apuestas())
 
	print ("Gana: %d, %s, %s.", mi_tirada.numero, mi_tirada.color, mi_tirada.par)
 
class Ruleta:Object
 
	prop numero:int = 0         // del 1 al 36
	prop color:string = "rojo"  // rojo o negro
	prop par:string = "impar"   // par o impar
 
	def jugar()
		numero = Random.int_range (1, 37) // un número del 1 al 36
		if numero % 2 == 0
			par = "par"
		col:int = Random.int_range (0, 2)
			if col == 0
				color = "negro"
 
	def apuestas ():string
		var ap = ""
		if numero == 0
		   ap = "Cierren sus apuestas.\n"
		else
		   ap = "No se admiten más apuestas.\n"
		return ap

Por ejemplo, si tenemos este código, podemos dividirlo en dos archivos.

tirada.gs:

init
	var mi_tirada = new Ruleta()
 
	print "%s",mi_tirada.apuestas()
	mi_tirada.jugar()
	stdout.printf ("%s",mi_tirada.apuestas())
 
	print ("Gana: %d, %s, %s.", mi_tirada.numero, mi_tirada.color, mi_tirada.par)

ruleta.gs:

class Ruleta:Object
 
	prop numero:int = 0         // del 1 al 36
	prop color:string = "rojo"  // rojo o negro
	prop par:string = "impar"   // par o impar
 
	def jugar()
		numero = Random.int_range (1, 37) // un número del 1 al 36
		if numero % 2 == 0
			par = "par"
		col:int = Random.int_range (0, 2)
			if col == 0
				color = "negro"
 
	def apuestas ():string
		var ap = ""
		if numero == 0
		   ap = "Cierren sus apuestas.\n"
		else
		   ap = "No se admiten más apuestas.\n"
		return ap

Y lo compilamos con:

$ valac -o juego ruleta.gs tirada.gs

Esto creará un archivo ejecutable llamado juego que usará como fuentes ambos archivos.

Lo mismo, también lo podemos escribir así:

$ valac ruleta.gs tirada.gs --output casino
🔝