Como bien indica Luis Maria, el uso de ON ERROR es una herencia de las versiones de VFP anteriores a la introduccion de TRY CATCH. En las aplicaciones modernos de VFP se recomienda ampliamente el uso de un TRY-CATCH general, que funcione como un fail-safe ante cualquier error no capturado localmente dentro de la aplicacion, y bloques TRY-CATCH locales para operaciones especificas.
Por ejemplo, un TRY CATCH global podria lucir asi:
PROCEDURE Main
*
* Seteos y configuracion inicial del programa
* Ciclo de eventos principal
TRY
DO FORM formularioPrincipal
READ EVENTS
CATCH TO ex
mostrarMensajeError(ex)
FINALLY
CLEAR EVENTS
ENDTRY
TRY
CLOSE ALL
SQLDISCONNECT(0)
CATCH TO ex
* Si ocurre un error durante el CLOSE ALL simplemente lo obviamos
ENDTRY
RETURN
PROCEDURE mostrarMensajeError(poEx)
MESSAGEBOX("Ha ocurrido un error: " + poEx.Message,"Error",0)
ENDPROC
Eso causaria que cualquier mensaje de error ocurrido en la aplicacion fuese capturado por el CATCH en el programa principal y se procederia a mostrar al usuario un mensaje con el error ocurrido y se finalizaria la aplicacion.
Lo cual me lleva a mi segundo punto: es PESIMA idea permitir que el usuario continue con la ejecucion del programa luego de un error no controlado. Entendemos por un error no controlado aquel error para el cual no estabamos explicitamente preparados en nuestro programa (explicare un poco mas esto mas adelante). Cuando un error no controlado sucede, lo mas sano es finalizar la aplicacion en ese mismo momento. Porque? porque si dejamos que el usuario continue con la ejecucion del programa podriamos correr el riesgo de que el error ocurrido haya creado una situacion de inestabilidad en el codigo del programa (por ejemplo, dejando en NULL una variable que normalmente se espera contenga algun valor) que podria resultar en data incorrecta en nuestra base de datos.
Adicionalmente, mi experiencia me ha indicado que los unicos errores que un usuario final reporta son aquellos que no le permiten trabajar; si el usuario ve que puede ignorar el error y seguir trabajando, su respuesta a la pregunta "como se comporta el sistema?" sera siempre "perfecto!! sin problemas...".
Ahora, cuando un error es "esperado"? cuando podemos anticiparlo. Por ejemplo, si tenemos una rutina que copia un archivo de una ruta a otra, podemos anticipar que la operacion de copiado puede fallar por muchas razones ajenas a nuestra aplicacion. Supongamos que tenemos una funcion copiarArchivo(), que toma dos parametros:
PROCEDURE copiarArchivo(pcOrigen, pcDestino)
COPY FILE (pcOrigen) TO (pcDestino)
ENDPROC
En esta version de la funcion, si la ruta contenida en pcDestino no estuviera accesible o fuese solo/lectura, la rutina fallaria y el error seria capturado por el ON ERROR o el TRY-CATCH general, lo cual en el mejor de los casos terminaria con un mensaje de error que finaliza la aplicacion y en el peor de los casos en un mensaje de error que le informa al usuario que la copia no funciono, pero que NO LE INDICA al programa que invoco a coparArchivo() que efectivamente la copia no funciono.
Por esto, una mejor version de la funcion seria esta:
PROCEDURE copiarArchivo(pcOrigen, pcDestino)
LOCAL lResult
lResult = .F.
TRY
COPY FILE (pcOrigen) TO (pcDestino)
lResult = .T.
CATCH TO ex
mostrarMensajeError(ex)
ENDTRY
RETURN lResult
ENDPROC
En esta version estamos reconociendo que PODRIA ocurir un error al realizar la copia y que, de ser asi, la funcion se encargara de notificar tanto al usuario (con la llamada a mostrarMensajeError) como al programa que invoco la funcion (con el RETURN lResult). Asi, en nuestro codigo podriamos hacer esto:
IF NOT coparArchivo(cFuente, cDestino)
RETURN
ENDIF
Un comentario sobre el ON ERROR, que me vino a la mente por un codigo que vi en este hilo: no tiene sentido colocar un ON ERROR en el evento LOAD de las formas, pues el ON ERROR no se ve afectado por las sesiones de datos. Por esa razon, el ON ERROR se coloca al inicio del programa principal ya que tiene alcance sobre toda la aplicacion.
Otra buena idea es usar el evento Error de los formularios, especialmente si basamos todos nuestros formularios en una unica clase base personalizada. Programar el evento Error nos da la ventaja de que si ocurre un error no esperado dentro del formularo, el mismo solo afectara al formulario actual por lo que nos seria posible mostrar el error y cerrar ESE formulario solamente en lugar de obligar al usuario a salirse de la aplicacion completa.
Un esquema ideal de manejo de errores seria asi:
a) Si ocurre un error esperado, el mismo se maneja localmente en la funcion o procedimiento y no afecta la ejecucion del programa
b) Si ocurre un error inesperado a nivel del formulario, el mismo sera interceptado por el evento Error, se le notificara al usuario el error ocurrido y se cerrara el formulario afectado solamente.
c) Si ocurre un error inesperado FUERA de un formulario o dentro del evento Error de la forma, el mismo seria interceptado por el TRY-CATCH general, notificado al usuario y se finalizaria la aplicacion inmediatamente.
Otra muy buena idea con respecto al manejo de errores es llevar un log de los mismos, de preferencia en un archivo de texto. Se que es mucho mas facil escribir en un DBF pero el problema con los DBFs es que necesitaras crear una aplicacion especial para leer esos archivos y ver el contenido (pues en los clientes no tendras fox instalado).
En mi opinion, una forma mas practica es usar archivos de texto donde cada linea corresponda a un error registrado, indicando datos como fecha/hora del error, usuario activo, estacion, objeto donde ocurrio (procedimiento, forma u otro), la linea dentro del programa donde ocurrio el error (si fuese posible obtener esa informacion), el stack-trace y la descripcion del error ocurrido. La ventaja del archivo log en texto es que todo lo que necesito para leerlo es el Notepad, que viene instalado en todos los Windows.
Justamente este tema del log es otra buena razon para tener una unica funcion para notificar errores al usuario, pues en dicha funcion debemos no solamente notificar al usuario el error ocurrido sino registrar el mismo en el log de errores de la aplicacion e, incluso, ofrecer al usuario la posibilidad de notificar el error al departamento tecnico y/o fabricante enviando los datos del mismo por correo (esta funcion es MUY util sobre todo con clientes que no viven en el area donde residimos). Y que seria aun mejor que la posibilidad de que el usuario nos envie los datos del error por correo? que el correo incluya una IMAGEN de la pantalla al momento de ocurrir el error!! Hay rutinas gratuitas que permiten capturar la pantalla ANTES de que mostremos el mensaje con el error y convertirla a JPG.
Para finalizar tengo que anadir que esto del manejo de errores puede llegar a ser un poco complicado si no se estructura correctamente. Un problema muy particular con el TRY-CATCH es que puede ser muy dificil ofrecer informacion sobre en DONDE ocurrio el error, pues al contrario del ON ERROR, para cuendo entra en juego el CATCH general, ya VFP perdio la posicion que tenia dentro del Stack de ejecucion, por lo que ya no es posible saber DONDE fue que ocurrio el error. Afortunadamente hay tecnicas para solucionar estos problemas, pero hay que investigar un probar un poco antes de implementarlas.
Les recomiendo ampliamente las siguientes lecturas para profundizar en el tema del manejo de errores en VFP:
Saludos
Victor Espina