3. Resolving Names and Sharing Objects

Previous chapter

Next chapter

This chapter describes how GemStone Smalltalk finds the objects to which your programs refer and explains how you can arrange to share (or not to share) objects with other GemStone users.

Sharing Objects
explains how GemStone Smalltalk allows users to share objects of any kind.

UserProfile and Session-Based Symbol Lists
describes the mechanism that the GemStone Smalltalk compiler uses to find objects referred to in your programs.

Using Your Symbol Dictionaries
discusses how you can enable other users of your application to share information.

3.1 Sharing Objects

GemStone Smalltalk permits concurrent access by many users to the same data objects. For example, all GemStone Smalltalk programmers can make references to the kernel class Object. These references point directly to the single class Object—not to copies of Object.

GemStone allows shared access to objects without regard for whether those objects are files, scalar variables, or collections representing entire databases. This ability to share data facilitates the development of multi-user applications.

To find the object referred to by a variable, GemStone follows a well-defined search path:

1. The local variable definitions: temporary variables and arguments.

2. Those variables defined by the class of the current method definition: instance, class, class instance, or pool variables.

3. The symbol list assigned to your current session (see the following discussion).

If GemStone cannot find a match for a name in one of these areas, you are given an error message.

3.2 UserProfile and Session-Based Symbol Lists

The GemStone system administrator assigns each GemStone user an object of class UserProfile. Your UserProfile stores such information as your name, your encrypted password, and access privileges. Your UserProfile also contains the instance variable symbolList.

When you log in to GemStone, the system creates your current session (which is an instance of GsCurrentSession) and initializes it with a copy of the UserProfile’s symbolList object. GemStone Smalltalk refers to this copy of the symbol list to find objects you name in your application. See Figure 3.1.

Figure 3.1 The GsSession symbolList — a copy of the UserProfile symbolList
 

This instance of GsCurrentSession is not copied into any client interface nor committed as a persistent object. Since the symbolList is transient, changes to it cannot incur concurrency conflicts, nor are they subject to rollback after an abort.

Changes to the current session’s symbolList (the transient symbolList) do not affect the UserProfile symbolList (the persistent symbolList). Thus, the UserProfile symbolList can continue to serve as a default list for other logins. Methods are provided to synchronize your session and UserProfile symbolLists.

 

What’s In Your Symbol List?

In creating your UserProfile symbol list, the data curator adds SymbolDictionaries containing associations that define the names of all objects that the data curator thinks you might need. Although the decision about which objects to include is entirely up to the data curator, your symbol list contains at least two dictionaries:

  • A “system globals” dictionary called Globals. This dictionary contains some or all of the GemStone Smalltalk kernel classes (Object, Class, Collection, etc.) and any other objects to which all of your GemStone users need to refer. Although you can read the objects in Globals, you are probably not permitted to modify them.
  • A private dictionary in which you can store objects for your own use and new classes you do not need to share with other GemStone users. That private dictionary is usually named UserGlobals.

The symbol list may also include special-purpose dictionaries that are shared with other users, so that you can all read and modify the objects they contain. The data curator can arrange for a dictionary to be shared by inserting a reference to that dictionary in each user’s UserProfile symbol list.

Except for the dictionaries Globals and UserGlobals, the contents of each user’s SymbolList are likely to be different.

Examining Your Symbol List

To get a list of the dictionaries in your persistent symbol list, send your UserProfile the message dictionaryNames. For example:

Example 3.1
topaz 1> printit 
System myUserProfile dictionaryNames
%
 1 UserGlobals
 2 UserClasses
 3 ClassesForTesting
 4 Globals
 5 Published
 

The SymbolDictionaries listed in the example have the following function:

  • UserGlobals
    Contains per-user application and application service objects.
  • UserClasses
    Contains per-user class definitions, and is created by GemBuilder for Smalltalk to replicate classes when necessary. Putting this dictionary before the Globals dictionary allows an application or user to override kernel classes without changing them. Keeping it separate from UserGlobals allows a distinction between classes and application objects.
  • ClassesForTesting
    A user-defined dictionary.
  • Globals
    Provides access for the GemStone kernel classes.
  • Published
    Provides space for globally visible shared objects created by a user.

To list the contents of a symbol dictionary:

  • If you are using Topaz, execute some expression that returns the dictionary. Example 3.2 lists the dictionary keys. Alternatively, you could execute UserGlobals to examine all keys and values.
  • If you are running GemBuilder for Smalltalk (GBS), select the expression UserGlobals in a GemStone workspace and execute GS-Inspect it.
Example 3.2
topaz 1> printit 
UserGlobals keys
% 
a SymbolSet 
  ... 
  #1 GcUser
  #2 UserGlobals
  #3 GsPackagePolicy_Current
  #4 PackageLibrary
  ...
 

If you examine all of your symbol list dictionaries, you’ll see that most of the kernel classes are listed. In addition, there are global variables, both public and for internal use. For a detailed description of GemStone kernel objects, see Appendix D of the System Administration Guide.

You’ll discover that most of the dictionaries refer to themselves. Since the symbol list must contain all source code symbols that are not defined locally nor by the class of a method, the symbol list dictionaries need to define names for themselves so that you can refer to them in your code. Figure 3.2 illustrates that the dictionary named UserGlobals contains an association for which the key is UserGlobals and the value is the dictionary itself.

The object server searches symbol lists sequentially, taking the first definition of a symbol it encounters. Therefore, if a name, say “#BillOfMaterials,” is defined in the first dictionary and in the last, GemStone Smalltalk finds only the first definition.

Figure 3.2 Self-Referencing Symbol Dictionary
 

Inserting and Removing Dictionaries from Your Symbol List

NOTE
To insert or remove a SymbolDictionary to/from your symbol list, you must have the necessary system privilege. For details, see "User Accounts and Security" in the System Administration Guide.

Creating a dictionary is like creating any other object, as the following example shows. Once you’ve created the new dictionary, you can add it to your symbol list by sending your UserProfile the message insertDictionary: aSymbolDict at: anInt.

Example 3.3
| newDict |
  newDict := SymbolDictionary new.
  newDict at: #NewDict put: newDict.
  System myUserProfile insertDictionary: newDict at: 1.
 

As you might expect, insertDictionary: at: shifts existing symbol list dictionaries as needed to accommodate the new dictionary. In Example 3.3, the new dictionary is inserted into the UserProfile symbolList and then updated in the current session.

Because the GemStone Smalltalk compiler searches symbol lists sequentially, taking the first definition of a symbol it encounters, your choice of the index at which to insert a new dictionary is significant.

The following example places the object MyCollection (a class) in the user’s private dictionary named MyClassDict. Then it inserts MyClassDict in the first position of the current Session’s symbolList, which causes the object server to search MyClassDict prior to UserGlobals. This means that the GemStone object server will always find MyCollection in MyClassDict, not in UserGlobals.

Example 3.4
| myClassDict |
(System myUserProfile resolveSymbol: #MyClassDict) isNil
	ifTrue:[myClassDict := (System myUserProfile createDictionary:
				#MyClassDict)]
	ifFalse:[myClassDict := (System myUserProfile resolveSymbol: 
				#MyClassDict) value].
 
Object subclass: 'MyCollection'
	instVarNames: #('this' 'that' 'theOther')
	classVars: #()
	classInstVars: #()
	poolDictionaries: {}
	inDictionary: myClassDict.
 
GsSession currentSession userProfile 
	insertDictionary: myClassDict at: 1.
 
Object subclass: 'MyCollection'
	instVarNames: #('snakes' 'snails' 'tails')
	classVars: #()
	classInstVars: #()
	poolDictionaries: {}
	inDictionary: UserGlobals
 

Recall that the object server returns only the first occurrence found when searching the dictionaries listed by the current session’s symbol list. When you subsequently refer to MyCollection, the object server returns only the version in MyClassDict (which you inserted in the first position of the symbol list) and ignores the version in UserGlobals. If you had inserted MyClassDict after UserGlobals, the object server would only find the version of MyCollection in UserGlobals.

You may redefine any object by creating a new object of the same name and placing it in a dictionary that is searched before the dictionary in which the matching object resides. Therefore, inserting, reordering, or deleting a dictionary from the symbol list may cause the GemStone object server to return a different object than you may expect.

This situation also happens when you create a class with a name identical to one of the kernel class names.

CAUTION
Avoid redefining any kernel classes. Their implementation may change from one version of GemStone to the next. Creating a subclass of a kernel class to redefine or extend that functionality is usually more appropriate.

To remove a symbol dictionary, send your UserProfile the message removeDictionaryAt: anInteger, passing in the index of the dictionary you want to remove.

Updating Symbol Lists

There are many ways that the current session’s symbol list can get out of sync with the UserProfile symbol list. As some of the examples in this chapter show, updates can made to the current session symbol list that exist only as long as you are logged in. By changing only the symbol list for the current session, you can dynamically change the session namespace without causing concurrency conflict. For example, if you are developing a new class, you can purposely set your current session symbol list to include new objects for testing.

Three UserProfile methods help synchronize the persistent and transient symbol lists:

insertDictionary: aDictionary at: anIndex
This method inserts a Dictionary into the UserProfile symbol list at the specified index.

removeDictionaryAt: anIndex
This method removes the specified dictionary from the UserProfile symbol list.

symbolList: aSymbolList
This method replaces the UserProfile symbol list with the specified symbol list.

Each of these methods modifies the UserProfile symbol list. If the receiver is identical to “GsSession currentSession userProfile”, the current session’s symbol list is updated. If a problem occurs during one of these methods, the persistent symbol list is updated, but the transient current session symbol list is left in its old state.

In Example 3.5, the transient symbol list is copied into the persistent UserProfile symbol list. The example continues with adding a new dictionary to the current session and finally resets the current session’s symbol list back to the UserProfile symbol list.

Example 3.5
"Copy the GsSession symbol list to the UserProfile"
System myUserProfile symbolList: 
	(GsSession currentSession symbolList copy).
 
"Check that the symbol lists are the same"
GsSession currentSession symbolList = 
	System myUserProfile symbolList.
 
"Add a new dictionary to the current session"
GsSession currentSession symbolList add: SymbolDictionary new.
 
"Compare the two symbol lists; they should differ"
GsSession currentSession symbolList =
	System myUserProfile symbolList.
 
"Update the UserProfile symbolList to current session"
GsSession currentSession symbolList replaceElementsFrom: 
	(System myUserProfile symbolList).
 

Finding Out Which Dictionary Names an Object

To find out which dictionary defines a particular object name, send your UserProfile the message symbolResolutionOf: aSymbol. If aSymbol is in your symbol list, the result is a string giving the symbol list position of the dictionary defining aSymbol, the name of that dictionary, and a description of the association for which aSymbol is a key. For example:

Example 3.6
topaz 1> printit
System myUserProfile symbolResolutionOf: #Bag%
2 Globals
    Bag  Bag
 

If aSymbol is defined in more than one dictionary, symbolResolutionOf: finds only the first reference.

To find out which dictionaries stores a name for an object and what that name is, send your UserProfile the message dictionariesAndSymbolsOf: anObject. This message returns an array of arrays containing the dictionaries in which anObject is stored, and the symbols which name that object in that dictionary.

Example 3.7 uses dictionariesAndSymbolsOf: to find out which dictionaries in the symbol list stores a reference to class DateTime.

Example 3.7
| anArray myUserPro |
myUserPro := System myUserProfile. 
 
"Find first Dictionary containing DateTime"
anArray := (myUserPro dictionariesAndSymbolsOf: DateTime) first.
anArray at: 1.
aSymbolDictionary
 
"Get the name of the SymbolDictionary"
(anArray at: 1) keyAtValue: (anArray at: 1)Globals
 

Note that dictionariesAndSymbolsOf: may return zero, one, or multiple dictionaries.

3.3 Using Your Symbol Dictionaries

As you know, all GemStone users have access to such objects as the kernel classes Integer and Collection because those objects are referred to by a dictionary (usually called Globals) that is present in every user’s symbol list.

If you want GemStone users to share other objects as well, you need to arrange for references to those objects to be added to the users’ symbol lists.

NOTE
To insert or remove a SymbolDictionary to/from your symbol list, or to make any changes to a UserProfile that is not your own, you must have the necessary system privilege. For details, see "User Accounts and Security" in the System Administration Guide.

Publishers, Subscribers and the Published Dictionary

The Published Dictionary, PublishedObjectSecurityPolicy, and the groups Subscribers and Publishers together provide an example of how to set up a system for sharing objects.

The Published Dictionary is an initially empty dictionary referred to by your UserProfile. You can use the Published dictionary to "publish" application objects to all users — for example, symbols that most users might need to access. The Published Dictionary is not used by GemStone classes; rather, it is available for application use.

The PublishedObjectSecurityPolicy is owned by the Data Curator and has World access set to none. Two groups have access to the PublishedObjectSecurityPolicy:

  • Subscribers have read-only access.
  • Publishers have read-write access.

Publishers can create objects in the PublishedObjectSecurityPolicy and enter them in the Published Dictionary. Then members of the Subscribers group can access the objects.

For example, your system administrator might add each member of a programming team to the group Publishers. After completing the definition of a new class, a programmer could make the class available to colleagues by adding it to the Published dictionary. Because this dictionary is already in each user’s symbol list, whatever you add becomes visible to users the next time they obtain a fresh transaction view of the repository. Using the Published dictionary lets you share these objects without having to put them in Globals, which contains the GemStone kernel classes, and without the necessity of adding a special dictionary to each user’s symbol list.

Previous chapter

Next chapter