Vision Class: Dictionary
Dictionary Overview
The subclasses of the class Dictionary are used to manage a set of names that return related objects. Dictionary classes do not have instances. All the messages defined for a particular Dictionary usually return objects of the same class. Operationally, a Dictionary is similar to the class IndexedList except that the index values are String objects when you work with a Dictionary.
The Dictionary class is a direct subclass of Object:
Object | Dictionary | |-- Environment | |-- LocalDBDictionary | |-- Named | |-- SystemDictionary | |-- XRef
Basic Access
To create a new Dictionary, use:
!newDictionary <- Dictionary new ;Initially the Dictionary is empty. You add objects to the dictionary by providing a name for referencing the object. For example, you can create a dictionary to translate externally defined codes into descriptive names using:
!Lookups <- Dictionary new ; Lookups at: "USA" put: "United States of America" ; Lookups at: "CAN" put: "Canada" ;The variable Lookups is defined to be a new Dictionary object. The at: id put: object message is used to associate an id in the dictionary with a specific object. In this example, the name USA is associated with the String object "United States of America" and the name CAN is associated with the String object "Canada". The at: id message is used to access the object associated with the specific id. For example:
Lookups at: "USA"returns the String "United States of America" and
Lookups at: "CAN"returns the String "Canada".
Any type of object can be associated with an identifier in a Dictionary. The following example creates a new class and several instances and uses a Dictionary to keep track of the instances by name:
#- Create a new Class !Industry <- Object createSubclass ; #- Define a Property at the Class Industry define: 'name' ; #- Create new Instances !autos <- Industry createInstance ; autos :name <- "Automotive" ; !tech <- Industry createInstance ; tech :name <- "Technology" ; #- Create a Dictionary to Reference Instances !LookupIndustry <- Dictionary new ; LookupIndustry at: "autos" put: autos ; LookupIndustry at: "tech" put: tech ;The expression:
LookupIndustry at: "autos"returns the instance of the class Industry representing the automotive industry. Since the object returned is the actual Industry object which responds to the name message, the expression:
LookupIndustry at: "autos" . namereturns the name of this industry, in this case the String "Automotive". You can add several identifiers to the Dictionary that all return the same object. For example:
LookupIndustry at: "cars" put: (LookupIndustry at: "autos")adds the name cars to the Dictionary and defines it to return the industry object representing the automotive industry. The expressions:
LookupIndustry at: "autos"and
LookupIndustry at: "cars"produce identical results.
The message displayMessages can be used to see all the names in a Dictionary. For example:
LookupIndustry displayMessagesdisplays the names autos, cars, and tech.
If there is no object associated with the supplied identifier, the value NA is returned. For example:
LookupIndustry at: "xyz"returns the value NA. The message uniformAt: id will return the object named Default in the Dictionary if the original name is not found. If no object named Default is found either, the value NA is returned. For example, add the name Default to the Dictionary to return the default Industry instance:
LookupIndustry at: "Default" put: Industry ;then:
LookupIndustry uniformAt: "xyz"returns the object representing the default Industry since the id xyz is not found in the dictionary.
The delete: message can be used to delete an entry from a Dictionary. For example:
LookupIndustry delete: "cars" ;deletes this entry from the dictionary. The expression:
LookupIndustry at: "cars"will now return the value NA. Note that the expression:
LookupIndustry at: "autos"will continue to return the industry object because the delete: message at Dictionary just deletes the reference from the Dictionary to the object but does not actually delete the object itself.
Access Shortcut
Internally, the at: message defines the supplied name as a class constant. The expression:
Dictionary at: "test" put: "this is a test"is equivalent to:
Dictionary define: 'test' toBe: "this is a test"The expressions:
Dictionary at: "test"is therefore equivalent to:
Dictionary testNote that if the identifier does not start with a letter or the _ character or if it contains any special characters, you need to use the \ (escape) character to precede the name (and each special character within the name). In these cases, it is often easier to use the at: form of the lookup. For example, if you added a multi-word identifier using:
Dictionary at: "this is a long identifier" put: "answer"then the expressions:
Dictionary at: "this is a long identifier"and
Dictionary this\ is\ a\ long\ identifierboth return the String "answer". In this case, the version using at: is probably simpler to read.
Additional information on valid identifiers is available.
Naming Dictionaries (Named)
The subclass Named is used to organize Dictionary classes that are used for naming instances of the different Entity subclasses. To avoid conflicting names across classes, a separate naming dictionary has been defined for each Entity subclass. For example, the company General Motors and the common stock security of General Motors would represent distinct objects in a Company and Security class. The name GM would be added to the dictionaries Named Company and Named Security. The expression:
Named Company at: "GM" .or
Named Company GMreturns the Company instance representing General Motors and the expression:
Named Security at: "GM" .or
Named Security GMreturns the Security instance representing General Motors common stock.
To display the set of naming dictionaries that have been defined, use the expression:
Named displayMessages
When a new entity subclass is created using the createSubclass: id message, a new naming dictionary is automatically defined at the class Named using the same identifier. For example, the expression:
Entity createSubclass: "Industry" ;creates the new subclass Industry and the new naming dictionary Named Industry. The Default identifier is automatically added to this naming dictionary to return the default instance in the new Entity class. The expressions:
Named Industry at: "Default"and
Named Industry Defaultwill therefore return the default Industry instance. The expression:
Named Industry uniformAt: "xyz"will return the default Industry if the identifier xyz has not been defined. When a new instance of an entity class is created using the createInstance: id message, the id is automatically added to the class naming dictionary, returning the newly created instance. For example, the expression:
Industry createInstance: "Auto" ;create a new instance of the Industry class and adds the name Auto to the Named Industry Dictionary. The expressions:
Named Industry at: "Auto"and
Named Industry Autowill therefore return the Industry instance representing the automotive industry.
Cross Reference Dictionaries (XRef)
The naming dictionaries defined for entity classes provides a useful way to track one or more standard aliases for an instance. It is often useful to track aliases for an entity that may be uniquely assigned by a specific source but which may overlap with aliases assigned by other sources. For example, two sources may supply currency information using different coding schemes. These schemes will not necessarily match the scheme used by your installation. To address this situation, a separate cross reference dictionary is set up to store the relationship between a specific alternative source's code and the actual entity instance.
The class XRef is a subclass of Dictionary and is used to store these cross references. The message createXRef: withProperty: is used to create a new XRef dictionary for a specific entity subclass. The first parameter is the name of the XRef dictionary and the second is the name of a property at the entity class that will store the cross reference values. For example, to create a currency cross reference to track Source1 currency codes use:
Currency createXRef: "Source1" withProperty: "source1Code" ;This message performs the following steps:
- Defines a new XRef dictionary named Currency XRef Source1.
- Adds the name Default to this XRef to return the default Currency instance (i.e., Currency XRef Source1 Default = Named Currency Default).
- Defines the property source1Code at the Currency class .
To obtain a list of the XRef instances defined for a class, use the expression:
entityClass XRef displayMessagesFor example:
Currency XRef displayMessagesreturns the names of all the Currency XRef dictionaries that have been created for the Currency class.
The message setXRefIn: xref to: id is used to add or change XRef values for a specific entity. For example, if Source1's code for the US currency is 1, use the expression:
Named Currency US setXRefIn: Currency XRef Source1 to: "1" ;This expression adds the id 1 to the XRef and sets the value of the "source1Code" property for currency US to "1". The expression:
Currency XRef Source1 at: "1" .returns the US currency instance. The expressions:
Currency XRef Source1 at: "1" . Currency XRef Source1 \1and
Named Currency USall return the same instance.
Each XRef is associated with a specific property. For example, Currency XRef Source1 is associated with the property source1Code at the class Currency. The message updateBlock defines a block that returns the property associated with a particular XRef. For example:
Currency XRef Source1 updateBlockreturns:
[ :source1Code ]and the expression:
Named Currency US source1Codereturns the value 1.
The message profile is defined at XRef to display the cross reference values defined in this XRef for all entities. For example, the expression:
Currency XRef Source1 profiledisplays:
Currency XRef Source1 For Item: [:source1Code] Code Name XRef Value . . . US U.S. Dollar : 1 / . . .Any number of aliases can be defined. If Source1 also uses the code "USA1" for the US currency, then you can set and use either alias. For example:
Named Currency US setXRefIn: Currency XRef Source1 to: "USA1" ; Currency XRef Source1 profile ;produces:
Currency XRef Source1 For Item: [:source1Code] Code Name XRef Value . . . US U.S. Dollar : 1 / USA1 / . . .The default profile message defined for the Entity class displays the value defined for each XRef property defined for the class. For example, the expression:
Named Currency US profileproduces:
*** Currency Profile For: US Dollars Code: US Aliases: US / --- Links --- --- XRefs --- source1Code: USA1
System Dictionaries
The subclass SystemDictionary is used to organize Dictionary classes that are supplied with the core Vision system and various optional ToolKits. The dictionary SystemDictionary UpperCaseDictionary is used to store the upper case equivalents of the letters 'a' through 'z'. This Dictionary was created using:
SystemDictionary newAs: "UpperCaseDictionary" ; SystemDictionary UpperCaseDictionary at: "a" put: "A" . at: "b" put: "B" . at: "c" put: "C" . ;The message capitalize is defined at the class String to use this dictionary to translate the first letter of a string to its capitalized equivalent. The dictionary SystemDictionary LowerCaseDictionary is defined in a similar way and is used to store the lower case equivalents of the letters 'A' through 'Z'.
Note that the newAs: message has been defined at Dictionary to name the new dictionary in the dictionary's parent dictionary. The expression:
SystemDictionary newAs: "Test"creates a new dictionary and automatically defines the message Test at the class SystemDictionary to return it. The expression:
SystemDictionary Testreturns this new dictionary instance.