[Modules] C and Smalltalk modules

Dirk Wessels icircle at xs4all.nl
Tue Nov 13 14:10:52 UTC 2001


Hello Antony,

I have thought about these things before, but there is one thing with
modules
where I think very different from what you describing.


----- Original Message -----
From: Anthony Hannan <ajh18 at cornell.edu>
To: <squeak-dev at lists.squeakfoundation.org>
Sent: Monday, November 12, 2001 9:59 PM
Subject: [Modules] C and Smalltalk modules

> Currently, the module interface of a C object file (*.o file in unix)
> is its symbol table containing names of functions and variables that it
> is available to other modules (exporting) and names of functions and
> variables it is using from other modules (importing).
The C object file is not a very good example of a module, since the linker
is just putting them together in a global namespace.
I also never liked the way C and C++ deal with objectfiles.
My favourite C++ code was usually one big file containing all the classes
and functions I needed.
(It compiled a lot faster!)

Anyway, I have also used Modula-2, Object Pascal (Delphi) and Java, that
have slightly different way of dealing with modules. They have possibilities
to leave parts of the module hidden so it is easier to understand them.

These are great in general use, especially for procedural structures and
splitting simple classes into libraries.

But, my experience with programming class-structures in modules, is that I
find it hard to split a set of classes into different modules. The best
results I found by splitting up the methods of the classes, and having only
a part of the class exposed in a public kind of module. Some parts of the
classes may also be dependent on modules that are very different (like
isMorph, and in window's case it may need the windows-system library for the
file-date function), which means that this part of my class-coding is better
left seperately.
Now I artificially create class constructions to overcome both problems, but
they may not be the best way to deal with them. So I create a class
WindowSystemFileDateManager for system calls. And a myPrivateWindowData for
my local data.
While one might discuss that one is supposed to split up classes like that,
it is a big effort to define and manage all these seperate classes. The
actual code without the modules could therefore be a lot smaller than using
the modules if one is not able to split up classes into aspect-modules.
The class definition data (variables etc.) could of course be done best in a
single module. Methods in many modules.

How to implement?
Each method is now defined seperately from each class, but managed by the
module-system.
One could define a class-method table, but this does not work if different
modules have defined
the same method internally and hidden (Foo>>bar, or Matrix>>clear, or
Application>>run).
Of course methods with the same name could be forbidden..
Anyway any call in the module to a method should logically only call methods
that have been
defined in other modules or in methods derived from main (or interface)
classes....
Except for smalltalk, where inheritance in not necessary to enable the call
to a method.

[MatrixModule]
Matrix>>new.  -- this method is also inherited
Matrix>>add:.
Matrix>>multiply:.
Matrix>>clear.
[InternalMatrixModule]
Matrix>>checkTypes.
Matrix>>internalMatrix.
Matrix>>getXDimension.
Matrix>>getYDimension.
[PrimitiveMatrixModule]
Matrix>>clear.   -- this duplicate method is locally defined..
Matrix>>primitiveNew.
Matrix>>primitiveMultiply.

My personal idea is that we should not allow calls to uninherited methods,
but that is not common in Smalltalk.
In that case the method lookup would be defined by the modules that are
defined as import. If a method is called the table of imported methods would
then be searched through. In the case of a single possibility (only Integer
imported) it would be able to link directly to this address. In the case of
a inherited method it could link to a inheritance table (whatever it looks
like).

We might choose for not allowing duplicate methods, but that might be
difficult to keep modules really seperate. Different versions of might
define the same method internally.


Now back to C.
My personal idea was to be able to define methods inside a "lowlevel"
module, so that we can create lowlevel code (C, pseudo-pascal, Assembler or
whatever) for defining primitives.
Each primitive would than be a single method defined for a single class with
certain class-parameters.
One could define more than one class-parameters for each method.
In pseudo pascal it would look like:

Function Matrix.Multiply( M:Matrix ): Matrix
var dimx,dimy:integer;
begin
  dimx:= self.Send(getXDimension) as Integer;
  dimy:= self.Send(getYDimension) as Integer;
  result:= self.Send(new);
  if self.Send(matrixHasOnlyInteger) then
   begin
     // claculate matrix with integer info
   end
  else if self.Send(matrixHasOnlyFloat) then
  begin
     // Calculate Matrix with float info
  end
   else
   begin
     // calculate matrix with class info.
   end.
end;

Function Matrix.Multiply( M:Object ): Matrix
begin
  self.Fail.
end;

One can not translate these into plain C object files or whatever.
But parts of it can translate directly to low-level code. Other parts (like
class-testing) should be implemented by the Smalltalk system.

My preference would be to enable property settings for each method, or even
within each block.

Matrix>>Multiply: aMatrix.
|  result ":Matrix" |
      "Compiler: optimise for Integer and Float, allow no other types unless
defined"
      " multiple types can be defined as Integer,Float  and allow other
types as:  Float,* "
result:= self new.
result.setDimensions: { xDimension yDimension }.
   0 to self xDimension do:[ :x ":Integer"
     0 to self.yDimension do: [ :y ":Integer"
       | res "Float" |
       res:= 0
       0 to self.xDimension do:[ :z (Integer)
         res add: "Float" (self at: { x z } "Float") *(self at: {z y}
"Float").
       ].
       result put: res at: { x y }.
   ].
^result

In this case the low-level-methods could even be smalltalk.
(but ofcourse I prefer assembler)


> With modules structured as layers of objects we automatically get
> transaction behavior, changeset behavior, name spaces, and
> component/project behavior, in addition to loadable code libraries.

Maybe you did actually mean something similar, but I did not understand it.
I think the process of defining the modularisation properly is a great part
of the actual module-implementation.








More information about the Squeak-dev mailing list