none
Qué es mas correcto al definir una variable local para un bucle (ciclo) ?

    Question

  • Ejemplo tengo un bucle que utiliza y asigna una variable local:

    string variable="algo";

    while (condicion)

    {...

    variable = "le asigno algo"; //puede ser una llamada a un metodo o un literal

      ...

    }

    Es preferible poner la definicion dentro del bucle (while) ?  tiene alguna implicacion en el performance?

    ej.

    while (condicion)

    {

    string variable="algo";

    ...

    variable = "le asigno algo"; //puede ser una llamada a un metodo o un literal

      ...

    }

     

    Monday, December 27, 2010 9:42 PM

Answers

  • hola

    no ha correcto ni incorrect, ni problemas de performance, todo depende de cual es el objetico que quieras logar con ese codigo

     

    Caso 1 : si en el while necesitas un contador de ciclos que luego necesitas mostrar es mas que logicvo que la variable ira por fuera del while, ya que de no ser asi el valor lo perderias

    Caso 2 : en cambio si la variable cumple la funcion auxiliar para algun camculo o tarea denteo del ciclo debera ir por dentro, asi limitas la asesibilidad a la misma

    pero ambas son validas y ninguna tiene problemas de performance, simpre define la asesibilidad de la variable lo asm local que puedas, siempre habra tiempo para moverla a un punto aon asesibilidad mayor

    ejemplos

    caso 1 incorrecto (es mas tampoco compila)

    int i=0;

    while(i<=10){

      int suma += i;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    caso1 correcto

    int i=0;

    int suma = 0;

    while(i<=10){

      suma += i;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    caso 2 incorrecto, pero igual funciona

    la visibilidad en este caso sobre "temp" se aumento cuando no era necesarios

    int i=0;

    int suma = 0;

    int temp = 0;

    while(i<=10){

      temp = Convert.ToInt32(txtValor.Text) + i;

      suma += temp;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    caso 2 correcto

    aqui se declara a "temp" como local porque solo es usas a efecto de un calculo local

    int i=0;

    int suma = 0;

    while(i<=10){

      int temp = Convert.ToInt32(txtValor.Text) + i;

      suma += temp;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    resumen, la ubicacion de la definicion de las variables depende del ambito en donde las uses, por eso analzia donde las necesitas y alli las declaras

    espero estos ejemplos sean de utilidad

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Tuesday, December 28, 2010 2:06 AM

All replies

  • Si la Definicion está dentro de un While, seguramente te dará error en el segundo recorrido. la Definicion se la hace fuera del ciclo, la asignación puedes hacerla dentro del While

     

    Saludos.


    Jackson Rosado Developer c#, VFP, PL/SQL DBA - Oracle 10g
    Monday, December 27, 2010 9:51 PM
  •  

     Hola, pues no da error poner la definición dentro del while.  Podés hacer la prueba.   En parte de ahí viene mi inquietud.  

    Monday, December 27, 2010 10:14 PM
  • Hice la prueba y tienes razón no se cae, al menos en la versión 2010 no, sin embargo te recomiendo que lo hagas fuera del While,  no se si realmente te afecte al performance, pero la lógica indica que debe ser fuerad el While. ese mismo algoritmo te debería funcionar en otros lenguajes.

     


    Jackson Rosado Developer c#, VFP, PL/SQL DBA - Oracle 10g
    Monday, December 27, 2010 10:45 PM
  • Pues es raro porque he visto mucho código en la web donde suelen poner la definicion dentro.
    Monday, December 27, 2010 11:57 PM
  • Lo correcto es declararla afuera del bucle, porque se supone que al estar declarada dentro del bucle, la variable se crea y destruye por cada iteracion. Esto es realmente asi en ciertos lenguajes. En el caso de c# el compilador es "inteligente" y al detectar este codigo, declara la variable fuera del bucle, evitando la creacion y destruccion de la variable. Mi consejo es que lo escribas de forma en que te resulte mas facil leer e interpretar el codigo. A veces (muchas) lo mas importante es que el codigo sea facil de seguir y descartar una optimizacion "discutible".
    Tuesday, December 28, 2010 1:09 AM
  • hola

    no ha correcto ni incorrect, ni problemas de performance, todo depende de cual es el objetico que quieras logar con ese codigo

     

    Caso 1 : si en el while necesitas un contador de ciclos que luego necesitas mostrar es mas que logicvo que la variable ira por fuera del while, ya que de no ser asi el valor lo perderias

    Caso 2 : en cambio si la variable cumple la funcion auxiliar para algun camculo o tarea denteo del ciclo debera ir por dentro, asi limitas la asesibilidad a la misma

    pero ambas son validas y ninguna tiene problemas de performance, simpre define la asesibilidad de la variable lo asm local que puedas, siempre habra tiempo para moverla a un punto aon asesibilidad mayor

    ejemplos

    caso 1 incorrecto (es mas tampoco compila)

    int i=0;

    while(i<=10){

      int suma += i;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    caso1 correcto

    int i=0;

    int suma = 0;

    while(i<=10){

      suma += i;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    caso 2 incorrecto, pero igual funciona

    la visibilidad en este caso sobre "temp" se aumento cuando no era necesarios

    int i=0;

    int suma = 0;

    int temp = 0;

    while(i<=10){

      temp = Convert.ToInt32(txtValor.Text) + i;

      suma += temp;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    caso 2 correcto

    aqui se declara a "temp" como local porque solo es usas a efecto de un calculo local

    int i=0;

    int suma = 0;

    while(i<=10){

      int temp = Convert.ToInt32(txtValor.Text) + i;

      suma += temp;

      i++;

    }

    txtResultado.Text = Convert.ToString(suma);

     

    resumen, la ubicacion de la definicion de las variables depende del ambito en donde las uses, por eso analzia donde las necesitas y alli las declaras

    espero estos ejemplos sean de utilidad

     

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Tuesday, December 28, 2010 2:06 AM
  • Leandro, si hay una cuestion de performance aunque no sea relevante. De hecho, solo para sacarme las dudas, hice una pequeña prueba, asignando un string dentro y fuera de un bucle de 20 millones de iteraciones. Corri las pruebas unas 20 veces aproximadamente para tener una idea de la relacion entre los metodos, descartando los 4 mejores y peores rendimientos de cada caso.

    Declarando la variable fuera tardo siempre entre 70 y 110 milisegundos. Con la variable dentro del bucle tardo siempre entre 700 y 770 milisegundos.

    Fijate si puedes hacer tu tambien unas pruebas y comparamos los resultados ya que es un tema interesante. Tal vez no tiene mucho sentido para el ejemplo que use en esta prueba pero se puede extender para analizar el comportamiento de otros tipos de datos como fonts, brushes, pens, etc.

     

    Este es el codigo que yo utilice:

     

                string s = "";

                DateTime t1 = DateTime.Now;
                for(int i = 1; i <= 20000000; i++)
                {
                    s = i.ToString();
                }
                DateTime t2 = DateTime.Now;

                TimeSpan ts1 = t2-t1;
                MessageBox.Show(ts1.Milliseconds.ToString());

                DateTime t3 = DateTime.Now;
                for(int i = 1; i <= 20000000; i++)
                {
                    string s2 = i.ToString();
                }
                DateTime t4 = DateTime.Now;

                TimeSpan ts2 = t4-t3;
                MessageBox.Show(ts2.Milliseconds.ToString());

     

    Tuesday, December 28, 2010 12:32 PM
  • hola Sinclair

    pero si el cliclo lo va a usar para unir cadenas no uses un string comun, usa el StringBuilder

    ya que la performance no la pierdes por la tecnica del cliclo, sino por un tema en la concatenacion de valores en un objeto string

    reemplaza el codigo por el StringBuilder y seguro cambian estos valores

    - un tema en s, une los valores usa: s += i.ToString()

    ademas pierdes el foco de la funcionalidad, porque que sucede si el resultado de la variable "s" debes mostrarlo al usuario, no te queda otra que declararlo por fuera, mas alla de la baja performance, usas "s" dentro del ciclo para mostrar el valor al usuario no servira de nada

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Tuesday, December 28, 2010 12:42 PM
  • Yo tambien me puse a hacer pruebas como esa utilizando la clase Stopwatch y efectivamente cuando se pone la variable fuera del bucle es significativamente mas rapido, por supuesto que esto tendria relevancia solamente cuando las iteraciones son muchisimas, lo cual es poco probable en aplicaciones normales.

    Sin embargo, buscando en la web vi que es una "buena practica" de programación poner la definicion dentro si dicha variable no se va a utilizar fuera del bucle para nada, es decir como si se asumiera que lo que esta entre llaves fuese como un metodo anonimo y por tanto le defines sus variables adentro.  También utilitarios que optimizan código casi siempre por defecto recomiendan eso (ej. ReSharper)

    En resumen, dos puntos contradictorios:

    -Es mas eficiente definirla afuera del bucle.

    -Es buena practica definirla en el bloque mas interno.

     

     

     

    Tuesday, December 28, 2010 1:14 PM
  • hola

    buscando en la web vi que es una "buena practica" de programación poner la definicion dentro si dicha variable no se va a utilizar fuera del bucle para nada

    coincido plemanente con este parrafo, la visibilidad debe ser la menor posible para la funcionalidad que implementas

    eso lo veras claro en los ejemplos que detalle

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina
    Tuesday, December 28, 2010 1:19 PM
  • La idea era probar la declaracion fuera o dentro del bucle, independientemente de que sea un string, un entero u otro tipo de variable.

    Fijate que los trings no los concateno, solo los asigno.

    "ademas pierdes el foco de la funcionalidad, porque que sucede si el resultado de la variable "s" debes mostrarlo al usuario, no te queda otra que declararlo por fuera, mas alla de la baja performance, usas "s" dentro del ciclo para mostrar el valor al usuario no servira de nada"

    Podria tratarse de que esos strings no se muestren sino que se agreguen a un file, por ejemplo, con lo cual no los muestro pero sin embargo los sigo creando y usando dentro del bucle.

    Igualemnte lo que tu dices es muy cierto, por eso te decia que habria que estudiarlo con otro tipo de datos como Font o Pen que se suele usar dentro de un bucle para dibujar en pantalla.

    Voy a hacer otras pruebas con otros tipos de datos y luego voy a postear los resultados.

    Tuesday, December 28, 2010 1:19 PM
  • Bloque más interno no siempre se refiere a dentro de un ciclo. Puede ser simplemente dentro de un if(), un switch(), etc. de una estructura anidada. En estos casos yo siempre defino la variable en el bloque 'más interno' si es de uso estrictamente local al bloque. Pero si este bloque está dentro de un loop de muchas iteraciones pues la defino fuera (antes). Quizas si el compilador se encargara de optimizarlo no fuera necesario, similar a lo que hace con la declaración de un for() o un foreach(). Pero de las pruebas se deduce que el compilador no lo optimiza.
    Tuesday, December 28, 2010 2:04 PM
  • La variables se deberian siempre declaran en el ambito donde se van a utilizar. Declarar una variable en un metodo fuera de un bucle y que solo se va a utlizar dentro del bucle termina siendo perdida de memoria hasta que se termina la ejecucion del metodo.

    Si uno esta muy justo con la memoria, la variable debe declararse dentro del bucle, asi una vez finalizado el bucle la variable se elimina de la memoria. Obviamente todo depende de si el GarbageCollector hace las cosas como las deberia hacer....:S Ya que puede ser que el compilador no te deje acceder a una variable declarada dentro del bucle desde afuera pero igual asi la siga manteniendo hasta la finalización del metodo.

    Hay que preguntarle a los muchachos del GC.

     

    Sparow

    Tuesday, December 28, 2010 2:13 PM
  • En realidad yo cometi un error con las pruebas, ya que siempre lo corri en modo debug y en ese caso el compilador no hace optimizaciones. En modo realase ambos metodos tardaron lo mismo, con lo cual queda claro que el compilador elige la mejor opcion. En cuanto tenga un poco de tiempo hago las pruebas con otros tipos de datos.
    Tuesday, December 28, 2010 2:16 PM
  • Buen punto ese. Hay que hacer las pruebas a ver si realmente optimiza y vale la pena.
    Tuesday, December 28, 2010 2:45 PM
  • Pues yo tambien hice mis pruebas con el modo debug y me dio bastante diferencia... En release parece que si hace una optimizacion y aunque da distinto es practicamente igual el tiempo, lo cual es una buena noticia y justifica por qué se recomienda como buena practica, asi que de ahora en lo adelante voy a meter siempre la declaracion dentro del bloque.

    Gracias a todos por sus aportes que han sido muy enriquecedores.

     

     

    Tuesday, December 28, 2010 2:54 PM
  • Claro creo que queda a criterio de cada quien y mas que nada dependiendo de la labor que debe realizar. sin embargo por costumbre, siempre lo he hecho fuera del bloque, hasta ahora me ha ido bien. sin embargo si nos basamos a resultados objetivos, y si en el caso de un Release da lo mismo. entonces no veo el porque no usar el otro metodo. si somos mas minuciosos tendríamos que investigar qeu hace el compilador internamente a ver que es mejor, pero de una forma generalizada y objetiva tiene el mismo peroformance y en algunas ocaciones hasta mejor gestion de memoria. pues a usarlo de esa manera.. 
    Jackson Rosado Developer c#, VFP, PL/SQL DBA - Oracle 10g
    Tuesday, December 28, 2010 3:13 PM