Calling handler on a different card - help me understand

LiveCode is the premier environment for creating multi-platform solutions for all major operating systems - Windows, Mac OS X, Linux, the Web, Server environments and Mobile platforms. Brand new to LiveCode? Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
Pomo
Posts: 11
Joined: Tue Mar 31, 2015 7:50 pm

Calling handler on a different card - help me understand

Post by Pomo » Tue Apr 07, 2015 9:05 pm

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
Attachments
tester1.livecode.zip
(1.1 KiB) Downloaded 235 times

Dixie
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 1336
Joined: Sun Jul 12, 2009 10:53 am

Re: Calling handler on a different card - help me understand

Post by Dixie » Tue Apr 07, 2015 9:26 pm

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..

Code: Select all

on mouseUp
   doit
end mouseUp
and call 'doit' from the stack script

Code: Select all

on doit
   put the long time into fld 1 of card 1
end doit

Simon
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3901
Joined: Sat Mar 24, 2007 2:54 am

Re: Calling handler on a different card - help me understand

Post by Simon » Tue Apr 07, 2015 9:28 pm

Code: Select all

   put the long time into fld "fText" of cd "card1"
Simon
I used to be a newbie but then I learned how to spell teh correctly and now I'm a noob!

Pomo
Posts: 11
Joined: Tue Mar 31, 2015 7:50 pm

Re: Calling handler on a different card - help me understand

Post by Pomo » Wed Apr 08, 2015 2:16 am

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.

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

Re: Calling handler on a different card - help me understand

Post by FourthWorld » Wed Apr 08, 2015 4:12 am

"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....
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

dave.kilroy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 858
Joined: Wed Jun 24, 2009 1:17 pm
Contact:

Re: Calling handler on a different card - help me understand

Post by dave.kilroy » Wed Apr 08, 2015 9:27 am

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.
"...this is not the code you are looking for..."

Dixie
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 1336
Joined: Sun Jul 12, 2009 10:53 am

Re: Calling handler on a different card - help me understand

Post by Dixie » Wed Apr 08, 2015 9:52 am

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 :x

dave.kilroy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 858
Joined: Wed Jun 24, 2009 1:17 pm
Contact:

Re: Calling handler on a different card - help me understand

Post by dave.kilroy » Wed Apr 08, 2015 10:02 am

@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
"...this is not the code you are looking for..."

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: Calling handler on a different card - help me understand

Post by sritcp » Wed Apr 08, 2015 6:29 pm

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.

Pomo
Posts: 11
Joined: Tue Mar 31, 2015 7:50 pm

Re: Calling handler on a different card - help me understand

Post by Pomo » Wed Apr 08, 2015 7:25 pm

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

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: Calling handler on a different card - help me understand

Post by jacque » Wed Apr 08, 2015 7:27 pm

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:

Code: Select all

put fld fText of cd 1
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.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Pomo
Posts: 11
Joined: Tue Mar 31, 2015 7:50 pm

Re: Calling handler on a different card - help me understand

Post by Pomo » Wed Apr 08, 2015 7:45 pm

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.

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: Calling handler on a different card - help me understand

Post by jacque » Wed Apr 08, 2015 7:53 pm

Right, it works in 6.7, fails in versions newer than that. So you were right there was a bug introduced in 7.x.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

dave.kilroy
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 858
Joined: Wed Jun 24, 2009 1:17 pm
Contact:

Re: Calling handler on a different card - help me understand

Post by dave.kilroy » Wed Apr 08, 2015 8:15 pm

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
"...this is not the code you are looking for..."

Post Reply