Anuncios Google

[TUTORIAL] Lua a prueba de errores (I)

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 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 retormar la aplicación después de ellos):

  •     Errores de sintaxis al teclear el código.
  •     Falta de memoria RAM.
  •     Fallo físico del disco que impide leer el script.

   
Errores en los que sería posible retomar la aplicación:

  •     Fallo al hacer una operación con nil. Por ejemplo sumar o mostrar un nil. Si ese nil se ha realizado por leer algo de un fichero (una canción vacía, una imagen con mal formato, etc.), se le puede dar la oportunidad al usuario de que seleccione otra canción u otra imagen y volver a intentarlo).
  •     Errores al conectar a una unidad de disco. Se puede pedir al usuario que vuelva a intentarlo.

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
    print("LanzarError: El total es: ", total)
end
 
LanzarError(33)
print ("continuamos la marcha...")

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
    print("LanzarError: El total es: ", total)
end
 
local ok 
ok = pcall(LanzarError, 33)
if not ok then
    print("Hubo un error al sumar el total. Disfruten las molestias.")
end
print("continuamos la marcha...")

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:

  •     script: Contiene el nombre del script, en este caso script.lua
  •     line: La linea del error, en este caso 2
  •     text: El texto del error. "attempt to perform arithmetic on a nil value"

   
Teniendo estos datos separados, podéis presentar los errores de forma "bonita", con vuestra fuente, color, un fondo especial para errores, etc.

Esta es la función extractError():

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

Y aquí está el último ejemplo:

function LanzarError(num)
    local total = num + nil
    print("LanzarError: El total es: ", total)
end
 
ok, msgError = pcall(LanzarError, 33)
if not ok then
    myError = extractError(msgError)
    print("Hubo un error al sumar el total. Disfruten las molestias.")
    print("Script : "..myError.script)
    print("Linea  : "..myError.line)
    print("Error  : "..myError.text)
    print("Consulte manual online para buscar una solución")
end
print("continuamos la marcha...")

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.


 


LuaDiE: Crea en Lua sin teclear código. Compatible HM7, HMv2, LuaPlayer, LuaDEV y PGE.


Anuncios Google

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de moikop

Genial.

Da gusto ver aportes con tanta calidad. Muchas gracias gorrister. Me encargo de ponertelo en portada ;-)

Un saludo crack.

Imagen de unai.

Que por cierto, para usar la

Que por cierto, para usar la librería ¿que tengo que copiar?

Imagen de moikop

Más que librería,

es una función. Y es esta:

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


Para recibir ayuda por parte de otros usuarios más rápidamente, recomendamos que pongas títulos descriptivos y no utilices abreviaturas (estilo MSN) en tus post de los foros. Recuerda que accediendo al Manual del perfecto forero y las Normas de la Comunidad aprenderas trucos para resolver tus dudas antes.

No preguntes por MP, mejor pregunta aquí.

Imagen de unai.

Ya ya, entonces para usarlo

Ya ya, entonces para usarlo si eso tengo que copiar esa funcion, ¿Verdad?

Imagen de -chus-

Gracias por estos tutoriales

Vaya tuto verdad, gracias aun que no entiendo muy bien, ya que tengo poco aprendiendo lua XD un saludo

Imagen de PSPPRECIZO

Que buen

tutorial, de verdad muchas gracias, esperamos mas tutoriales de este tipo.

Gracias, un saludo.

Imagen de unai.

¡Tio, asustas! Tu has nacido

¡Tio, asustas! Tu has nacido para esto.
Grandioso aporte.

Imagen de klozz

ORALE man gracias por el tuto

ORALE man gracias por el tuto n.n

me servira para proximos proyectos :D

Imagen de --Gomasz--

Esto

se agradece bastante pspgorrister   muchas Gracias lastima que no tiene tanta "popularidad" como es un post OFFTOPIC

espero mas tutos :)

Salu|2|



\\m// ₪₪₪₪₪₪--  ☠ ☠ ☠ ☠ ☠ ☠ --₪₪₪₪₪₪ \\m//

Imagen de d.m.n.

No te he comentado en los

No te he comentado en los demás tutos pero te felicito y se agradece que hagas este tipo de tutoriales de LUA. =)

 

Imagen de pspgorrister

Re:

Gracias ^ ^

Imagen de DeViaNTe

:)

ya era hora, un compendio de tutoriales decentes :)
Aunque viendo el título creo que no hará falta que diga que tb existe xpcall, pq imagino será el segundo :D


Actualmente desarrollando nuestra web y UXCode : http://www.gcrew.es

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.