Largest Provider of Commercial Smalltalk
Cincom is one of the largest commercial providers of Smalltalk, with twice as many partners and customers than other commercial providers.

Tom Nies

Controlling Load Order in Cincom® ObjectStudio® 8.3

For ObjectStudio 8.3 we moved all Smalltalk source code that was still file based into Store, which gives us a much nicer source code control mechanism. For release versions we save the proper version of the code into a parcel file for distribution, and parcels load very quickly at runtime. We encountered one problem with this though – it was tough getting the load order right for OLE. Our OLE code has some highly order dependent initialization. For one example, OLEConstants must be initialized first, then a hierarchy of Structure subclass definitions that need OLEConstants (or other Structures), and then the external procedure definitions that need those Structures. To get it all to load properly we found that we had to do some investigation into how to manage load order issues using the VisualWorks source code control mechanisms that are now part of ObjectStudio 8, and we’d like to pass what we learned on to you.

First, a little history

ObjectStudio classic had only one mechanism for storing source code – a kind of chunk format in *.CLS files. There was also only one mechanism for loading a group of classes – a .TXT file with a list files to load. There were lots of limitations I never liked about that:

  • The .TXT file grouping was effectively invisible from within your Smalltalk image
  • Source code control was not visible from Smalltalk either
  • It was very easy to get the source code and image out of synch

We could go on and on about the drawbacks.

When we moved OLE code to Store, we created a package for it called “ObjectStudio OLE”. The code did not load properly though, since you can’t explicitly control the load order of the classes in a package. When you load code from Store it does some analysis to figure out the proper load order, but we learned that you sometimes need to help it to do the right thing.

Bundles vs. Packages

We first tried converting “ObjectStudio OLE” from a package to a bundle. In Store, a bundle lets you group packages of code (and other bundles) into a larger unit. One of its features is that when you define the bundle structure you can define the load order of its components. We soon discovered though that the bundle structure alone wasn’t enough to let us control the interdependencies of our OLE code, and we found that there are better ways to control load order.  The answer in this case was to switch back to a single package and use the methods below to control the load order within the package.

Prerequisites For Loading

When you load the OLE loadable application (which loads the parcel for the ObjectStudio OLE package) you can see the most important method we used to control load order – the prerequisitesForLoading class method. That method should answer an OrderedCollection of the classes that need to be loaded before loading the receiver. The inherited version makes sure that your superclass is always loaded first, and you can refine it to add other prerequisite classes, as we did to ensure that contained structures are loaded before containing structures, and all structures are loaded and defined before the function descriptions that use them. Here’s a simple example for the OLEStatStg class, a Smalltalk representation of OLE’s STATSTG struct, which contains an OLE ULARGE_INTEGER struct.:

OLEStatStg class>>prerequisitesForLoading
     ^super prerequisitesForLoading
           add: OLEULarge_Integer;
           yourself

Package Loading

There are some other interesting and useful load order related features when loading source code from a package in Store.

  1. All classes get installed into the system before shared variables.
  2. Shared variables (whether defined by a class or namespace) are initialized next. When loading from Store, Namespace shareds will initialize before class shareds.
  3. Classes are initialized (class initialize methods are invoked) after shareds. The ordering used for installing classes (based on prerequisitesForLoading) is used for initialization as well.

Parcel Loading

As mentioned before, the situation is a little different when loading code from a parcel file instead of from Store. For instance, when loading from a parcel, you can’t guarantee that Namespace shareds will initialize before class shareds. We had one case where this was a problem: the shared variable KnownProperties in AmbientProperty depends on OLEConstants. Our solution in this case was to create this class initialize method on AmbientProperty:

initialize
     "reinitialize, just in case OLEConstants
      wasn't properly initialized the first time"
     #{KnownProperties} initialize

This runs the initializer for KnownProperties again at class initialize time, when we know for sure that all shared variables have been initialized.

Summary

ObjectStudio 8 has an incredible increase in capabilities over ObjectStudio 7, gained by the access to VisualWorks functionality we get by running on the VisualWorks object engine. But what we’ve found is that, although we were very successful overall in making ObjectStudio 7 code run unmodified in ObjectStudio 8, there are always cases like this, where although the method source itself hasn’t changed, some aspect of how the code is managed has changed, requiring a migration in our understanding of how to use the environment it’s running in. We hope the information above is helpful when you migrate your own source code to Store, and you can be sure that you have all of the Cincom Smalltalk Support and Development groups behind you in everything you do with ObjectStudio.