Ir al contenido


Foto

Diseño de constantes de error acumulativas

constantes error

  • Por favor identifícate para responder
15 respuestas en este tema

#1 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 abril 2015 - 09:30

Les comento que tengo un módulo que contiene varios métodos (casi un centenar). Por diseño, se necesita estar controlando y operando constantemente y hay varias variables en juego.

Por todo esto, es que algunos de esos métodos son funciones diseñadas para hacer las comprobaciones y devolver un boolean.

Si todo anda bien, el valor como es de esperar es true. Por el contrario si es false algo ha fallado.

Para saber ese algo se dispone de un parámetro por referencia que almacena una especie de código de error. Para facilitar un poco las cosas estos códigos los tengo declarados como constantes:


delphi
  1. const
  2. TODO_BIEN = 0;
  3. ERROR_TIPO1 = 1;
  4. // ...
  5. ERROR_TIPO6 = 6;

Bueno. La cosa es que estas funciones reciben entre 1 a 3 parámetros a los que somete a prueba. Ahora es cuando se pone un poco pesada la cosa. Algunas de estas funciones invocan a otras y que son más específicas para evaluar a cada tipo de parámetro. Estas "subfunciones" además de ese parámetro por referencia para el código de error regresan información adicional de interés (que no son más de 2).

 

Entonces en una función "padre" puede que requiera llamar a 1 o hasta 3 subfunciones. Cada una hace lo suyo y regresa el código de error para el caso detectado, más la/s info/s adicional/es:


delphi
  1. SePuede1 := VerificarParametroTipo1(Param1, info11, info12, Cod1);
  2. SePuede2 := VerificarParametroTipo2(Param2, info21, info22, Cod2);
  3. SePuede3 := VerificarParametroTipo3(Param3, info31, info32, Cod3);

Siendo Cod1 a Cod3 las variables destinadas para detectar el código de error para cada parámetro e infoXY la variable de información Y-ésima para el parámetro X.

 

Estas subfunciones evalúan de forma "interna" cada parámetro. Más no lo "externo", que es lo que terminará realizando la función padre. Para eso son las InfoXY.

 

Entonces, al evaluar las variables SePuede se sabe que con los parámetros dados puedo trabajar... Pero hace falta hacer unas pocas pruebas más para ver si es "legal" operar con ellos.

 

Tengo al final esto:


delphi
  1. result := SePuede1 AND SePuede2 AND SePuede3;
  2. if result
  3. then begin
  4. // Aqui se evalúan las InfoXY y se generan Cod. de error específicos en caso de no pasar algunas pruebas.
  5. // Si todo OK: se trabaja.
  6. end
  7. else CodErr = Cod1 + Cod2 + Cod3;

Como pueden ver, si inicialmente ya se detecta que no se puede, regreso en la variable de referencia del código de error general (como para ponerle un nombre y diferenciarlo de los específicos para cada parámetro) una simple suma de los errores.

 

A mi en su lugar me gustaría poder devolver en el código de error un valor "acumulativo" de errores que tenga todos los errores detectados. Es decir, O bien todos los errores específicos/internos acumulados, o bien los errores generales externos acumudos.

 

Entre los errores internos (4) y externos (los 2 últimos) contabilicé 6. De allí que he diseñado 6 constantes.

 

Es decir que:

CodError = "suma" errores internos. cuando la evaluación SePuede da negativo. O bien...

CodError = "suma" errores externos. cuando la evaluación SePuede da positivo.

 

Naturalmente las constantes no debieran de tener valores consecutivos. Porque de esa forma por ejemplo al sumar TIPO1 y TIPO2 daría el TIPO3 y no necesariamente eso quiere decir que se ha detectado esto.

 

La intención de hacerlo "acumulativo" es que se pueda distinguir los errores y desde el módulo cliente regresar un mensaje alusivo a modo de advertencia señalando puntualmente la seguidilla de errores. No sólo en cuanto interno vs externo sino también para que cuando sea interno se pueda diferenciar el error de cada parámetro.

 

Es decir que CodError exprese numéricamente algo como "Che, mirá, las evaluaciones indican que se han detectado:

1. En el parámetro 1 te falló X.

2. Para el parámetro 2 tenés Y.

3. Y por último en 3, el Z no vá.

Así no se puede trabajar viejo. Empezá todo de nuevo"

 

Cuando todo sea por causa interna. Y cuando es externa, que diga por ejemplo:

"Che... todo bien, pero para operar con param 1 y param 2 deben coincidir el índice. Pasame otro y opero perfecto"

 

¿Me explico?

 

¿Que alternativa consideran viable?

 

He pensado en un diseño con número de error basado en potencias:

 

ERROR_TIPO1 = 1;

ERROR_TIPO2 = 2;

ERROR_TIPO3 = 4;

ERROR_TIPO4 = 8;

ERROR_TIPO5 = 16;

ERROR_TIPO6 = 32;

 

Esto es para que la "suma" no se "pisen" los valores. Pero claro, ¿Y cómo podría a su vez hacer que detecte si es para param1, param2, param3?

 

Pensé que podría ser útil entonces hacer que sea por rangos: Para Param1 que el valor sea 100 + Nro, para Param2 le corresponda 200 + Nro y para Param3 el 400 + Nro. Pero presiento que así tampoco puede funcionar.

 

Si logro hacer esto desde el módulo "cliente" bastarían cosas como:


delphi
  1. if EvaluarPadreCon3ParamsParaLaOperacion1(Param1, Param2, Param3, Err)
  2. then Operar1(Param1, Param2, Param3)
  3. else DarAviso(Err);
  4.  
  5. ...
  6.  
  7. if EvaluarPadreCon2ParamsParaLaOPeracion2(Param1, Param2, Err)
  8. then Operar2(Param1, Param2)
  9. else DarAviso(Err);

Y así DarAviso() centraliza todo y el se encarga de armar y dar las malas noticias.

Lo máximo que estuve pensando, y a lo que quisiera evitar, es tener que definir constantes específicas para cada caso.

 

Quizá les parezca medio a los palos el diseño, pero bueno... es lo más aceptable y lógico que mi mente ha logrado hacer para poder lograr manerar la cantidad de variables que juegan. Si mis Operar() tuvieran que manerar parte de la decisiones y evaluaciones que se hacen en los Evaluar() padres e hijos la complejidad se disparaba mucho.

A pesar de eso, me gusta la buena biblioteca que he generado. :)

 

El manejo de error es dentro de todo un detalle algo menor. La biblioteca está funcionando. Pero quisiera escuchar otras alternativas y opciones y ver que posibilidades hay de llegar a algo como lo que quiere inducirme este Delphius inconsciente :lol:

 

Saludos,


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 06:08

Otra forma que podrias hacerlo es en ves de retornar el codigo de error en un integer, hacerlo en un set
 
Y no seria mejor usar enumerativo en ves de costantes?


delphi
  1. TErrorParam1 =
  2. ERRP1_TIPO_1 = $1, // 001
  3. ERRP1_TIPO_2 = $2, // 010
  4. ERRP1_TIPO_3 = $3); // 100
  5.  
  6. TErrorParam2 =
  7. ERRP2_TIPO_1 = $1,
  8. ERRP2_TIPO_2 = $2);

Saludos!


  • 0

#3 Rolphy Reyes

Rolphy Reyes

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.092 mensajes
  • LocationRepública Dominicana

Escrito 29 abril 2015 - 06:20

Saludos.

 

¿Pensaste en usar un tipo de datos record para almacenar los errores registrados o tal vez algún descendiente del TList?

 

Así simplemente recorres o preguntas por los valores almacenados o cambiados.


  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 06:58

Otra forma que podrias hacerlo es en ves de retornar el codigo de error en un integer, hacerlo en un set
 
Y no seria mejor usar enumerativo en ves de costantes?


delphi
  1. TErrorParam1 =
  2. ERRP1_TIPO_1 = $1, // 001
  3. ERRP1_TIPO_2 = $2, // 010
  4. ERRP1_TIPO_3 = $3); // 100
  5.  
  6. TErrorParam2 =
  7. ERRP2_TIPO_1 = $1,
  8. ERRP2_TIPO_2 = $2);

Saludos!

 

Umm. Tengo el cerebro chamuscado. No termino de captar tu idea. :(  El punto es que no necesariamente se trabajan con 3 parámetros. Algunos métodos reciben 1, otros trabajan con 2 y otros con 3.

Los códigos de error fueron pensados para ser reutilizados y describir interna y externamente lo que puede suceder con cualquiera (y/o todos) de éstos. No es que hay errores específicos para el parámetro 1 y otros para el 2do y el 3ro. ERROR_TIPO1..ERROR_TIPO4 pueden darse para el parámetro 1, 2 y/o 3. ¿Me explico?

 

Saludos.

 

¿Pensaste en usar un tipo de datos record para almacenar los errores registrados o tal vez algún descendiente del TList?

 

Así simplemente recorres o preguntas por los valores almacenados o cambiados.

 

La verdad que no. Descendientes de TList u otros tampoco. ¿Que propones? ¿Puedes concretar un poco más tu idea?

Al ser una biblioteca en la que el enfoque OO no ofrecía grandes ventajas respecto a un pensamiento más "estructurado" no pensé en clases. Esta biblioteca es parte de mi colección de bibliotecas bases para otros proyectos. Ha pesar de ser una biblioteca base, es lo suficiente específica como genérica para ciertos proyectos que estoy llevando a cabo.

 

Ando bastante dormido todavía... y son las 10am.

 

Saludos,


  • 0

#5 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 07:57

Ahora me mareaste jaja
 

A mi en su lugar me gustaría poder devolver en el código de error un valor "acumulativo" de errores que tenga todos los errores detectados. Es decir, O bien todos los errores específicos/internos acumulados, o bien los errores generales externos acumudos.

 
 
La sugerencia de usar un conjunto era para simular ese codigo de error "acumulativo"
 

 ¿Y cómo podría a su vez hacer que detecte si es para param1, param2, param3?
 
Pensé que podría ser útil entonces hacer que sea por rangos: Para Param1 que el valor sea 100 + Nro, para Param2 le corresponda 200 + Nro y para Param3 el 400 + Nro. Pero presiento que así tampoco puede funcionar.

 

Y el tema de usar enumerativo para definir los distintos codigos como otra propuesta para no andar dependiendo de los sub rangos

 

 

 

El punto es que no necesariamente se trabajan con 3 parámetros. Algunos métodos reciben 1, otros trabajan con 2 y otros con 3.

 

 

Esto lo podrias resolver mandando, en ves de X parametros, un arreglo dinamico de parametros

 

 

Leyendo y releyendo el primer post creo que la duda puntual que tenes es como diferenciar que "tan mal le fue" (dicho en criollo) en las pruebas a cada parametro, de ahi este parrafo

 

 

[...] se pueda diferenciar el error de cada parámetro.

 

Es decir que CodError exprese numéricamente algo como "Che, mirá, las evaluaciones indican que se han detectado:

1. En el parámetro 1 te falló X.

2. Para el parámetro 2 tenés Y.

3. Y por último en 3, el Z no vá.

Así no se puede trabajar viejo. Empezá todo de nuevo" Cuando todo sea por causa interna.

 

Y cuando es externa, que diga por ejemplo:

"Che... todo bien, pero para operar con param 1 y param 2 deben coincidir el índice. Pasame otro y opero perfecto"

 

Si no te sigo mal le encuentro similitud al compilador. Cuando te salta un error chau, no compilas. Si es un hint o un warning te sale el mensaje con el codigo de error "Che mira te salto el warning nro xxx, revisa aca porque puede pasar tal cosa", pero aun asi te compila el programa. Pero eso si, si pasa X, yo te avise

 

Es mas o menos esa tu idea?


  • 0

#6 cram

cram

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 832 mensajes
  • LocationMisiones, Argentina

Escrito 29 abril 2015 - 08:16

Si no entendí mal el asunto, yo preferiría usar los bits, pero en varias variables, una para cada parámetro. El único problema es que si tienes unas cien funciones, no habrá número que alcance o al menos no de forma sencilla. Recientemente utilicé ese método para marcar campos obligatorios con entrada satisfactoria, pero se trata de los que se pueden contar en un form y son pocos.

Una vez agrupados los errores y separados en por ejemplo X, Y y Z para los -hasta- tres posibles errores en parámetros por cada función, podrías almacenar en un registro. Lo que no se me ocurre es como manejar la cantidad aproximada de 100, ya que 64 será un máximo posible en enteros.

Lo positivo del método de usar los bits es que puedes utilizar los operadores booleanos para manipular los agregados de errores y la consulta final.

 

Saludos


  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 09:12

No es un compilador o algo por estilo. Es una biblioteca de propósito general que tengo diseñada para mis proyectos que cuenta con tipos y métodos para explotarlos. Cada proyecto usará esta biblioteca según para lo que necesite. Las funciones y procedimientos que contiene mi biblioteca son lo suficiente básicos para que cada proyecto pueda adaptarse, pero también ofrece procedimientos más específicos para ciertas tareas.

 

Quizá se parece en algo a lo que dicen sobre el compilador en la forma de tratar los errores.

 

En parte debe ser posible de ofrecer información de errores específicos y puntuales (los errores internos detectados) que advierta de que con dichos parámetros no es posible operar por lo que no es deseable invocar al método OperarX() que se desea. Para estos casos es que justamente he detectado hasta 4 posibles errores que sean de interés. NO TODOS LOS ERRORES SE DAN SIEMPRE.

Pero por otro lado también debe ser posible de ofrecer información de errores generales, en lo que si bien las estructuras que se pasan como parámetros están en condiciones internas de ser utilizadas, para el contexto (algún método OperarY) no se han dado las condiciones necesarias. En estos casos hay hasta 2 posibles errores, aunque para la mayoría de las funciones Verificar() sólo le es de utilidad y necesita devolver uno. Pero para otras en su implementación está pensado que pueda dar como error estos 2.

 

La constante ERROR_TIPO1 representa un caso/tipo de error de estructura con memoria no reservada. INDEPENDIENTE de si es una matriz, vector, grafo, o la estructura que imaginen.

La constante ERROR_TIPO2 representará el tipo de error en donde la estructura no tiene dimensiones uniformes. Y esto es válido para cualquiera de los 3 parámetros.

Y asi para TIPO3 Y TIPO4.

 

Para TIPO5 Y TIPO6, que son los errores generales los errores hacen referencia a que no hay cierta concordancia entre los parámetros pasados.

 

Por otro lado los métodos son lo suficientemente independientes uno del otro, aunque se podría agruparlos por la afinidad de sus algoritmos, lo que tienen en común son que TODOS aprovechan los tipos de datos que ofrece mi biblioteca.

 

De allí que verían algo como:

 

VerificarOp1()

Operar1()

 

...

 

VerificarOp2() overload;

VerificarOp2() overload;

Operar2(); overload;

Operar2(); overload;

 

Para una buena mayoría de las operaciones OperarN() concebidas existe su contraparte VerificarN() específicamente diseñado. Algunos son sobrecargados. Pero también existen otros Verificar() que son generales y pueden ser aprovechados por y para varios Operar().

 

Por esto es que los métodos no estan relacionados con los errores tampoco. Es responsabilidad de la unidad "cliente" que haga(n) uso de esta biblioteca decidir al final que van a hacer. La blbioteca solo se limita a reportar la seguidilla de errores. Las clientes Invocarán a los métosos y funciones que se necesiten... usarán 50, otras 10... otras los 100. La clase que inova a un método concreto Operar() está consciente de la cantidad y tipos de parámetros que pasa. El código de error, le indicará que ha sucedido.

 

Creo que con esto ya me explico un poco mejor.

 

Saludos,


  • 0

#8 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 29 abril 2015 - 10:18

Hola Delphius y que tal algo así, te pongo dos implementaciones que obtienen el mismo resultado usando records, en la primera devuelve los errores en un array de record y en la segunda devuelve los errores directamente en un string:


delphi
  1. unit UMain;
  2.  
  3. interface
  4.  
  5. uses
  6. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  7. System.Classes, Vcl.Graphics,
  8. Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
  9.  
  10. type
  11. ErrosRecord = Record
  12. TipoError: integer;
  13. NumParametro: integer;
  14. End;
  15.  
  16. type
  17. BoxErrors = array of ErrosRecord;
  18.  
  19. type
  20. TMainForm = class(TForm)
  21. Label1: TLabel;
  22. Label2: TLabel;
  23. Label3: TLabel;
  24. Edit1: TEdit;
  25. Edit2: TEdit;
  26. Edit3: TEdit;
  27. Button1: TButton;
  28. Button2: TButton;
  29. procedure Button1Click(Sender: TObject);
  30. procedure Button2Click(Sender: TObject);
  31. private
  32. FErrores: BoxErrors;
  33. FCadenaErrores: string;
  34.  
  35. function EvaluarPadre(Par1, Par2, Par3: integer;
  36. var AErrors: BoxErrors): Boolean;
  37.  
  38. function EvaluarPadreCadena(Par1, Par2, Par3: integer;
  39. var AErrors: string): Boolean;
  40. public
  41. end;
  42.  
  43. var
  44. MainForm: TMainForm;
  45.  
  46. implementation
  47.  
  48. {$R *.dfm}
  49. { TMainForm }
  50.  
  51. function TMainForm.EvaluarPadre(Par1, Par2, Par3: integer;
  52. var AErrors: BoxErrors): Boolean;
  53. var
  54. i: integer;
  55. begin
  56. Result := False;
  57. i := 0;
  58.  
  59. if Par1 > 25 then
  60. begin
  61. SetLength(AErrors, i + 1);
  62. AErrors[i].TipoError := 1;
  63. AErrors[i].NumParametro := 1;
  64. inc(i);
  65. end;
  66. // else evaluar otra sub funcion
  67.  
  68. if Par2 < 0 then
  69. begin
  70. SetLength(AErrors, i + 1);
  71. AErrors[i].TipoError := 1;
  72. AErrors[i].NumParametro := 2;
  73. i := i + 1;
  74. end;
  75. // else evaluar otra sub funcion
  76.  
  77. if Par3 > 50000 then
  78. begin
  79. SetLength(AErrors, i + 1);
  80. AErrors[i].TipoError := 1;
  81. AErrors[i].NumParametro := 3;
  82. inc(i);
  83. end;
  84. // else evaluar otra sub funcion
  85.  
  86. Result := i = 0;
  87.  
  88. end;
  89.  
  90. function TMainForm.EvaluarPadreCadena(Par1, Par2, Par3: integer;
  91. var AErrors: string): Boolean;
  92. var
  93. i: integer;
  94. ABoxErrors: BoxErrors;
  95. S: string;
  96. begin
  97. Result := False;
  98. i := 0;
  99.  
  100. if Par1 > 25 then
  101. begin
  102. SetLength(ABoxErrors, i + 1);
  103. ABoxErrors[i].TipoError := 1;
  104. ABoxErrors[i].NumParametro := 1;
  105. S := S + 'error ' + IntToStr(ABoxErrors[i].TipoError) +
  106. ' en el parámetro ' + IntToStr(ABoxErrors[i].NumParametro) + #10 + #13;
  107.  
  108. inc(i);
  109. end;
  110. // else evaluar otra sub funcion
  111.  
  112. if Par2 < 0 then
  113. begin
  114. SetLength(ABoxErrors, i + 1);
  115. ABoxErrors[i].TipoError := 1;
  116. ABoxErrors[i].NumParametro := 2;
  117. S := S + 'error ' + IntToStr(ABoxErrors[i].TipoError) +
  118. ' en el parámetro ' + IntToStr(ABoxErrors[i].NumParametro) + #10 + #13;
  119.  
  120. i := i + 1;
  121. end;
  122. // else evaluar otra sub funcion
  123.  
  124. if Par3 > 50000 then
  125. begin
  126. SetLength(ABoxErrors, i + 1);
  127. ABoxErrors[i].TipoError := 1;
  128. ABoxErrors[i].NumParametro := 3;
  129. S := S + 'error ' + IntToStr(ABoxErrors[i].TipoError) +
  130. ' en el parámetro ' + IntToStr(ABoxErrors[i].NumParametro) + #10 + #13;
  131. showmessage('Se encontraron los siguientes errores: ' + #10 + #13 + S);
  132. inc(i);
  133. end;
  134. // else evaluar otra sub funcion
  135.  
  136. Result := i = 0;
  137. if not Result then
  138. AErrors := 'Se encontraron los siguientes errores: ' + #10 + #13 + S;
  139. end;
  140.  
  141. procedure TMainForm.Button1Click(Sender: TObject);
  142. var
  143. i: integer;
  144. S: string;
  145. begin
  146. S := '';
  147. if not EvaluarPadre(StrToIntDef(Edit1.Text, 0), StrToIntDef(Edit2.Text, 0),
  148. StrToIntDef(Edit3.Text, 0), FErrores) then
  149. begin
  150. for i := Low(FErrores) to High(FErrores) do
  151. S := S + 'error ' + IntToStr(FErrores[i].TipoError) +
  152. ' en el parámetro ' + IntToStr(FErrores[i].NumParametro) + #10 + #13;
  153. showmessage('Se encontraron los siguientes errores: ' + #10 + #13 + S);
  154. end
  155. else
  156. showmessage('ok');
  157. end;
  158.  
  159. procedure TMainForm.Button2Click(Sender: TObject);
  160. begin
  161. if not EvaluarPadreCadena(StrToIntDef(Edit1.Text, 0),
  162. StrToIntDef(Edit2.Text, 0), StrToIntDef(Edit3.Text, 0), FCadenaErrores) then
  163. showmessage(FCadenaErrores)
  164. else
  165. showmessage('ok');
  166. end;
  167.  
  168. end.


  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 11:13

Ummm. No se porqué no pensé en la posibilidad de emplear un array. No es un defecto ni tiene de malo devolver una estructura matricial en una variable por referencia, pero no me imaginaba estar usando una.

 

Admito que es un tanto "rara" la forma en que he diseñado la biblioteca.

 

Ahora que mi cabecita anda pensando un poquito más, tomando partes de sus ideas... puede que definir un tipo propio para el error no sea mal idea. ¿Que tal ven esta idea descabellada?:


delphi
  1. type
  2. TError = record
  3. EInternal: integer;
  4. EExternal: integer;
  5. end;

De ese modo el código de error podría ir en forma de potencias como estaba pensando para que pueda ser acumulado. Lo que queda por incorporar al diseño es poder diferenciar cual hace a cada parámetro. Lo que comentaba sobre de hacerlo por bit o llevarlo agrupado... ¿Puede ir? Ummm

 

Al tenerlo separado en EInternal y EExternal me permitiría que en las Verificar "hijas" y Verificar "padres" escriban en su parte correspondiente y puedan acumularse sus errores de forma independiente. Ahora el lío es hacer que las del código interno se vaya acumulando y pueda diferenciarse entre cada parámetro. Tendría ahora esto:


delphi
  1. function VerificarOperarAlgo(Param1: tipo1, Param2: tipo2, Param3: tipo3, Err: TError): boolean;
  2. var Info11: tipo; ... Info32: tipo; // etc...
  3. begin
  4. // 1. Verificar internamente:
  5. Puede1 := VerificarParametroTipo1(Param1, Info11, Info12, ErrInt1);
  6. Puede2 := VerificarParametroTipo2(Param2, Info21, Info22, ErrInt2);
  7. Puede3 := VerificarParametroTipo3(Param3, Info31, Info32, ErrInt3);
  8. result := Puede1 AND Puede2 AND Puede3;
  9. if result
  10. then begin
  11. // Verificaciones para Info's y ver si hay un Err.External = Error5 + Erro6
  12. end
  13. else Err.EInternal := ErrInt1 + ErrInt2 + ErrInt3;
  14. end;

Entonces un VerificarParametroTipo1 sería algo como:


delphi
  1. function VerificarParametroTipo1(Par1: Tipo1; var Info1: tipoInfo1; ... E1: TError): boolean;
  2. begin
  3. result := Asigned(Tipo1);
  4. if NOT result
  5. then E1.Einternal := ERROR_TIPO1;
  6. // ... otras evaluaciones posibles
  7. end;

El error externo no necesita diferenciar si corresponde a uno u otro parámetro. Pero como dije, puede darse el TIPO5, TIPO6 o incluso ambos.

 

¿Como le ven?

 

Saludos,


  • 0

#10 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 29 abril 2015 - 12:00


delphi
  1. De ese modo el código de error podría ir en forma de potencias como estaba pensando para que pueda ser acumulado. Lo que queda por incorporar al diseño es poder diferenciar cual hace a cada parámetro.

 

Hola Delphius, disculpa mi ignorancia, pero me asalta una duda; ¿Cuál es el objetivo de acumular los códigos de error? ¿Acaso el valor obtenido no toca volver a decodificarlo? Dado que en la estructura matricial puedes devolver en detalle el tipo de error, el parámetro, etc, (basta agregar campos al record), incluso de errores en parámetros de  funciones anidadas.

 

Un cordial saludo.


  • 0

#11 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 12:19

Hola Delphius, disculpa mi ignorancia, pero me asalta una duda; ¿Cuál es el objetivo de acumular los códigos de error? ¿Acaso el valor obtenido no toca volver a decodificarlo? Dado que en la estructura matricial puedes devolver en detalle el tipo de error, el parámetro, etc, (basta agregar campos al record), incluso de errores en parámetros de  funciones anidadas.

 

Un cordial saludo.

 

Entiendo que puedo extender el diseño a algo más completo. Incluso hasta hacer una especie de Tabla de doble entrada en donde se marque la casilla en donde se registren errores.

Pero eso ya sugiere un tratamiento dentro de cada función verificar más elaborado.

El que pueda ser a potencias o trabajar a bits incluso, permite que se pueda hacer cosas como sumar o trabajar a nivel boolean sin mayores complicaciones.

 

La solución fácil y barata es directamente sumar todo, como lo tengo actualmente, y que no haya distinción o forma de verificar que parámetro o situación interna/externa se ha presentado.  Como diciendo "Che, mirá tengo toda ese código de error acumulado. Ya no recuerdo cual es cual, encargate vos de que tus patitos estén en fila" Y que las unidades clientes se encarguen de comprobar cual de todas es/son las conflictiva/s a la adivinanza parámetro por parámetro. Con pocos métodos con los que intervenir no hay problema.

Más cuanto son bastantes las operaciones me parece buena idea que al menos la biblioteca tenga una forma de hacerle un poquito más fácil la vida.

 

La última de las posibilidades, y a lo que no quisiera llegar, es directamente disponer de tantas constantes como combinaciones posibles.


  • 0

#12 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 02:06

Al carajo. ¡Que se jodan las unidades clientes! 04.gif  Que se encarguen ellas de averiguar en los casos en que algo mal sale (casos externos y/o internos acumulados). Después de todo ellas

piden, que también den che. Para cuando el error sea unitario la cosa es directa.

Ya llevo casi una semana de análisis, diseño, implementación, y documentación con esta unidad. Entre ayer y hoy tengo el bocho apagado. Agrego 2 constantes nuevas:


delphi
  1. TODO_BIEN = 0;
  2. ERROR_TIPO1 = 1;
  3. ERROR_TIPO2 = 2;
  4. ERROR_TIPO3 = 4;
  5. ERROR_TIPO4 = 8;
  6. ERRORES_INTERNOS = 16;
  7. ERROR_TIPO5 = 32;
  8. ERROR_TIPO6 = 64;
  9. ERRORES_EXTERNOS = 128;

Me aseguro que cuando se trate de 2 o más parámetros y se determine que no se pasa la prueba interna el error sea ERRORES_INTERNOS. Y de forma análoga, que sea ERRORES_EXTERNOS para cuando se me presente el error de tipo 5 y 6 en una evaluación de las variables Info.

 

Documento bien la lista de errores que cada método puede tirar. Y ya que quede a cargo de cada cliente en buscar el modo de hacerse fácil la vida.

 

Ya se verá cuando en los próximos días deba explotar esta unidad en mis proyectos... controlar cada caso bien tranquilo. Vamos a instalarle el disco Zen a NewDelphius por las dudas... y si es que se deja.

 

Les agradezco sus propuestas. Las voy a considerar por si es necesario hacer una reingeniería.

 

Saludos,


  • 0

#13 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 29 abril 2015 - 04:46

Veo correcto el tratamiento de errores en código binario, como ya has apuntado. Un DWORD (Cardinal) puede ser usado como pensaste, Los 16 bits mas significativos para hacer referencia a la variable que causa el error (16 variables) y los menos significativos para el error (16 errores posibles) Si precisas de mayos amplitud puede unas un int64.

 

El operador binario or acumularía los errores y para extraerlos (interpretar el DWORD) sólo tendrías que realizar un and entre un valor obtenido de error y el valor a testar, encontrando el tipo de error y la variable que lo causa. Es un modo muy habitual de trabajar a bajo nivel y economizando variables de error:


php
  1. ERROR and (codigo_variable or tipo_error)

Saludos.


  • 1

#14 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 29 abril 2015 - 06:01

Veo correcto el tratamiento de errores en código binario, como ya has apuntado. Un DWORD (Cardinal) puede ser usado como pensaste, Los 16 bits mas significativos para hacer referencia a la variable que causa el error (16 variables) y los menos significativos para el error (16 errores posibles) Si precisas de mayos amplitud puede unas un int64.

 

El operador binario or acumularía los errores y para extraerlos (interpretar el DWORD) sólo tendrías que realizar un and entre un valor obtenido de error y el valor a testar, encontrando el tipo de error y la variable que lo causa. Es un modo muy habitual de trabajar a bajo nivel y economizando variables de error:


php
  1. ERROR and (codigo_variable or tipo_error)

Saludos.

 

¿Te refieres al listado de constante y valores del primer post en valores consecutivos? ¿O este último?

Porque este último tiene la forma 2^Nro. Y no creo que fuera tan posible ir sumándole los errores así tan simple. Fíjate que para el caso de un método Operar que recibe 3 parámetros, se puede llegar a tener error1 + error2 + error3. Supongamos que para el parámetro1 y el parámetro3 se detectó el TIPO2 (que vale 2) y que en parametro2 se ha detectado TIPO3 (que vale 4). La suma de estos errores da justamente 2 + 2 + 4 = TIPO4 = 8. De esta forma se ha "pisado" una constante de error y no será posible determinar si tuvo lugar un TIPO4 o bien el TIPO3 + 2 TIPO2.

 

He descubierto que para efectuar estos tipos de sumas acumuladas se necesita emplear una base mayor que la de parámetros se necesita. Para este caso como los parámetros no exceden de 3, la base debe ser 4 y allí si se puede generar los valores para las constantes:

 

TODO_BIEN = 0;

ERROR_TIPO1 = 1;

ERROR_TIPO2 = 4;

ERROR_TIPO3 = 16;

...

 

De esa forma aún sumando los 3 errores internos no se pisa el valor de otro error.

 

Recién acabo de terminar de aplicar los cambios que les comenté antes.

 

Saludos,


  • 0

#15 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 30 abril 2015 - 02:53

¿Te refieres al listado de constante y valores del primer post en valores consecutivos? ¿O este último?
Porque este último tiene la forma 2^Nro.


Me refiero al tratamiento binario puro, potencias enteras de 2
 

...no creo que fuera tan posible ir sumándole los errores así tan simple. Fíjate que para el caso de un método Operar que recibe 3 parámetros, se puede llegar a tener error1 + error2 + error3. Supongamos que para el parámetro1 y el parámetro3 se detectó el TIPO2 (que vale 2) y que en parametro2 se ha detectado TIPO3 (que vale 4). La suma de estos errores da justamente 2 + 2 + 4 = TIPO4 = 8. De esta forma se ha "pisado" una constante de error y no será posible determinar si tuvo lugar un TIPO4 o bien el TIPO3 + 2 TIPO2.


El problema que encuentras es que en realidad no es una suma sin o una operación or binaria.
En tu ejemplo tenemos:


php
  1. 2 or 2 or 4 = 6 => 0000 0110 b

El bit menos significativo es el error tipo1, el siguiente es el 2 y así... Potencias de 2.

Para extraer el error usarás un operador and: ejemplo, saber si el error contiene el tipo 2
 


php
  1. Error and 2:
  2. 0000 0110 and 0000 0010 = 0000 0010 => 2

Si el resultado fuese cero, quiere decir que no contiene el error tipo 2

Como ves, los errores sólo se pisan si confundimos el operador + con el or

 

Lo más complejo es asociar el error con su parámetro. Dado que son tres parámetros, lo sencillo es usar un tipo de datos de tres BYTES (8bits x 3)  cada byte correspondería al error de un parámetro. La suma de errores (or de los tres bytes) te da el error global.

 

Tres bytes los consigues en un DWORD (4 bytes) pero te obliga a operar con desplazamientos de bits para acceder a cada parámetro. Una solución más fácil de entender es una estructura de tres bytes, un error acumulado por cada parámetro.

 

Tu decides como hacerlo, solo quiero mostrarte que es posible y no complejo de implementar.

 

 

Saludos.


  • 1

#16 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 30 abril 2015 - 07:58

Me refiero al tratamiento binario puro, potencias enteras de 2
 


El problema que encuentras es que en realizad no es una suma sin o una operación or binaria.
En tu ejemplo tenemos:


php
  1. 2 or 2 or 4 = 6 => 0000 0110 b

El bit menos significativo ees el error tipo1, el siguiente es el 2 y así... Potencias de 2.

Para extraer el error usarás un operador and: ejemplo, saber si el error contiene el tipo 2
 


php
  1. Error and 2:
  2. 0000 0110 and 0000 0010 = 0000 0010 => 2

Si el resultado fuese cero, quiere decir que no contiene el error tipo 2

Como ves, los errores sólo se pisan si confundimos el operador + con el or

 

Lo más complejo es asociar el error con su parámetro. Dado que son tres parámetros, lo sencillo es usar un tipo de datos de tres BYTES (8bits x 3)  cada byte correspondería al error de un parámetro. La suma de errores (or de los tres bytes) te da el error global.

 

Tres bytes los consigues en un DWORD (4 bytes) pero te obliga a operar con desplazamientos de bits para acceder a cada parámetro. Una solución más fácil de entender es una estructura de tres bytes, un error acumulado por cada parámetro.

 

Tu decides como hacerlo, solo quiero mostrarte que es posible y no complejo de implementar.

 

 

Saludos.

 

Gracias por la aclaración amigo. Ya veo donde estaba metiendo la pata.

 

Ya veré, en base a mis experiencias de uso que tenga con esta biblioteca si la dejo como está o implemento tus ideas.

Por ahora necesito ir avanzando en otras unidades.

 

Saludos,


  • 0





Etiquetado también con una o más de estas palabras: constantes, error

IP.Board spam blocked by CleanTalk.