Ir al contenido


Foto

Combinar genéricos y arrays dinámicos

genéricos arrays dinámicos

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

#1 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 12:39

Hola a todos,

 

Me encuentro con una duda de diseño, y que no me convence del todo... Necesito trabajar con estructuras dinámicas, de diferentes tipos.

 

Todos conocemos el esquema:

 

TMiEstructura = array of tipo;

TMiEstructura2 = array of array of tipo;

...

 

tipo´puede ser integer, double, TComplex, TLoQueSea...

 

Inicialmente lo estaba entendiendo como una clase abstracta que me permitiera definir lo básico, con algunos métodos virtuales y/o abstractos para que las clases que hereden de esta pudiera aprovechar. Por darle un nombre digamos TArray.

De ésta pensaba heredar una TMatrix, para llevarlo al plano de 2 dimensiones. Esta clase se encarga de hacer el trabajo de mantener la estructura, de dimensionarla, ofrece propiedades para saber la cantidad de filas y columnas, y obviamente una propiedad (quizá doble vectorial... si es que el compilador no se queja) para poder acceder a la "data" matricial.

 

Y aquí me puse a pensar ¿Y como le hago para meterle los tipos? No quisiera estar generando TIntegerMatrix, TDoubleMatrix, TLoQueSea... En cierta forma, independiente del tipo el "cuerpo" de éstas especializaciones es el mismo: lo que cambia es el tipo, asi que... me puse a pensar, ¿Se podría usar el poder de los genéricos?

 

Es decir, ¿es posible combinar arrays dinámicos que acepten integer, double, TComplex, TLoQueVenga....? ¿Hasta donde se puede llegar? ¿El poder y gracia de los genéricos es que uno no necesita estar generando clases y decirle al compilador usame la clase X con el tipo Y? ¿Voy entendiendo bien?

¿Hasta donde llega el poder de los genéricos? ¿Es sólo con tipos de datos simples? ¿O puede aceptar un tipo record/clase?

 

No estoy encontrando material de referencia como para sacarme estas dudas.

 

¿Y si yo ahora, necesito definir otra clase más, una T3DArray que se especialice en 3 dimensiones? Como ven, tengo una combinaciones interesantes de dimensiones y tipos y la verdad se me está comiendo un poco la cabeza.

 

¿Que alternativas y/o propuestas imaginan ustedes?

 

Saludos,


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 01:40

Desde luego que se puede: cualquier tipo que puedas declarar, puede ser utilizado para instanciar un genérico: primitivos, clases, interfaces, meta clases, récords, punteros, métodos anónimos, etc
 
En tu caso si no entendí mal querés hacer esto:
 

delphi
  1. type
  2. TArray<T> = array of T; // array dinámico genérico
  3. TMatrix<T> = array of TArray<T>; // array dinámico genérico

Los array dinámicos los manipulas usando la sintaxis y métodos que ya conoces (corchetes e índice, SetLength).

 

De hecho las implementaciones de lista de T simplemente envuelven un array dinámico genérico, lo van agendando o achicando según sea necesario, entre otras cosas

 

En definitiva esos tipos de arriba sería el tipo de las variables internas de las clases de alto nivel que permiten manipularlos. No podes agregar métodos a un array of T, porque no es una clase.

 

Volviendo al ejemplo de la lista, en ese caso tendrías esto:


delphi
  1. type
  2. TList<T> = class
  3. private
  4. FData: TArray<T>;
  5. public
  6. procedure Add(const Value: T);
  7. function Count: Integer;
  8. end;

La idea es que la clase lista administre un arreglo dinámico para que pueda ser usado como lista


  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 28 enero 2017 - 08:07

Es bastante similar a los Templates de C++ con los que haces funciones con tipos genéricos y clases genéricas independientes de tipo.

 

Saludos.


  • 0

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 10:31

 

Desde luego que se puede: cualquier tipo que puedas declarar, puede ser utilizado para instanciar un genérico: primitivos, clases, interfaces, meta clases, récords, punteros, métodos anónimos, etc
 
En tu caso si no entendí mal querés hacer esto:
 

delphi
  1. type
  2. TArray<T> = array of T; // array dinámico genérico
  3. TMatrix<T> = array of TArray<T>; // array dinámico genérico

Los array dinámicos los manipulas usando la sintaxis y métodos que ya conoces (corchetes e índice, SetLength).

 

De hecho las implementaciones de lista de T simplemente envuelven un array dinámico genérico, lo van agendando o achicando según sea necesario, entre otras cosas

 

En definitiva esos tipos de arriba sería el tipo de las variables internas de las clases de alto nivel que permiten manipularlos. No podes agregar métodos a un array of T, porque no es una clase.

 

Volviendo al ejemplo de la lista, en ese caso tendrías esto:


delphi
  1. type
  2. TList<T> = class
  3. private
  4. FData: TArray<T>;
  5. public
  6. procedure Add(const Value: T);
  7. function Count: Integer;
  8. end;

La idea es que la clase lista administre un arreglo dinámico para que pueda ser usado como lista

 

 

Creo que te voy entendiendo. Una vez definidos mis arrays dinámicos genéricos, defino las clases para sus respectivas dimensiones: Vector -> 1, Matriz -> 2, etc.

Lo que me gustaría probar es si era posible una propiedad vectorial de doble índice. No recuerdo bien si admite eso.

 

Es bastante similar a los Templates de C++ con los que haces funciones con tipos genéricos y clases genéricas independientes de tipo.

 

Saludos.

 

De hecho el concepto de genéricos proviene de los templates de C++ amigo. Fue la propuesta de la comunidad Object Pascal para dar una solución similar a ellos.

 

Saludos,


  • 0

#5 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 10:43

Si, las array property pueden ser multidimensionales

http://www.freepasca...x87-1090006.6.3
  • 0

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 28 enero 2017 - 11:23

Lo ideal sería poder sobrecargar el operador [] como en C++ pero creo que Lazarus no puede hacerlo, así que tendrás que simularlo con funciones y propiedades como te indica Agustin Ortu.

 

 

Saludos.


  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 12:01

Lo ideal sería poder sobrecargar el operador [] como en C++ pero creo que Lazarus no puede hacerlo, así que tendrás que simularlo con funciones y propiedades como te indica Agustin Ortu.

 

 

Saludos.

 

No me molesta tener que hacerlo por la vía de funciones.

Es más justo así lo estaba pensando. Voy a estar jugando un rato a ver que me sale y si me convence la idea.

Pensé en un momento en no encararlo a este diseño por el lado de las clases y el uso de genéricos. En realidad, primero pensé en usar registros avanzados, y me estaba tentando la idea de hacer sobrecarga de operadores. De ese modo podría hacer un Matrix1 + Matrix2 por ejemplo. Pero como hay ciertas limitaciones en el uso de registros avanzados (como la herencia), para algunas cosas tendría que estar duplicando código y no me estaba convenciendo.

Aún me tienta un poco en probar la sobrecarga de operadores. Para algunos tipos que tengo planeado incorporar va a ser necesario implementarla.

De lo que estoy leyendo de algunos resultado de consulta sobre generics, hay dos formas de hacerlo, según si está definido o no FPC. Acá un ejemplo que encontré en un hilo de PGD:


delphi
  1. type
  2. {$ifdef FPC}
  3. generic TGenericType<T> = class
  4. {$else}
  5. TGenericType<T> = class
  6. {$endif}
  7. function Test(AArg: T): T;
  8. end;
  9.  
  10. TSomeGeneric = {$ifdef FPC}specialize {$endif}TGenericType<longint>;
  11.  
  12. implementation
  13.  
  14. function TGenericType.Test(AArg: T): T;
  15. begin
  16. result := T*2;
  17. end;

Aunque la doc oficial, expone el tema únicamente basado en FPC. Es decir se debe usar la palabra reservada generic y specialize para sus declaraciones.

Saludos,


  • 0

#8 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 12:47

Exacto una sintaxis es propia de FPC (con más ceremonia a mí gusto, es decir, más "verbose"con eso del specialize y el generic; la otra busca ser compatible con Delphi

Creo que en algún punto te va a resultar muy útil incorporar colecciones genéricas: https://github.com/d...ics.collections

Estoy seguro haber leído en los foros de Lazarus que se estaba discutiendo de incluir esa misma biblioteca. Alguna distro, sino CodeTyphon, ya lo han hecho. Creo que ese mismo tipo tiene un fork de Lazarus o CT, es decir, solo el IDE

Lo cierto es que explorar código que usa y sobretodo abusa genéricos es muy interesante. A veces tienen ciertas limitaciones, algunas impuestas por diseño (varianza, covarianza), bugs, porque los genéricos han costado mucho trabajo en Delphi (de hecho aún tienen varios cabos sueltos), así que espero lo mismo de FPC

No te quiero desanimar ni mucho menos! Creo que para poder que tenés planeado hacer, el uso de genéricos es obligado. El peor de los costos que podes pagar es mantener 2 o 3 clases vs N clases sino usas genéricos

Por cierto acá hablan de arreglos de dos dimensiones, hace casi medio año

https://github.com/d...ctions/issues/3

No sé qué tanto habrá avanzado el compilador desde entonces
  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 01:35

Exacto una sintaxis es propia de FPC (con más ceremonia a mí gusto, es decir, más "verbose"con eso del specialize y el generic; la otra busca ser compatible con Delphi

Creo que en algún punto te va a resultar muy útil incorporar colecciones genéricas: https://github.com/d...ics.collections

Estoy seguro haber leído en los foros de Lazarus que se estaba discutiendo de incluir esa misma biblioteca. Alguna distro, sino CodeTyphon, ya lo han hecho. Creo que ese mismo tipo tiene un fork de Lazarus o CT, es decir, solo el IDE

Lo cierto es que explorar código que usa y sobretodo abusa genéricos es muy interesante. A veces tienen ciertas limitaciones, algunas impuestas por diseño (varianza, covarianza), bugs, porque los genéricos han costado mucho trabajo en Delphi (de hecho aún tienen varios cabos sueltos), así que espero lo mismo de FPC

No te quiero desanimar ni mucho menos! Creo que para poder que tenés planeado hacer, el uso de genéricos es obligado. El peor de los costos que podes pagar es mantener 2 o 3 clases vs N clases sino usas genéricos

Por cierto acá hablan de arreglos de dos dimensiones, hace casi medio año

https://github.com/d...ctions/issues/3

No sé qué tanto habrá avanzado el compilador desde entonces

 

En realidad FPC y Lazarus ya vienen con su "juego" de colecciones, generics, etc. Aquí hay una lista (aunque posiblemente no completa) de lo que se tiene hasta ahora, tanto a nivel RTL, FPC, FCL, Lazarus y de 3ros.

 

Seguramente tendré que ver en algún punto el tema de colecciones.

El hilo al que te refieres posiblemente es éste.

 

Eso de los bugs, y que todavía no está del todo afinado el tema tanto en Delphi como en Lazarus es lo que me da un poco de miedo. En parte es lo que me a mi en lo personal me tiene un tanto a la defensiva. Mi biblioteca ha estado avanzando, y he estado un tanto preocupado por la enorme cantida de duplicidad de código debido a su diseño a lo "old school" y con mucha sobrecarga para ir trabajando con los tipos a medida que me surjen más operaciones a implementar.

Esto me lleva a pensar a que de seguir ese ritmo pasaré más tiempo implementando versiones sobrecargadas para tipos y no tanto en avanzar en cuestiones más importantes. Y es que llego a pensar algo más centrado en genéricos.

 

El tema tiene su potencial, aunque para alguien muy de la "vieja escuela" puede resultarle complicado abstraerse a este nuevo nivel.

 

Saludos,


  • 0

#10 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 01:44

El siguiente codigo compila lo mas bien en FPC, usando {$MODE Delphi}
 


delphi
  1. type
  2. TArray<T> = array of T;
  3.  
  4. Matrix<T> = array of TArray<T>;
  5.  
  6. TMatrix<T> = class
  7. private type
  8. // no soportado en FPC, preferia "esconder" el tipo Matrix
  9. // Matrix<T> = array of TArray<T>;
  10. private
  11. FData: Matrix<T>;
  12. function GetItem(const X, Y: Integer): T;
  13. procedure SetItem(const X, Y: Integer; Value: T);
  14. public
  15. constructor Create(const Capacity: Integer);
  16. destructor Destroy; override;
  17. property Items[const X, Y: Integer]: T read GetItem write SetItem; default;
  18. end;

Y ya con escribir esta simple clase me doy cuenta de los "problemillas" que tiene Lazarus con respecto a genericos. Son caracteristico de los problemas de los genericos que no son "graves" en el sentido de que te impiden continuar el desarrollo. La palabra para describirlo es "tocacoj...". Por ejemplo:

 

La linea que esta comentada: No puedo declarar un tipo generico adentro de otro generico

 

Solucion (si quiero esconder la declaracion de Matrix<T>): Declarar el tipo como protegido en una clase abstracta no generica y heredar TMatrix<T> de esa clase:


delphi
  1. type
  2. TArray<T> = array of T;
  3.  
  4. TMatrix = class abstract
  5. protected type
  6. Matrix<T> = array of TArray<T>;
  7. end;
  8.  
  9. TMatrix<T> = class(TMatrix)
  10. private
  11. FData: Matrix<T>;
  12. function GetItem(const X, Y: Integer): T;
  13. procedure SetItem(const X, Y: Integer; Value: T);
  14. public
  15. constructor Create(const Capacity: Integer);
  16. destructor Destroy; override;
  17. property Items[const X, Y: Integer]: T read GetItem write SetItem; default;
  18. end;

Ahora, problema numero dos. Al hacer esto, el class completion (control + shift + c) da error de "ciclo detectado". Si elimino el ancestro el class completion hace su trabajo (a medias, ver problema tres). Osea que es el parche del parche, tengo que andar quitando o poniendo el ancestro para que el class completion funcione

 

Problema tres: El class completion implementa mal los metodos. La forma facil de describirlo, para la clase anterior, implementa el constructor asi:


delphi
  1. constructor TMatrix.Create(const Capacity: Integer);
  2. begin
  3.  
  4. end;

Osea, se olvido del <T>. Deberia ser: 


delphi
  1. constructor TMatrix<T>.Create(const Capacity: Integer);
  2. begin
  3.  
  4. end;

Hay que agregar el <T> a mano en todos los metodos! Un embole!

 

Y no he probado las herramientas de refactoring. Seguro que algun problema hay! Delphi de hecho los tiene

 

Pero como ves, si bien son cosas que molestan, no te impiden trabajar. Que es tedioso, si. Los bugs mas graves lo que te impiden es escribir el codigo mas limpio o "realmente generico" 


  • 0

#11 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 01:56

El siguiente codigo compila lo mas bien en FPC, usando {$MODE Delphi}
 


delphi
  1. type
  2. TArray<T> = array of T;
  3.  
  4. Matrix<T> = array of TArray<T>;
  5.  
  6. TMatrix<T> = class
  7. private type
  8. // no soportado en FPC, preferia "esconder" el tipo Matrix
  9. // Matrix<T> = array of TArray<T>;
  10. private
  11. FData: Matrix<T>;
  12. function GetItem(const X, Y: Integer): T;
  13. procedure SetItem(const X, Y: Integer; Value: T);
  14. public
  15. constructor Create(const Capacity: Integer);
  16. destructor Destroy; override;
  17. property Items[const X, Y: Integer]: T read GetItem write SetItem; default;
  18. end;

Y ya con escribir esta simple clase me doy cuenta de los "problemillas" que tiene Lazarus con respecto a genericos. Son caracteristico de los problemas de los genericos que no son "graves" en el sentido de que te impiden continuar el desarrollo. La palabra para describirlo es "tocacoj...". Por ejemplo:

 

La linea que esta comentada: No puedo declarar un tipo generico adentro de otro generico

 

Solucion (si quiero esconder la declaracion de Matrix<T>): Declarar el tipo como protegido en una clase abstracta no generica y heredar TMatrix<T> de esa clase:


delphi
  1. type
  2. TArray<T> = array of T;
  3.  
  4. TMatrix = class abstract
  5. protected type
  6. Matrix<T> = array of TArray<T>;
  7. end;
  8.  
  9. TMatrix<T> = class(TMatrix)
  10. private
  11. FData: Matrix<T>;
  12. function GetItem(const X, Y: Integer): T;
  13. procedure SetItem(const X, Y: Integer; Value: T);
  14. public
  15. constructor Create(const Capacity: Integer);
  16. destructor Destroy; override;
  17. property Items[const X, Y: Integer]: T read GetItem write SetItem; default;
  18. end;

Ahora, problema numero dos. Al hacer esto, el class completion (control + shift + c) da error de "ciclo detectado". Si elimino el ancestro el class completion hace su trabajo (a medias, ver problema tres). Osea que es el parche del parche, tengo que andar quitando o poniendo el ancestro para que el class completion funcione

 

Problema tres: El class completion implementa mal los metodos. La forma facil de describirlo, para la clase anterior, implementa el constructor asi:


delphi
  1. constructor TMatrix.Create(const Capacity: Integer);
  2. begin
  3.  
  4. end;

Osea, se olvido del <T>. Deberia ser: 


delphi
  1. constructor TMatrix<T>.Create(const Capacity: Integer);
  2. begin
  3.  
  4. end;

Hay que agregar el <T> a mano en todos los metodos! Un embole!

 

Y no he probado las herramientas de refactoring. Seguro que algun problema hay! Delphi de hecho los tiene

 

Pero como ves, si bien son cosas que molestan, no te impiden trabajar. Que es tedioso, si. Los bugs mas graves lo que te impiden es escribir el codigo mas limpio o "realmente generico" 

 

Pues si... son piedras que te frenan.  Ya estuve viendo un poco la biblioteca que pusiste en el enlace y está plagada de comentarios sobre bugs...

Yo voy a probar en el modo objfpc que es por defecto con el que trabajo. Seguro que encuentro otras cosillas con que lidiar.

Te agradezco la ayuda.

 

Saludos,


  • 0

#12 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 02:39

Por cierto, esta bueno tener en la cabeza un par de conceptos relacionados con los genericos (mejor de antemano.. no? :D)
 
Uno es varianza:


delphi
  1. type
  2. TPersona = class
  3. end;
  4.  
  5. TEmpleado = class(TPersona)
  6. end;
  7.  
  8. TGerente = class(TEmpleado)
  9. end;
  10.  
  11. var
  12. Personas: TList<TPersona>;
  13. Empleados: TList<TEmpleados>;
  14. Gerentes: TList<TGerente>;
  15. begin
  16. Personas := CrearListaPersonas; // devuelve una TList<TPersona> con algunos objetos TPersona..
  17. Empleados := Personas; // no compila, aunque los "Empleados" sean "Personas"
  18. Gerentes := Personas; // no compila, aunque los gerentes sean "Empleados" que son "Personas"
  19. Empleados := Gerentes; // no compila, y eso que los "Gerentes" son "Empleados"
  20. Gerentes := Empleados; // no, tampoco :)
  21. end;

Este articulo, en ingles y enfocado a Delphi, explica porque. En realidad no es ninguna locura, ya que en teoria "si se puede castear de forma segura un TEmpleado a TPersona, cual es el problema con las listas". Y todo toma sentido cuando uno se da cuenta de que existe la clase TJefe que es subclase de TPersona pero no de TEmpleado.. osea que al castear la lista de Personas a Empleados podria haber algun objeto que es de otra rama de TPersona
 
http://delphisorcery...d-variance.html
 
 
Otro detalle: lo mismo que haber enriquecido la RTTI o la posibilidad de compilar codigo en linea (inline) incremento el tamaño de los ejecutables, los genericos tambien sufren del mismo problema. Si para vos el tamaño de los ejecutables es importante (mantenerlo bajo) los genericos de pronto no son tan amigos
 
http://delphisorcery...e-annoying.html
 
A mi me encanta usar interfaces (creo que a vos no tanto :)) y si hay algo que me molesta es que las interfaces no pueden tener metodos genericos:


delphi
  1. type
  2. IFoo = interface
  3. procedure Blabla<T>(const Value: T); // no compila
  4. end;
  5.  
  6. IFoo<T> = interface
  7. procedure Blabla(const Value: T); // esto si compila bien
  8. end;

 
Los metodos genericos son los que en su firma se declaran como genericos. Incluso podes tener un metodo generico en una clase no generica:
 


delphi
  1. type
  2. TNoGenerica = class
  3. public
  4. procedure Procesar<T>(const Value: T);
  5. end;

Los record si pueden tener metodos genericos, por ejemplo, yo tengo este record definido:


delphi
  1. type
  2. /// <summary> Factory para crear enumerables nulos (enumerables vacios) </summary>
  3. Enumerable = record
  4. public
  5. /// <summary> Devuelve un enumerable nulo (vacio) para un determinado tipo generico </summary>
  6. class function Empty<T>: IEnumerable<T>; static;
  7. end;

Otro detalle con las interfaces es el GUID. Las interfaces genericas no deben llevar GUID. Esto es porque al "instanciar" IFoo<T> como IFoo<string> y como IFoo<TObject> ambas llevan el mismo GUID! Los cual las hace "compatibles"! Ya te imaginaras los quilombos que se pueden armar cuando un Supports() o un QueryInterface devuelven "todo ok"  
 
Tampoco podes escribir ayudantes (helpers) para genericos
 
Y por ultimo, a veces el compilador simplemente se rehusa a "leer" tu codigo y retorna algo como "Internal Error W4234-ASD3423". Simplemente lo enloqueciste, ni siquiera es capaz de decirte donde esta el error, tenes que reescribir parte del codigo de otra manera "para ver si lo entiende"

 

En muchos casos igualmente el compilador si que se expresa bien, pero te puede obligar a cambiar tu diseño:


delphi
  1. type
  2. TFoo<T> = class
  3. public
  4. procedure Process(const Value: T); virtual; // todo bien
  5. end;
  6.  
  7. TBar = class
  8. public
  9. procedure Process<T>(const Value: T); virtual; // no compila
  10. // E2533 Virtual, dynamic and message methods cannot have type parameters
  11. end; 

 
Por supuesto que cuando te empezas a topar con este tipo de cosas es cuando estas escribiendo codigo muy generico, muy abstracto (ya pensando en frameworks o grandes bibliotecas) y no un simple contenedor de cosas; para eso estas sobrado
 
Simplemente es un aviso por si le llegas a agarrar el gustito y te agarra el ataque de refactorizar toda tu biblioteca para usar genericos.


Editado por Agustin Ortu, 28 enero 2017 - 02:49 .

  • 2

#13 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 28 enero 2017 - 03:00

Y pensar que hay gente que odia precisamente C/C++ por las macros, Templates y sobrecarga de operadores... Y ahora delphi vira a las características innatas de C++, pero lleno de piedras por el camino... *-)

 

No me malinterpretéis, es que C++ no es tan malo como algunos lo pintan.  :)

 

 

Saludos.


  • 1

#14 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 03:24

Se ve que tu tienes alguna relación amor/odio con los genéricos después de todo :D

 

Es cierto que me faltan algunos conceptos relacionados con el tema. De a poco le voy agarrando la mano... No digo el gusto porque todavía una parte de mi cabeza me dice que estos genericos ornitorrincosos desafían algunos conceptos OO.

 

Saludos,


  • 1

#15 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 28 enero 2017 - 03:27

Y pensar que hay gente que odia precisamente C/C++ por las macros, Templates y sobrecarga de operadores... Y ahora delphi vira a las características innatas de C++, pero lleno de piedras por el camino... *-)

 

No me malinterpretéis, es que C++ no es tan malo como algunos lo pintan.  :)

 

 

Saludos.

 

Ssshhhhh, que no queremos que los demás desarrolladores de C/C++  se den cuenta de que en secreto siempre les hemos envidiado sus tringulitis crípticas. :D

 

Saludos,


  • 1

#16 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 28 enero 2017 - 03:33

Ssshhhhh, que no queremos que los demás desarrolladores de C/C++  se den cuenta de que en secreto siempre les hemos envidiado sus tringulitis crípticas. :D

 
:D :D :D :D

 

En realidad estos temas añaden un poco de ofuscación al código pero son muy útiles y ahorran trabajo una vez escrita la clase,

 

 

Saludos.


  • 0




IP.Board spam blocked by CleanTalk.