Local variables defined in layout objects live long and travel widely

The FileMaker documentation says:

When you define a variable, you can specify its scope by adding a prefix before the variable name.

Scope Prefix Example Availability
function None variableName Only within the function where it is defined
local $ $variableName Only within the script where it is defined (not available to sub-scripts); cleared when the script ends
global $$ $variableName Anywhere within the file where it is defined; cleared when the file is closed

For local (single dollar prefix) variables it seems clear that they are only available within the script and cleared when the script ends. That is true for scripts, but variables can be used wherever we can utilise a calculation. That means the layout is full of opportunities to create and display variables.

This is covered in part by the discussion of merge variables on layouts. However this document doesn't discuss variable scope, beyond saying It’s a good idea to create global variables for use as merge variables.

As it turns out, the scope of a local variable can be much greater than you might imagine and it can live much longer than you expect.

I'm attaching a file which declares local variables on one layout that can then be used throughout every other layout in the file. The file is rough, it isn't complete and there may be more to discover, but it shows that a local variable declared in a layout object can behave much more like a global variable.

Retaining_local_Variables.fmp12.zip (89.3 KB)

6 Likes

"local" just means locally scoped to the area defined. In the case of scripts the scope is the script. In the case of a calculation the scope is the calculation, and so on. As you've shown there are other "scopes" that are available such as the design layer.

I feel like the FileMaker documentation needs a bit of an update in regards to the usage of local variables as FileMaker suggests they only can be defined and used in scripts which is incorrect.

6 Likes

And a local variable declared in any calculation (like conditional formatting, etc.) can be picked up by a running script.

5 Likes

The real issue here is that $variables contain a value, but are not visible in in the 'current' tab of the dataviewer.

These invisible $variables are simply created by declaring with let-function the in the calculation for a scriptparameter on a button. Another way to create such an astray-$variable is with a tooltip.

According to MrWatson these variables were visible in the current-tab of the dataviewer in an ETS-version (FM8?) but due to confusion are taken out.

Imho this is a major bug, because in this way a local $variable actually behaves the as a very persistant global $$variable.

You can open een new window or got to a different layout, the $variable keeps its value. You can NOT clear it with a script, nor can you assign another value. But you can also not use the value of the variable in a script. Only in another layoutobject you will be able to do something with it

The only way you can change this variable is to either use the exact same method you used to create it, see the attachment:

Retaining_tooltip_Variables.zip (86.7 KB)

1 Like

This is an undocumented feature issue.

The FileMaker documentation says a $ variable is a local variable. It goes on to say that $ variables are only available within scripts and that scripts automatically clear them when they end. It implies they can only be created within scripts. Believe it or not, this implied meaning is true.

@Malcolm's file defines $ variables in a hide object calculation within a button object in the Settings layout. What, in your opinion, is the scope of the $ variable? The button object? The layout? The file? A script, as implied by FileMaker's documentation?

It isn't the button object because the $ variable resolves in other layouts. It isn't the layout for the same reason. It isn't the file as that would put both $ variables and $$ variables in the same scope and introduce a world of naming conflicts. If a script, then what script?

I heard many years ago during a SOFA (Southern Ontario FileMaker Association) meeting that there is a "script" that runs continuously as a sort of top-level script when no script is running. This "script", or whatever feature this truly is, is the scope for all the $ variables that were defined outside of scripts. Each file has its own "script". It starts when the file opens and ends when the file closes. You can't access this "script" directly.

The FileMaker documentation doesn't document this "script". This requires us to guess, devine or infer what happens to $ variables defined outside of scripts and how they behave. This is poor technical writing that, in my opinion, needs revision.

Hope this helps.

3 Likes

What that means is since it is not documented, it may go away any time. And if someone uses that hidden feature, things may go wrong unexpectedly :worried:.

Should that be documented ? Damn if Claris does, damn if Claris don't.

The feature that may go away at any time is already being used. As it stands, developers are defining $ variables outside scripts left, right and centre and FileMaker Pro allows it. Nothing prevents FileMaker from changing the feature in a future release and giving guidance to developers to adapt existing solutions if needed.

I suggest Thesoup has a place where those kind of undocumented features ... are documented !

1 Like

I asked Claris about using this feature of local variables some time ago and I was told that it's unlikely to change. However, anyone who wanted to take advantage of this feature has to be aware that it is undocumented, and that Claris recommends the use of Global variables.

In my experiments I've bumped into numerous issues.

  • They may not be accessible in other layouts
    • It may require user interaction with the layout that defines the variables - but I do not know exactly what interaction is the trigger.
    • It may require scripted interaction with the layout that defines the variables - but I do not know exactly what interaction is the trigger.
  • They may be used by local variables in other objects.
    • A collision may cause a variable to be populated when it shouldn't be
    • or cause it to have the wrong value
  • They may be overwritten by local variables in other objects
    • This could cause the new data to bleed out into the layout
    • when the scope of the object closes, the local variable could retain the new value, or be undefined.
  • They are unreliable in other scopes. In one experiment I wrote a script that copied the local variable $A (defined in a layout object) into a new local variable $B (defined in the script). I used both local variables in a custom dialog. A custom dialog was able to display $A but $B was empty.

I've found that they are handy for use within a layout for dynamic content. @menno's warning has to be observed. If they are used for layout elements, it may be necessary to destroy them on leaving the layout or explicitly create/destroy them on entering a record.

1 Like

I have prepared a little file that demonstrates the scope of layout-variables, so you can see for yourself and decide what you'd like to do with it.

In a nutshell: the scope of these layout-variables actually is only the layout-level of a file.

  1. You can not use a layout-variable in a script, you have to transport it explicitly to a script with a script-parameter calling the script with a button.
  2. It is not possible to alter any layout-variable from a script.
  3. In script-parameters you can put the result of a calculation on/with a layout-variable and use that in your script.
  4. Pointing at •2 in this list: you can, for the scope of your script use a variable(name) which is also an existing layout-variable(name) or vice-versa. They will not influence/overwrite one another outside their own scope.

Problems occur when the watch-tab of the dataviewer is used..... If a variable-name is created and used in both the layout and the script: at which value are you then looking?
For the duration of a script running, it is the value of the script and as soon as the script is done, the layout-value appears .... I experienced that to be very tricky and indeed confusing.

I have a few cases where I have used $variables in the calculations of script-parameters on buttons and in tooltips. That was not delibarate, but just happened by transfering a calculation after testing in the dataviewer to a button or a tooltip.

I never expected this practice to become a problem, but since quite some time I sometimes noticed astray variables in my dataviewer an now i finally understand why and how they are created. I will start looking for the instances I have used layout-variables where there's no need for them and "clean house".

The discussions here and in the FM-community have helped me a lot to better understand what is happening.

Scope_of_Layoutvariables.zip (88.5 KB)

3 Likes

Regarding layout variables not being readable within a script:

I have seen cases where a layout object calculation called a custom function that set a $variable. That layout was visible while a script was running. The script tried to set the same $variable, which did not change the $variable value. The script then used $variable and received the value set by the custom function called from the layout object, resulting in unexpected behavior in the script.
So, it IS possible for a script to read the value of a $variable set by a layout object, at least if done indirectly by the layout object calling a custom function. I think it is also readable if there is a Let statement directly in a layout object calc, but don’t recall whether I’ve tested that.

Moral of the story: if you are going to set $variables in custom functions, make very sure you choose non-generic names for those variables.

2 Likes

I've got a file that contradicts you on points 1, 2 and 4.

It's a bit hard to ascertain the full extent of the problem but my conclusion is that local variables in the layout can collide with local variables in scripts.

I've recorded an example, which I cannot post here. It exceeds the 10MB limit on content so I'll upload it to the web and post a link.

Here's a link to a video that walks through the issues. At 10 min it may be a bit long - probably best to play it at 2x

there is no need to use $localVars in custom functions - it is bad design ..
EDIT: or let's say "dangerous" exceptions for military use only

Hi Malcolm, for some unknown reason I can't access your video.

Same thing for me. I right clicked, copied the address of the video to clipboard and copied it to a new tab. I was told that (translated from French:

This page in not available for the moment
businessdatasystems.co.nz can't handle the request at this moment
HTTP ERROR 500

This feels like poor coding practices - more obfuscation of content that is not likely a good practice.

You can do extreme things like creating an off-screen right, text box containing the LET statement calculation, with a hide condition, so that the LET statement is evaluated on layout open. It works, but it certainly does not feel like a manageable element. Future self will likely be very upset with current self for doing things like this (technical debt)

Technical Debt is a serious concern in long term (or even short term) development/maintenance

2 Likes

It is poor coding practice because we now know since only recently that:
using a let-statement in a layout-tooltip where a $variable gets a value assigned, that $variable lives a lot longer than just the duration of the calculation.
The same statement is valid for creating a script-parameter for a layout-button iwith the same method.

The documentation from Claris/FileMaker is incomplete at this point. I understand that it maybe hard to for them to correctly explain. The same as we have here in the discussion, we all (in any case I do) need a lot of words to exactly descibe what's going on. It certainly does not mean that any of us is propagating the use of a technique like this, it is more of an advocacy against it.

This discussion is not about telling how foolish the appliance of a technique is, that ship has sailed. It's about warning one another what may happen if you just make assumptions, like I did: I assumed that "on a layout-object" a $variable would only exist or live during the runtime of the calculation that creates it and that turned out to be a totally incorrect assumption.

TFM doesn't say one character about it, so it was discovered by some of us (myself, Malcolm and others) to be a hard to recognize problem. Most of the time it even doesn't cause any problem, only in very speciific circumstances you'll bump into it. Since it isn't descibed by the manual, a lot of trail and error comes into play to determine what really goes on. On top of this we do not agree on all perimeters of this problem .... yet

2 Likes

If that is so… then the documentation should say so.

Is it a design flaw or a lack of documentation?

Please try again. I saw a glitch myself but after uploading a second time I thought it was ok. My web service may not be responding quickly enough. I may need to move the video to YouTube.

I've pushed the video onto YouTube. The URL above is still good, and now that YouTube is hosting the content, it's being streamed properly.