|
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:
- Structures often represent a physical data layout which
needs to be precisely defined to allow access
- Structures are much more space efficient than classes
- 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
|