Procedural/Function calls with results


#1

I know this is probably out of the scope of webC0RE but can you use a piston as a function call with a result? I know I can pass a $arg or set a Global variable and test that.
i.e. If execute piston(var) = result then do …
or If execute piston(boolean) then do …

I would like to call common subroutines cleanly and not execute pistons and check global variables if possible.


#2

It has been talked about before (a long time ago) and it didn’t really have any traction at the time. Webcore was still new and we were all in awe over the interface. Now that people have started creating more complex pistons than ever imagined it is certainly becoming more of a necessity.

So for now your only solution is to use the $args. There is an option to wait for piston completion. So your pistons can ask and wait for an answer then proceed afterwards.

Also go ahead and drop a request in #Meta:Feat-reqs to get the ball rolling.


#3

Thanks for the update.
I posted another question recently which relates to this and I assume the answer is NO.
Just because you wait for a piston to finish still doesn’t afford you the current answer in a global var it updates.


#4

Instead of using global variables you should just being sending arguments back and forth. The pistons have options to execute a piston and then wait for that piston to finish before the original caller answers back/finishes.


#5

Ok, sad to say example required. :frowning:
I know I can execute a piston with an arg as part of the add a task window but how do I receive a result from the called piston? Edit - I found examples to receive the arg - just don’t see how to send back the answer.
Basically I want to call a piston and have it return true/false as a result but I don’t see the mechanism to pass and receive.


#6

Give me some time. On my phone right now.


#7

From all that I have seen, you are correct that there is no way to read a result from any external variable change and continue where execution left off. That doesn’t mean it is impossible to make reusable functions, just inconvenient at this time. I believe the following would be possible though likely slow:

Consider pistons A, B, C, and Router, where B and C operate as functions. Router knows how to pass a result back to the piston that requested it.

When run with no arguments, A clears the value of its local variables resultB and resultC then executes piston B with whatever args are pertinent, including a caller id to let the Router know to dispatch the result back to A and a callee id to distinguish which result it’s getting back.

B operates on the provided arguments then passes the caller id, callee id, and result to the Router.

The Router has a switch statement mapping caller id to piston (because Execute Piston does not allow a variable piston id). It executes the original caller piston with two args: the callee ID and the result.

Piston A checks args on launch and sees the known callee id; it has been sent the result it requested from piston B. It stores the result to a local variable then calls piston C in the same way, with the same caller ID but a distinct callee id and whatever args C requires.

C gets its own result and sends it back to A via the Router.

A gets the result from C and now has all the data it needs to move forward and act on the two results.

I’m very curious to see how this would work in practice, will try in the morning. The problem space would have to be complex enough to justify all the boilerplate to share routines in this way and also resilient to the asynchronous flow that would result.


Execute a piston with arguments - Solved
Subroutine and Function call with results
#8

Here is a proof of concept. A piston logs a random string to the console a random number of times, where the string and repeat count are provided by pistons operating as reusable functions. Arguments are passed to the repeat count to restrict the range of the random number.

Our two functions randomString and randomNumber calculate a result and pass it to the Result router:

The piston that makes use of the functions:

The router that knows how to link a result back to the piston that requested a result from a function:

A few additional things to consider with this:

  • After importing these pistons you will need to fix the Execute piston statements to map to the correct piston
  • Variable naming for function arguments could be an issue, min and max are too generic and would prevent a piston using the function from making use of those variable names for other purposes. Easy workaround with alternate naming or a dedicate argument naming format like min__
  • You cannot use arguments to initialize const variables, leave them dynamic
  • $args.$null in the switch was needed to get the case where the argument is undefined; the expression null did not work because the value is actually undefined or not set. The name $args.$null is arbitrary, it just needs to be a value that will never actually be passed in as an argument.
  • Pure functions (i.e. just return a result with no external side effects) and the router should probably enable the piston setting Piston execution parallelism to avoid blocking when the function is executing for another purpose. However, the caller cannot use parallelism to guarantee that its local variables will be updated between each invocation.

#9

Any idea if you can use a list of devices as arguments? I tried this but doesn’t seem to work