Thank you for your post.
The "Install OnTimer Script" script step will call a script at a specified interval. When that interval occurs, the script executes. Since the parameter you are calling is a local variable, the executed script will not have access to that local variable. Therefore, change your script to use a global variable. Your initial script should appear as follows:
Set Variable [ $$variable ; Value: "Hello World" ]
Install OnTimer Script [ "A" ; Parameter: $$variable; Interval: 1 ]
Let me know if you need additional clarification.
I just found this response when searching after having the same problem. Your answer, TSGal, doesn't quite make sense, as local variables are never available outside of the scope of the currently running script, and the executed sub-script never has access to a local variable from the parent script, whether called by Install OnTimer Script or Perform Script.
If I run the script Main as seen below:
Set Variable [$x; Value: 1]
Perform Script ["sub"; Parameter $x]
Set Variable [$y; Value: Get ( ScriptParameter )]
The variable $y will have the value "1" as expected. The actual variable $x is not being passed and the subscript "Sub" does not have access to the variable $x. The parameter being passed is a calculation, and the result of the calculation (the number 1) is what (should be) is passed as a parameter.
It seems to be that there is just some funny behavior with how script parameters are evaluated in FileMaker. It looks like they are not evaluated at the time the script step Install OnTimer Script (or probably Perform Script either) is called with the result of the calculation passed as a parameter as one would expect them to be, but are instead evaluated at the time the subscript is run with the context of the parent script. Since the parent script no longer exists once the OnTimer script is actually run the variables do not exist.
This isn't a problem with using a local variable as a parameter within the general rules of how FileMaker works and programming works in general, but seems to be an odd behavior of how FileMaker actually calculates a script parameter. This is something that I believe should be considered a bug and addressed.
EDIT: I've done some additional testing and this is exactly how it works. A script parameter calculation is not evaluated until the subscript is actually run, at which point is evaluated from the context of the parent script. I tested this by running Install OnTimer Script with a delay of 10 seconds and a parameter which included a plugin function to create a folder on my desktop. This allowed me to see when the calculation was actually evaluated. In this example the folder was not created until 10 seconds after the Install OnTimer Script step was executed, at the time the OnTimer script was run, meaning the script parameter wasn't evaluated until the subscript was actually run.
This ends up being even weirder behavior if you use a field in your calculated parameter. The value of the field is not evaluated until the subscript is run, so you can call the script with a field with a specific value as a parameter, change the value of the field before the OnTimer script actually executes, and then see the new field value used in the subscript. Changing records, layouts, or editing a record can give you a different value for your script parameter from when you called it, which is totally incorrect behavior.
This is definitely unexpected, unfortunate behavior for both Perform Script and Install OnTimer Script and should be considered a bug.
What should happen: A calculated script parameter should be evaluated and the result of that calculation should be passed as a parameter.
What is actually happening: The entire, un-evaluated calculation is passed as a parameter. The calculated script parameter is not evaluated until the subscript is run. The subscript then evaluates the calculation from the context of the parent script.
EDIT 2: To clarify further, the script parameter isn't just a value that you're setting for the perform/ontimer script to evaluate at the time it is called (as that would be totally pointless). If this was the case you would never be able to use local variables from a parent script as a script parameter. FileMaker is actually "faking" evaluating the value at the time Perform Script or Install OnTimer Script is run by evaluating the parameter from the context of the parent script, but the delay with Install OnTimer Script makes this "faking" not work.
If I am understanding you correctly, which I may not be, I don't think there is a bug here.
On Timer scripts are different to regular scripts. They are somewhat asynchronous and therefore they do not have parent scripts. And they are installed rather than performed.
In practice this means that a script that is installed via the Install On Timer Script step will not launch until all other scripts in the stack have finished executing. This means that the script stack that exists when you run the Install On Timer Script step will definitely not exist when the script specified in the Install On Timer Script step runs. To put it another way, a script installed via the Install On Timer Script step is always a parent script and never a subscript.
If you want a static parameter that remains constant for the life of the On Timer Script, use a global variable, global field or record data that you are confident will be static for the life of the timer. If you want a dynamic parameter, use a calculation that evaluates the condition at run time.
Is there some other parameter scenario that isn't covered by the above?
On Timer scripts aren't any different than regular scripts and are not performed asynchronously from the script stack. If an OnTimer script would be triggered in the middle of execution of another script it waits until the completion of the script currently in progress to run.
You are correct, though, that it doesn't have a parent script like a script called with Perform Script would. The lack of a parent script shouldn't matter, though, as scripts don't have any knowledge of the script stack, their parent script, or their parent script's local variables.
...in the case of a script parameter. This is the really weird thing which I'm pointing out here. When a script parameter is passed the parameter's calculation is not evaluated until the child script is actually run. It is instead passed to the child script as an unevaluated calculation. When the child script is run, the parameter calculation is evaluated in the context of the parent script.
The script parameter calculation should be evaluated at the time the Perform Script or Install OnTimer Script script steps are executed and the result of that calculation should be the final value passed to the script being executed as the script parameter, but it isn't, which is weird.
This isn't just a problem for variables, but getting field values as well as they are not evaluated until the OnTimer/subscript is actually called. It makes passing a field value also impossible (since it won't be the same when it's actually evaluated) and the fact that there is a parameter not useful, as it gives you no more features than a regular script step within the script. Why pass a calculation as a parameter if it will give you the same thing as a script step within the script?
I've uploaded a sample file that demonstrates this unexpected behavior and the delay in evaluation which happens.
On Timer scripts aren't any different than regular scripts and are not performed asynchronously from the script stack.
I am fairly confident that this is not the case. The OnTimer script does not run until the entire script stack it is called from resolves. That includes subscripts called after the install On Timer Script step and parent scripts of the script that runs the Install On Timer Script step. You can see this behavior clearly in the Script Debugger, assuming you are using Pro Advanced. This is why all the variables are gone by the time the On Timer script starts and why the script parameter is not evaluated until after the stack has resolved. You have not "Performed" the On Timer script, you have just "Installed" it, which means you have indicated that you want it to run after the current script stack completes with the specified parameter evaluated at run time.
In any case, for the test file: If you want to see the id of the record you were looking at 2 seconds ago, just use a global as TSGal suggested earlier in the thread:
This uses the the state of the parameter calculation at installation time, rather than run time.
FileMaker scripting doesn't do anything asynchronously or in a multi-threading way (other than soooort of Perform Script On Server without "wait for completion" selected). OnTimer scripts aren't part of the same stack, as you said, and are executed afterwards, but if they were executed asynchronously they would be run "asynchronously," (at the same time) while another script is already in progress and could both be running at the same time, but in a different thread and wouldn't need to wait until the main stack. Instead, OnTimer scripts aren't run until after the currently running script stack is competed, which is the opposite of asynchronous as the script must wait for the first one to finish. We may just be having a programming terminology discussion here, which we don't need to do as it's clear we understand when OnTimer scripts are run.
I also understand the work-around for this, so there's not a problem with getting the desired end-result to work.
The issue being brought up here is that FileMaker handles script parameters in a very odd, unexpected way that doesn't seem match conventional programming's standard order of operations. This is really some odd FileMaker behavior rather than a bug that needs to be fixed, but it would make sense to change this behavior in a future version of FileMaker to more closely match how a software developer might expect a calculation to be evaluated.
Perhaps non-synchronus is a better term: the script specified in an on timer step does not get executed right away, and that is unusual for FileMaker. It was not clear that you had grasped that but now I see that you had.
I don't see how you could maintain FileMaker's scoping rules and change the behaviour as you suggest. Where would the literal value of the parameter be stored in the dead time between installation stack completing and the run stack starting?
The thing that what we're pointing out here is that this is a place where FileMaker currently ISN'T following its scoping rules. This is exactly what the problem is. If it followed the scoping rules this wouldn't be a problem here. A script being run, either by Perform Script or Install OnTimer Script shouldn't have any knowledge of any local variables outside of its scope (which is just the script itself), yet clearly it is depending on the script stack to evaluate the parameter. Parameters are being evaluated outside of a scripts normal scope, which is the problem.
I don't have the source code of FileMaker to suggest which blocks of memory the value should be stored in or which classes in the source code need to be edited, but the evaluated result of the script parameter calculation should be handled right along with the name (or ID or whatever) of the script that is being triggered after however many seconds.
What you are saying makes sense only if you are still holding on to the idea that Installing a script is the same as performing it. Saying you want to install a script is the same as saying:
1) After this script stack is finished, create an anonymous virtual button that is automatically present on all layouts visited in the current window
2) Assign a script to that button, with an optional parameter, just as you would with a regular button
3) Virtually press the virtual button as soon as the current script stack is finished* and repeatedly at the specified interval until the window is closed or the on timer is uninstalled
The optional parameter attached to the virtual button behaves just as a parameter attached to a regular button would, it evaluates at the time the button is "pressed". To bind that parameter to an install-time state you can use a global variable. I see no need to remove the dynamic behavior in this instance. On Timers add functionality. The change you suggest would limit this functionality.
*unless something in that script stack causes this window to close or the timer is uninstalled (via Install Timer with no script attached)
Installing the script is definitely not the same as performing it, but in either case I would expect the parameter to be evaluated before the script is run, not at the time it is run, and evaluated within the current scope.
Your description of how the Install OnTimer Script step works seems to be pretty accurate, and makes its behavior match the behavior of the Perform Script script step, which is good. Those two things should work pretty much the same way.
At the same time, it makes buttons with Perform Script seem to have a weird scope. If you run a script, put a pause in the script, and then click a button you can use a variable from your paused script as a parameter for your button. This seems odd to me, as I would expect the button not to have any knowledge or way of interacting with the paused script stack, yet it's able to access the scope of the paused script.
I think the way FileMaker handles scope is just a little different than I and some others may expect, and ends up explaining all of this behavior. Scope for a local variable isn't just within the script the local variable is defined in like you might find with a local variable in another programming language, but that local variable is available to lots of different things while the script it is defined in is the currently executing script in the script stack.
1 of 1 people found this helpful
I understand the issue you are referring to. I ran into this issue a couple weeks ago. A couple of thoughts:
1. A local variable can indeed exist outside of a script. Let statements in conditional formatting or hide calcs can set them. Though they are not available to the script to use.
2. Because the originating script completes before the OnTimer script starts, the value in the variable is cleared. The script passes the variable in a non-evaluated state, because the variable could change before the OnTimer script actually runs.
Set Variable [ $$var ; 1 ]
Install OnTimer Script [ "scriptName" ; parameter: $var ; Interval: .1 ]
Set Variable [ $$var ; 2 ]
Which value should it use in the OnTimer? FMI says 2. To go the other route and evaluate at the runtime of the step, well, that would seem to break a lot of other principles that function in FM. Typically, the evaluation of variables happens as they are needed. I wouldn't expect that behavior to change.
Yeah, local variables are a bit larger than just local to the script they're in, which is a bit odd when compared to other programming languages, but it explains everything being discussed in this thread.