How to avoid Memvar use ( Public and Private ) re: STATIC

Issues and Discussions related to Harbour

Moderator: Rathinagiri

Post Reply
User avatar
IMATECH
Posts: 188
Joined: Sun May 27, 2012 9:33 pm
Location: Brazil: Goiânia-GO.

How to avoid Memvar use ( Public and Private ) re: STATIC

Post by IMATECH »

Hi All !

Since Clipper 5, is high reccomended to avoid use of Memvar ( Public and Private ): it's over 20 year ago !!!

But frequently I see code fragments using this poor habit ( if it work's then I dont care about nothing )

May be some user's dont know what to do for this case, for this peoples I create the below samples.

Case 1: Replace a Public Array ( Like in HMG: _HMG_SYSDATA )

Code: Select all

// *---------------------------------------------------------------------------*
// MR_Set_Arr( n_aElement__, e_Value__ )
// *---------------------------------------------------------------------------*
FUNCTION  MR_Set_Arr( n_aElement__, e_Value__ )

   LOCAL xAux

   STATIC aAux := {}

   IF ( Len( aAux ) < n_aElement__ )
      ASize( aAux, n_aElement__ )
   ENDIF

   xAux := aAux[ n_aElement__ ]

   IF PCount() > 1
      IF HB_ISARRAY( e_Value__ )
         aAux[ n_aElement__ ] := AClone( e_Value__ )
      ELSE
         aAux[ n_aElement__ ] := e_Value__
      ENDIF
   ENDIF

RETURN( xAux )
How to use

Code: Select all

   LOCAL xAux

   MR_Set_Arr( 1 'Hello Word !' )
   MR_Set_Arr( 2, 'This is soo easy :)' )
   MR_Set_Arr( 3, date() )
   
   xAux := MR_Set_Arr( 1 ) + hb_eol()
   xAux += MR_Set_Arr( 2 )
   xAux += DTOS( MR_Set_Arr( 3 ) )

   MSGINFO( xAux, xAux )
Case 2: Replace various Memvar ( eg: a memvar for each field of a DBF )

Code: Select all

// *---------------------------------------------------------------------------*
// MR_Set_Hash( c_hElement__, e_Value__ )
// *---------------------------------------------------------------------------*
FUNCTION MR_Set_Hash( c_hElement__, e_Value__ )

   LOCAL xAux

   STATIC hAux := { => }

   IF PCount() > 1
      IF HB_ISARRAY( e_Value__ )
         hAux[ c_hElement__ ] := AClone( e_Value__ )
      ELSE
         hAux[ c_hElement__ ] := e_Value__
      ENDIF
   ELSE
      xAux := hAux[ c_hElement__ ]
   ENDIF

RETURN( xAux )
How to use

Code: Select all

   LOCAL xAux

   MR_Set_Hash( 'any_string', 'Hello Word !' )
   MR_Set_Hash( 'new_element', 'This is soo easy :)' )
   MR_Set_Hash( 'date_element', date() )
   
   xAux := MR_Set_Hash( 'any_string' ) + hb_eol()
   xAux += MR_Set_Hash( 'new_element' )
   xAux += dtos( MR_Set_Hash( 'date_element' ) )

   MSGINFO( xAux, xAux )

Internally - Clipper/Harbour use this technique intensively, like:
setkey( ..., ... )
set( ..., ... )
hb_gtInfo( ..., ... )
...



Feel free to ask any thing about this treat :)


Regards
Last edited by IMATECH on Fri Oct 04, 2013 10:39 pm, edited 3 times in total.
M., Ronaldo

By: IMATECH

Imation Tecnologia
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by esgici »

Hi Ronaldo

Thank to warn and suggestions ( nice code snippets ).

My opinion is :

- You are right in principle, usage of PRIVATE and especially PUBLIC variables not good programming practice and need to avoid them in general; but: there are many places and conditions that these type of usage is neither important nor inconvenient even necessary; database FIELDs, SET's and core data structures like _HMG_SYSDATA are typical examples of this needs.

- Again, you are right, may many people are using this way due to ignorance, if it work's then don't touch it !); but we couldn't assume all usages in this category, we should take aside conscious usages.

As a result, we can consider "variable scoping" only as a "style" issue, because probable unfavorable results will affect the author only, I think.

Happy "conscious" programming ;)
Viva INTERNATIONAL HMG :D
User avatar
IMATECH
Posts: 188
Joined: Sun May 27, 2012 9:33 pm
Location: Brazil: Goiânia-GO.

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by IMATECH »

Hi Esgici !



Thanks for reply :)



The sample functions can be called in global scope, replacing any Memvar used/needed in a project ( except if declared as static functions: visible only for a .prg file )

New case: Using to store/restore field values

Code: Select all

   LOCAL i
   LOCAL aStructure
   Local cAlias := 'any'
   
   USE 'Any_File.dbf' alias cAlias
   
   aStructure := ( cAlias )->( dbstruct() )
   
   /* Store Data */
   FOR i := 1 TO LEN( aStructure )
      MR_Set_Hash( aStructure[ i, 1 ], ( cAlias )->( Field(Get( i ) ) )
   NEXT

   /* Restore and display Data */
   FOR i := 1 TO LEN( aStructure )
      ? MR_Set_Hash( aStructure[ i, 1 ] )
   NEXT


I can't see any situation that Memvar's can't be replaced by a function that holds a statics inside var !


Qualit of Code
Imho: Good practices will help for good code and programs :)



Regards
M., Ronaldo

By: IMATECH

Imation Tecnologia
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by esgici »

Hi Ronaldo

Replacing MEMVARs by functions :?
I can't see any situation that Memvar's can't be replaced by a function that holds a statics inside var !
Regarding SCOPE factor may be you are right. But IMHO property of MEMVAR is not only SCOPE.

Consider this : Say we are USE-ing a DBF with fields NAME and SURNAME.

How we can replace MEMVAR->NAME notation by a function call and for what ?
Good practices will help for good code and programs :)
Sure.

But practice isn't everything, we need also ( even a few ) theory; otherwise we will need always help of experts; even sometime one isn't enough, may require two gurus ;)

Happy programming :D
Viva INTERNATIONAL HMG :D
User avatar
IMATECH
Posts: 188
Joined: Sun May 27, 2012 9:33 pm
Location: Brazil: Goiânia-GO.

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by IMATECH »

Hi Esgici !

Esgici whote:
Regarding SCOPE factor may be you are right. But IMHO property of MEMVAR is not only SCOPE.
Consider this : Say we are USE-ing a DBF with fields NAME and SURNAME.
How we can replace MEMVAR->NAME notation by a function call and for what ?
I can think in many possibilites using this typo !

Can you send a SSW code that you think only can be made using a Memvar ?
Then I will convert it to use that sample functions instead memvar



regards
M., Ronaldo

By: IMATECH

Imation Tecnologia
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by esgici »

Hi Ronaldo
IMATECH wrote: I can think in many possibilites using this typo !
Agreed; your MR_Set_Hash() function is a "registry manager", I liked it :)

Only hesitation is : when used for separate data items from different modules with the same name :?
Can you send a SSW code that you think only can be made using a Memvar ?
With pleasure :

Code: Select all

   MEMVAR->NAME := "Ronaldo"
    
   DBCREATE( "TEST", { { "NAME", "C", 10, 0 } },,.T.,"TEST" )
   DBAPPEND()
   
   TEST->NAME := "IMATECH"
   
   ? TEST->NAME    // IMATECH
   ? MEMVAR->NAME  // Ronaldo  ( maybe M->NAME too )
PS : Please don't modify / edit your sent ( especially answered ) posts;
I'm an old man, couldn't follow up :(

Saludos
Viva INTERNATIONAL HMG :D
User avatar
IMATECH
Posts: 188
Joined: Sun May 27, 2012 9:33 pm
Location: Brazil: Goiânia-GO.

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by IMATECH »

Hi Esgici :)
Esgici whote:
Agreed; your MR_Set_Hash() function is a "registry manager", I liked it :)
Only hesitation is : when used for separate data items from different modules with the same name :?
Thanks Esgici
You can solve it using 2 Functions/Versions

Global: visible to all program modules

Code: Select all

Function Global_Set_Hash( ... )
...
Return( ... )
Local: Visible only at .prg file ( cloned/repeated at all .prg needed )

Code: Select all

STATIC Function Local_Set_Hash( ... )
...
Return( ... )
If you declare a "Static Funcion": it will be visible only by routines in the same .prg file
If you declare a "Static Var", at begginng of a .prg file: it will be visible only by routines in the same .prg file
If you declare a "Static Var", inside a function: it will be visible only by that function/procedure

Code: Select all

Proc start_a()

   Local_Set_Hash( 'NAME', "Ronaldo" )
    
   DBCREATE( "TEST", { { "NAME", "C", 10, 0 } },,.T.,"TEST" )

   DBAPPEND()
   TEST->NAME := "IMATECH"
   TEST->( dbCommit() )

Return

Proc Next_a()
   
   ? TEST->NAME    // IMATECH
   ? Local_Set_Hash( 'NAME' ) // Ronaldo

   DBAPPEND()
   TEST->NAME := Local_Set_Hash( 'NAME' )
   TEST->( dbCommit() )

   ? TEST->NAME    // Ronaldo
   ? Local_Set_Hash( 'NAME' )  // Ronaldo

Return

STATIC Function Local_Set_Hash( ... )
...
Return( ... )
Esgici whote:
PS : Please don't modify / edit your sent ( especially answered ) posts;
Triyng, but sometimes I need to optimize/correct something for better learning


Best regards
M., Ronaldo

By: IMATECH

Imation Tecnologia
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: How to avoid Memvar use ( Public and Private ) re: STATI

Post by esgici »

Hi Ronaldo :)

Definitely, the issue become more complex while adding new "features" :(

IMHO the best is following ways offered and obey rules posed by system ;)

Anyway thank to your warn and given samples.

Saludos :D
Viva INTERNATIONAL HMG :D
Post Reply