How do I set individual return value from 2+ function calls?

Get help using Construct 2

Post » Thu Apr 06, 2017 10:05 am

I have a project with quite a lot of multitasking inside, with each task might call for specific function, or 2 tasks call for 1 function with different parameter(s), either manually called or automatically scheduled.

From what I have experienced, return value applies globally, meaning that whichever condition at the same tick request a return value, all will read the same value returned.

On my project, I have a "synchronize" group that call for a sync function at every set duration. The sync will send an AJAX request to a remote server so the syncing process took several ticks to complete (~10 ticks). At the same time, I have a "user interface" group that will call for a function whenever a user calls them (~5 ticks).

Short illustration of the sync group:
Code: Select all
every 300 tick {
   value = get_sync();
   [some actions...]
   end
}
get_sync() {
   var x;
   [some actions...]
   set return value to x;
}

Short illustration of the UI group:
Code: Select all
if ( button_a pressed ) {
   pin = get_auth(user_a);
   [some actions...]
   end
}
get_auth(var user) {
   var y;
   [some actions...]
   set return value to y;
}

The problem will occur if:
Code: Select all
@ 1670 tick: get_sync (supposed to end at 1680)
@ 1675: get_auth()
@ 1680: value = pin = [returned value from one of the function above]

Is there a way to differentiate a return value, to identify which function calls for it? Maybe like Function.ReturnValue("my_function")?
B
33
S
10
G
2
Posts: 46
Reputation: 3,063

Post » Thu Apr 06, 2017 12:05 pm

Rather than set a return value, can you set a variable (or push to array) directly? I was under the impression that return values in construct were mostly for interfacing with JavaScript directly, I've never really needed them.

After you have your values saved to data structure of choice, you have more control to schedule what the function object returns on any given tick.
Mistakes were made.
B
51
S
25
G
107
Posts: 1,581
Reputation: 60,458

Post » Thu Apr 06, 2017 1:12 pm

The var value and pin is a sort of global object (in json form). Generally speaking, I'm trying to avoid setting the value directly within the function as this will makes it harder for me to manage the modules (I've use that method before but now I'm trying to do it more object oriented).
B
33
S
10
G
2
Posts: 46
Reputation: 3,063

Post » Thu Apr 06, 2017 1:36 pm

With other asynchronous objects, there is always a trigger condition to use the returned value immediately. On the other hand, those usually support tags. I don't know if you'd be able to apply something like that for your own system. Maybe someone else more familiar with the topic can help, sorry.
Mistakes were made.
B
51
S
25
G
107
Posts: 1,581
Reputation: 60,458

Post » Thu Apr 06, 2017 5:58 pm

If i read you the right way, then the function is not the problem.

It should not be too. Because functions act as they are 'in place'. Replace the 'function call' with the contents of the 'on function' and nothing is changing. Read 'as in place'.

The problem is the way you use Ajax (educated gamble).

If this is what happens .....

On function (sync group)
____ Get ajax data
____ Set something to last Ajax data
____ Bunch of actions dealing with the data

On function (UI group)
____ Get ajax data
____ Set something to last Ajax data
____ Bunch of actions dealing with the data

Then... As you stated, getting Ajax data is not instantly. It takes time.
So, the last Ajax data are for sure not ready to use in the scope of this function call.
At some time, one of those functions is called again, and there will be data from some previous request data action.
From which request action is totally not known, and cant be known, that way.

It is obvious not the way to use Ajax. To avoid asynchronous blending, the Ajax requests are paired up with a tag.
To know which data are in the last data, and to know when the data are ready to use, you have the condition 'On completed (tag)'.
Or 'On any completed' , and the expression Ajax.tag is returning the tag.

I suggest to call the function, request data in the 'on function' with a tag "sync" or "UI".
Have a root event 'On any completed'
Have a sub with a compare 2 values. Compare Ajax.tag to "sync"
Set something to last data and do the stuff that belongs to "sync"
Use 'else' or a compare for "UI"
Set something to last data and do the stuff that belongs to "UI"

That would be the basic stuff. But now, those darn users could be multitasking. And you dont know which "UI" stuff belongs to which 'user call'.

Well, user needs to be identified. By example. Give each user an array. Give the array a instance variable with a value that is unique for that user, so you can pick it easy.

Now call the "UI" function with a parameter holding that user id.
Request Ajax data with a tag "UI"&"/"&user id

If you now use the 'On any completed' as a root.
then compare 2 values ... tokenat(Ajax.tag,0,"/") = "UI"
then pick array with instance variable 'id' = tokenat(Ajax.tag,1,"/")
____ store the last data in that array
____ do stuff with the data all you want
____ update the information to the user straight a head, or 'signal' the postponed action by a 'wait for signal' right after the function call made by the user

Hope that makes sense to you.
B
33
S
18
G
28
Posts: 2,493
Reputation: 20,950

Post » Thu Apr 06, 2017 6:38 pm

That 'signal thing' works this way.

User pressed button <--- root event
_____ request Ajax data with tag "user id"
_____ Wait for signal tag "user id" <----- actions that come after are postponed until the signal (WITH THE RIGHT TAG) is given
_____ display result to user
_____ delete dictionary key

Ajax > On any completed <----- root event
_____ do stuff with the last data, store the result in a dictionary with key "user id" and value result
_____ signal with tag "user id" <---- run the postponed actions
B
33
S
18
G
28
Posts: 2,493
Reputation: 20,950

Post » Fri Apr 07, 2017 5:31 am

Thank you for your suggestion but the problem is not on the AJAX. I use AJAX a lot too and all already using its own on 'tag' completed. I never use AJAX on any completed. I've also been using a lot of signaling, so far so good.

I've boiled down my problem and I think the problem is because the return value is only available after some ticks, so the caller already "expired", thus the return value is not returned to the right caller. So this probably is because of my method, not what I originally thought that return value applies to all functions globally.

I run some test with 2 methods, a main body which call for 2 functions, and the function A and B itself, each wait for 1 second before returning the value (simulating this function requires some ticks to complete). Here's what I tried:

Code: Select all
-----FUNCTION A (NOT WORKING)-----
function run_A {
   wait 1.0 second
   set return value to "result of A"
}

-----FUNCTION B (WORKING)-----
function run_B {
   set return value to "result of B"
}

void main() {
   on button clicked {
      set var A to Function.Call("run_A");
      set var B to Function.Call("run_B");
   }
}


Result:
Code: Select all
A = 0
B = "result of B"


I'm guessing that on my project, because both functions takes some ticks to complete, the return value isn't received by the caller. So my question is, how can I return a value that is not available at an instant or should I use other method than return value (static var and signaling perhaps)?
B
33
S
10
G
2
Posts: 46
Reputation: 3,063

Post » Fri Apr 07, 2017 9:26 am

Out of scope it cant return a value. The wait brings things out of scope.

If its not a Ajax request, then what else would take time to complete inside the function ?
B
33
S
18
G
28
Posts: 2,493
Reputation: 20,950

Post » Fri Apr 07, 2017 11:08 am

There are a couple of calculations and draw calls which need to be run sequentially. It use either wait for signal or wait 0 second (next tick) before running. Let's say it is possible to run things without waiting at all, but this will require whole lots of sub-events and it's going to be hard to manage (calling sub functions etc). Any suggestion to workaround this?

Another thing that I want is to make a function, for example, to request a user input a pin number, then return the result 1/0 (success/failed) to the caller. Surely waiting for user input require a lot of ticks. Can this be done?
B
33
S
10
G
2
Posts: 46
Reputation: 3,063

Post » Fri Apr 07, 2017 12:55 pm

Wait 0 = happens at the end of the tick that ran that wait.

Any wait/delay escapes the scope of the function. Cant start a start time consuming task and return the result of it inside the same function. Unless you prolong the tick.

A time consuming loop stays in the function. The tick just gets longer.
But you can not use triggers inside a loop.
And when the loop is running it will not (multitask) do anything else.

So pretty useless for you. I think (but i am not the smartest) that you need another way.
B
33
S
18
G
28
Posts: 2,493
Reputation: 20,950


Return to How do I....?

Who is online

Users browsing this forum: Anonnymitet, jorgmaquoi, Yahoo [Bot] and 6 guests