Page 1 of 1
Calling handler on a different card - help me understand
Posted: Tue Apr 07, 2015 9:05 pm
by Pomo
Hi. In trying to call a handler on a different card, I am confused about the behavior I am seeing. I've attached a sample stack to show the questions.
Card1's script contains a handler "doIt". doIt puts the current time into field fText also on card1. Button1 on card1 sends "doIt" to card1. All works as I expect - the time shown in fText gets set to the current time.
card2 has a button2 that sends "doIt" to card1, intending to invoke card1's doIt handler.
1) When button2 invokes card1's doIt handler, it gives a "no such object" error, apparently unable to find field "fText". Why? I would expect it to work since field fText is on card1 as is doIt. And the handler works when called from Button1 of card1. BTW, using call instead of send makes no difference.
2) Next I tried adding "of me" to the field specifier, as in
put the long time into fld "fText" of me.
According to the debugger, me evaluates during the handler to 'card "card1"', just as I expect. However, even though the script executes without error, the field fText remains unchanged by the script. Here I'd expect either an error, or no error and success changing fText. But not no error and no action. So what's going on?
3) Next, I changed "of me" into 'of card "card1"', the value of me. Now doIt (from Button2) executes without error AND correctly modifies fText. This is what I want and expect in this case. Yet I would like to understand why the field needs to be specified with its card name and why "of me" fails to update the field.
I am new to LC, and therefore don't know if this behavior is to be expected and a mis-understanding on my part, or perhaps is a bug.
I am using LC 8 DP1.
Thanks for your help.
Doug
Re: Calling handler on a different card - help me understand
Posted: Tue Apr 07, 2015 9:26 pm
by Dixie
I think that you should read this article by Richard Gaskin on the message path...
http://www.fourthworld.com/embassy/arti ... _path.html
your problem outlined in your test stack is solved by...
put this into each of the buttons..
and call 'doit' from the stack script
Code: Select all
on doit
put the long time into fld 1 of card 1
end doit
Re: Calling handler on a different card - help me understand
Posted: Tue Apr 07, 2015 9:28 pm
by Simon
Code: Select all
put the long time into fld "fText" of cd "card1"
Simon
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 2:16 am
by Pomo
Thanks for the replies. But I was asking why does LC behave this way, what's its internal model and the intention behind it.
I'd already found the same workaround in experiment 3).
It's an unsatisfactory workaround because it requires uglying up my code by adding explicit card references to every object reference in every handler that might ever be called from outside the card that owns the handlers. That's thirty or so places. "of me" doesn't even work right, you have to use the name of the card. Change the name of the card someday, and all the scripts will have to be re-edited.
After more experimentation, I think I see what's happening. If you put a field "fText" on card2, the handler in card1 writes the time to it. So this is not a message path issue, but one of how LC switches the object context when send and call are used. Object references from card1's handler are resolving to objects on card2.
The docs are a bit muddled on these points, but I think that with send LC is supposed to switch to the context of the handler and evaluate object references in the handler within its context. From the docs of call:
"When executing a handler invoked by the call command the defaultStack remains the same as it was when the call command was issued. Therefore any object references in the called handler are evaluated in the context of the call command that invoked the handler. For example, button 3 may commonly refer to button 3 of the current card of the stack from which the target handler was called. This differs from the send command which temporarily changes the context so that object references are evaluated in the context of the object containing the target handler."
For send, LC is failing to do what is stated above. I sure hope this is a bug, because if it's intentional such design would be a major setback for localization and encapsulation. Plus, the whole "vibe" of LiveCode is that object references gracefully resolve within the context that contains them structurally.
The docs for send do state that the handler's stack and card temporarily become the defaults. However, they then go on to explain how references will be evaluated "in the message", never directly mentioning how references in the handler itself are evaluated. The docs for call are more clear on this point.
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 4:12 am
by FourthWorld
"Send" and "call' are useful, but they're like a canoe on a river - it's nice to be able to paddle upstream if that's what you need to do, but life is so much easier when you're floating downstream with the flow of the natural message path.
Maybe there's a way you could set up those objects so you don't need to add any "of me"s, or even use "send" at all....
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 9:27 am
by dave.kilroy
Hi Doug
Yes LiveCode can be confusing sometimes. Try using 'the target':
Code: Select all
on dolt
put the long time into fld "fText" of the target
end dolt
Edit: Just checked my own code and of course it failed!
Code: Select all
on dolt
put the target into tTarget
put the seconds into fld "fTime" of tTarget
end dolt
The reason it failed is (I think) that by the time it is evaluated in my first attempt it is already starting to change to reference fld "fTime" instead of the card - there are other fleeting and fast-changing entities in LiveCode such as 'it'. The solution is to capture it's value in a variable and then use the variable.
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 9:52 am
by Dixie
Dave..
Your second offering fails as well, since there is only one field into which the time is placed but there are multiple places 'doit' can be called from

Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 10:02 am
by dave.kilroy
@Dixie - interesting, my first attempt resolved ok but didn't populate the field but my second attempt works ok here... I have the dolt handler in the script of the card containing fld "fTime" and use 'send' from a button on a different card.
Edit: also, the target should resolve to the name of the containing script (the card) that receives the message
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 6:29 pm
by sritcp
Pomo wrote:........This differs from the send command which temporarily changes the context so that object references are evaluated in the context of the object containing the target handler."
For send, LC is failing to do what is stated above. I sure hope this is a bug, ..........
It certainly seems to be. If you add
Put the name of this card into msg
into the target handler, you can clearly see that the "current" card is the one containing the source handler, not the target handler.
Regards,
Sri.
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 7:25 pm
by Pomo
All,
I will go ahead and file a bug report on send failing to switch the context, and also on 'put the long time into fld "fText" of me' neither throwing an error nor setting anything. Let's see what the official developers want to do about it.
For my app, I have appended the equivalent of "...of card card1" to every object reference in any of card1's handlers that might be invoked from outside that card. Not pretty or portable, but it gets the job done for now. As for placing card1's handlers in the stack (those called from other cards), I would guess that the object references would necessarily have to be fully specified with "...of card card1". It may make the message path cleaner, but does not address the namespace problem.
Thanks for the replies.
Doug
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 7:27 pm
by jacque
Pomo wrote:
2) Next I tried adding "of me" to the field specifier, as in
put the long time into fld "fText" of me.
According to the debugger, me evaluates during the handler to 'card "card1"', just as I expect. However, even though the script executes without error, the field fText remains unchanged by the script. Here I'd expect either an error, or no error and success changing fText. But not no error and no action. So what's going on?
This works okay for me. The keyword "me" evaluates to the card reference and the field text changes. Could something else be resetting the field content by the time you go there to check? What happens if you remain on the originating card and put this into the message box:
Do you get a value back?
The dictionary says "When the send command is used the stack containing the target handler temporarily becomes the defaultStack. All object references in the message are evaluated in the current context i. e. the defaultStack. Therefore references within the message that refer to "this card" or "this stack" will be referring to the card or stack where the target handler is located."
Note that it says the defaultstack is changed, but not the default card. If the target is within the same stack as the "sending" handler, the defaultstack is the same as it was before. The card you are on is the same as it was before too -- "this card" is the one you're looking at, not the one you're sending to.
That's why you need a card reference in the receiving handler. Since "me" evaluates to the object running the handler, your "doIt" handler should resolve "me" to the card it is in. It does that here.
EDIT: I was testing in 6.7 where it works fine. I just tried in 7.0.4rc3 and it fails as you describe. So yes, a bug.
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 7:45 pm
by Pomo
Hi.
We agree that me should evaluate to the card with the doIt handler. It does in fact:
- In doIt: put the name of me into tMe
- place breakpoint after
- click Button2
- at he breakpoint, tMe is: card "card1"
The problem is that when
put the long time into fld "fText" of me
is executed next, there is no error and no change to fText on card1.
Also, "put fld fText of cd 1", from card2 messagebox gives the old, unchanged value of fText.
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 7:53 pm
by jacque
Right, it works in 6.7, fails in versions newer than that. So you were right there was a bug introduced in 7.x.
Re: Calling handler on a different card - help me understand
Posted: Wed Apr 08, 2015 8:15 pm
by dave.kilroy
just a quick note to say that the following still works and does populate the field on LC 7.0.4 rc3 (on Yosemite)
Code: Select all
on dolt
put the target into tTarget
put the seconds into fld "fTime" of tTarget
end dolt