A la hora de lanzar un juego o una aplicación, una de las cosas más frustantes tanto para el Coder como para el usuario, es ver el típico mensaje de error. En este tutorial, veremos cómo evitar la interrupción del error en el programa y la forma de modificar ese mensaje.
El típico mensaje de error es parecido a este:error: fichero.lua:239: attempt to perform arithmetic on a nil value
Y que la aplicación finalice de forma brusca.
Desde luego, hay errores, los llamados "fatales", que por mucho que nos empeñemos harán que no podamos seguir nuestra aplicación, pero otros, aunque el intérprete lua haga terminar el script, nosotros sí podríamos volver a tomar el control y continuar con la aplicación o volver a un punto anterior.
Errores "fatales" (no podemos retornar a la aplicación después de ellos):
Errores en los que sería posible retomar la aplicación:
Espero que hayáis captado la idea.
Lenguajes compilados como C++, FreePascal, Visual Basic, y otros interpretados como PHP o Python, tienen una forma más elegante y efectiva de tratar las excepciones (se le suele llamar así a los manejos de errores), Lua lo hace de una forma poco usual y bastante "cutre" a mi modo de ver, pero es lo que toca, así que no nombraré las técnicas "normales" y me centraré en la técnica "a lo Lua", para no confundir (y daros pena xD). Comencemos pues:
function LanzarError(num) local total = num + nil screen:print(0,0,"LanzarError: El total es: "..total),blanco) end LanzarError(33) screen:print (0, 15, "continuamos la marcha...", blanco)
Si ejecutamos este código, fallará en la linea 2, y nunca imprimirá "continuamos la marcha...", porque estamos sumando 33 + nil, lo que nos daría el siguiente error:
error: script.lua:2: attempt to perform arithmetic on a nil value
Bueno, vamos a suponer que nosotros sabemos que aunque ese total esté erróneo, podemos continuar la aplicación. Recordad que DEBÉIS TENER UN PLAN ALTERNATIVO en caso de error, sino, de nada sirve continuar si 3 lineas después vamos a usar esa variable que está mal y nos va a dar de nuevo error.
Ahora es cuando la sentencia pcall(), llega al rescate. Mismo código usándola:
function LanzarError(num) local total = num + nil screen:print(0,0,"LanzarError: El total es: "..total, blanco) end local ok ok = pcall(LanzarError, 33) if not ok then screen:print(0,15,"Hubo un error al sumar el total. Disfruten las molestias.", blanco) end screen:print(0,30,"continuamos la marcha...",blanco)
Ahora tenemos la siguiente salida:
Hubo un error al sumar el total. Disfruten las molestias. continuamos la marcha...
Si os fijáis, el programa ha continuado y lo mejor de todo es que no se ha visto "el típico mensaje de error", sino uno que le hemos puesto. Esto da a nuestras aplicaciones un acabado más profesional. Es decir También hemos personalizado el error, es más, no podríamos haber puesto ningún mensaje.
Comentando el código anterior, si os fijáis, pcall(), tiene como primer parámetro la función a la cual se llama y los siguientes parámetros son los que se le envían a la función llamada, en este caso, sólo enviamos un parámetro, el núm. 33. pcall() retorna más de un parámetro, pero eso lo vamos a ver un poco más adelante, de momento quedaros con que envía como primer parámetro true si todo fue bien y false si hubo un error.
Personalizando MEJOR nuestros errores:
Lo cierto, es que más que el mensaje de "disfruten las molestias", es conveniente indicar el script, la linea y la descripción del error, tal y como lo hace Lua por defecto, esto nos permite localizar rápidamente los errores. Pero vamos a ver la forma de hacer esto "más bonito" y no como una simple linea.
Como dije anteriormente, pcall() devuelve más de un valor. Si no hay error, devuelve true como primer parámetro y el siguiente parámetro o parámetros, son los que enviaría la función normalmente si es que devuelve alguno. En caso de error, el primer parámetro será false, y el segundo (IMPORTANTE), es el texto con el error. Si volvemos al ejemplo inicial, este sería el texto que contendría el segundo parámetro (se omite el primer "error: ").
script.lua:2: attempt to perform arithmetic on a nil value
Ojo con ese segundo valor que unas veces puede ser esa cadena y otra lo que devuelva vuestra función, tenedlo en cuenta.
He creado una función que podéis usar en vuestros proyectos, descompone esa cadena en una tabla con 3 elementos:
Teniendo estos datos separados, podéis presentar los errores de forma "bonita", con vuestra fuente, color, un fondo especial para errores, etc.
function extractError(err) --[[ 1.0.1 : 2010-06. By GorristeR. Under GPL3 License. Desglosa en una tabla un mensaje de error devuelvo por pcall(). Dicha tabla 3 elementos: script: Nombre del script donde se produjo el error line: Linea del error text: Texto descriptivo del error --]] local result = {} local pos1, pos2 pos1 = string.find(err, ":") pos2 = string.find(err, ":", pos1+1) result.script = string.sub(err, 1, pos1-1) result.line = string.sub(err, pos1+1, pos2-1) result.text = string.gsub(string.sub(err, pos2+1), "^%s*(.-)%s*$", "%1") return result end
Esta es la función extractError():
Y aquí está el último ejemplo:
function LanzarError(num) local total = num + nil screen:print(0,0,"LanzarError: El total es: "..total,blanco) end ok, msgError = pcall(LanzarError, 33) if not ok then myError = extractError(msgError) screen:print(0,15,"Hubo un error al sumar el total. Disfruten las molestias.",blanco) screen:print(0,30,"Script : "..myError.script,blanco) screen:print(0,45,"Linea : "..myError.line,blanco) screen:print(0,60,"Error : "..myError.text,blanco) screen:print(0,75,"Consulte manual online para buscar una solución",blanco) end print(0,90,"continuamos la marcha...",blanco)
No creo que el código requiera mucha explicación. Como veis podéis personalizar un error como queráis.
Hubo un error al sumar el total. Disfruten las molestias. Script : script.lua Linea : 2 Error : attempt to perform arithmetic on a nil value Consulte manual online para buscar una solución continuamos la marcha...
En la siguiente entrega, Os enseñaré una forma un poco diferente, y más "elegante" de tratar los errores en Lua, seguramente uséis esa nueva forma en vez de ésta, pero siempre es bueno saber de más.
Comentarios se agradecen y motivan a seguir haciendo tutoriales ;-).
Comentarios
Me encantó.
Sin palabras, esto yo ya me lo sabía pero de esta forma se me hace muchísimo màs fàcil.
Yo utilizaba solamente la función "error()" u otras formas para que me dijiera si había otro error pero este es muchísimo mejor.
Muchas gracias Gorrister.
Hazme la pregunta que quieras ANONIMAMENTE desde aquí.
Icon0 sin linkear
Icon0 sin linkear
Solucionado.
Gracias.
Je, je
La verdad es que ya había un tutorial de Pipagerardo que explicaba más o menos el uso de la funcion pcall y el manejo de los errores, aunque aqui está todo mucho más claro y mejor explicado, viendo el proceso por pasos y ejemplos. Como siempre se agradecen mucho tus aportes de Lua ;)
Un saludo.
-----[[7 años en Scenebeta, con la misma ilusión que la del primer día]]----
Extraordinario ;)
Extraordinario ;)
Que bien
Una cosa, la funcion es para todos los ''luas''
Sí, todo el código usado aquí
Sí, todo el código usado aquí vale para cualquier Lua, la diferencia es el uso de "print", para PSP hay que usar "screen:print(columna, fila, mensaje, color)", y para Windows, Linux etc. tan sólo "print(mensaje)", el resto es "Lua estándar".
Un saludo.
LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.
Tremendos turoriales que haces!!!
WOW!!, estos ultimos tutos que haz hecho ya hacian falta ;)
Muchas Gracias GorristeR :D