Excepciones en Xojo: Errores en tiempo de ejecución

Gestión de excepciones en XojoTodo buen lenguaje de programación, y Xojo lo es, incorpora los mecanismos necesarios para que nuestras aplicaciones puedan salir airosas frente a los errores que puedan producirse en tiempo de ejecución: las Excepciones. Es decir, aquellos aspectos que no hayamos previstos durante la fase de desarrollo o que, por la propia naturaleza de la aplicación propiamente dicha, no podemos controlar o prever.

El primero de estos mecanismos, y que encontrarás en prácticamente cualquier lenguaje de programación, es la gestión de Excepciones en tiempo de ejecución. Estos son los errores que se producen cuando nuestro código indica una acción que no se puede satisfacer, y probablemente se corresponda con los mensajes de error que hayas recibido con más frecuencia al dar tus primeros pasos programando con Xojo.

Por ejemplo, uno de los errores o Excepciones más comunes en tiempo de ejecución es cuando intentamos acceder a la posición de un elemento de Array que sobrepasa su capacidad (es decir, el número utilizado como índice es superior al de los propios elementos almacenados por el Array), o bien cuando utilizamos una Key (clave) no registrada en un Diccionario.

También es frecuente encontrarnos con la excepción que nos indica el intento de acceso o uso a un objeto no inicializado. Ya sabes, me refiero al típico y temido: “Nil Object Exception”; aunque también se pueden producir otros tipos de excepciones que no están ligados a nuestra pericia como desarrolladores, sino que se producen, por ejemplo, debido a que el sistema sobre el que se ejecuta nuestra aplicación no dispone de la cantidad de recursos suficientes como para satisfacer la petición del código (por ejemplo, cuando ya no queda más memoria libre).

Sea cual sea el tipo de Excepción producida en tiempo de ejecución, el resultado será siempre el mismo: la interrupción o salida inesesperada de nuestra aplicación; algo que, de cara a nuestros usuarios, es uno de los errores más bruscos y que pueden ser percibidos como una falta de cuidado en nuestro software (tranquilo, todos hemos pasado por esta experiencia en el despliegue de nuestros productos).

Excepciones

La instrucción que nos permite atrapar las excepciones producidas en tiempo de ejecución es Exception. Dicha intrucción debe figurar obligatoriamente al final del bloque de código normal, y puede incluir opcionalmente una variable así como el tipo de excepción en tiempo de ejecución que deseamos tratar (si proporcionamos este segundo parámetro, también ha de figurar obligatoriamente entonces la variable).

Veamos algunos ejemplos.

En este caso se trata de un bloque de código que producirá un error en tiempo de ejecución y que, al no ser tratado, finalizará con la salida abrupta de nuestra aplicación (estamos intentando acceder a un elemento cuyo indice es superior a la cantidad de elementos almacenados por el array).

dim a() as string = Array("Uno", "Dos", "Tres")
MsgBox a(3) //recuerda que en los Array el primer elemento es ‘0’, por tanto el máximo índice es ‘2’ en este caso

OutOfBoundsException mostrado como resultado de la no gestión de excepciones en programa Xojo

La forma más sencilla de solucionarlo será añadiendo simplemente la palabra clave ‘Exception’ al final del bloque de código:

dim a() as string = Array("Uno", "Dos", "Tres")
MsgBox a(3)

Exception
Msgbox (“¡Ha ocurrido un problema!”)

Resultado como consecuencia de atrapar y gestionar correctamente una excepción en Xojo

Cuando ejecutes este bloque de código de ejemplo observarás que en este caso la excepción queda recogida en tiempo de ejecución, mostrando a continuación el mensaje que hemos incluido sólo con el propósito de ver que efectivamente funciona (¡algo que puedes observar también trazando la aplicación mediante el depurador del IDE, claro!).

La buena noticia en este caso es que nuestra aplicación de ejemplo continuará funcionando, evitando así la salida abrupta. Eso sí, has de tener en cuenta que en muchos de los casos en los que se produce una excepción en tiempo de ejecución significará que nuestra aplicación seguirá funcionando… de forma inestable. Es decir, si se ha producido una excepción es probable que no se haya podido asignar u obtener el elemento que esperábamos, inicializar un recurso, etc.; por tanto, a partir de dicho punto es bastante probable que la aplicación no funcione como es de esperar.

Puedes preguntarte que al ser este el caso, ¿de qué nos sirve gestionar las excepciones? La primera de las respuestas es que, de este modo, podemos proporcionar al usuario la oportunidad de guardar los documentos en los que estuviese trabajando, guardar en definitivo el estado de la aplicación, y dar la opción a que salga de la aplicación y vuelva a ejecutarla de una forma más suave o controlada. Por otra parte, también le brinda a nuestra aplicación la oportunidad de comprobar si es factible continuar su funcionamiento de forma segura (es decir, el recurso que ha producido la excepción no es vital para el correcto funcionamiento del programa a partir de ese punto, o bien se puede subsanar).

Ahora bien, para lidiar con este segundo caso hemos de obtener más información sobre el tipo de excepción que se ha producido, algo que no podemos saber cuando utilizamos la forma más general de la palabra clave ‘Exception’.

Por tanto, el modo recomendable de tratar las excepciones consiste en asociar también el tipo de excepción en el que estamos interesados:

Sub Open()
dim a() as string = Array("Uno", "Dos", "Tres")

elemento = a(3)

MsgBox elemento

Exception err as OutOfBoundsException
elemento = a(a.Ubound)
End Sub

En este ejemplo podemos ver varias cosas interesantes que nos permitirán comprender mejor como funcionan las Excepciones en Xojo.

La primera de las cuestiones es que ya trataremos sólo las excepciones que se correspondan con el intento de acceso a un elemento más allá de los límites de cualquier Array (OutOfBoundsException).

La segunda de las cuestiones es que proporcionaremos una resolución de compromiso para que nuestra aplicación pueda continuar funcionando. Como puedes observar, se intenta asignar a la propiedad ‘elemento’ el valor contenido en el tercer índice del array ‘a’, motivo que activará la excepción en tiempo de ejecución y que pasará a ser recogida y tratada por nuestro bloque ‘Exception’. Aquí, nos encargaremos de asignar, por lo menos, a la propiedad ‘elemento’ el valor correspondiente al último índice disponible en el array ‘a’. En definitiva, una solución de compomiso.

La tercera cuestión que podemos observar es que, una vez que se produce (y opcionalmente gestiona) una excepción, se interrumpe el flujo normal en la ejecución del código. Por tanto, en este caso nunca llegará a ejecutarse la siguiente instrucción:

MsgBox elemento

Como puedes ver, hemos pasado de utilizar una forma genérica que nos permitía recoger todo tipo de excepciones a una restrictiva donde solo capturaremos aquella excepción en la que estemos interesados. ¿Qué ocurre si deseamos capturar y tratar más tipos de excepciones? Sencillo, la buena práctica consiste en incorporar tantas líneas Exception err as TipoDeExcepcion como precisemos (incluso puedes utilizar el mismo nombre de variable en todos los casos).

Try… Catch

En los ejemplos con Exception se ha visto como podemos hacer que nuestras aplicaciones reaccionen frente aquellos errores producidos en tiempo de ejecución y que no podemos prever con antelación; es decir, durante el desarrollo. Ahora bien, hay otros casos en los que sí podemos pensar que no siempre podamos contar, por ejemplo, con el acceso a un recurso determinado… como pueda ser el acceso a un archivo, conexión de red, etc.

Es precisamente para estos casos para los cuales contamos con la ayuda del bloque ‘Try…Catch’, y que podemos traducir mentalmente como “Intenta ejecutar el siguiente código y, si se produce algún error en tiempo de ejecución, trátalo en las instrucciones que figuran tras la palabra clave ‘Catch’”.

Volvamos a nuestro código de ejemplo y utilicemos en este caso el bloque ‘Try…Catch’:

Sub Open()

dim a() as string = Array("Uno", "Dos", "Tres")
try
elemento = a(3)
Catch err as OutOfBoundsException
elemento = a(a.Ubound)
end
MsgBox elemento

End Sub

En esta estructura de bloque es la instrucción ‘Catch’ la encargada de capturar el tipo de error en el que estemos interesados. Como ves, se utiliza la misma sintaxis que ya hemos visto para ‘Exception’.

Una diferencia fundamental en el uso del bloque ‘Try…Catch’ frente a ‘Exception’ es que en este caso no se interrumpe el flujo del programa, de modo que independientemente de que ocurra un error en tiempo de ejecución, podremos tomar el control, intentar arreglar el problema producido y continuar con la ejecución del código a partir de la línea que se encuentre tras el ‘end’ que indica el final del bloque.

Otras observaciones interesantes acerca del bloque ‘Try…Catch’ son que puede complementarse mediante el uso de la palabra clave ‘Finally’ y mediante la cual se indica el código que se ejecutará tanto si se produce y atrapa la excepción como si no. Es decir, conel uso de ‘Finally’ estableceremos el código que se ejecutará en todo caso.

Otro aspecto a destacar es que podemos anidar varias estructuras de bloque ‘Try…Catch’ de modo que las externas podrán tener la oportunidad de atrapar las excepciones no tratadas por los bloques ’Try…Catch’ internos.

Por último, también cabe destacar que podemos combinar el uso de los bloques ’Try…Catch’ con la palabra clave ‘Exception’ en los bloues de código correspondientes a nuestras funciones y/o métodos. En definitiva, ¡un buen modo de lidiar con los imprevistos en tiempo de ejecución para nuestras aplicaciones!

Un comentario en “Excepciones en Xojo: Errores en tiempo de ejecución

  1. Crear Servicio Web con Xojo, Parte I - AprendeXojo

    […] como por ejemplo proteger nuestras aplicaciones frente a ataques por Inyección SQLite o la gestión de Excepciones, entre […]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *