Structures

Search
 

Structures are command to a C/C++ programmer, but need some explanation in the Smalltalk world.

First of all we might ask, "why use a structure when a class will do"?

There are three possible answers:

  1. Structures often represent a physical data layout which needs to be precisely defined to allow access
  2. Structures are much more space efficient than classes
  3. Structures are much faster to access than classes

For example, in Windows, an ICONINFO is a structure that contains information about an icon or a cursor. This structure is used in a Windows call like GetIconInfo. This Windows call expects a structure of 20 bytes. If we just pass a ByteArray of 20 bytes, then to retrieve fields we would have to code things like myICONINFO longAtOffset: 16 to retrieve the hbmColor field. While possible, this is cumbersome and involves a method call.

When we are dealing with structures, we are typically interested in C speed access to the structures and this is what Smalltalk MT provides. To accomplish this, a structure class has an initialize method on the class side that describes the layout of the structure. You can actually create this method from the C structure definition by creating the structure class (a subclass of Struct) and right clicking on the new structure class a choosing Generate... which opens a text window. Paste the C definition in this text window and choose Ok. Smalltalk MT will create a class initialize method that attempts to replicate the C definition. I say attempts because it is quite possible that the C definition uses other defines in the structure definition that are declared elsewhere.

Once the initialize method is created, you must initialize the class (actually the Generate method does this for you). From the Classes Menu -> Advanced -> Initialize Class which executes the initialize method and creates the structure definition. If you change the structure definition, you must again Initialize the class before using the structure. Note that loading a project automatically initializes Structure classes.

Structures are more efficient than classes because no object header space is required. Imagine that you wanted to have a number of Star instances. Each star needs 10 floats (RA, declination, magnitude etc).

If we create a class called Star and store these 10 instance variables, the total size of each instance would be (16 + (10 * (16 + 8))). This is computed as follows:

16 bytes for the object header for each Star instance.
10 floats where each float has a 16 byte object header and 8 byte (64 bit) float value.

Total of 256 bytes per instance. But what if I wanted to track 1 million stars? Now I am using 256,000,000 bytes!

By using a structure I get two advantages. First each float held in the structure does not have an object header and secondly I can specify either a 32 bit float (4 bytes)  or a 64 bit float (8 bytes). If I use the 32 bit value my memory usage is now (16 + (10 * 4)) i.e. 56 bytes or 22% of my original requirements.

In the initialize method of the structure for the 32 bit float you would use:

addAccessor: #magnitude type: FT_FLOAT size: FLOAT;

For the 64 bit float you would use:


addAccessor: #magnitude type: FT_DOUBLE size: QWORD;
 

Thus structure give you much greater control over memory usage.

Finally, since the structure now has a definition, the Smalltalk MT compiler can generate the code necessary to access fields in the structure directly without requiring a method send.

All you need to do is reference the field name. For example:

a := ICONINFO new.
a hbmColor