Errare humanum est

Anonimo
Anuncios

Bienvenidos sean a este post, tal como lo indica la frase podemos cometer errores y debemos aprender a manejarlos de la mejor forma que podamos, porque Lua es un lenguaje de extension, frecuentemente incluido en una aplicacion, y no puede simplemente interrumpirse o salir cuando un error ocurra, cuando esto pasa Lua termina el chunk actual y regresa a la aplicacion.

Cualquier condicion inesperada que Lua encuentra ocasiona un error, estos pueden ocurrir cuando intentas agregar valores que no son numeros, llamar a valores que no son funciones, indexar valores que no son de una tabla, etc, tambien puedes plantear un error explicitamente llamando a la funcion error con el mensaje de error como argumento y usualmente esta funcion es la forma mas apropiada para manejar los errores en tu codigo:

print("Ingresa un numero")
n = io.read("*number")
if not n then error("Ingreso invalido") end

La variable llamada n recibe solamente numeros por medio del *number, luego viene un condicional que en caso de que n no sea un numero nos devolvera el error informado en la funcion error, como esta practica se volvio tan habitual con el tiempo, Lua creo una funcion interna para este trabajo llamada assert:

print("Ingresa un numero:")
n = assert(io.read("*number"), "Ingreso invalido")

Como pueden ver esto equivale justamente al codigo anterior, si lo probamos obtendremos la siguiente salida:

stdin:1: Ingreso invalido
stack traceback:
        [C]: in function 'assert'
        stdin:1: in main chunk
        [C]: in ?
Anuncios

Observen como la primera linea nos devuelve el error que creamos ingresando un valor que no sea numerico, en este caso assert devolvera un error siempre que el primer argumento sea falso o nil, el segundo argumento sera el mensaje que mostraremos en caso de que el primer argumento devuelva el estado antes descripto, sin embargo assert es una funcion regular, y como tal Lua siempre evalua sus argumentos antes de llamar a las funciones, por ejemplo si tuvieramos la siguiente situacion:

n = io.read()
assert(tonumber(n), "entrada invalida, " .. n .. " no es un numero.")

Lua siempre hara la concatenacion, inclusive cuando n es un numero, por esto seria mas sabio usar una prueba explicita en tales casos.

Cuando una funcion encuentra una situacion inesperada, esto es llamado excepcion, puede asumir dos conductas basicas:

  • Puede devolver un codigo de error, usualmente nil
  • Puede plantear un error llamando a la funcion error

Aunque no haya reglas fijas para elegir entre estas dos opciones si existe una guia, una excepcion que es facilmente evitada deberia plantear un error, o de lo contrario deberia devolver un codigo de error, consideremos a la funcion sin, como deberia comportarse cuando sea llamado en una tabla? Supongamos que devuelva un codigo de error, y si necesitamos chequear por errores debemos escribir algo semejante a esto:

local res = math.sin(x)
if not res then
	<codigo de manejo de error>
Anuncios

Sin embargo, podriamos facilmente chequear esta excepcion antes de llamar a esta funcion:

if not tonumber(x) then
	<codigo de manejo de error>

Habitualmente, no chequeamos ni el argumento o el resultado de una llamada a sin sino que verificamos si el argumento no sea un numero, esto significara que algo funciona mal en nuestro programa, en tales situaciones detener el computo y emitir un mensaje de error es la mas simple y poderosa forma de manejar la excepcion, tomemos otro ejemplo y consideremos la funcion io.open, la cual abre un archivo.

Como deberia comportarse cuando es llamada para leer un archivo que no existe? En este caso, no hay manera simple para chequear la excepcion antes de llamar a la funcion, en muchos sistemas la unica forma de conocer cuando un archivo existe es tratando de abrirlo, por lo tanto si io.open no puede abrir un archivo porque una razon externa, tal como “el archivo no existe” o “permiso denegado”, devuelve un nil ademas una cadena con un mensaje de error, en este sentido tienes una forma de manejar la situacion en una forma apropiada, veamos el siguiente ejemplo:

Anuncios

error.lua

local archivo, msj
repeat
	print("Ingresa un nombre de archivo:")
	local nombre = io.read()
	if not nombre then return end
	archivo, msj = io.open(nombre,"r")
	if not archivo then print(msj) end
until archivo

Con este codigo tenemos un condicional que al no haber un valor en nombre nos devolvera al prompt, pero en caso de necesitar hacer mas seguro el programa simplemente usa assert para guardar la operacion, tomemos el codigo anterior y modifiquemos la siguiente linea:

archivo, msj = io.open(nombre,"r")

Por esta otra:

archivo = assert(io.open(nombre,"r"))

Si lo probaramos obtendremos una salida semejante a esta:

lua5.3: error.lua:6: prueba.txt: No such file or directory

En este caso podemos ver como el resultado del error del io.open pasa como segundo argumento del assert, recuerden que primero devuelve nil y luego ese mensaje se asigna automaticamente.

Anuncios

En resumen, hoy hemos visto como podemos manejar los errores en Lua, tambien conocidos como excepciones, explicamos porque puede deberse una excepcion, algunas caracteristicas de como manejarlas y como puede presentarse en la vida real, espero les hayas sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00