Panorama allows a programmer to set up multiple “global dictionaries”. These are similar to Data Dictionaries stored in global variables, but are much faster because these global dictionaries are not converted to/from binary data each time they are modified, they are simply kept full time in the internal dictionary format. So if you need to frequently access or modify a large dictionary (hundreds of items or more), a global dictionary can give you much improved performance. Note: If needed, you can use the getglobaldictionary( function to convert a global dictionary into a regular data dictionary, and use this statement to convert a regular data dictionary into a global dictionary.

A global dictionary is set up automatically whenever you use the setglobaldictionaryvalues statement to set a value in the dictionary. This example sets up a global dictionary with three values: Color, Scale and Size.

setglobaldictionaryvalues "MyValues","Color","Violet","Scale",80,"Size","Large"

Later, you can use the globaldictionaryvalue( function to retrieve any of these values, for example the scale.

globaldictionaryvalue("MyValues","Scale") ☞ 80

If you need to change the scale value, you can do so at any time with another setglobaldictionaryvalues statement, like this:

setglobaldictionaryvalues "MyValues","Scale",45

This will change the scale value while leaving the color and size (and any other values) alone.

Global Dictionaries vs. Regular Data Dictionaries

You may have noticed that global dictionaries are similar to regular Data Dictionaries, so why the extra complication? Normally there is no reason, you should just stick with ordinary Data Dictionaries, for example, the previous example could be set up like this:

letglobal MyValues = initializedictionary("Color","Violet","Scale",80,"Size","Large")

and then access the contents of regular dictionary like this:

getdictionaryvalue(MyValues,"Scale") ☞ 80

The reason you might want to choose to use a global dictionary in some situations is performance. Global dictionaries use a special internal data format that is very fast, but is not compatible with the data format used by regular Panorama variables. In our tests global dictionaries are at least twice as fast as regular dictionaries, and if an application is frequently modifying values, at least ten times as fast, and possibly even many times faster than that. So if you have a task that does a lot of access and/or modification of a dictionary, it is worth a bit of extra trouble to use a global dictionary instead of a regular dictionary in a variable. If needed, you may even want to convert a regular dictionary to a global dictionary (see below), perform the time intensive task, and then convert back to a regular data dictionary again at the end (with the getglobaldictionary( function).

Converting Between Global Dictionaries and Regular Data Dictionaries

Use the setglobaldictionaryvalues statement to convert a regular data dictionary into a global dictionary. When used this way the first parameter is the global dictionary name (as normal), and the second parameter is the data dictionary you want to convert. For example, this code creates a data dictionary named temp, then converts that into a global dictionary named Order.

let temp = jsonimport(||| {"Name" : "Jack", "Color" : "Blue", "Size" : 38} |||)
setglobaldictionary "Order",temp

Later you could use the getglobaldictionary( function to convert this global dictionary back into a data dictionary, and then into JSON.

let revisedOrder = getglobaldictionary("Order")
let orderJson = jsonexport(revisedOrder)

You would also use the getglobaldictionary( function to convert the global dictionary into a permanent variable, so that it could be saved.

letpermanent mostRecentOrder = getglobaldictionary("Order")

If you wanted to restore the global variable the next time the database opens, use this code in the .Initialize procedure:

setglobaldictionary "Order",mostRecentOrder

Deleting Global Dictonaries and Dictionary Values

Normally Panorama keeps a global dictionary until you quit Panorama. If you need to remove an entire global dictionary, use the deleteglobaldictionaryvalues statement.

deleteglobaldictionaryvalues "Order"

You can also use this statement to delete an individual value from a dictionary, like this:

deleteglobaldictionaryvalues "Order","Color"

Or, you can delete several values at once, simply list each one.

deleteglobaldictionaryvalues "Order","Name","Color","Price"

Finally, you can clear a global dictionary (remove all of the values) without actually deleting the dictionary itself. This leaves an empty dictionary.

clearglobaldictionaryvalues "Order"

Listing the Contents of a Global Dictionary

To get a list of all the global dictionaries that currently exist, use the globaldictionarykeys( function. If this function is used with no parameters, it will list all of the dictionaries.

globaldictionarykeys() ☞ list of all global dictionaries

If you supply one parameter, it will list all of the values in the specified dictionary. Please note that the values may be listed in any order, you cannot control the order.

commalist(globaldictionarykeys("Order"),cr()) ☞ Name, Color and Size

If you want to list the contents of a global dictionary, use the getglobaldictionary( function to convert it to a regular data dictionary, then use the dumpdictionary( function to list the contents, like this:

dumpdictionary(getglobaldictionary("Order"))

This will list all of the keys and values in the Order dictionary.

Name Scope and Conflicts

In spite of the similar nomenclature, global dictionaries have nothing to do with global variables. They are completely separate, and you can create both a global variable and a global dictionary with the same name.

letglobal MyValue = "hello"
setglobaldictionaryvalue "MyValue","Color","Blue"

If you run the code above, you will now have two separate independent entities, a global variable named MyValue, and a separate global dictionary also named MyValue. This could be very confusing, so we recommend that you avoid using the same name for a global variable and a global dictionary, but Panorama will not stop you from doing this.

Since global dictionaries are global, they are shared among all databases. This means you need to take care that different databases and procedures don’t accidentally use the same name. The examples on this page used short names like MyValue and Order, but you want to avoid short names like that, and use long names that will avoid conflict, like OrderEntryPriceInfo.

Building a Global Dictionary from a Database

The globaldictionarybuild statement builds a global dictionary by scanning an open database. It’s similar to the arraybuild statement, but builds a global dictionary instead of an array.

The primary purpose of this statement is that once the global dictionary is built, you can look up values in it with the globaldictionaryvalue( function. Because global dictionaries use a structure that is very efficient for searching, lookups performed this way can be hundreds of times faster than looking up directly from the database with the lookup( function. However, this speed increase is only practical if you plan to do many lookups without ever modifying the data. If you just plan to do a single lookup, or if the data is modified frequently (every time the data is modified you would have to use the globaldictionarybuild statement again), just using a regular lookup( statement is better.

For example, suppose you have a database named Contacts that contains names and email addresses. You can build a global dictionary with this information with a single line of code:

globaldictionarybuild "ContactEmails","Contacts",Name,Email

Now suppose you have another database that also contains names and email addresses, and you wish to update the email addresses with the email addresses from the Contacts database. This database has fields named FullName and E-mail. This code will fill the E-mail field with the latest email addresses gleaned from the Contacts database.

field "E-mail"
formulafill catcherror(«E-mail»,globaldictionaryvalue("ContactEmails",FullName))

We tested this code on two databases with 20,000 records of data, the entire process (first building the global dictionary and then doing the formula fill) took about 3 seconds. We then tried this same operation using the lookup( function, like this:

field "E-mail"
formulafill lookup("Contacts",Name,FullName,Email,«E-mail»)

With the same 20,000 record databases, this operation took almost 7 minutes! Using globaldictionarybuild was 134 times faster. In our tests, the speed difference was larger as the databases got larger.

If you are considering using globaldictionarybuild with formulafill, however, you should probably take a close look at the join statement. Using the join statement, you can update the email addresses with a single line of code.

join "Database","Contacts","Key","Name","SourceKey","FullName","«E-mail»",{Email}

The join statement uses the same high performance internal structure used by global dictionaries, so the perfomance is also very fast – about 3 seconds for our 20,000 record test databases.


See Also


History

VersionStatusNotes
10.2NewNew in this version.