When Globals are not Global

I’ve been encountering issues with getting Global variables recognized across databases.

As a test I created two new empty databases; Files A and B. This was to ensure there are no fields or other variables interfering. I Quit Panorama between numerous tests to also ensure there was nothing in memory carrying over from one sequence of opening the files to another.

I want A to be the source of the Global value but I need to avoid errors if B has been opened without A.

If A is opened first all seems to be well. If B is opened first, then A, GTest never shows as having a value in B.

info(“globalvariables”) sometimes shows it as existing in both databases, but only A shows it as having a value.

Of course there are various ways to create and define globals. I’ve tried a number of combinations without success but the approach I’ve used here should work.

Try checking info(“filevariables”) as well. It may be that a form object is creating a fileglobal with that name, and you’ve got a name conflict.

Good thought and it did bring up more info and did show a FileGlobal in FileB with the name of my Global. Even with FileB opening to nothing but the datasheet, subsequently opening the only form it lists the FileGlobal. GTest is set as the formula in a TextDisplay in order to show me the Global’s value but having been declared as a Global it should not cause a like-named FileGlobal.

I removed that TextDisplay and tried it all again. Same result. Same too if I made the initial value more than just empty.

There are no other forms, no other procedures and no other objects. This is a barebones file for the purpose of running this test.

I tried just FileA and it performed as I’d expect. The Global shows with it’s value and even with a TextDisplay, no FileGlobal is present. None.

Back to FileB, I changed Define GTest,“Whatever” to GTest = “Something”. Voila! Define is apparently the culprit here.

But I need FileB to open without overriding a value already in GTest, so I altered the .Initialize:

Global GTest
GTest = GTest
If Error GTest = "" EndIf

That works too.

Define is the issue.

The define statement will only set the value if it is not defined in any scope. In your case you have duplicate variables with the same name in different scopes, so define is not and cannot work as you intended.

You wound up with this code:

Global GTest
GTest = GTest
If Error GTest = "" EndIf

You say this works, but if there is a fileglobal variable named GTest, that is the variable being referenced in the second and third lines. You did create a global variable, but it still has no defined value. So I think this code actually isn’t working the way you intended.

Panorama X does allow you to create code that will assign a value to this global variable. In fact it can be done in a single line.

letglobal GTest = catcherror("",globalvalue("GTest"))

If there is a concern that there might be a fileglobal variable named GTest, as apparently there is in this case, you should only ever reference this global value with the globalvalue( function, never by just using the variable name. That way there is no possible ambiguity about what variable is being referenced. Any other variable (or field) with the same name will be ignored.

Here is a code example I created to show how two variables with the same name in different scopes can be used:

Here is the instrumentation output from running this code:

[Untitled/Procedure_F] testVariable: local
[Untitled/Procedure_F] fileglobalvalue("testVariable") --> fileglobal

If you have access to the Fields & Variables video course from 2015, I spent the better part of an hour discussing how different variable scopes interact.

The simplest way to deal with this is to avoid using global variables if at all possible, and if you do use them, give them really long descriptive names. If you are using global variables to hold preference values, consider using getpreferencevalue( and setpreferencevalues instead.

In his case, it appears to be the define statement itself that created the fileglobal, even though a global already existed.

I opened two new untitled databases, and wrote a procedure that declared a global variable, and then attempted to use a define statement to give it a value.

In Untitled, where the procedure was run, the variable exists and has a value. In Untitled 2, the variable exists, but does not have a value.

Exactly!

But I have not created duplicate variables. Panorama has done it and has done it in error. Define is not working as you intended.

My original pursuit was to create a global variable. I want a global so that a set of several databases have access to its value which may be changed on occasion. I don’t want to avoid using it.

GTest is a simple name, applied solely for the sake of running down the issue that none of those databases picking up the variable if they are opened before the database that sets the value. But the name is not the issue.

There is nothing, nothing , in my two little test files that should be creating a fileglobal of that name whether it’s a simple or a complex name. The only time such a variable comes into existence is if I use Define right on the heels of creating the global by that name.

Per the documentation on Define:

"This statement defines a value for a variable, unless that variable already has a value. In other words, this statement will initialize the variable if the variable’s value has not been defined yet, but if the variable already has a value it will not touch the value. (If the variable doesn’t exist at all, it is created as a fileglobal variable and given the specified value.)”

and

"The global statement creates one or more global variables.”

So in my code "Global GTest” creates a global variable named GTest. The global variable now exists but has no value unless it has been already created and defined elsewhere.

Since the variable now exists, Define should then be assigning a value to it, not creating a new Fileglobal.

Define is malfunctioning.

The documentation says:

If the variable doesn’t exist at all, it is created as a fileglobal variable and given the specified value.

This documentation is a bit ambigous. Currently, the define statement is treating a variable with no value as “not existing” even if it has been allocated with the global statement. This doesn’t really conflict with what the documentation says, it could be a valid interpretation. However, I think it is not really useful, and also I think it’s not how Panorama 6 worked. So I’ll agree, define is malfunctioning. I’ve fixed it for b22. If you can’t wait for that, you’ll have to use the technique I described above.

letglobal GTest = catcherror("",globalvalue("GTest"))

In B25 I’m continuing to have this same problem with both Define and CatchError(.

If the Global is created and given a value, databases that open after that point recognize it as having that value. Databases opened prior to it being given a value see it as being empty even after it has subsequently been given a value. They seem to be stuck on it being empty. Checking dbinfo( “filevariables”, the variable is not listed, so it hasn’t been given a mistaken attribute there. info(“globalvariables”) lists it once.

I can create a new database and without declaring the Global at all, have it recognize its existance and value. So it is a Global with a value. Yet any databases opened before it was assigned a value, never recognize it as anything but empty.

I stand corrected about CatchError(. It does prevent this issue. I found a Define that preceded it so it appeared that CatchError( was having the same issue.

In converting a large number of procedures in several databases from Pan 6 to Pan X, there are many such instances in which I need to discover and change Define.

You are correct. The fix made in b22 wasn’t correct. I just now made this test code:

global mytestvariable
define mytestvariable,"hello"
message scopes("mytestvariable")
message scopevalue("global","mytestvariable")

With b25, the first message statement should just display global, but instead it displays:

fileglobal
global

And the second message statement produces an error.

I found one incorrect symbol in the code for the define statement. I have now corrected this, and the test code works properly. The first message statement displays:

global

And the second one displays:

hello

If you can hang on, once b26 comes out you should no longer need to discover and change this code.

I will gladly hang on. :grinning: