Certain commonly used features are available in all programs, without any declarations being necessary. These are the system features. This is very useful, but not all the procedures or classes required for a particular programmer to produce his programs will be found in the list of SIMULA system features.
Some versions of SIMULA have extra system features, but programs written for such systems will not run on standard systems. Even the best of these extended systems cannot have all the features which may be required.
In practice each type of program will probably want to use a set of features suited to the problems being solved. We have seen that word processing programs can make use of many features which might appear in several different parts of a system or in completely different programs. The word processing programmer would like to have these available as system features. On the other hand, a mathematical programmer would probably find little to interest him in line breakers, chapter classes or whatever. He would prefer to have complex number procedures, matrix classes or things of that sort.
There are two possible solutions to the problem. One is to keep extending the language to try to provide all the possible features which will be required. This leads to impossibly complicated languages and cumbersome compilers and runtime systems. I will not name any of the languages which have fallen into this trap. If you ever meet any, you will recognise the description.
SIMULA is already a fairly substantial language. Its origins in Algol60 have made it larger than it needs to be. To add further complication is not a good idea. In general, the system features in SIMULA only provide facilities which would be impossible or very inefficient if they were written in SIMULA itself. This leaves the second solution.
If a programmer could produce a library of procedures and classes suited to his particular needs and make it available wherever he needed it, in a simple way, the problem would be solved. This concept is sometimes called a library and sometimes a package.
Example 16.1: A simple prefixed block.
begin class MyFeatures: begin procedure OutLine(T); text T; begin OutText(T); OutImage end..of..OutLine; procedure DoubleSpace(T); text T; begin OutLine(T); OutImage end..of..DoubleSpace; end--of--MyFeatures; MyFeatures begin OutLine("First"); DoubleSpace("Second"); OutLine"Fourth") end--of--prefixed--block end**of**programIt is also useful sometimes to be able to use just one or two features, independently of a package. If these can be included in a concise way, it can save effort. This can be done as well, using "separate compilation".
Finally, it is useful to be able to compile a package separately, as well as odd procedures or whatever. The advantage is that this part of your program is already compiled. It does not need to be completely reprocessed by the compiler. This can make compilation of the program using the separately compiled feature much faster. Since it is often necessary to recompile a program several times before it is correct and working, the saving can be considerable.
Clearly this example gains no advantage from using a prefixed block. We could simply have declared the two procedures outside of MyFeatures and called them anywhere in the program. It merely serves to illustrate the nature of a prefixed block.
In its simplest form, a prefixed block is a prefixing class identifier, followed by the keyword begin, followed by a sequence of declarations and statements, followed by the keyword end.
All the visible attributes of the prefixing class are available inside the block that it prefixes without further declaration.
The declaration of the prefixing class must be made in the block which immediately encloses the block that it prefixes. In the example, the class MyAttributes is declared in the program block. This is also the block immediately surrounding the prefixed block and so the program is legal SIMULA.
Note that the use of the keyword this inside the prefixing class is both meaningless and forbidden.
In general, this simple kind of prefixed block is only of academic interest. One simple extension is to prefix more than one block with the class. This is possible only where the blocks meet the condition in the last paragraph but one, i.e. they are both sub-blocks of the block where the prefixing class is declared. Different blocks can also be prefixed with different classes, but again the usefulness is limited if the full class declaration has to be made in the immediately enclosing block.
A rather more interesting possibility is to use parameters to the prefixing class. This allows different blocks with the same prefix to be set up differently. A somewhat contrived example is shown in example 16.2. Note that the parameter values must follow the class identifier which prefixes each block.
Example 16.2: Prefixed blocks with parameters.
begin class Printing(Spaces); integer Spaces; begin procedure OutLine(T); text T; begin integer Count; OutText(T); for Count := 1 step 1 until Spaces do OutImage end..of..OutLine; end--of--Printing; Printing(1) begin OutLine("First"); OutLine("Second") end--of--first--prefixed--block; Printing(2) begin OutLine("First"); OutLine("Third") end--of--second--prefixed--block end**of**programStill, there is no great benefit to be seen from such a device. In itself the prefixed block provides no great power. It is, however, immensely powerful in practice, when combined with other features.
The first benefit is that two system classes are provided for use as prefixes. Each covers a particular area which is not of sufficiently general interest to be included in the basic language. These are SIMSET, which provides powerful list handling, and SIMULATION, which provides discrete event simulation features. They are described in chapter 17 and chapter 19 respectively.
The second benefit is that a class can be compiled on its own then brought into the programs you write by a single line "external" declaration. It is this second point that we shall consider next.
The precise way of specifying that a class is to be compiled on its own rather than as part of a program, varies amongst SIMULA systems. You should check the documentation for the one you wish to use. Some older systems may not even allow it, in which case you are advised to move to one that does, if at all possible.
When a class is separately compiled one or more extra files are generated, compared with a normal compilation. These are called attribute files and contain details of the visible attributes of the class. They will be needed by the compiler whenever you compile a program which contains an external declaration of the class. Again, you should consult carefully the documentation for the system you are using.
To use a separately compiled class, you must include an external declaration in the place of the full class declaration. Example 16.3a shows example 16.1 with MyFeatures assumed to have been compiled separately.
The syntax of this external declaration is quite simple. The keyword external is followed by the keyword class, followed by the class identifier. This identifier will enable the compiler to locate the attribute file or files for MyFeatures. These contain all the information it needs about the class. The parameters, if any, should not be specified. They will be described in the attribute file or files.
Note that the external declaration is given at exactly the place where the full class declaration was given, so as not to violate the rule concerning declaration inside the block enclosing the prefixed block.
Examples 16.3: Using a separately compiled class as a block prefix.
a) begin external class MyFeatures; MyFeatures begin OutLine("First"); DoubleSpace("Second"); OutLine(Fourth") end- -of-- prefixed-- block end**of**program b) begin external class MyFeatures = "ERCS12.MYFEATURESATR"; MyFeatures begin OutLine("First"); DoubleSpace("Second"); OutLine("Fourth") end--of--prefixed--block end**of**programExample 16.3b shows the same program with a slight twist. It may be that the particular SIMULA system has file names which do not conform to the syntax of SIMULA identifiers. It may be that you need to show that the attribute files for the class are in another directory or belong to a different user. It may even be that you wish to give the class a different name in your program to the one it had when it was separately compiled. The use of an "external identifier" as well as an "internal identifier" can allow for all of these.
The external identifier is an optional addition in an external declaration. It follows the internal identifier, separated by an equals sign and enclosed in double quotes. The use made of this string is system dependent, although I have tried to give examples of typical uses.
The example in 16.3b shows how it would be possible to specify on the 2900 EMAS SIMULA system that the attribute files for the class known with the program as MyFeatures actually belong to user ERCS12.
Yet again, read the documentation carefully to see how your system interprets the external identifier.
Note how much more compact even such a trivial program can become.
16.2 Rewrite example 16.2 using separate compilation.
16.3 Start building your own libraries. Remember to include only items needed for a particular type of programming in each one.
It is also possible to use one separately compiled class to prefix another. This would allow one package to be an extension of another. This is important, because a block can only be prefixed by one class. To make the attributes of two separately compiled classes available, it is necessary to make one a subclass of the other and use the subclass as a prefix.
A common way of organising this is to have your most widely used features declared in a basic class. This is then used to prefix a wide range of more specialised classes. These can, in turn, be used to prefix even more specialised ones and so on.
Examples 16.4a, b and c show how this works.
This ability to extend the language according to the special needs of a user led the original designers of SIMULA to call it the "Common Base Language". Their intention was that very few people would need to write in straight SIMULA. Most would use packages of ready built components suited to their needs.
Examples 16.4: Subclass prefixing of blocks.
a) The parent class, compiled separately. class MyFeatures; begin procedure OutLine(T); text T;.......; procedure DoubleSpace(T); text T;........; etc. end--of--MyFeatures; b) A more specialised sub-class, also compiled separately. external class MyFeatures; MyFeatures class LinkList; begin class Linker;.......; class ListHead;.......; etc. end--of--LinkList; c) A program using LinkList. begin external class LinkList; LinkList begin ref(Linker) L; Linker class LinkObj;.......; etc. OutLine("Hello"); etc. end--of--prefixed--block; end**of**program
The instructions up to the inner statement, if present, or the final end, if not, are executed when the block which is prefixed is entered. If there is an inner statement, the instructions which follow it are executed when the prefixed block is left through its final end.
Example 16.5 shows a trivial example of this.
The initial sequence can be used to set values in variables, print headings and any other preliminary tasks. The prefixed block is then executed. The sequence after an inner can then be used to tidy up, print summaries, close files or any concluding tasks.
The outermost class is called Environment. This contains the system procedures not connected with files, such as Call.
This class prefixes one called BasicIO, which contains the declarations of File and all its subclasses. SysIn and SysOut are declared here.
These classes can be regarded as having been separately compiled to produce the runtime system. We have already seen most of the contents of BasicI0. The environment is covered more fully in chapter 20.
A normal program can be regarded as being as shown in figure 16.1. Note that BasicIO is shown as having two parameters. These are the image lengths to be used for SysIn and SysOut respectively. They are set by the system to match the devices being used for default input and output.
Figure 16.1: The program as a prefixed block.
When you write
begin ... ... end++of++programit is interpreted by the system as
BasicIO(InLength,OutLength) begin inspect SysIn do inspect SysOut do begin ... ... end++of++program end--of--prefixed--block--and--inspectionsExamples 16.5: Prefixed block with actions.
a) The separately compiled class. class TopandTail; begin OutText("Top and Tail, version 1.1"); OutImage; inner; OutText("Top and Tail has finished"); OutImage end--of--TopandTail; b) A program using TopandTail. begin external class TopandTail; TopandTail begin OutText("The prefix block's actions come here"); OutImage end--of--prefixed--block end**of**program
Such classes and procedures are introduced by external declarations, as we have seen with prefixing classes. For a procedure, the keyword procedure is used where previously the keyword class was. Having been declared in this way, these procedures may then be used as if they had been fully declared inside the program.
It is not sensible to cover all the variations here. The only reliable guide is the documentation for the system you are using.
Be especially careful that such differences do not cause problems when moving your programs from one system to another. Check also the range of parameter types allowed, which can be very different between systems where "foreign" language procedures are used.
One useful device is to create a separately compiled class containing SIMULA procedures which call all the non-SIMULA procedures in a particular library. This class is then the only place where the non-SIMULA procedures need to be declared. Any programs using them can be prefixed with the class containing their declarations and use the SIMULA procedures which call them. This means that when you move to another system, only the interfacing class needs to be changed to match the form of non-SIMULA external declaration for that system.
We have seen how separately compiled SIMULA modules, especially packages contained in classes, can be used through external declarations.
The notion of the program block as being enclosed in an invisible prefixed block and two inspections has been introduced. This explains the presence and meaning of system features in SIMULA.
A summary of the types of block possible in SIMULA has been given.
We have noted that is is possible to use separately compiled procedures from other programming languages, by making external declarations. We have also noted that the use of such declarations varies widely amongst existing SIMULA systems and the problems that this can cause, when moving programs from one to another.