Pienso-Pienso: Cual es la salida de este programa?

(ejemplo brindado por Alejandro Rinaldi).


Tengo dos tablas:

Casaslamp12

CasaId PersonaId Color
PEPE01 MUJICA NEGRO
CUQUI01 LACALLE BLANCO
CUQUI02 LACALLE VERDE

Autos

AutoId PersonaId Color
PEPE10 MUJICA BLANCO
PEPE11 MUJICA NEGRO
CUQUI10 LACALLE NEGRO

También existen una tabla de colores y de personas, pero no son relevantes para el problema.

Necesito hacer un programa que liste las casas, con sus dueños e indique si hay autos con el mismo color, no importado que los autos sean de la misma persona que la casa.

Para esto hago un procedimiento (main, command line, en C#) que hace

for each CasaId
 &Color=Color 
 do 'BuscoAutosDelMismoColor'
 Msg(format('Casa %1 de %2 es color %3. Hay autos del mismo color %4 ',CasaId,PersonaId,Color,&HayAutosDelMismoColor),status)
endfor
Sub 'BuscoAutosDelMismoColor'
    &HayAutosDelMismoColor='N'
    for each AutoId
 where Color=&Color
 defined by AutoId,PersonaId,Color
   &HayAutosDelMismoColor='S'
    endfor
endsub

Cuando ejecuto el programa, cual es la salida del mismo? Justifique su respuesta

1)

Casa CUQUI01 de LACALLE es color BLANCO . Hay autos del mismo color S
Casa CUQUI02 de LACALLE es color VERDE . Hay autos del mismo color N
Casa PEPE01 de MUJICA es color NEGRO . Hay autos del mismo color S

2)

Casa CUQUI01 de MUJICA es color BLANCO . Hay autos del mismo color S
Casa CUQUI02 de LACALLE es color VERDE . Hay autos del mismo color N
Casa PEPE01 de MUJICA es color NEGRO . Hay autos del mismo color S

3)

Casa CUQUI01 de LACALLE es color BLANCO . Hay autos del mismo color S
Casa CUQUI02 de LACALLE es color VERDE . Hay autos del mismo color S
Casa PEPE01 de MUJICA es color NEGRO . Hay autos del mismo color S





SOLUCION:
El programa tiene como salida la 2).
El problema es que la subrutina "pasa por arriba" el valor de PersonaId, y el valor que se traia en el primer for each, son sobreescritos por los traidos en la subrutina.

Una solucion, es sacar el defined by de la subrutina, y ahi si la respuesta sera la correcta (la 1))

Hay que utilizar con mucho cuidado las subrutinas, pues todas las variables (incluyendo los atributos leios) son globales a todo el objeto.

Comentarios

  1. Si fuera por el lado de "como debe ser" según el código me voy por la 1, pero siento que hay trampa en el pienso pienso.

    Justificarlo? el único que tiene una casa verde es Lacalle y no existen autos verdes.

    Yo le agregaría al for each de busco un exit cuando encuentra un auto del mismo color, solo para que sea mas eficiente.

    hay trampa?

    ResponderEliminar
  2. Voy por la dos porque por ahí Gx se tara y se queda con la persona de la subrutina, pido perdón si es un disparate pero hace como 1 anio y medio que no toco gx.

    ResponderEliminar
  3. ñ... al fin la encontré pero ya había mandado el comentario :)

    ResponderEliminar
  4. Una SubRutina y un procedimiento Externo (call) deberían dar los mismos resultados, por lo que si difieren el uno del otro es ERROR de GX.
    Debería ser el 1.
    Si difiere el resultado por usar subrutina? Cuando debemos usarlas? para algo "simple"? o hacemos prueba y error?

    ResponderEliminar
  5. David:
    Es un programa GeneXus y no es intutivo. No se si llamarlo tramposo.

    Andres:
    Siempres sirve el ALT-164 para la minuscula y 165 para la mayuscula. Tu respuesta es correcta.

    ResponderEliminar
  6. Anonimo:
    Concuerdo que es confuso. No se si llamarlo error, porque no segun las especificaciones las variables son globales. Pero que recorrer otra tabla, modifique el resultado de lo que traje en otra recorrida, es muy confuso y produce errores dificiles de detectar.

    Por ejemplo, si en mi codigo saco el defined by (que a los efectos del codigo no agrega nada) la salida es la 1).

    Seria bueno encontrarle una solucion, pero creo que no debe ser facil.

    Tener subrutinas con parametros y variables de alcance limitado solo dentro de ellas, puede ayudar mucho a ahorrarnos estos dolores de cabeza.

    Gracias por el comentario.

    ResponderEliminar
  7. La verdad que el uso de subrutinas, cuando se "corta" una recorrida (como el caso del ejemplo), nos ha traído más de un dolor de cabeza.
    Muchas veces cuando un programa no hace lo que debería, mi primer consejo al que me lo presenta es hacer un call a un procedimiento y no usar la subrutina.
    Es muy complejo ponerse a analizar porqué funciona "mal", o "distinto" que en un call, pero si quiero seguridad siempre hago un call y me ahorro dolores de cabeza.
    Y ni que hablar si viene de una migración de versiones anteriores. (por los problemas que hemos tenido, no se comportan 100% igual)
    Nos ha pasado que nos cambia los valores de la recorrida principal ... el porqué no lo sé, es más fácil hacer un call que analizarlo !!! ;.)

    ResponderEliminar
  8. jaja, yo ya conocia el "bug", pero me hice el choto.
    Este bug fue reportado ya en las primeras versiones del generador C#, fue reportado muchas veces (tengo idea de ver este tema en el foro), e inclusive ya fue un tema de un viejo pienso pienso de Marcos Crispiono similar a este caso: http://blog.marcoscrispino.com/2008/07/pienso-pienso-subrutina-que-recorre-la.html

    Este problema si no mal recuerdo no se da con otros lenguajes, pero tendria que verificarse.

    La verdad que por mi lado estoy estancado en las versiones de GX, tenia en mente que este problemas estaban solucionado en las versiones actuales. Hicieron la prueba en la evo 1/2 ?

    Habria que reportarlo nuevamente si no fue solucionado, desde mi punto de vista no es el comportamiento correcto el que una subrutina pise el valor de los atributos del for each padre.

    ResponderEliminar

Publicar un comentario

1) Lee el post
2) Poné tu opinión sobre el mismo.
Todos los comentarios serán leidos y la mayoría son publicados.

Entradas más populares de este blog

El Sordo

Paleta de colores en GeneXus