Biblioteca de clases genéricas - errores, descripción, preguntas, características de uso y sugerencias - página 20

 
Sergey Dzyublik:

1. Eliminar los comportamientos ambiguos:
Si pasamos "INT_MAX - 10" como parámetro a CPrimeGenerator::ExpandPrime, se devolverá el resultado "INT_MAX".
Si pasamos "INT_MAX - 10" como parámetro a CPrimeGenerator::GetPrime, se devolverá el mismo resultado: "INT_MAX - 10".

En ambos casos, el valor devuelto no es un número primo, lo que induce a error al usuario.

Sobre el primer punto:

Aquí no hay ambigüedad.

El método GetPrime debería devolver el número primo más cercano de arriba, pero en el intervalo de INT_MAX - 10 a INT_MAX no hay ninguno, por lo que se devuelve INT_MAX - 10.

El método ExpandPrime duplica primero el valor de entrada y se llama al método GetPrime a partir del número recibido.

Además, ExpandPrime tiene una comprobación para el rebasamiento de INT_MAX:

   if((uint)new_size>INT_MAX && INT_MAX>old_size)
      return INT_MAX;
   else
      return GetPrime(new_size);

En mi opinión, la lógica del comportamiento de estos métodos es absolutamente inequívoca y correcta.


En cuanto al segundo y tercer punto:

Los cambios que sugieres sólo son relevantes en su mayoría para problemas marginales, cuando los tamaños de CHashMap son muy grandes. Sin embargo, no hay garantía de que tengan un impacto positivo en el rendimiento, por lo que hay que hacer estudios separados para determinar la corrección de los cambios que sugiere.

 
Roman Konopelko:

Aquí no hay ambigüedad.
El método GetPrime debería devolver el número primo más cercano de arriba, pero no hay ninguno entre INT_MAX - 10 e INT_MAX, por lo que se devuelve INT_MAX - 10.
El método ExpandPrime duplica primero el valor de entrada y se llama al método GetPrime a partir del número recibido.
Además, ExpandPrime tiene una comprobación para el rebasamiento de INT_MAX:
La lógica del comportamiento de estos métodos es absolutamente inequívoca y correcta.


1. Las funciones pueden devolver números desconocidos en lugar de números primos.
La forma en que el usuario utilice estos datos es su problema, tal vez los arroje al largo y los pase a las funciones de supercomputación, a quién le importa.
El hecho es que podemos devolver algo diferente de lo que se declara y se espera de las funciones por defecto.

2. ¿Cómo podemos comprobar que la llamada a la función ha devuelto un número primo y no otra cosa?
No se puede comparar simplemente con INT_MAX.
Debe compararlo con el último número primo disponible menor que INT_MAX.
Cada vez que se compara el resultado de las llamadas de estas funciones con algún número mágico para asegurarse de que todo está bien, me parece absurdo.

 
Sergey Dzyublik:

1. Las funciones pueden no devolver números primos, sino números oscuros.
La forma en que el usuario utilice estos datos es su problema, tal vez los convierta en long y luego los pase a funciones de supercomputación, a quién le importa.
El hecho es que podemos devolver algo diferente de lo que se declara y se espera de las funciones por defecto.

2. ¿Cómo podemos comprobar que la llamada a la función ha devuelto un número primo y no otra cosa?
No se puede comparar simplemente con INT_MAX.
Debe compararlo con el último número primo disponible menor que INT_MAX.
Comparar el resultado de cada llamada de estas funciones con algún número mágico cada vez para asegurarse de que todo es correcto, me parece absurdo.

1. Tu caso de obtener un número no simple usando el método GetPrime es el único que he encontrado hasta ahora. Esta incidencia se solucionará cambiando la comprobación al generar números primos:

//--- outside of our predefined table
   for(int i=(min|1); i<=INT_MAX; i+=2)
     {
      if(IsPrime(i) && ((i-1)%s_hash_prime!=0))
         return(i);
     }
   return(min);

2. El método CPrimeGenerator::IsPrime se utiliza para comprobar el número por simplicidad

 

Traté de cambiar de mi ArrayList a la tuya, que está en Generic/ArrayList.mqh

ME no da nada después de ".".

¿Cómo se obtiene el valor? Faltan Get() y [] en la clase.

Y no tiene en cuenta que puede haber un array de punteros.

¿Y quién crea esta biblioteca?

Aquí está mi versión de ArrayList de Java:

Archivos adjuntos:
ArrayList.mqh  46 kb
 
No había plantillas de clases cuando creé esta variante.
 
Roman Konopelko:

Para que las colecciones genéricas funcionen correctamente con objetos de clase, estas clases deben implementar la interfaz IEqualityComparable en la que se definen los métodos Equals y HashCode. Es decir, el usuario tiene que establecer los métodos de cálculo de los códigos hash y esta es la única opción hasta ahora, ya que es imposible implementar estos métodos de forma automática, como se hacía en .Net, por ejemplo, mediante MQL5.

Entonces, ¿por qué su plantilla funciona con cualquier tipo, engañando al programador? Si sólo las clases heredadas de IEqualityComparable funcionan correctamente, entonces deberíamos deshabilitar el trabajo con otros tipos a nivel de compilador.

Permítame recordarle este código:

//+------------------------------------------------------------------+
//| Returns a hashcode for custom object.                            |
//+------------------------------------------------------------------+
template<typename T>
int GetHashCode(T value)
  {
//--- try to convert to equality comparable object  
   IEqualityComparable<T>*equtable=dynamic_cast<IEqualityComparable<T>*>(value);
   if(equtable)
     {
      //--- calculate hash by specied method   
      return equtable.HashCode();
     }
   else
     {
      //--- calculate hash from name of object
      return GetHashCode(typename(value));
     }
  }

Creo que esta función debería ser sustituida por esta otra:

template<typename  T>
int GetHashCode(IEqualityComparable<T> &value)
  {
    return value.HashCode()
  }
 
Alexey Navoykov:

Entonces, ¿por qué su plantilla funciona con cualquier tipo, engañando al programador? Si sólo las clases heredadas de IEqualityComparable funcionan correctamente, entonces debería desautorizar el trabajo con otros tipos a nivel de compilador.

Será un inconveniente trabajar con este tipo. Las sobrecargas de GetHashCode para los tipos estándar muestran la interfaz de obtención del código hash.


Lo que molesta es su ausencia.

template<typename T>
interface IEqualityComparable
  {
//--- method for determining equality
   bool              Equals(T & value);
//--- method to calculate hash code   
   int               HashCode(void);
  };


Es decir, para los objetos de la basura ahora.

 
fxsaber:

Esto sería incómodo para trabajar. Las sobrecargas de GetHashCode para los tipos estándar muestran la interfaz para obtener el código hash.

¿Y qué es lo conveniente ahora? El hecho de que al pasar un enum o puntero de una clase que no soporta la interfaz a esta función, sólo se obtiene el nombre de la clase? ) Y lo más importante, el código funciona y compila como si todo fuera normal.

 
Alexey Navoykov:

¿Cuál es la conveniencia ahora? ¿Que al pasar un enum o puntero de una clase que no soporta la interfaz en esta función, sólo se obtiene el nombre de la clase? Impresionante hash ) Y lo más importante, el código funciona, compila como si todo fuera normal, lo cual no es el caso.

Sí, hicieron una basura. Copiaron y pegaron irreflexivamente de NetFramework cuando es obvio que sin soporte para interfaces a nivel de lenguaje no puede funcionar adecuadamente. Recuerdo el nivel de los códigos MQ hace 6-7 años y ahora es una basura comparado con aquella época.

 
Alexey Navoykov:

¿Qué es lo conveniente ahora? El hecho de que al pasar un enum o un puntero de una clase que no soporta la interfaz en esta función, sólo se obtiene el nombre de la clase? Bonito hash ) Y lo más importante, el código funciona y compila como si todo estuviera bien, lo cual no es el caso.

Estoy de acuerdo, es mejor obtener un error de compilación de inmediato que lidiar con el largo problema de por qué no funciona.

Para ser honesto, ni siquiera veo por qué han metido una interfaz allí. Al fin y al cabo, sólo hay que sobrecargar GetHashCode para el tipo requerido y no empezar a crear IEqualityComparable.