Fun with arrays!

Started by snowsnowsnow, April 26, 2016, 01:19:07 PM

Previous topic - Next topic

snowsnowsnow

Try out this program.  Why doesn't array "A" in the main program retain the values assigned to it in the Function?  Remember that arrays are passed "by reference", which, in layman's terms, means that the object referred to inside the function is the same object as the object that exists in the caller.

Note: Yes, I know all about how DefineFunction works and that most variables are "local" to the function and thus not visible outside.  But arrays passed as arguments *are* different (special).

Code (winbatch) Select

#DefineFunction udfArrayize(s,d,A)
A = Arrayize(s,d)
Return ArrInfo(A,1) - 1
#EndFunction

A = Arrayize("","")
n0 = udfArrayize("a b c"," ",A)
Pause("Result: %n0%",StrCat("ArrInfo(A,1) = ",ArrInfo(A,1)))
FOR I = 0 TO n0
    Pause(I,A[I])
NEXT

td

Me things you are confusing variables containing references with pointers to variables.   If you assigned an integer value of 0 to your A variable and passed it to your UDF and in the UDF assigned the value of 1 to that same A variable, you certainly would not  expect (I hope) the A variable to have changed after the script returns from the UDF call.  Your UDF creates an entirely new array reference and assigned it to the variable with UDF scope. Since that variable has UDF scope, the array reference it contains is destroyed when the variable goes out of scope.  The passed in array has its reference count incremented when the reference is assigned to the UDF parameter variable and decremented when the UDF assigns a completely different array references to that variable.  The net affect on the original array variable and reference is nada.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Consider the following and how it demonstrates the concept of array references:
Code (winbatch) Select
#DefineFunction udfArrayize(s,d,A)
   nMax = min(ItemCount(s, d),ArrInfo(a,1)) - 1
   for i = 0 to nMax
      A[i] = ItemExtract(i+1, s, d)
   next
   Return ArrInfo(A,1) - 1
#EndFunction

A = Arrayize("1 2 3"," ")
n0 = udfArrayize("a b c"," ",A)
Pause("Result: %n0%",StrCat("ArrInfo(A,1) = ",ArrInfo(A,1)))
for i = 0 TO n0
    Pause(i,A[i])
next

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

OK - I get it (I think).

The point is that Arrayize() does not populate an existing array (As I lazily assumed, although I should have known better).  Rather, it creates a brand new array - wiping out any existing array that might have existed with the name to which the new array has been assigned.

td

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Quote from: td on April 27, 2016, 08:14:22 AM
Right on.

Which leads to the question of whether there is anyway to implement what I'm actually trying to do here.  That is, a version of Arrayize() that returns the number (minus 1 - for a reason that should, I would hope, be clear) of elements created (*), as well as making the array itself available to the caller.

As I think about it, it seems it might actually be do-able using gosub (which would keep everything in scope of the caller) rather than UDF or UDS...

(*) I.e., the highest legal subscript, which is what I usually want.

td

I believe with your  version of WinBatch, you could simply use the '&' pointer creation operator to make your array parameter an [in] and [out] parameter (burger parameter?).   Something like:

Code (winbatch) Select
udfArrayize("a b c"," ",&A)

and

Code (winbatch) Select
*A=Arrayize(s,d)
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Quote from: td on April 27, 2016, 10:55:24 AM
I believe with your  version of WinBatch, you could simply use the '&' pointer creation operator to make your array parameter an [in] and [out] parameter (burger parameter?).

Yes!  Thank you, that works!

Here is the revised code:

Code (winbatch) Select

#DefineFunction udfArrayize(s,d,A)
*A = Arrayize(s,d)
Return ArrInfo(*A,1) - 1
#EndFunction

n0 = udfArrayize("a b c"," ",&A)
Pause("Result: %n0%",StrCat("ArrInfo(A,1) = ",ArrInfo(A,1)))
FOR I = 0 TO n0
    Pause(I,A[I])
NEXT


But I am curious about one thing - you will notice that in the above code, I did not have to initialize (i.e., create) the A array before passing &A to the UDF.  Doesn't that seem odd by the usual WinBatch standard - which is that any variable (i.e., object) has to be initialized before it an be used?  What exactly is &A when A has not been referenced previously?

td

No mystery.  The & operator instantiates the variable on as needed basis just like the PtrGlobalDefine function does.  From the function's documentation:

'If "variable-name" does not already exist, it will be created.' 
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Quote from: td on April 27, 2016, 01:44:36 PM
No mystery.  The & operator instantiates the variable on as needed basis just like the PtrGlobalDefine function does.  From the function's documentation:

'If "variable-name" does not already exist, it will be created.'

OK - then no worries.

Anyway, thanks again - this solves my problem.
And now I get to reverse my previous position that pointers are not useful.

snowsnowsnow

Actually, it occurs to me that one could just as easily do it using a UDS instead of with pointers.  This has the feature that it always uses the same array - Yes, this is a feature, not a bug/limitation.

This works:

Code (winbatch) Select

#DefineSubroutine udsArrayize(_s,_d)
A = Arrayize(_s,_d)
Return ArrInfo(A,1) - 1
#EndSubroutine


Note, incidentally, the need to precede the 's' and 'd' parameters with the underscore...

td

UDFs have several advantages over UFSs but that is a discussion for another day.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade