English Русский Português
preview
Del básico al intermedio: Comandos BREAK y CONTINUE

Del básico al intermedio: Comandos BREAK y CONTINUE

MetaTrader 5Ejemplos | 9 enero 2025, 12:47
206 0
CODE X
CODE X

Introducción

El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse como una aplicación final cuyo propósito no sea el estudio de los conceptos mostrados.

En el artículo anterior, "Del básico al intermedio: Comando WHILE y DO WHILE", comenzamos a hablar sobre bucles. Por lo tanto, el requisito previo para que puedas seguir y comprender de manera adecuada lo que se verá en este artículo es, precisamente, haber comprendido lo mostrado y explicado en el artículo anterior.

Sé que muchos programadores principiantes tienen mucha dificultad para comprender de manera adecuada el funcionamiento de los comandos que generan bucles. Sin embargo, los bucles son importantes y forman parte de casi todos los programas que llegarás a construir a lo largo de tu vida, incluso si programas solo como un PASATIEMPO. Entender y saber trabajar con comandos que generan bucles es algo fundamental.

Existe otro tipo de bucle que no utiliza los comandos convencionales, esto será tratado en otro momento. Sin embargo, hay tres comandos que aparecen con cierta frecuencia dentro de un bucle. Aunque sean tres, dos de ellos pueden aparecer fuera de un bucle. No obstante, uno de ellos solo existirá dentro de un bucle. Aunque nunca, al menos sin una justificación muy sólida, se verá de manera aislada dentro de un bucle.

Aquí trataremos estos comandos, pero principalmente dos de ellos, los cuales aparecen justamente en el título del artículo. Es decir, ha llegado el momento de entender cómo se controla el bucle desde dentro. En este punto, quiero pedirte toda tu atención a lo que se explicará, querido lector. Porque, si no entiendes lo que este artículo demostrará, definitivamente te meterás en serios problemas en algún momento de tu vida como programador.


Una posible respuesta

Bien, antes de comenzar, dejé un pequeño desafío para ti en el artículo anterior. El desafío consistía en transformar el código que se muestra a continuación en un código que utilizara un bucle:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Factorial();
07.     Factorial();
08.     Factorial();
09.     Factorial();
10.     Factorial();
11. }
12. //+------------------------------------------------------------------+
13. void Factorial(void)
14. {
15.     static uchar counter = 0;
16.     static ulong value = 1;
17. 
18.     Print("Factorial of ", counter, " => ", value);    
19.     counter = counter + 1;
20.     value = value * counter;
21. }
22. //+------------------------------------------------------------------+

Código 01

Bien, si no logras idear una manera de hacerlo, está bien, es parte del proceso en este inicio de aprendizaje. Sin embargo, no dejes que el material se acumule antes de empezar a estudiarlo, ya que los conceptos se irán acumulando muy rápido a medida que avancemos hacia un nivel que considero intermedio.

Existen diversas formas de transformar, o mejor dicho, utilizar un bucle en el código 01, para hacerlo más eficiente. Una de estas formas ya la podemos aplicar, gracias a lo que se presentó en el artículo anterior, y conectando el conocimiento transmitido en los artículos previos.

En términos generales y de manera sencilla, podrías simplemente usar lo que sería una modificación del código 07 mostrado en el artículo anterior. Esto con el propósito de generar el mismo resultado que obtendrías al ejecutar el código 01. ¿Cómo? Simplemente utilizando el código 02 que se encuentra más abajo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     uchar counter = 0;
07. 
08.     while (counter < 5)
09.         Factorial(counter);
10. }
11. //+------------------------------------------------------------------+
12. void Factorial(uchar &counter)
13. {
14.     static ulong value = 1;
15. 
16.     Print("Factorial of ", counter, " => ", value);    
17.     counter = counter + 1;
18.     value = value * counter;
19. }
20. //+------------------------------------------------------------------+

Código 02

Esta es solo UNA manera de resolver el problema. Existen otras, más o menos elaboradas. Pero con lo que hasta ahora se ha explicado, esta sería una buena solución. Ahora, si no entiendes qué está haciendo realmente este código 02, pero especialmente por qué logra obtener el mismo resultado que el código 01, detente inmediatamente y regresa a los artículos anteriores. Esto con el fin de comprender este código 02. Solo cuando logres entender este código estarás listo para continuar con este y los próximos artículos.

Bien, dado el aviso, podemos empezar con lo que será el primer comando a analizar en este artículo. Comenzaremos con lo que sería el comando más sencillo que puede estar presente dentro de un bucle. Pero para hablar de él, introduciremos un nuevo tema.


Comando RETURN

Sé que muchos de ustedes, que ya han tenido algún contacto y cuentan con una experiencia mínima en programación en MQL5, me dirán: "Pero este comando no tiene nada que ver con bucles, tiene más relación con funciones". De hecho, querido lector, el comando RETURN tiene mucho más que ver con funciones que con bucles. Sin embargo, aunque es un comando obligatorio en una función, es opcional en procedimientos. Precisamente por el efecto que tiene en los procedimientos donde aparece, es que puede surgir dentro de un bucle.

Ahora presta atención. El comando RETURN tiene como objetivo devolver, o retornar, el flujo de ejecución al autor de llamada de la función o procedimiento. Sin embargo, y aquí es donde muchos principiantes suelen tener dificultades para entender, si estás dentro de un procedimiento o función principal de tu aplicación, como puede ser OnInit o OnStart, dependiendo del caso, el comando RETURN, cuando se ejecute, finalizará tu aplicación, haciendo que MetaTrader 5 la elimine del gráfico. Esto se debe a que, en última instancia, cualquier aplicación es una función o procedimiento que el sistema operativo está ejecutando. Comprender esto de esta manera hace que sea más sencillo entender por qué un comando RETURN colocado en OnInit o OnStart puede hacer que tu aplicación finalice de manera prematura.

Bien, en el caso de que RETURN aparezca en OnInit, la aplicación podría finalizarse o no, dependiendo del valor que estemos retornando a MetaTrader 5. Sin embargo, si RETURN aparece y se ejecuta dentro del procedimiento OnStart, de hecho, la aplicación será finalizada.

Para comprender esto, comencemos viendo un ejemplo pequeño y sencillo. Este se muestra a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     return;
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " This line will never be executed...");
11. }
12. //+------------------------------------------------------------------+

Código 03

El resultado de ejecutar este código puede verse a continuación.


Imagen 01

La parte que necesitas entender es que el comando RETURN, que se encuentra en la línea ocho, está dentro de un procedimiento. Lógicamente, al tratarse de un procedimiento, NO DEBE tener ningún valor asociado a él. Esto es para evitar conflictos con el compilador durante la creación del ejecutable. Sin embargo, si RETURN estuviera presente en una función, sería obligatorio asociarle un valor. Esto es para informar al autor de llamada cuál es el valor de retorno de la función. Ya vimos esto aplicado anteriormente cuando hablamos sobre variables.

Sin embargo, el interés aquí y en este momento es otro, que es poder salir de un bucle de manera anticipada. Esto se debe a que, muchas veces, resulta interesante e incluso deseable salir de un bucle antes de que termine, debido precisamente a alguna condición especial. A continuación se muestra un ejemplo sencillo de cómo podría aplicarse.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     Procedure_Loop();
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
11. }
12. //+------------------------------------------------------------------+
13. void Procedure_Loop(void)
14. {
15.     char info = 10;
16. 
17.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
18.     
19.     while (info)
20.     {
21.         info = info - 3;
22.         
23.         Print("Loop : ", info);
24.         
25.         if (info < -5) return;
26.     }
27.     
28.     Print(__FUNCTION__, " ", __LINE__, " This line will never be executed...");
29. }
30. //+------------------------------------------------------------------+

Código 04

Este código 04, cuando se ejecuta, generará el resultado que puede observarse en la imagen de abajo.


Imagen 02

Aquí tenemos algo que puede parecer un tanto extraño para ti, querido lector. Esto se debe a que, si queremos que el bucle se cierre cuando tenemos un valor de info menor que menos cinco, ¿por qué no colocar esta condición directamente en la expresión de prueba del bucle? El motivo para no hacerlo es que, a veces, queremos que el bucle no alcance un determinado valor, pero si llega a otro valor, queremos que el resto, ya sea de la rutina o del procedimiento donde se encuentra el bucle, sea ignorado por completo.

Por este simple detalle, es que la línea 28 jamás será ejecutada dentro del código 04. Dado que el valor de info no alcanzará el valor cero antes de que la expresión de prueba en el IF dispare la ejecución del comando RETURN. Por esta razón, en la imagen 02 se imprimen valores que van desde siete hasta ocho en negativo.

Muy bien, pero ¿por qué la aplicación no se está finalizando en el momento en que se ejecuta la línea 25? Permitiendo que la línea 10 sea ejecutada, diferente de lo que sucedió en el código 03. La razón de esto, querido lector, es precisamente el hecho de que OnStart es el procedimiento o función inicial que es llamada por MetaTrader 5, pero Procedure_Loop es llamada por OnStart. Por lo tanto, cuando se ejecuta el comando RETURN, este retornará a quien llamó el procedimiento o función donde se encuentra. En este caso, a OnStart.

Este tema sobre qué función llama MetaTrader 5 será explicado con mayor detalle en otra oportunidad. Pero, básicamente, MetaTrader 5 llama dos funciones: OnStart y OnInit. Solo en estos casos, el comando RETURN hará, o podría hacer, que tu aplicación se finalice. Fuera de esto, el uso del comando RETURN no finalizará la aplicación.

Perfecto. Creo que ha quedado claro cómo se puede utilizar RETURN dentro de un bucle. Si tienes dudas, practica un poco con estos ejemplos más sencillos para comprender mejor. Dicho esto, podemos avanzar al próximo comando que será analizado en este artículo.


Comando BREAK

El comando BREAK es bastante interesante. Sin embargo, necesitas tomar algunas precauciones y estudiarlo con calma. Esto se debe a que, al principio, no es raro que te compliques al usar este comando. No en bucles simples, sino en aquellos un poco más elaborados.

Uno de los errores más comunes al usar el comando BREAK es pensar que este, al estar asociado a un bucle, influirá en otro bucle o incluso en otro comando de control de flujo. Esto ocurre porque BREAK no solo se usa en bucles, sino que también puede utilizarse en otro tipo de control que veremos más adelante. Sin embargo, por ahora no te preocupes por esto. Vamos a centrarnos únicamente en su aplicación dentro de los bucles.

En este contexto, hay algo que necesitas entender y que muchas personas olvidan o ignoran. El comando BREAK sigue un principio muy similar al comando RETURN. Es decir, no se encuentra suelto dentro del bucle. Normalmente forma parte de la rutina de un comando IF. Por lo tanto, podemos usar el mismo código 04, visto en el tema anterior, y en lugar de colocar un comando RETURN, usar un comando BREAK. Así, el código queda como se muestra a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     Procedure_Loop();
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
11. }
12. //+------------------------------------------------------------------+
13. void Procedure_Loop(void)
14. {
15.     char info = 10;
16. 
17.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
18.     
19.     while (info)
20.     {
21.         info = info - 3;
22.         
23.         Print("Loop : ", info);
24.         
25.         if (info < -5) break;
26.     }
27.     
28.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
29. }
30. //+------------------------------------------------------------------+

Código 05

Al ejecutar este código 05, el resultado que se muestra en el terminal de MetaTrader 5 es el que podemos ver a continuación.


Imagen 03

Hmm, interesante. Esta vez tenemos una información que no se mostraba antes. Curioso, parece bastante sencillo trabajar con bucles. Ahora ya estoy listo para manejar códigos más elaborados. (RISAS). Calma, querido lector, calma. Apenas estamos comenzando. Existe una trampa, aunque en realidad se trata de un malentendido que los nuevos programadores suelen tener sobre estos comandos. Por ello, te pido que practiques usando pequeñas variaciones de los códigos mostrados aquí.

El primer malentendido está relacionado con el uso del comando BREAK en bucles anidados. Sí, de la misma forma que podemos anidar varios comandos IF, también podemos anidar varios bucles uno dentro del otro. Esto es muy común en trabajos con matrices multidimensionales, donde no queremos realizar cálculos de índices manualmente. Pero veamos un ejemplo simple de bucle anidado para que puedas comprender cómo se comporta el comando BREAK en este caso. Un ejemplo sencillo se muestra en el código a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     Procedure_Loop();
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
11. }
12. //+------------------------------------------------------------------+
13. void Procedure_Loop(void)
14. {
15.     char    info = 10,
16.             limit = 5;
17. 
18.     do
19.     {
20.         Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")  Limit (", limit, ")");
21. 
22.         while (info > limit)
23.         {
24.             if (limit < 0) break;
25. 
26.             info = info - 3;
27. 
28.             Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")  Limit (", limit, ")");
29.         }
30.         info = info + limit;
31.         limit = limit - 2;
32. 
33.         Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")  Limit (", limit, ")");
34. 
35.     }while (info > 0);
36. 
37.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")  Limit (", limit, ")");
38. }
39. //+------------------------------------------------------------------+

Código 06

Aunque pueda parecer complicado debido a la cantidad de mensajes que estamos imprimiendo, este código 06 es, de hecho, bastante simple y sirve para ilustrar perfectamente el comportamiento del comando BREAK dentro de bucles anidados. Cuando ejecutes este código 06, el resultado será realmente interesante, y se puede observar en la imagen que aparece más abajo.


Imagen 04

Ahora presta atención a algo aquí, querido lector. Dentro del bucle que comienza en la línea 18, tenemos otro bucle que se inicia en la línea 22. Dentro de este nuevo bucle, encontramos una prueba en la línea 24. Aquí es donde las cosas se ponen interesantes. Esto se debe a que puedes experimentar, más adelante, cambiar este comando BREAK por un comando RETURN para observar lo que ocurre en el código. Pero enfoquémonos en lo que sucede al usar el comando BREAK.

Es un hecho que aquí tendremos una cuenta en curso. Pero, ¿cómo se está controlando? Esta es la gran cuestión. Muchas veces necesitamos contabilizar ciertos valores, pero resulta un tanto complicado analizar la salida de un conjunto de bucles anidados. Lo que sucede en muchas ocasiones es que creamos una expresión o fórmula matemática que nos indica cómo debe realizarse el cálculo. Una vez que tenemos esta fórmula, la trasladamos a una expresión matemática en forma de código.

Al hacer esto, necesitamos confiar en nuestra capacidad para transformar expresiones y fórmulas matemáticas en código. Esto se debe a que, si la cantidad de valores o la forma en que los valores serán generados es un tanto complicada o extensa, no analizaremos uno por uno. Lo hacemos por muestreo. Es decir, sabemos cuáles serán los valores dentro de un cierto límite y analizamos únicamente ese límite. Por esta razón, es importante que domines muy bien cada comando y cómo funciona cada operación.

Bien, volviendo al código, puedes notar que en la imagen 04 hay solo algunos puntos donde, de hecho, la línea 28 está siendo impresa, aunque la expresión del bucle en la línea 22 indique que deberían ser más veces. Esta menor cantidad de ejecuciones de la línea 28 se debe precisamente al hecho de que el comando BREAK hace que el bucle interno se finalice antes de que la expresión indique que debería finalizarse. Sin embargo, el hecho de que el bucle interno se finalice no implica, en este caso del uso del comando BREAK, que el bucle externo también se finalice. Por eso es importante que experimentes usar el comando RETURN aquí también, para ver lo que ocurrirá, ya que existe una diferencia en el resultado final que se observará en el terminal.

Básicamente, si sigues el flujo de ejecución, comprenderás esto de manera muy simple. Como el flujo de ejecución del comando WHILE y del par DO WHILE, así como del comando IF, se mostró en los artículos anteriores, podrás dibujar los mismos aquí. Sin embargo, aún no se ha mostrado cómo sería el flujo en el caso de encontrarse un comando BREAK. Pero esto puede observarse a continuación.


Imagen 05

Aquí, LOOP indica cualquier comando que permita la creación de bucles. Sin embargo, el comando BREAK se muestra como si estuviera colocado de manera aislada en el código. En este punto, necesitamos hacer una aclaración. Esto se debe a que, si tuviéramos que mostrar todo el conjunto necesario para implementar correctamente el comando BREAK, sería necesario incluir en este mismo lugar el flujo del comando IF. Y cuando la expresión de prueba del comando IF fuera verdadera, entonces entraría el comando BREAK, y el flujo seguiría lo que se muestra en la imagen. También nota que el comando BREAK puede aparecer antes, durante o después de que la rutina del bucle haya sido ejecutada. Normalmente, estará antes o después. Cuando se encuentra en el medio, esto significa, en realidad, que hemos dividido la rutina en dos partes. Pero, para simplificar el flujo de ejecución, no estoy incluyendo este tipo de operación.

Sin embargo, creo que lograste entender el concepto que se debe aplicar aquí. Pero recuerda algo importante: el comando BREAK también está relacionado con otro tipo de comando de control de flujo. No obstante, por ahora, dejaremos las cosas así y avanzaremos paso a paso.

Ahora podemos analizar otro comando, que es el último que puede aparecer dentro de un bucle. Sin embargo, a diferencia de los demás comandos vistos hasta el momento, este próximo comando solo existe dentro de bucles, y requiere un cuidado extra al utilizarlo.


Comando CONTINUE

El comando CONTINUE es esencialmente peligroso cuando se usa dentro de un bucle, especialmente en uno que utilice el comando WHILE o el par DO WHILE. Esto se debe a que es muy, pero muy común crear bucles infinitos cuando este comando aparece en un bucle. Sin embargo, incluso en un bucle FOR, que podría parecer más resistente a convertirse en un bucle infinito, también es posible que ocurra esto. Una breve distracción durante la fase de implementación, en la que se utilice el comando CONTINUE, puede ser suficiente para crear un bucle infinito. Por eso, mantente atento y en alerta siempre que tengas que usar o encuentres este comando CONTINUE en algún fragmento de código. Este comando siempre estará vinculado a algún bucle, pero presta especial atención cuando se trate de bucles WHILE y DO WHILE.

Dado que este comando es extremadamente arriesgado si se utiliza de forma incorrecta, haremos las cosas de manera un poco diferente en este caso específico. Comenzaremos primero entendiendo el flujo de ejecución cuando ocurre este comando. Para ello, utilizaremos la imagen que aparece a continuación.


Imagen 06

El mismo aviso dado para los demás comandos, BREAK y RETURN, aplica también aquí. Sin embargo, en este caso específico, el consejo de usar estos comandos, ya sea BREAK o RETURN, como una rutina dentro del comando IF, cobra aún más relevancia. Esto se debe a que, como puedes observar en la imagen 06, nada de lo que esté dentro de lo que sería la rutina del bucle será ejecutado. Y, a diferencia de los otros comandos que hacen que el bucle se cierre, este comando CONTINUE hace que el flujo de control pase inmediatamente al inicio del bucle.

Por lo tanto, si no existe algún tipo de condición vinculada a un evento que haga que la expresión del bucle sea falsa, el bucle inevitablemente entrará en un bucle infinito. Por esta razón, es necesario tener un cuidado extra al utilizar este comando CONTINUE. Muchas lenguajes de programación no utilizan ni implementan el comando GOTO precisamente debido a este tipo de problema potencial. Sin embargo, si se usa e implementa de manera correcta, este comando CONTINUE es, de hecho, muy útil en diversas situaciones. Pero mantén la calma y presta mucha atención al usarlo.

Para demostrar el riesgo potencial de una implementación descuidada en la que aparece este comando, vamos crear un código que, de manera intencionada, solo se cerrará debido a algún evento externo. Para esto, utilizaremos el código que se muestra a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     Procedure_Loop();
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
11. }
12. //+------------------------------------------------------------------+
13. void Procedure_Loop(void)
14. {
15.     char info = 10;
16. 
17.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
18.     
19.     while ((info) && (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) && (!IsStopped()))
20.     {
21.         if (info) continue;
22. 
23.         info = info - 3;
24.                
25.         Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
26. 
27.         if (info < -5) return;
28.     }
29.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
30. }
31. //+------------------------------------------------------------------+

Código 07

Antes de explicar lo que está ocurriendo en este código 07, veamos el resultado de su ejecución. Dado que se trata de un código que entrará en un bucle infinito esperando que ocurra algún evento, no utilizaremos una imagen estática. En su lugar, mostraremos una animación en la que se puede observar cómo hice para finalizar la ejecución de la aplicación. Esta animación puede verse a continuación.


Animación 01

Ahora presta atención, querido lector. Esto solo ocurrió porque implementé una manera de salir del bucle infinito que estamos creando. Si no se hubiera realizado esta implementación, habríamos quedado atrapados allí para siempre, o hasta que alguien decidiera eliminar la aplicación a la fuerza, forzando su cierre desde MetaTrader 5. En ninguna otra situación se cerraría. Dado este aviso y alerta, analicemos lo que está ocurriendo en el código 07.

Como este código es una variación de los demás códigos que hemos utilizado en este artículo, podemos centrar la explicación en las partes realmente importantes. La primera es el hecho de que la variable en la línea 15 se declara de manera que permite que el bucle WHILE se ejecute, como puedes observar en la línea 19, donde comienza el bucle. Lo siguiente a tener en cuenta es que hay tres condiciones para poder finalizar el bucle. La primera es que la variable info se vuelva falsa. La segunda es que se presione la tecla ESC. Y la tercera es que solicites finalizar el script. En el caso de esta tercera condición, si no se hubiera añadido, al intentar cerrar el script, MetaTrader 5 intentaría hacerlo hasta lograrlo. Cuando lo consiguiera, se mostraría otro mensaje en el terminal. Como puedes notar en la imagen que aparece a continuación.


Imagen 07

Este sería el peor de los escenarios posibles para finalizar el código Sin embargo, cabe destacar una vez más que este mensaje, que aparece en la imagen 07, solo se produciría si la tercera condición, que se ve en la línea 19 del código 07, no existiera. Como esta condición está presente, el resultado final sería el mismo que se observa en la animación, dando la impresión de que el código se finalizó de manera adecuada.

Pero el punto aquí es precisamente la línea 21. Observa que, a pesar de la presencia del comando IF para verificar si cambiaríamos algo en el bucle, el hecho de que la rutina dentro del comando IF sea únicamente un comando CONTINUE obliga a que todo el bucle entre en un loop infinito. Esto ocurre porque ninguna otra parte de la rutina del comando WHILE será ejecutada.

Sin embargo, pequeñas variaciones en estos mismos códigos pueden hacerlos menos arriesgados, aunque las líneas 23 a 27 nunca lleguen a ejecutarse. Un ejemplo de esto sería modificar el código 07 para algo como lo que se muestra en el código 08, que aparece a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     Procedure_Loop();
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
11. }
12. //+------------------------------------------------------------------+
13. void Procedure_Loop(void)
14. {
15.     char info = 10;
16. 
17.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
18.     
19.     while (((info = info - 3) > 0) && (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) && (!IsStopped()))
20.     {
21.         if (info) continue;
22. 
23.         info = info - 3;
24.                
25.         Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
26. 
27.         if (info < -5) return;
28.     }
29.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
30. }
31. //+------------------------------------------------------------------+

Código 08

En este caso, al ejecutar el código 08, veremos en el terminal una información diferente a la que se mostró en la animación 01. Como puedes observar a continuación.


Imagen 08

Nota que aquí tenemos valores diferentes para info. ¿Pero cómo sucedió esto? Bien, querido lector, esto se debe precisamente a un pequeño cambio en el código, específicamente en la línea 19, en la primera condición presente en la expresión del comando WHILE. Observa que, en este caso particular, ya no estamos creando un bucle infinito. Pero esto no convierte al resto de la rutina dentro del bucle en algo ejecutable. Esto ocurre porque, en el fondo, este procedimiento Procedure_Loop puede resumirse como lo que se muestra en el fragmento a continuación.

                   .
                   .
                   .
12//+------------------------------------------------------------------+
13void Procedure_Loop(void)
14{
15    char info = 10;
16
17    Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
18    
19    while (((info = info - 3) > 0) && (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) && (!IsStopped()));
20
21    Print(__FUNCTION__, " 29 : Info (", info, ")");
22}
23//+------------------------------------------------------------------+

Fragmento 01

Esto sucede precisamente debido a la presencia del comando CONTINUE en la línea 21, dentro de un comando IF que lo hace ejecutarse cada vez dentro del bucle. Bien, esto fue interesante. Pero, ¿y si en lugar de usar el comando WHILE, utilizáramos, por cualquier motivo, el comando DO WHILE? ¿Qué podría suceder? En este caso, querido lector, definitivamente tendríamos un escenario bastante interesante, que para muchos sería intrigante. Esto se debe a que, dependiendo de cómo implementes tu código, podría comportarse de una manera bastante compleja.

Entonces, probemos una versión muy simple, cuyo objetivo es mostrar lo que ocurre cuando usamos un comando CONTINUE en un bucle DO WHILE. Este ejemplo se muestra en el código 09 que aparece a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
07. 
08.     Procedure_Loop();
09. 
10.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
11. }
12. //+------------------------------------------------------------------+
13. void Procedure_Loop(void)
14. {
15.     char info = 10;
16.     ulong counter = 0;
17. 
18.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
19.     
20.     do
21.     {
22.         Sleep(500);
23. 
24.         Print(__FUNCTION__, "  ", __LINE__, " : Counter (", counter = counter + 1, ")");
25. 
26.         if (info) continue;
27.               
28.         Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
29. 
30.     }while ((info = info - 2) > 0);
31. 
32.     Print(__FUNCTION__, "  ", __LINE__, " : Info (", info, ")");
33. }
34. //+------------------------------------------------------------------+

Código 09

Aunque probablemente imagines que aquí se está creando un bucle infinito, esto no ocurrirá debido a un detalle simple que ya se mostró en los códigos anteriores dentro de este tema. Sin embargo, muchos programadores con menos experiencia con el bucle DO WHILE suelen imaginar que, en el momento en que se ejecuta la línea 26, el bucle regresará a la línea 20. Sin embargo, este tipo de pensamiento surge debido al desconocimiento del flujo de ejecución del comando DO WHILE. En el artículo anterior vimos cuál sería este flujo de ejecución. Por lo tanto, no entraré en detalles nuevamente aquí. Pero un hecho puede y será comprobado cuando estudies este código: que la línea 28 jamás será ejecutada dentro de lo que se muestra en el código 09. Esto ocurre precisamente debido a la línea 26 y a cómo funciona el flujo de ejecución en el comando DO WHILE.

Para probar esto, en lugar de colocar una imagen, consideré mejor usar una animación. Así, desde mi punto de vista, la enseñanza se vuelve mucho más clara y puedes empezar a reflexionar sobre el motivo que explica por qué el código 09 funciona de la manera en que lo hace. La animación correspondiente se muestra a continuación. Presta atención a ella e intenta entender cómo y por qué ocurre tal como sucede.


Animación 02


Consideraciones finales

En este artículo, intenté explicar de la forma más didáctica y sencilla posible cómo trabajar con los comandos RETURN, BREAK y CONTINUE cuando los utilizamos dentro de algún bucle. Aunque todo el contenido se centró en la utilización de los bucles WHILE y el par DO WHILE, lo demostrado en este artículo también se aplica al comando FOR, a pesar de que este último aún no haya sido explicado.

Sin embargo, es imprescindible que tú, mi estimado lector, te esfuerces en estudiar al máximo y practiques ampliamente lo que se ha presentado en este artículo. Esto es porque, a medida que avancemos hacia un nivel más avanzado de programación, será cada vez más importante comprender perfectamente lo que aquí se expone. Los temas y conceptos ya explicados no serán discutidos nuevamente cuando las cosas se tornen más complejas.

Por lo tanto, aprovecha al máximo los códigos que estarán disponibles en el anexo. Estudia con calma, dedicación y atención, intentando entender cómo estos tres comandos vistos en este artículo afectan el flujo del código durante la ejecución de tus aplicaciones. Sin más, nos vemos en el próximo artículo. ¡Hasta pronto!


Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/15376

Archivos adjuntos |
Anexo.zip (2.72 KB)
Aprendizaje automático y Data Science (Parte 27): Redes neuronales convolucionales (CNN) en los robots comerciales de MetaTrader 5: ¿Merecen la pena? Aprendizaje automático y Data Science (Parte 27): Redes neuronales convolucionales (CNN) en los robots comerciales de MetaTrader 5: ¿Merecen la pena?
Las redes neuronales convolucionales (CNN) son famosas por su destreza en la detección de patrones en imágenes y vídeos, con aplicaciones que abarcan diversos campos. En este artículo, exploramos el potencial de las CNN para identificar patrones valiosos en los mercados financieros y generar señales comerciales eficaces para los robots comerciales de MetaTrader 5. Descubramos cómo puede aprovecharse esta técnica de aprendizaje automático profundo para tomar decisiones de negociación más inteligentes.
Del básico al intermedio: Comando WHILE y DO WHILE Del básico al intermedio: Comando WHILE y DO WHILE
En este artículo veremos de manera práctica y bastante didáctica el primer comando de bucle. A pesar de que muchos principiantes sienten temor al enfrentarse a la necesidad de crear bucles, saber cómo hacerlo de manera adecuada y segura, es algo que solo la experiencia y la práctica pueden proporcionar. Pero, ¿quién sabe? Tal vez pueda ayudarte a reducir las dificultades y el sufrimiento, mostrándote los principales problemas y precauciones que debes tener al utilizar bucles en tus códigos. El contenido expuesto aquí tiene como objetivo exclusivamente la enseñanza didáctica. En ningún caso debe considerarse como una aplicación destinada a otro fin que no sea el aprendizaje y estudio de los conceptos presentados.
Del básico al intermedio: Directiva Include Del básico al intermedio: Directiva Include
En este artículo, hablaremos de una directiva de compilación ampliamente utilizada en los diversos códigos que puedes encontrar en MQL5. Aunque esta directiva de compilación se explicará aquí de manera bastante básica y superficial, es importante comenzar a entender cómo usarla, ya que pronto será indispensable para avanzar hacia un nivel de programación superior. El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse una aplicación cuya finalidad no sea el aprendizaje y el estudio de los conceptos presentados.
Combinación de estrategias de análisis técnico y fundamental en MQL5 para principiantes Combinación de estrategias de análisis técnico y fundamental en MQL5 para principiantes
En este artículo, analizaremos cómo integrar sin problemas el seguimiento de tendencias y los principios fundamentales en un Asesor Experto para crear una estrategia más sólida. Este artículo demostrará lo fácil que es para cualquiera comenzar a desarrollar algoritmos comerciales personalizados utilizando MQL5.