LOCAL array and Object Behaviour with ONCLICK

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

Zimbo
Posts: 56
Joined: Mon Nov 05, 2012 1:28 pm
Location: Scotland
Contact:

LOCAL array and Object Behaviour with ONCLICK

Post by Zimbo »

Friends. I need your help - I need to understand why some code works when I think it should not!!!

I am working on a piece of sample code to use in the next chapter of my guide to programming in Harbour and HMG and have spotted something that I think should NOT work but it actually does. I really do not know why although I have my suspicions; if any one of the experts on Objects can help, I would really appreciate it!

As you can see, I declared a LOCAL array in FUNCTION Main. There are several other LABEL and BUTTON definitions but the one I am confused by is BUTTON btn_09 where ONCLICK calls another function called SortArray(aTrolley) which passes the LOCAL array to the function.

In the SortArray function, I call the COPY of the aTrolley array declared in FUNCTION main something else and then sort that copy before doing a number of other things.

If my understanding is right, this should only sort the COPY of the array it has been passed and should not change the original array which is LOCAL in the original function. BUT somehow it does sort the original array as well and the program works the way I expect it to. Why?

Is this something to do with Object behaviour where Win_1.btn_09 can see the original LOCAL (aTrolley) array and works that no matter what my UDF calls the copy of the array that it receives?

I am not as good with objects as I need to be, so it's quite good that I spotted this because I should learn something!

Many thanks,

Zim
http://www.harbour-guide.com

Code: Select all

#include "hmg.ch"

FUNCTION Main()

LOCAL nlblRow  :=  16
LOCAL nlblCol  :=  16

// Create a LOCAL memory variable that will be an array
LOCAL aTrolley := ARRAY(0)

SET FONT TO "Arial", 10
SET DATE BRITISH

// Add new elements to the array
AADD(aTrolley, "Potatoes")
AADD(aTrolley, "Mushrooms")
AADD(aTrolley, "Large Steak")
AADD(aTrolley, "Small Steak")
AADD(aTrolley, "Asparagus")
AADD(aTrolley, "Bottle of Wine")

DEFINE WINDOW Win_1 ; 
    AT 0,0 ;
    WIDTH  704 ;
    HEIGHT 480 ;
    TITLE "Array Test" ;
    MAIN
    
    // Other code appears here to display a number of labels - removed to focus on the problem

    DEFINE BUTTON btn_09
        ROW nlblRow * 10
        COL nlblCol * 15
        CAPTION "Sort Array"
        AUTOSIZE .T.
        // When this button is clicked on, I am calling a function (see below) that sorts the array. As I declared
        // the array LOCAL, I have passed the name of the variable as a parameter to the sort function.
        ONCLICK SortArray(aTrolley)
    END BUTTON
    
END WINDOW

CENTER WINDOW Win_1
ACTIVATE WINDOW Win_1

Return Nil    /* -- End of FUNCTION Main() -- */

FUNCTION SortArray(aToSort)

// A COPY of the LOCAL array declared in the main function is received in this UDF which is then sorted. What is VERY
// strange is that this actually sorts the main array (aTrolley) as well as the copy called aToSort. I suspect that
// this is because the Object Win_1.btn_01 can "see" the array called aTrolley so it sorts that array no matter what
// I call the copy passed to this array. Am I right?

ASORT(aToSort)

// A few properties are changed after the array is sorted - example: Win_1.btn_01.Caption := "Sorted 1"

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

Re: LOCAL array and Object Behaviour with ONCLICK

Post by esgici »

Hi Zim

I couldn't found in the documentations; but we have a strong rule about arrays : "array passed ALWAYS by reference".

For a separate array you need use ACLONE() funtion.

I hope this will solve your problem.

Happy HMG'ing :D
Viva INTERNATIONAL HMG :D
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: LOCAL array and Object Behaviour with ONCLICK

Post by esgici »

I hope found something here.

Look at especially function example "Factorial" at and of article.

Happy HMG'ing :D
Viva INTERNATIONAL HMG :D
User avatar
Rathinagiri
Posts: 5471
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Contact:

Re: LOCAL array and Object Behaviour with ONCLICK

Post by Rathinagiri »

Rightly said Esgici.

Array is so powerful! We have to handle it carefully. If you don't want to change the original array, you have to send aclone( aOriginal ) as the parameter as suggested by Esgici..
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.
Zimbo
Posts: 56
Joined: Mon Nov 05, 2012 1:28 pm
Location: Scotland
Contact:

Re: LOCAL array and Object Behaviour with ONCLICK

Post by Zimbo »

Thanks guys, for jogging my memory! I did want the original array changed (this will be an example in the next chapter of my guide, demonstrating the basics of arrays). ACLONE is also covered but in a different code sample.

I will ensure I include a detailed discussion about array scope in the next chapter and operators (including the pass by reference operator) is also included in a later chapter where I cover all of the operators.

All of this is really useful as I am a little rusty with certain parts of the language and, I hope, the guide will be useful to others in future!
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: LOCAL array and Object Behaviour with ONCLICK

Post by esgici »

Zimbo wrote: I will ensure I include a detailed discussion about array scope in the next chapter and operators (including the pass by reference operator) is also included in a later chapter where I cover all of the operators.
Hi Zimbo

My two cent :

Code: Select all

#include <hmg.ch>

PROC Main()

  DEFINE WINDOW frmTestArrScop ;
      AT 0,0 ;
      WIDTH 400 ;
      HEIGHT 250 ;
      MAIN;
      ON INIT DoTest() ;
      TITLE 'Test array scope'

      @ 50, 20 BUTTON btnDoTest CAPTION 'Repeat Test' ACTION DoTest()

  END WINDOW

  frmTestArrScop.Center
  frmTestArrScop.Activate
 
RETU // Main()   

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

PROC DoTest()

   LOCA aArray := { 1, 2, 3 }

   ChangeOrj( aArray )       // Change both local and original array

   MsgDebug( PROCNAME(), aArray )        // 1, 2, 3, 4

   aArray := { 1, 2, 3 }    

   DontChngOrj( aArray )     // Change local and but original remain intact 

   MsgDebug( PROCNAME(), aArray )        // 1, 2, 3


RETU // DoTest()

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

PROC ChangeOrj( aArr1 )     // Send and receive by reference
   AADD( aArr1, 4 )        // Original array changed 
   MsgDebug( PROCNAME(), aArr1 )        // 1, 2, 3, 4   
RETU // ChangeOrj()

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

PROC DontChngOrj( aArr1 )     // Send and receive by reference
   LOCA aArr2 := ACLONE( aArr1 )
   AADD( aArr2, 4 )        // Original array changed 
   MsgDebug( PROCNAME(), aArr2 )        // 1, 2, 3     
RETU // DontChngOrj()

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
Please continue :arrow:

Happy HMG'ing :D
Viva INTERNATIONAL HMG :D
KDJ
Posts: 243
Joined: Mon Sep 05, 2016 3:04 am
Location: Poland

Re: LOCAL array and Object Behaviour with ONCLICK

Post by KDJ »

For more accurate.
The following means that, aArr variable contains the reference (pointer) to the array {1,2,3}:
aArr := {1,2,3}

This reference can be passed to a function by value or by reference.

Passing the reference by value (passed is copy of the reference, not copy of the array):
MyFunction(aArr)

Passing the reference by reference (passed is oryginal of the reference, not the array):
MyFunction(@aArr)
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: LOCAL array and Object Behaviour with ONCLICK

Post by esgici »

KDJ wrote:For more accurate.
The following means that, aArr variable contains the reference (pointer) to the array {1,2,3}:
aArr := {1,2,3}

This reference can be passed to a function by value or by reference.

Passing the reference by value (passed is copy of the reference, not copy of the array):
MyFunction(aArr)

Passing the reference by reference (passed is oryginal of the reference, not the array):
MyFunction(@aArr)
Are you sure ( did you tested ) ? :?

Happy HMG'ing :D
Viva INTERNATIONAL HMG :D
KDJ
Posts: 243
Joined: Mon Sep 05, 2016 3:04 am
Location: Poland

Re: LOCAL array and Object Behaviour with ONCLICK

Post by KDJ »

esgici

Of course, I tested.
And it is described in your documentation of Clipper 5.0:
esgici wrote:
I hope found something here.
Read this chapter: "Passing Arrays and Objects as Arguments".
User avatar
esgici
Posts: 4543
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Contact:

Re: LOCAL array and Object Behaviour with ONCLICK

Post by esgici »

KDJ wrote:
Of course, I tested.
And it is described in your documentation of Clipper 5.0:
esgici wrote:
I hope found something here.
Read this chapter: "Passing Arrays and Objects as Arguments".
Well, you are right :oops:

Modified above sample by adding two rutin from Clipper 5.0 Manual:

Code: Select all

#include <hmg.ch>

PROC Main()

  DEFINE WINDOW frmTestArrScop ;
      AT 0,0 ;
      WIDTH 400 ;
      HEIGHT 250 ;
      MAIN;
      ON INIT DoTest() ;
      TITLE 'Test array scope'

      @ 50, 20 BUTTON btnDoTest CAPTION 'Repeat Test' ACTION DoTest()

  END WINDOW

  frmTestArrScop.Center
  frmTestArrScop.Activate
 
RETU // Main()   

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

PROC DoTest()

   LOCA aArray := { 1, 2, 3 }   
   
   ChangeOrj( aArray )       // Change both local and original array
   MsgDebug( 1, aArray )        // 1, 2, 3, 4

   aArray := { 1, 2, 3 }    
   DontChngOrj( aArray )     // Change local and but original remain intact 
   MsgDebug( 2, aArray )             // 1, 2, 3 
   
   ChangeElement( aArray )
   MsgDebug( 3, aArray[ 1 ] )        // 10
                            
   aArray := { 1, 2, 3 } 
   ChangeArray( aArray )
   MsgDebug( 4, aArray[ 1 ] )        // 1      
   
   ChangeArray( @aArray )
   MsgDebug( 5, aArray[ 1 ] )        // 4
   
      
RETU // DoTest()

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

PROC ChangeOrj( aArr1 )     // Send and receive by reference
   AADD( aArr1, 4 )        // Original array changed 
RETU // ChangeOrj()

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

PROC DontChngOrj( aArr1 )     // Send and receive by reference
   LOCA aArr2 := ACLONE( aArr1 )
   AADD( aArr2, 4 )        // Original array changed 
RETU // DontChngOrj()

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 

* Rutins borrowed "Functions and Procedures" section of Clipper 5.0 Manual

PROC ChangeElement( aArr1 )
   aArr1[ 1] := 10 
RETURN

* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
   
PROC ChangeArray( aArr1 )
   aArr1 := { 4, 5, 6 }
RETU
   
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 
   
But I confused :?

What is difference (by mean of passing argument) between ChangeOrj() and ChangeArray() functions ?

In the first adding an element ( by AADD() ) to orijinal array and array changed;
in the second array reassigned entirely new elements and array not changed;

whereas both two calling array send without "@" sign :?

What is your opinion :?:

Happy HMG'ing :D
Viva INTERNATIONAL HMG :D
Post Reply