- Obtener una lista general de las propiedades del terminal y del programa
- Número de versión del terminal
- Tipo de programa y licencia
- Modos de funcionamiento del terminal y del programa
- Permisos
- Comprobación de las conexiones de red
- Recursos informáticos: memoria, disco y CPU
- Especificaciones de la pantalla
- Propiedades del terminal y de la cadena de programa
- Propiedades personalizadas: límite de barras e idioma de la interfaz
- Vincular un programa a propiedades en tiempo de ejecución
- Comprobar el estado del teclado
- Comprobar el estado del programa MQL y motivo de finalización
- Cierre programático del terminal y establecimiento de un código de retorno
- Tratamiento de errores en tiempo de ejecución
- Errores definidos por el usuario
- Gestión de depuración
- Variables predefinidas
- Constantes predefinidas del lenguaje MQL5
Errores definidos por el usuario
El desarrollador puede utilizar la variable integrada _LastError para sus propios fines aplicados. Esto se facilita mediante la función SetUserError.
void SetUserError(ushort user_error)
La función establece la variable integrada _LastError al valor ERR_USER_ERROR_FIRST + user_error, donde ERR_USER_ERROR_FIRST es 65536. Todos los códigos por debajo de este valor se reservan para errores del sistema.
Utilizando este mecanismo, puede eludir parcialmente la limitación de MQL5 asociada al hecho de que no se admiten excepciones en el lenguaje.
A menudo, las funciones utilizan el valor de retorno como señal de error. Sin embargo, hay algoritmos en los que la función debe devolver un valor del tipo de la aplicación. Hablemos de double. Si la función tiene un rango de definición de menos a más infinito, cualquier valor que elijamos para indicar un error (por ejemplo, 0) será indistinguible del resultado real del cálculo. En el caso de double, por supuesto, existe la opción de devolver un valor NaN (Not a Number, véase la sección Comprobación de la normalidad de los números reales). Pero, ¿y si la función devuelve una estructura o un objeto de clase? Una de las posibles soluciones es devolver el resultado a través de un parámetro por referencia o puntero, pero tal forma imposibilita el uso de funciones como operandos de expresiones.
En el contexto de las clases, consideremos las funciones especiales denominadas «constructores». Estas funciones devuelven una nueva instancia del objeto. Sin embargo, a veces las circunstancias impiden construir el objeto completo, y entonces el código de llamada parece obtener el objeto pero no debe utilizarlo. Es bueno si la clase puede proporcionar un método adicional que le permita comprobar la utilidad del objeto. Pero como enfoque alternativo uniforme (por ejemplo, que abarque todas las clases), podemos utilizar SetUserError.
En la sección Sobrecarga de operadores encontramos la clase Matrix. La complementaremos con métodos para calcular el determinante y la matriz inversa, y luego la utilizaremos para demostrar los errores del usuario (véase el archivo Matrix.mqh). Se han definido operadores sobrecargados para matrices, lo que permite combinarlos en cadenas de operadores en una única expresión, y por tanto sería inconveniente implementar una comprobación de posibles errores en ella.
Nuestra clase Matrix es una implementación alternativa personalizada para el tipo de objeto integrado recientemente añadido en MQL5 matriz.
Comenzamos validando los parámetros de entrada en los constructores de la clase principal Matrix. Si alguien intenta crear una matriz de tamaño cero, vamos a establecer un error personalizado ERR_USER_MATRIX_EMPTY (uno de los varios proporcionados).
enum ENUM_ERR_USER_MATRIX
|
Estas nuevas operaciones sólo están definidas para matrices cuadradas, así que vamos a crear una clase derivada con una restricción de tamaño apropiada.
class MatrixSquare : public Matrix
|
El segundo parámetro en el constructor debería estar ausente (se asume que es igual al primero), pero lo necesitamos porque la clase Matrix tiene un método de transposición de plantilla en el que todos los tipos de T deben admitir un constructor con dos parámetros enteros.
class Matrix
|
Debido al hecho de que hay dos parámetros en el constructor MatrixSquare, también tenemos que comprobar su igualdad obligatoria. Si no son iguales, activamos el error ERR_USER_MATRIX_NOT_SQUARE.
Finalmente, durante el cálculo de la matriz inversa, podemos encontrar que la matriz es degenerada (el determinante es 0). El error ERR_USER_MATRIX_SINGULAR está reservado para este caso.
class MatrixSquare : public Matrix
|
Para la salida visual de errores, se ha añadido un método estático al registro, lo que devuelve la enumeración ENUM_ERR_USER_MATRIX, que es fácil de pasar a EnumToString:
static ENUM_ERR_USER_MATRIX lastError()
|
El código completo de todos los métodos se encuentra en el archivo adjunto.
Comprobaremos los códigos de error de la aplicación en el script de prueba EnvError.mq5.
Primero, asegurémonos de que la clase funciona: invierta la matriz y compruebe que el producto de la matriz original y la invertida es igual a la matriz identidad.
void OnStart()
|
Este fragmento de código genera las siguientes entradas de registro:
Test matrix inversion (should pass)
|
Nótese que en la matriz identidad, debido a errores de coma flotante, algunos elementos cero son en realidad valores muy pequeños cercanos a cero, y por tanto tienen signo.
A continuación, veamos cómo maneja el algoritmo la matriz degenerada.
Print("Test matrix inversion (should fail)");
|
Los resultados se presentan a continuación:
Test matrix inversion (should fail)
|
En este caso, simplemente mostramos una descripción del error. Pero en un programa real, debería ser posible elegir una opción de continuación, dependiendo de la naturaleza del problema.
Por último, simularemos situaciones para los dos errores aplicados restantes.
Print("Empty matrix creation");
|
Aquí describimos una matriz vacía y una matriz supuestamente cuadrada pero con tamaños diferentes.
Empty matrix creation
|
En estos casos no podemos evitar crear un objeto porque el compilador lo hace automáticamente.
Por supuesto, esta prueba viola claramente los contratos (las especificaciones de datos y acciones que las clases y los métodos «consideran» válidos). Sin embargo, en la práctica, los argumentos se obtienen a menudo de otras partes del código, en el curso del procesamiento de grandes datos de «terceros», y detectar las desviaciones con respecto a las expectativas no es tan fácil.
La capacidad de un programa para «digerir» datos incorrectos sin consecuencias fatales es el indicador más importante de su calidad, junto con la producción de resultados correctos para datos de entrada correctos.