Strategies for avoiding the use of global variables

Having been much criticised for my frequent use of global variables, I am anxious to mend my ways and become a responsible Panorama X citizen but I can’t see how to do that with my current project.

In my nascent farm management system, comprising about ten databases, I have a master database, A, which, in its .Init procedure, opens several others, extracts data from them and stores it in four or five data dictionaries. These dictionaries are accessed in a multitude of procedures in several other databases and in the Object Inspector panels of a heap of forms.

Declaring the dictionaries as global variables is the simple and foolproof approach. How else might I handle it?

Michael, you have my vote. Making dictionary contents available to a number of files is about the only way I use a global now.

David

For being hooked on global variables, can’t we blame Jim? Back at the dawn of time Panorama had no variables, then Jim introduced local and global variables, just the two. From memory it was some more years before fileglobals made their appearance, and following that some more years, wasn’t it, before grabfilevariable( came along to make fileglobals accessible from other databases?

We became addicted to globals long before we realised they were so bad for us.

Sure, blame me if you want. Though I believe fileglobal variables appeared a the same time as global variables. Otherwise, your chronology is more or less correct, I think. By the way, Panorama X now includes the setfilevariable statement, which makes it much easier to manipulate variables in the non-current database. Panorama X also adds the capability to set and get preference values – basically this gives a “blessed” way to implement permanent global values. Panorama X uses the same “official” preference value system that OS X uses, so when you use this system you are using the same system used by Apple and most other programs. I would recommend that you use a unique prefix for any preferences you save, for example Panorama X itself uses the PX prefix. That way any preferences you create won’t conflict with Panorama or any other Panorama database someone might happen to load on their system. Maybe someone will load both your database and a database from Gary Yonaites, for example.

Global variables can work fine if your application is small, but as things get more complex, they can turn into a nightmare. When everything has global scope, it’s super easy to wind up with unintended conflicts. And when a conflict does occur, it can be very difficult to track down, and can cause intermittent problems. There are some techniques for mitigating that, like using very long variable names with an organized naming scheme. So at a minimum, I urge you to do that.

There are a number of places in the Panorama libraries where using global variables would definitely have been more convenient. For example, all of the dialogs Panorama displays (Find/Select, Sort, etc.) use a form in a different database than the target database. Using global variables would have made it much easier to set up and get information out of these dialogs. Instead, I use only fileglobal (or sometimes windowglobal) variables and use the fileglobalvalue( function to extract information from the other database. This took quite a bit of extra typing but eliminates any possibility of conflict with the user’s databases (or code and formulas in the users datababses).

I think you must be talking about criticism from me. The context for that has generally been code that was proposed for inclusion in Panorama’s libraries. Use of global variables in Panorama’s libraries is a definite no-no with me. After all, that is a case where it is guaranteed that this code will be sharing the variable space with any code that any user writes.

In your own code, perhaps it’s not necessary to be so strict. I believe you can be a “responsible citizen” and use global variables. But doing so responsibly takes extra discipline. I believe that Panorama X has all the tools needed to completely avoid global variables if you want, and I think that is good practice. But if you feel the need to use global variables, don’t beat yourself up – just be careful.

Panorama 2 had local and global variables but no fileglobal variables.

This is a great feature. Thank you for your mini tutorial, for me another great Panorama moment.

I’m clearly missing something here - this seems to me to be exactly what I should do if I use global variables. If preferences can interfere with other databases, how are they an improvement on globals?

I have a vague memory that global variables may be lost when installing a new version of Panorama. Is that correct? If so, that would provide an excellent reason to use preferences. (Edit, I think I am confusing ‘permanent’ variables potentially being lost, not global variables.)

I also think, but am not sure, that preferences are stored in the user’s account, so two different users with their own accounts on the computer could have different values for preferences used by Panorama. (In fact, I use preferences to store user information, which I retrieve when I open a database.) That provides some flexibility in using preferences. (Edit: and preferences persist when you quit Panorama, like a permanent variable does/should.)

For one thing you can list all the preferences in use with info("preferences"),

For me the disadvantage with using global variables to contain dictionaries is that every file that uses them has to check when it opens that the variables exist, and if they don’t it has to go about having them created. Storing the dictionary as a preference value outside Panorama means that it will always be available, even when Panorama first launches.

If you are referring to so-called preference domains, Jim says they use an API which has been deprecated by Apple and not replaced, although they are still working in the latest OS release.

I don’t know what a preference “domain” is. I am referring to preferences the way Jim used it above: “Panorama X uses the same “official” preference value system that OS X uses, so when you use this system you are using the same system used by Apple and most other programs.” I hope that has not been deprecated and would not use it if it were.

I haven’t tried it yet but I suspect that the setfilevariable statement might be the best solution. The general purpose of a global variable is to convey a value from one database to another and the setfilevariable statement does just that with no unwanted side effects.

Jim was referring to preference domains, not preferences.

Preference domains are basically identifiers for all frameworks and applications that have stored preferences on a computer.

David, thanks for the information.

I think I was correct above when referring to preferences. One can store information in a preference by using the setpreferencevalues statement. That value can even be binary. It is stored outside of Panorama files. It would be accessible to any database opened in the same Macintosh user account. It seems to me that you could use these preferences instead of a global variable if you wanted, although Jim has already suggested better solutions for Michael’s issue.

Some day I will be using the files in a server environment. In that case each user can store pieces of data. In one case, the individual user’s name, initials, and email are stored. I could imagine other uses, like preferred window locations. I don’t know if there are practical limits of the size of what is stored and have only stored very small pieces of data.

Since preference domains have come up, let me explain them a bit. Every application has it’s own preference domain – this is what allows different applications to have it’s own preference settings. So Panorama X has a domain, Word has a domain, Keynote has a domain, etc. This allows different applications to have the same preference without interfering with each other. For example, two or more different applications could have a preference named Spot. Let’s say that Panorama and Keynote both have a Spot preference. The Spot preference could be different for these two programs – it could even have a different meaning.

Preference domains are not deprecated. However, Apple has an API that returns a list of all of the preference domains that exist on the computer – in other words, all of the applications that have saved preferences. It is this API that is deprecated, with no replacement. So at the moment, there is no official way to get a list of all of the preferences domains that exist on your computer. However, that probably isn’t very important, in Panorama there is really no reason you need to know this list. In fact, in general you don’t need to use any domain other than the Panorama X domain. Panorama has functions that allow you to read (but not modify) preferences from other applications, but why would you ever do that? In general there would be no reason why a Panorama database would care what a Keynote preference was set to, for example.

By the way, if you have multiple user accounts on your computer, each user has it’s own set of preference domains. So if someone and their wife share a computer, and have different accounts on that computer, when they log off and then log on with the other user, a whole new set of preferences kicks in.

There also seems to be some conflation of preferences vs. global variables. Preferences are more like a special type of file – you can read from them and write to them. Unlike regular files, you don’t know where the data is kept on the file system, and they are different for each user account (if a computer has multiple user accounts).