Поделиться через


Se puede justificar el uso de goto?

goto  es tal vez una de los statements más cuestionados en los lenguajes de programación modernos.

Por años fue la pasta causante del código espagueti y miles de developers han denigrado de el pobre.

 Image result for goto spaghetti code

Pero en realidad... no habrán formas en las que usarlo sea adecuado?

Consideremos el siguiente loop:

 while (currentFibonacciNumber <= maxLimit)  
{  
    var lastCurrentFibonacciNumber = currentFibonacciNumber;  
    currentFibonacciNumber += previousFibonacciNumber;  
    previousFibonacciNumber = lastCurrentFibonacciNumber;  
    if (currentFibonacciNumber % 2 == 0 &&  
        currentFibonacciNumber <= maxLimit)  
        sum += currentFibonacciNumber;  
}

Es un sencillo loop que suma los números pares de la serie de Fibonacci, tendiendo en cuenta que hay un límite superior, donde la suma se detiene (maxLimit).

Con este loop, dándole a maxLimit un valor de 4000000000, el algoritmo se resuelve en promedio en 550 ticks.

Obsérvese que por cada iteración, se hacen 3 comparaciones.

Podemos reducir el número de comparaciones a 2:

 while (true)
{
     var lastCurrentFibonacciNumber = currentFibonacciNumber;
     currentFibonacciNumber += previousFibonacciNumber;
     if (currentFibonacciNumber <= maxLimit)
     {
         previousFibonacciNumber = lastCurrentFibonacciNumber;
         if (currentFibonacciNumber % 2 == 0)
             sum += currentFibonacciNumber;
     }
     else break;
 }

 return sum;

Curiosamente, el tiempo empleado es muy similar: 545 ticks.

Al parecer la mera estructura del loop implica esfuerzo de proceso.

Y que tal si traemos al no muy querido goto a escena?

 IterateFibonacci:
var lastCurrentFibonacciNumber = currentFibonacciNumber;
currentFibonacciNumber += previousFibonacciNumber;
if (currentFibonacciNumber <= maxLimit)
{
    previousFibonacciNumber = lastCurrentFibonacciNumber;
    if (currentFibonacciNumber % 2 == 0)
        sum += currentFibonacciNumber;
    goto IterateFibonacci;
}

return sum;

En este caso, el tiempo promedio se reduce a 455 ticks!

Esto en loops mucho más grandes o con comparaciones más complejas, podría significar una gran diferencia!

De aquí también puedo rescatar que el uso de goto fue muy específico y con un alcance muy bien delimitado. Y en tiempos de ejecución está dando mejor resultado que los otros métodos. Además es más entendible a primera vista que por ejemplo el segundo método donde con lo que uno se encuentra al principio es con un loop infinito. Algo que no es realmente el objetivo del algoritmo.

Sin embargo, como siempre hay que poner todo en una balanza. Es en verdad la mejora que se gana con goto justificable para usarlo? eso depende de cada caso de uso.

Cuando no es así, el primer procedimiento da más claridad para los posteriores lectores del código que por ejemplo el segundo y teniendo un tiempo de ejecución muy similar, podría pensarse en preferirlo.

Todos estos son simples hallazgos que no determinan ninguna regla pero si amplían nuestro horizonte para poder escoger la mejor opción según sea el caso.