Objeto ficticio

Objeto ficticio

Postby antolin » Wed Sep 24, 2014 12:17 pm

Hola foreros.

Ultimamente, desarrollando una CLASE propia me han surgido una gran cantidad de problemas, que, por otra parte, me han enseñado muchas cosas nuevas y me han llevado a desarrollar nuevos procedimientos y técnicas de programación. una de esas técnicas es la que me gustaría comentar aquí, pues la veo interesante.

Resulta que en esta famosa/dichosa CLASE quito o pongo un SCROLL según que la cantidad de datos a mostrar en cada momento quepa o no quepa en la amplitud del control.

Significa que, por ejemplo, siempre que pulso una tecla tengo que controlar si el SCROLL está visible o no (existe o no existe). Supone una buena cantidad de líneas como esta:
Code: Select all  Expand view
IF ::oVSCroll # NIL
   ::oVSCroll:SetPos( nPos )
ENDIF


Code: Select all  Expand view
En principio lo solucioné añadiendo un DATA a mi CLASE "::bVSCRoll" que defino como:

::bVSCRoll := { || ::oVSCroll:SetPos( nPos ) } cuando creo el SCROLL

Y como

::bVSCRoll := { || NIL } al inicio de la CLASE o cuando borro el SCROLL.

Así tras programar cada tecla, y en otros sitios hago:

EVAL(::bVSCRoll) y se acabaron los IFs.

Pero resulta que además de esos IFs que enlentecen el programa hay algunos más que se repiten bastante y que quería quitar. Así que he creado un objeto ficticio, y creo que tiene posibilidades en programación. Este sería:
Code: Select all  Expand view
#include "FiveWin.ch"


CLASS VoidObject

DATA nTop,nLeft,nRight,nBottom  AS NUMERIC  INIT  0
DATA nWidth,nHeight     AS NUMERIC  INIT  0
DATA nMin,nMax,nMaxCol      AS NUMERIC  INIT  0
DATA lReDraw,lCaptured      AS LOGICAL  INIT .F.
DATA hDc,hCDC,hWnd,oWnd
DATA lVbx

METHOD New()

METHOD Paint()      INLINE NIL
METHOD Refresh()    INLINE NIL 
METHOD Move()       INLINE NIL
METHOD SetPos()     INLINE NIL
METHOD SetRange()   INLINE NIL
METHOD End()        INLINE NIL

ENDCLASS

// *******************************************************

METHOD New()        CLASS VoidObject
   ::oWnd := GetWndDefault()
   ::lVbx := .T.
   ::hWnd :=  0
   ::hDc  :=  0
RETURN Self

Ahora:
Code: Select all  Expand view
Al inicio de la CLASE hago:

::oVSCroll := VoidObject():New()

Cuando tengo que crear el SCROLL, hago:

::oVSCroll := NIL
@ nY,nX SCROLLBAR ::oVSCroll of Self SIZE .....

Y cuando tengo que volver a quitarlo hago:

::oVSCroll := NIL
::oVSCroll := VoidObject():New()

Y ya no necesito ::bVSCRoll.

Ya no tengo que preocuparme de si el SCROLL está presente o no. Si existe, ::oVSCroll:SetPos( nPos ) me posisiona el SCROLL, y si no existe, no hace nada pues hay un método en el objeto ficticio que se llama SetPos() y que devuelve NIL sin más. La cantidad de IFs que me he quitado de encima. Lo único que hay que tener en cuenta es que en el objeto ficticio existan las variables y métodos que vamos a necesitar durante la programación, que no tienen por que ser todos, sólo los que vamos a emplear en algún momento.

Otro problema que me surgió fue: ¿cuándo sé si el SCROLL existe de verdad o es ficticio? Tenía que buscar un DATA que existiese en cualquier CLASE de FWH y se me ocurrió utilizar ::lVbx, que normalmente está en .F. y se utiliza muy muy poco (yo nunca lo he usado). En el objeto ficticio lo defino como .T. y ahora cuando ::lVbx está en .T. sé que es un objeto ficticio y si está en .F. sé que es un objeto de verdad.

Creo que añadiendo algún DATA y unos pocos métodos, este objeto ficticio podría sustituir a más de un objeto, especialmente algún TSAY, TGET, CHECKBOX o RADIOBUTTON que, en un mismo módulo, a veces se ponen y otras no, y que hay que estar constantemente comprobando si están o no presentes.

Ya os iré contando.

Saludos.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby antolin » Wed Sep 24, 2014 12:24 pm

Estoy abierto a cualquier sugerencia o modificación. Por ejemplo añadir ::cCaption y ::Cargo al objeto ficticio, pues son datos que se utilizan mucho.

Ha! y un ClassName() sugiero "VOID"
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby Antonio Linares » Wed Sep 24, 2014 3:29 pm

Antolin,

Muy bien. Precisamente esa es la gran ventaja de la herencia en programación orientada al objeto:

Puedes partir de un concepto virtual que luego vas modificando en clases derivadas.

De hecho la mayoria de los métodos pueden ser virtuales (VIRTUAL) y en clases derivadas implementar esos métodos.

La programación orientada al objeto es muy potente y cuando se asimila bien, las posibilidades son enormes :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Objeto ficticio

Postby hmpaquito » Wed Sep 24, 2014 4:40 pm

Antolín,

Parece una idea genial... Hace tiempo tuve que hacer algo parecido...

Una técnica complementaria con OOP que se ha desarrollado en los últimos tiempos es el Modelo Vista Controlador. Yo no lo he utilizado... sólo he leído... ya sabes... hay que arrastrar lo desarrollado e innovar queda para el año que viene...

Me gustan muchos tus comentarios... siempre me resultan interesantes. Gracias.

Saludos
hmpaquito
 
Posts: 1482
Joined: Thu Oct 30, 2008 2:37 pm

Re: Objeto ficticio

Postby Carlos Mora » Wed Oct 01, 2014 7:07 am

antolin wrote:Ha! y un ClassName() sugiero "VOID"


VOID tiene un significado diferente, es como decir NULL o NIL. ¿Que te parece dummy? Es una buena analogía, una de las definiciones de 'dummy' de Google Translator es: "algo diseñado para parecerse y actuar como un sustituto de lo real o de costumbre; una falsificación o fraude."

A lo que me gustaría encontrarle una alternativa es al uso de lVbx. No es que yo lo use, pero desde un punto de vista 'purista' lVbx ya tiene una función, es confuso usar algo con un nombre tan específico para algo tan diferente, y eventualmente podría romper algo de código. En las viejas Clipper Advisor un artículo sugería normalizar el uso de la variable Cargo como un array de pares clave/valor, lo que permitiría añadir todas las variables que necesitemos a un objeto, aunque seguramente hoy sería más conveniente usar un hash.
Otra alternativa podría ser usar directamente el método IsKindOf( 'NombreDeClase' ) -> .T. o .F. si es o deriva de la clase determinada. La ventaja añadida es que funciona también con las subclases.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Objeto ficticio

Postby antolin » Wed Oct 01, 2014 10:51 am

Carlos, todo eso que dices es muy cierto y tiene mucha lógica, aunque implica tener que cambiar todas las clases de FWH para añadirles el método IsKindOf() o algún data nuevo común a todas ellas. Y como comprenderás, no pretendo cambiar nada de FWH, sólo adaptarme a lo que hay. Este objeto ficticio lo he creado de acuerdo a mis necesidades y para mi lVbx me va de maravillas. Claro que cada cual puede utilizar el que más le satisfaga. Por ejemplo si añades el método:
Code: Select all  Expand view
METHOD ClassName() INLINE "Dummy"

Podrías utilizar ObJ:ClassName() para distinguir entre objeto real y ficticio. O el ::cCaptión (aunque en alguno objetos vale NIL y hay que tener cuidado).

De todas formas, toda sugerencia es bien venida. Gracias

Saludos
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby antolin » Wed Oct 01, 2014 11:10 am

Perdona Carlos, no sabía que existía el método IsKindOf(), pobre ignorante. Al leerlo pensé que quería añadir ese método después al leerlo más despacio lo interpreté como Dios manda y lo probé. Efectivamente IsKindOf() sería una solución magnífica.

Tras meditarlo un poco, me pregunto ¿Qué sería más rápido procesar IF oBj:lVbx ó IF IsKindOf("Dummy")? habría que preguntárselo a algún experto.

Un saludo

Por cierto, perdonad mi ignorancia, pero, hay más métodos/Datas ocultos de esos como IsKindOf().
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby Antonio Linares » Wed Oct 01, 2014 11:57 am

ClassH(), ClassName(), ...

Revisa FWH\samples\ClassTree.prg e inspecciona las clases, encontraras cosas que te gustarán :-)
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 41314
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: Objeto ficticio

Postby antolin » Wed Oct 01, 2014 12:23 pm

Ok, manos a la obra...

Gracias
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby antolin » Wed Oct 01, 2014 12:30 pm

Poca obra, pues mi FWH es muy antiguo (DIC 2007) y no tiene ese PRG entre sus samples. Mala suerte
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby Carlos Mora » Wed Oct 01, 2014 2:43 pm

Bueno, Antonio ya adelantó lo que te quería decir de ClassH, ClassName, etc. que ¡vienen de la época del Clipper! ¡Si habré trasteado con ellas y el módulo Send!
Lo bueno e interesante de Harbour es que ha añadido un gran número de funciones y métodos estándares que se incorporaron a partir de librerías de objetos como Objects, Class(y), etc. e ideas de otros lenguajes.
Si quieres mirar cosas interesantes, chequea los ejemplos del propio Harbour, el directorio Test tiene muuuucho para ver.
Es cierto lo que tu dices: es dificil enterarse de todas las novedades que incorpora [x]Harbour. xHarbour lo tiene un poco mejor, hubo un esfuerzo importante de xHarbour.com para escribir un muy buen manual donde incluye todas las nuevas funcionalidades y extensiones, pero es de pago. Nos hace falta gente que haga divulgación, que creo que es uno de los puntos más flojos del entorno [x]Harbour.

Respecto de la velocidad de lVbx vs. IsKindOf(): Optimizar eso me parece que es hilar muy fino. IsKindOf está escrita en C, es interna al lenguaje, pero mas aláa de eso la diferencia de tiempos no va a afectar sensiblemente el resto del proceso, seguramente hay muchos puntos más importantes con más peso en el proceso. De echo

Code: Select all  Expand view
   IF ::oVSCroll # NIL
       ::oVSCroll:SetPos( nPos )
    ENDIF


es MUCHO más rápido que

Code: Select all  Expand view
EVAL(::bVSCRoll)


Ya que SI o SI pones Eval y el codeblock en la stack y haces una llamada, + la llamada dentro del codeblock a ::oVSCroll:SetPos( nPos ) cuando toca, que ADEMAS cuando defines ese codeblock como

Code: Select all  Expand view
::bVSCRoll := { || ::oVSCroll:SetPos( nPos ) }


estás creando una DETACHED LOCAL con Self , lo que implica que mueves y marcas referenciada una variable dentro de la stack, puff internamente es un rollo mucho más complejo que la estructura IF/ENDIF

Te propongo una alternativa para escribir menos código usando preprocesador (es lo que más me gusta de Clipper/[x]Harbour ):

Code: Select all  Expand view
#command EVALIFNOTNIL( <bBlock>[, <param1>[, <paramN>]] ) => IF <bBlock> != NIL ; <bBlock>:Eval(  <param1>[, <paramN>]  ) ; ENDIF


Simplificamos la escritura, y usamos el método que me parece más rápido.

PD: A ver si le robo tiempo al tiempo y termino unas líneas que empecé y no terminé respecto de Hash, que seguramente servirá al menos de repaso para los compañeros y es una de las partes menos conocidas de las innovaciones.
Y hablando de falta de divulgación, mirando std.ch en el directorio include de Harbour ME ACABO DE ENTERAR que SET RELATION SOPORTA LA CLÁUSULA SCOPED del Comix RDD.

"SET RELATION TO ... SCOPED lets you handle true one to many relationships with ease! When you select the child workarea, only the records related to the current parent record are visible." Es como si el Set Relation no solo hace un Seek, sino también un SET SCOPE. ¡Fantástico!
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 988
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Objeto ficticio

Postby xmanuel » Wed Oct 01, 2014 10:26 pm

Carlos ISKINDOF está escrita en PRG mira la clase HBObject que está en "harbour\src\rtl". Si no se dice lo contrario, todas las clases de harbour que se hagan a nivel de PRG están derivadas de HBObject y por lo tanto heredan las datas y los métodos de ella.
Si observas HBObjects podrás aprender muchísimo, al menos yo me sirvió. Podrás ver que el prototipo del metodo addMethod de la clase HBClass (un ejemplo de metaclase por cierto, una clase capaz de crear clases)... bueno bueno que me voy...
El prototipo es AddMethod( cMethod, sFuncSym, nScope )
o sea "cMethod" una cadena con el nombre del metodo, "sFuncSym" un puntero a la funcion que implementa el metodo en sí y QUE SE PUEDE LLAMAR COMO SEA y por último la visibilidad del metodo.
Que quiero decirte?
Que puedes crear dos implementaciones funciones-metodos para un mismo método. Lógicamente sólo una de las dos implementaciones estaría activas. Esto quiere decir que te ahorrarías absolutamente todos los IF menos el que cambia la implementación del método. Así esta Eagle1 pero en C. Yo trabajo muy parecido a como lo hace las RDD, o sea con una estructura de punteros a funciones que cambio a mi antojo, con lo cual elimino los típicos "IF TYPE == "C" ... "IF TYPE == "N" ...

No sé si me he explicado :?: :shock: :oops: :D

Odio los EVAL que son muuuuuuuuuuuu leeeeeeeeeeentossssssssssssssss

PD: Antolín, no serás bético por casualidad?
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 756
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Objeto ficticio

Postby antolin » Fri Oct 03, 2014 10:14 am

Muchas gracias a Carlos y a xManuel. Por cierto xManuel, que no me he enterado de mucho, la verdad es que siempre he sido autodidacta y hay grandes conjuntos de la informática que nunca he tocado, como lo de las metaclases y menos aun los punteros a funciones (me interesa). Lo que si me interesa y mucho es lo de "sFuncSym" que no sé lo que es pero tiene muy buena pinta.

La otra cosa que me ha sorprendido es lo de los EVALS. Tenía entendido que un CodeBlock era más rápido y eficiente que una función. Tampoco había caído en el espacio que ocupa el CodeBlock en memoria, las referencias, el stack lo del Self etc... Muuuuy interesante. En principio me apunto al código preprocesado y después ya veré.

Muchas gracias, de verdad.
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Re: Objeto ficticio

Postby xmanuel » Fri Oct 03, 2014 4:53 pm

Hola Antolin...

No me has contestado por lo que supongo que eres del Sevilla no?
jejeje

Es fácil de comprobar lo que digo, puedes crear una función y ejecutarla por ejemplo 100000 veces y luego hacer la prueba con un eval:

Code: Select all  Expand view

procedure main()
  local nSeg, n
  local cb := { || miFuncion() }

  nSeg := seconds()
  for n := 1 to 100000
        eval( cb )
  next
  alert( "El tiemp empleado con eval es: " + allTrim( str( seconds() ) )

   nSeg := seconds()
  for n := 1 to 100000
        miFuncion()
  next
  alert( "El tiempo empleado sin eval es: " + allTrim( str( seconds() ) )
return

procedure miFuncion()
   ? time()
return  
 
 


Ve aumentando las iteraciones y ya veras....

El motor de objetos de harbour guarda los métodos en una tablas hash con una key y un valor que puedes cambiar en tiempo de ejecución.

Tu puedes cambiar el metodo setPos para que haga algo o que llame a una funcion que no haga nada o algo que tu necesites con lo que evitara el if y el error:

IF ::oVSCroll # NIL
::oVSCroll:SetPos( nPos )
ENDIF

pasaría a

::oVSCroll:SetPos( nPos )

siempre...

Si eres de Sevilla podríamos que dar algún día o llamarnos por telefono y te lo explico sobre la marcha :-)
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 756
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Objeto ficticio

Postby antolin » Sat Oct 04, 2014 8:27 am

Hola, Xmanuel.

Primero y más importante. Gracias por tu interés.

Segundo y no menos importante. No soy del Betis, tampoco del Sevilla. Normalmente suelo decantarme por el equipo que más me haga tilin cada año de entre los más destacados que no sean ni Madrid ni Barça. Me considero amante del buen juego, no del más rico. El año pasado, por ejemplo, el Atlético de Madrid. Este año apoyo al Valencia, a mi parecer, el que más promete. Cierto es que a igualdad de condiciones, el Betis me atrae más que el Sevilla.

En cuanto a mi, ahora vivo en Jerez , pero trabajo en Morón y mi hijo acaba de empezar la Universidad en Sevilla (químicas)por lo que últimamente me paso a menudo por allí.

En cuanto al tema este, lo de cambiar SetPos() en tiempo de ejecución, no sabía que se podía hacer, aunque lo había pensado, supongo que se hará con ClassH o ClassName (o algo así) de xHarbour. Lo investigo y comento. Desde luego, es una solución que me gusta mucho.

Muchas gracias
Peaaaaaso de foro...
antolin
 
Posts: 491
Joined: Thu May 10, 2007 8:30 pm
Location: Sevilla

Next

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 88 guests