A question about call by reference

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

PlaidFlannel
Posts: 43
Joined: Fri Aug 21, 2020 7:06 pm

A question about call by reference

Post by PlaidFlannel » Sat Feb 06, 2021 4:44 pm

I have a script in which I invoke a function to extract a long string from an array and then pass that string to another handler. The string may be as long as 10,000 characters. So it seemed that using a reference parameter instead of a value parameter might speed things up, because the handler is used many times.

My handler had this structure:

Code: Select all

on myHandler @pString, pOtherParameter
...
end myHandler
This statement in my script did not work:

Code: Select all

myHandler myFunction(myInstanceVariable), myOtherParameter
But this did work:

Code: Select all

get myFunction(myInstanceVariable)
myHandler it, myOtherParameter
However, both ways of invoking the handler work if I change the reference parameter to a value parameter:

Code: Select all

on myHandler pString, pOtherParameter
...
end myHandler
What am I not understanding about call by reference?

I might note that I come to LiveCode from programming languages that implement call by value by pushing a copy of the actual parameter on the call stack, and implement call by reference by pushing the address of the original actual parameter on the call stack. Does LiveCode behave differently?

Or is it the case that the function that returns a string extracted from an array sends back a value that is somehow different from other LiveCode values? I ask this because the original problem can also be solved by changing my function structure from this:

Code: Select all

function myFunction pInstanceVariable
    ...
    return pInstanceVariable[tKey]
end myFunction
to this:

Code: Select all

function myFunction pInstanceVariable
    ...
    get pInstanceVariable[tKey]
    return it
end myFunction
(Note: the function knows that pInstanceVariable is actually a LiveCode array; code that invokes the function does not know that. This is object-oriented programming adapted to LiveCode, and myFunction is one of the class getter methods.)

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sat Feb 06, 2021 6:38 pm

Hi.

You are asking few things, not all of which I understand.

First off, passing by reference requires that the "@" symbol be placed in the called, not the calling handler. Second, there is nothing wrong with placing a function call in the parameter list:

Code: Select all

on mouseUp
   put 5 into a
   testhandler a
   answer doubler(a)
end mouseUp

on testHandler @a
   put 7 into a
end testHandler

function doubler var
   return var * 2
end doubler
But if you swap the "@" from the called to the calling handler, you get "10", not "14".

Anyway, I think that, I at least, need more context to speak to the other points you made.

HTH

Craig

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sat Feb 06, 2021 6:59 pm

Hi.

Picking apart your post, the size of ones data probably does not matter in terms of wasting time. I cannot see how passing a large variable as a parameter is an issue however you move it from one handler to another, or how the called handler receives it.

Craig

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: A question about call by reference

Post by FourthWorld » Sat Feb 06, 2021 7:35 pm

Passing by reference does make a modest difference, usually not noticeable unless you have large data, but I never hurts to be lean.

In fact, it's so useful to pass by reference that the engine now does that automatically by default (as of v8 or so).

It uses "copy on write" by default, so even if you don't explicitly declare a param as reference ("@"), it won't actually make a copy into you perform some action which would alter it. If you want that alteration to be reflected in the calling handler, use @ before the arg name in the definition handler.

In your case, the only operation is read, so you should see no difference in performance whether you use @ or not, since only a pointer to the original data is what's being used by default.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sat Feb 06, 2021 7:44 pm

Richard.

Please explain so even I can understand it.
n fact, it's so useful to pass by reference that the engine now does that automatically by default (as of v8 or so).
Then how do we see the difference ("10" vs. "14") in the example I posted above?

It must be a wholly internal process, and the engine "restates" the values after all is said and done?

Craig

PlaidFlannel
Posts: 43
Joined: Fri Aug 21, 2020 7:06 pm

Re: A question about call by reference

Post by PlaidFlannel » Sat Feb 06, 2021 8:37 pm

Thanks to all who responded.

To simplify the discussion, let's go back to the central question. That is, this code will not even execute:

Code: Select all

myHandler myFunction(myInstanceVariable), myOtherParameter
Whatever myFunction returns, the engine won't even try to pass it to myHandler. It gives a runtime error that the parameter is invalid.

Why?

(Remember that by using the intermediate variable "it", this not only executes but gives the correct result.)

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sat Feb 06, 2021 9:26 pm

I don't know either, again, without more context. This all works for me, and seems generic enough:

Code: Select all

on mouseUp
   put 42 into myInstanceVariable
   put 54 into myOtherParameter
   myHandler myFunction(myInstanceVariable), myOtherParameter
end mouseUp

on myHandler var,var1
   answer var && var1
end myHandler

function myfunction var
   return var
end myfunction
Craig

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: A question about call by reference

Post by FourthWorld » Sat Feb 06, 2021 9:53 pm

dunbarx wrote:
Sat Feb 06, 2021 7:44 pm
Richard.

Please explain so even I can understand it.
n fact, it's so useful to pass by reference that the engine now does that automatically by default (as of v8 or so).
Then how do we see the difference ("10" vs. "14") in the example I posted above?
In that example the @ in the arg being called tells LC to alter the original source value, which it faithfully does.

LC's new copy-on-write comes into play when args have no @; it will use the original source for actions that read but don't alter ("write") the original source value, and copy them only when writes occur.

Functionally you should never notice the difference, nor really ever need to even think about it. It's just nice to be aware of it because it saves us from using @ for read-only operations (though there's no harm in continuing to do so), and it shows the level of detailed effort the team expends to find and implement opportunities to speed up execution while maintaining backward compatibility.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sat Feb 06, 2021 9:57 pm

Richard.

Thanks again for being you.

Craig

PlaidFlannel
Posts: 43
Joined: Fri Aug 21, 2020 7:06 pm

Re: A question about call by reference

Post by PlaidFlannel » Sat Feb 06, 2021 10:13 pm

The issue is that myFunction is trying to return an element of an array.

I have separate scripts (as of now, each attached to a button) for each of my OO classes. In each, the data members of an object-oriented class are elements of an array. An array with those elements is created for each instance of the class.

The class constructor, coverted to LiveCode, looks something like this:

Code: Select all

function newClassName
    local tObject
    put initialAlphaValue into tObject["mAlpha"]
    put "a very long string" into tObject["mBeta"]
    put initialGammaValue into tObject["mGamma"]
    return tObject
end newClassName
The mBeta data member is my 10,000-character string.

Suppose function getBeta() is the typical OO getter function for mBeta, and is implemented as:

Code: Select all

function getBeta pInstanceVariable
    return pInstanceVariable["mBeta"]
end getBeta
In another script are statements to create a new instance of the class and then get mBeta from that instance for the purpose of using it as a parameter to handler MyHandler. Something like this:

Code: Select all

...
put newClassName() into tInstanceVariable
...
MyHandler getBeta(tInstanceVariable), tOtherParameter
...
This last handler call fails with an invalid parameter error.

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: A question about call by reference

Post by FourthWorld » Sun Feb 07, 2021 1:53 am

dunbarx wrote:
Sat Feb 06, 2021 9:57 pm
Richard.

Thanks again for being you.
You're quite welcome, Craig, but the real thanks here goes to Mark Waddingham for staying up late putting a really great feature into the language so smooth we don't even need to think about it. :)
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

bwmilby
Posts: 462
Joined: Wed Jun 07, 2017 5:37 am
Contact:

Re: A question about call by reference

Post by bwmilby » Sun Feb 07, 2021 5:31 am

PlaidFlannel wrote:
Sat Feb 06, 2021 10:13 pm
In another script are statements to create a new instance of the class and then get mBeta from that instance for the purpose of using it as a parameter to handler MyHandler. Something like this:

Code: Select all

...
put newClassName() into tInstanceVariable
...
MyHandler getBeta(tInstanceVariable), tOtherParameter
...
This last handler call fails with an invalid parameter error.
In order for a parameter to be explicitly passed by reference, it must be a variable. It can't be a function or constant. That is why "it" worked. As stated earlier, if you are not changing the value then there is probably not a huge cost since the engine does a copy on write. (In a tight loop with many calls you could achieve some speed gains by explicitly doing a pass by reference since the engine wouldn't need to set up the additional variable that supported the copy on write. I did a quick test and the difference was roughly 10ms for 50,000 calls passing a simple integer without changing the value.)

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10043
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: A question about call by reference

Post by FourthWorld » Sun Feb 07, 2021 6:58 am

bwmilby wrote:
Sun Feb 07, 2021 5:31 am
In order for a parameter to be explicitly passed by reference, it must be a variable. It can't be a function or constant. That is why "it" worked. As stated earlier, if you are not changing the value then there is probably not a huge cost since the engine does a copy on write. (In a tight loop with many calls you could achieve some speed gains by explicitly doing a pass by reference since the engine wouldn't need to set up the additional variable that supported the copy on write. I did a quick test and the difference was roughly 10ms for 50,000 calls passing a simple integer without changing the value.)
That distinction about the variable instantiation is very helpful. Thank you, Brian.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sun Feb 07, 2021 7:03 pm

In order for a parameter to be explicitly passed by reference, it must be a variable. It can't be a function or constant.
It looks to me that passing by reference is simply not pertinent with function calls, because the value of any particular variable is returned explicitly, sort of separately, so that its value in the calling handler don't enter into it. I am not sure I explained that very well.

Craig

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: A question about call by reference

Post by dunbarx » Sun Feb 07, 2021 7:21 pm

Here is a oddity, that I do not understand, and likely matters not a whit. This:

Code: Select all

on mouseUp
   put 5 into a
   testhandler testFunction(a)
end mouseUp

function testFunction a
   return 42
end testFunction

on testHandler @a -- the "@" is not permitted
  answer a
end testHandler
throws an error. Losing the "@" cleans it up, and you get "42".

Even if the "@" is irrelevant, why does the program flow break? Just an esoteric no-no?

Craig

Post Reply