PiensoPienso: Cual es la salida de estos programas.
Problema: Listar los clientes que tienen Saldo 0
*ClienteId
ClienteNombre
ClienteSaldo
La tabla tiene los valores
ClienteId | ClienteNombre | ClienteSaldo |
1 | Gill Bates | 0 |
2 | Jeeve Stobs | 10 |
3 | Jicolas Nodal | 20 |
Hay 2 versiones del programa que son procedure GeneXus (main y command line) con el código:
//==== Version 1 ============
for each order ClienteNombre
If ClienteSaldo = 0
Msg(Format('Cliente %1 %2 Saldo: %3 ',ClienteId, ClienteNombre, ClienteSaldo),status )
endif
endfor
// ==== Version 2 usando rutinas ====
for each order ClienteNombre
do 'Mensaje'
endfor
Sub 'Mensaje'
If ClienteSaldo =0
Msg(Format('Cliente %1 %2 Saldo: %3',ClienteId, ClienteNombre, ClienteSaldo),status )
Endif
endSub
Cual es la salida de ambos programas?
21756 registros cagados ;)
ResponderBorrarNo estoy como para probarlo, pero pienso que la salida puede ser esta:
ResponderBorrar// == Version 1 ==
Cliente 1 Gill Bates Saldo: 0
// == Version 2 ==
Cliente 0 Gill Bates Saldo: 0
Cliente 0 Jeeve Stobs Saldo: 0
Cliente 0 Jicolas Nodal Saldo: 0
Porque en la versión 2 el único atributo que participa del For Each es ClienteNombre y por lo tanto es el único que tiene valores.
Yo creo que es:
ResponderBorrar// == Version 1 ==
Cliente 1 Gill Bates Saldo: 0
// == Version 2 ==
Cliente 1 Gill Bates Saldo: 0
Cliente 2 Jeeve Stobs Saldo: 0
Cliente 3 Jicolas Nodal Saldo: 0
Porque el for each carga ClienteNombre por estar en el order y ClienteId por ser clave, pero no ClienteSaldo...
Igual, ¿a quién se le ocurre programar así? :)
Lo mejor sería hacer:
for each
order ClienteNombre
where ClienteSaldo = 0
Msg(Format('Cliente %1 %2 Saldo: %3 ',ClienteId, ClienteNombre, ClienteSaldo),status )
endfor
para que se resuelva en el servidor...
Alejandro: :)
ResponderBorrarPablo:
Tu respuesta es correcta.
A mi me gustaria que GeneXus avisara toda vez que se accede a un atributo en el codigo fuera de un for each, pues la mayoria de las veces pasa inardvertido y es fuente de errores, como en el este ejemplo.
Por un error de interpretacion, quedan todos los registros como con saldo 0 y no es la respuesta correcta.
Si por algun motivo se hubiese accedido a un ClienteSaldo con un valor <> 0 listaria todos los clientes con ese valor.
Es bastante peligroso!.
Gracias por los comentarios.
Marcos:
ResponderBorrarEs ciero lo que decis. Queda mejor programado como vos lo planteas, pero lo que queria mostrar es lo dificil que queda leer el codigo cuando se accede a atributos fuera de for eachs. Hay errores que quedan muy escondidos y seria bueno contar con ayuda de GX para detectarlos.
Gracias
No es la primera vez que ponés un Pienso Pienso de este estilo.
ResponderBorrarLa verdad nunca programo así, en ningún caso utilizo en una subrutina atributos de otro For Each, siempre los cargo en variables o lo paso a un procedimiento.
Pero tampoco evita problemas, ya que es muy común olvidarse de cargar alguna de esas variables.
100% de acuerdo con qué GX debería avisar, o al menos permitir configurarlo para avisar en estas situaciones.
Pablo:
ResponderBorrarNadie programa asi de entrada.
Este tipo de problemas, viene cuando se hace algun refactoring de la aplicacion para mejorar el codigo y se introducen este tipo de errores.
Los problemas que planteo, son cosas que me encuentro en el desarrollo diario. Se que ya hice un problema parecido, pero creo que esta bueno tener bien presente este tipo de problemas. A mi plantearlo de forma bien sencilla me ayuda a conceptualizarlo mejor. A lo mejor podemos lograr que proyectos como el Genoma incorporen alguna forma de deteccion de este tipo de defectos.
Muy bueno!!
ResponderBorrarRecuerdo ese caso, en algún momento me tocó corregir algunos programas con ese problema.
Y la navegación que te muestra?
Me hizo acordar a los casos de "Los atributos perdidos" que infieren navegaciones" (atributos que están en Printblocks, pantallas o código que hacen navegar con tabla base.. por descuido de alguien.. suele suceder con los saveas, o copy paste.. detectarlos en programas grandes después es un parto).
David: La navegacion no muestra nada anormal, solo que no muestra que accede al atributo ClienteSaldo. Estaria bueno que mostrara un warning..
ResponderBorrarLo interesante entonces está en que le falta inferir información desde las subrutinas.
ResponderBorrarAsí como infiere información de los "Print", debería de poder hacerlo de los DO.
Y claro, si una subrutina llama a otra, debería también inferir navegaciones hasta lograr todo el árbol de llamadas.
De todas formas.. yo soy "contra" las inferencias automáticas, para mí todo tiene que ser visualmente inferido (alguien que se pone a leer el código fuente tiene que poder conocer qué está haciendo).
Me encantaría en un futuro que GeneXus a medida que programamos tenga información de especificación en línea y que "autodocumente" con comentarios las navegaciones.
Hoy eso lo hago a mano (Buena Práctica), lo que hago es documentar accesos e inclusive indicar en los comentarios el índice utilizado (el que GeneXus dice que va a usar, ya que es importante para tener la información en modo lectura).
Habría que ver si es posible hacerse de una extensión que pueda autodocumentar esa información infiriendo de las navegaciones obtenidas de la spec :)
Y estaría también ver de poder indicar de alguna forma o crear una extensión en donde no se permita usar algunas técnicas de inferencia o lo que algunos ven como malas prácticas (como el caso que mencionas en este post).
Yo pienso, pienso, vuelvo a pensar y descubro algo que ustedes no vieron.
ResponderBorrarNunca GeneXus va a advertir si en los datos de prueba el que debe más es Jicolás Nodal, jeje.
Arturo de Puerto Sauce