The ModulaTor logo 7KB

The ModulaTor

Oberon-2 and Modula-2 Technical Publication

The ModulaTor

Erlangen's First Independent Modula_2 Journal! Nr. 5, Jun-1994 
______________________________________________________________

 
What is a Module in Modula-2? 

by Keith Hopper, EMail: kh@athens.cs.waikato.ac.nz 

This article tries to answer the (apparently) vexed question of what is the nature 
of a module -- from the point of view of extending [ISO] Modula-2 as an 
object-oriented language. 

Over the last couple of years I have been reviewing the whole topic of 
programming and trying to develop a model of a program which is independent 
of the form of the source language in which it is expressed. This has led me to 
some interesting conclusions which I am happy to talk about at some other time. 
For the moment, however, looking at the task in hand there are a couple of 
points from the model which might offer us some insight into what we are really 
doing when we write a program. If you could suspend judgment for a couple 
more paragraphs, you will see where I am leading in all this. 

The model I have built considers all program entities as descriptions which are 
instantiated in one of two ways -- by declaration or by invocation (calling). The 
program itself is instantiated by being called from its environment. This is a 
dynamic activity as far as the environment is concerned which may (dependent 
on the description involved) set up values and things like storage for variables 
which have been declared as entities within the program directly. The general 
pattern for instantiation is as follows :-- 

a. Bind any arguments. 

b. Determine any values/space. 

c. Determine any properties. 

d. Initialise. 

e. [When deleting the entity from its environment] Finalise. 

between d and e all sorts of other actions can take place as other entities are 
instantiated by declaration/invocation. 

It is important to stress that this instantiation pattern applies to EVERY entity in a 
program - constant, type (whether 'class', ADT or ...), or variable. A procedure 
definition is in this model merely a constant definition of some appropriate type. 
A program itself is one of these. A module (or package or unit or whatever some 
language may call it) may be any of the three -- a constant, a type or a variable. 

In Modula-2 as currently defined we permit modules to be constants (if they 
define no "global" state) or variables (if they do) only. We don't permit them to be 
types. 

All that I am suggesting is that the so-called (and I write that not in any pejorative 
sense) object-oriented extensions are really only wanting to permit the definition 
of modules as types. The problems seen by other researchers about classes 
and multiple inheritance and the like, together with the specific problem of 
constants mentioned, all fall into place if we permit type modules with 
parameters. After all, we permit other type definitions with parameters, we 
permit variable definitions with parameters (Well! at least with the absolute 
address as a parameter), we permit (procedure) constants with parameters, so 
what is wrong with having type modules with parameters, which could 
themselves be (other) types or values -- bound at instantiation time, just like 
every other argument is bound then. 

The inheritance problem goes neatly and entirely away because since a type 
module is a definition, then anything which it imports is also a definition and 
therefore is not instantiated per se. There is no 'own state' for such an imported 
(inherited if you will) type entity. It is only when an object of a particular type is 
DECLARED (whether 'dynamically' or 'statically') that, being a variable, it 
acquires storage for the type of which it is declared --- and NOT for entities of 
any other types imported into its definition. Of course initialisation and 
finalisation of declared objects fall neatly into the pattern suggested above 
(which is only relatively slightly extended from the way that M-2 is currently 
defined). 

The interesting thing about this is that it closely follows the way in which 
Oberon-2 and Ada 9X behave, although being much broader and simpler in 
concept, particularly with negligible syntax changes for M-2. The only 'extra' 
primitive is the need for a dynamic type-test predicate. In saying this I am not 
precluding going the C++ 'magic' way, but I do rather deplore it, preferring the 
explicit use of type testing -- mind you, we will have to have a run-time type tag 
anyway. 

Which all brings me back to the numbers of module kinds. I count two at the 
moment, those which are constants and those which are variables. There is a 
unique member of the set of variable modules which exports nothing. This is 
referred to as the 'program module' -- I always view this a little bit like the 
'distinguished token' in some grammar definition -- separate but equal! 

The most unfortunate part about Modula-speak is that the word 'module' is used 
in two quite different senses -- the sense in which I have used it above and in the 
sense of 'a compilation unit'. The compilation unit meaning requires that two 
units may form, together, a module in the earlier meaning -- one containing the 
public portion and the other the private portion. I know that we can't change the 
terminology for historical reasons, but I have always considered that a 
DEFINITION MODULE and an IMPLEMENTATION MODULE are parts of the 
same entity. The unfortunate part is that the single keyword DEFINITION masks 
what might be a constant module or a variable module, since only the 
IMPLEMENTATION 'knows'. Perhaps this is not too important as they are only 
defined/declared once in an invoked program anyway. The TYPE MODULE has 
to be different because objects of its type will be declared somewhere in a using 
program, either directly or by inheriting properties, etc. 

Given this argument, it seems to be relatively painless to permit the definition of 
a TYPE MODULE in either one or two components -- ie as a separate 
compilation unit (or part of one, of course) and as an entire unit which, of course 
can be declared in a suitable operating system and appear to be a daemon -- 
but that is an operating system matter and nothing to do with language 
extensions. The use of the keyword IMPLEMENTATION to introduce the private 
part of any kind of module seems fine with me. Note, however, that this means 
that if a programmer desires to define a collection of types then the public part 
appears in the definition 'module' and the private part in the implementation 
'module'. Pause for a moment here, because the consequences of this are 
potentially interesting. We are then faced with parameterisable hidden types (no 
problem that I see there -------------- but! The current rules for hidden types are 
that they have to be mystery pointers, not any other kind of type. As a limitation 
on the public definition I don't see any problem -- the problem may lie in the 
implementation of the ADT which merely has to be a TYPE MODULE which is 
automatically an anonymous pointer because it appears inside an 
IMPLEMENTATION MODULE. This seems to be a reasonable compromise 
without damaging any existing code, so that a full ADT of arbitrary shape must 
therefore be confined to being a TYPE MODULE as a separate public part of a 
module (for which the implementation is compiled separately).  

Let me illustrate the differences with a skeleton syntactic example of each. First 
the separate parameterised type definition -- 

     TYPE MODULE Buffer(
                        Unit : TYPE ;
                        Size : CARDINAL
                        ) ;

          IMPORT
               EXCEPTIONS,
               IOChan ;

          TYPE
               Contents = [0 .. Size] ;

               Locations = Contents[0 .. (Size - 1)] ;

          VAR
               Lost_Data
                          : EXCEPTIONS.EXCEPTION ;

     PROCEDURE Fill(
                   Src : IOChan.ChanId
                   ) ;

     PROCEDURE Empty(
                    Dest : IOChan.ChanId
                    ) ;

     PROCEDURE Modify(
                     Val : Unit
                     ) ;

     PROCEDURE Retrieve(
                       ) : Unit ;

     PROCEDURE Peek(
                   ) : Unit ;

     PROCEDURE Position(
                       Where : Locations
                       ) ;

     PROCEDURE Contains(
                       ) : Contents ;

     PRIVATE
          Buff
               : ARRAY Locations OF Unit ;

          Modified
                   : BOOLEAN ;

          Offset
                 : CARDINAL ;

          Current
                  : Contents

     END Buffer.
 

Note 1. This uses my earlier suggestion of a private part NOT visible to an 
importing unit! 

2. This contravenes my 'rule' about not exporting variables, which is why I 
believe that exceptions should be something separate from constants, types 
and variables (as we all know, they are really all tied up with continuations --- 
so!!!!!!.....).  

The corresponding implementation is sketched in skeleton form only as 

     IMPLEMENTATION MODULE Buffer(
                                  Unit : TYPE ;
                                  Size : CARDINAL
                                  ) ;

          IMPORT
               EXCEPTIONS ;

       (* Lots of procedures! *)

     BEGIN
          Current := Size ;            (* ie Empty! *)
          Modified := FALSE
     FINALLY
          IF Modified THEN
               EXCEPTIONS.Raise(Lost_Data)
          END
     END Buffer.
  

This kind of buffer is then usable in some using code by declaring appropriate 
variables where needed -- the space needed is taken up when the declaration is 
instantiated (as discussed earlier) --- thus - 

MODULE Example ;

     IMPORT
          Storage,

          Buffer,               (* The ADT! *)
          COROUTINES,           (* This could be an ADT too! *)
          Widget ;              (* Some other ADT *)

     VAR
          Widget_Buff(01234567H)
                                  : Buffer(Widget,42) ;

     (* NOTE that, purely for illustration I have parameterised the variable
             as well as the type here in parentheses - rather than square
             brackets! *)

          Size
               : CARDINAL ;

          Buff_Ptr
                   : POINTER TO Buffer ;

PROCEDURE Co_buffer(
                    ) ;

     VAR
          Num_Buff
                    : Buffer(CARDINAL,Size) ;

     BEGIN
             ...
     END Co_buffer ;

BEGIN
     NEW(Buff_Ptr(REAL,999)) ;   (* Initialises here! *)

     (* Obtain Size dynamically -- eg interactively from user! *)

     COROUTINES.NEWCOROUTINE(.....,Co_buffer,....) ;

     (* Do other things! *)
END Example.
  

The alternative way of doing things, both of which I believe must be available in 
the extended language would look something like 

DEFINITION MODULE Buffers ;

          IMPORT
               EXCEPTIONS,
               IOChan ;

     TYPE MODULE Buffer(
                        Unit : TYPE ;
                        Size : CARDINAL
                        )  = [            (* Some sort of bracket!!! *)

          TYPE
               Contents = [0 .. Size] ;

               Locations = Contents[0 .. (Size - 1)] ;

          VAR
               Lost_Data
                          : EXCEPTIONS.EXCEPTION ;

     PROCEDURE Fill(
                   Src : IOChan.ChanId
                   ) ;

     PROCEDURE Empty(
                    Dest : IOChan.ChanId
                    ) ;

     PROCEDURE Modify(
                     Val : Unit
                     ) ;

     PROCEDURE Retrieve(
                       ) : Unit ;

     PROCEDURE Peek(
                   ) : Unit ;

     PROCEDURE Position(
                       Where : Locations
                       ) ;

     PROCEDURE Contains(
                       ) : Contents ;

                                   ] ;

     END Buffer.
  

The corresponding implementation is sketched in skeleton form only as 

IMPLEMENTATION MODULE Buffers ;

          IMPORT
               EXCEPTIONS ;

     TYPE MODULE Buffer(
                       Unit : TYPE ;
                       Size : CARDINAL
                       ) ;

          IMPORT
               EXCEPTIONS ;

          TYPE
              Buffer = POINTER TO Buff_Rec ;

              Buff_Rec = RECORD
                              buff : ARRAY Locations OF Unit ;
                              modified : BOOLEAN ;
                              offset : CARDINAL ;
                              current : Contents
                         END ;

          VAR
               Me
                  : Buffer ;

       (* Lots of procedures! *)

     BEGIN
          NEW(Me) ;

          WITH Me^ DO
               current := Size ;            (* ie Empty! *)
               modified := FALSE
          END
     FINALLY
          IF Me^.modified THEN
               EXCEPTIONS.Raise(Lost_Data)
          END ;

          DISPOSE(Me)
     END Buffer ;

END Buffers.
  

This kind of buffer is then usable in some using code by declaring appropriate 
variables where needed -- the space needed is taken up when the declaration is 
instantiated again, but this time on the heap. The using code is almost identical 
to the previous example --- thus - 

MODULE Example ;

     IMPORT
          Storage,
          Buffers,

          COROUTINES,           (* This could be an ADT too! *)
          Widget ;              (* Some other ADT *)

     VAR
          Widget_Buff(01234567H)
                                  : Buffers.Buffer(Widget,42) ;

     (* NOTE that, purely for illustration I have parameterised the variable
             as well as the type here in parentheses - rather than square
             brackets! *)

          Size
               : CARDINAL ;

          Buff_Ptr
                   : POINTER TO Buffers.Buffer ;    (* Pointer to pointer!!! *)

PROCEDURE Co_buffer(
                    ) ;

     VAR
          Num_Buff
                    : Buffers.Buffer(CARDINAL,Size) ;

     BEGIN
             ...
     END Co_buffer ;

BEGIN
     NEW(Buff_Ptr(REAL,999)) ;   (* Initialises here! *)

     (* Obtain Size dynamically -- eg interactively from user! *)

     COROUTINES.NEWCOROUTINE(.....,Co_buffer,....) ;

     (* Do other things! *)
END Example.
  

This relatively simple example can be extended in various ways, even doing it 
recursively perhaps by declaring a multi-buffer 

      Multi-buff : Buffer(Buffer(LOC,1024),1024)
 

perhaps to give one a two-dimensional buffer of a megabyte! 

The possibilities - like all programming examples - are more or less endless. I 
leave it up to you to think about the concepts and try out your favourite 
examples using this kind of mechanism. I honestly see it as being so very simple 
-- the only minor awkward features are those which seem to be tied up with 
'backward compatibility' issues. 

Over to you! 

Keith 

[Ed. note: This article, posted under the subject: (SC22WG13.345) Type modules -- module types 
to the WG13-email-list in 09-Mar-1994, was submitted for publication in the ModulaTor by the 
autor in 13-Mar-1994. The introduction was slightly modified by the editor to make the article 
self-contained. Also, two references to previous postings were deleted for the same reason.] 
________________________________________________________________

The ModulaTor Forum 

 

On Legacy Applications and Previous Work 

by Paul Robinson, Tansin A. Darcos & Company, Silver Spring, MD USA, 

Message-Id: <94-03-034@comp.compilers> 

Most articles in the comp.compilers newsgroup are discussions of new work 
being done in the development of translator applications. (I say that rather than 
'compilers' because a lot of the discussion involves tools like Yacc that are used 
to build compilers). 

I notice how much - if not most or almost all - of the material deals with the 
implementation of the latest techniques in improving code generation, improving 
the way compilers are built and designed, and the latest techniques for 
implementing the newest ideas. 

I'm going to make some comments that I think need to be thought about in this 
forum, since people here are probably directly involved in the creation and 
maintenance of compilers. (I am assuming people use the information here for 
more than just academic background, and that some real work goes on.) 

I wouldn't have thought much about real issues until my eyes were opened. I 
happened to purchase a copy of Edward Yourdon's "Death of the American 
Programmer." People may not agree with all of his ideas, but he made a couple 
of very important points that I do agree with. You may scoff at the points I am 
about to make, but would someone have believed someone, say, in 1971 saying 
that Japanese cars would almost kill the Auto Industry in 10 years? Two years 
later the oil crisis struck. 

This article focuses rather heavily on COBOL, but I suspect that in all but the 
newest places, more than 1/2 of all pre-existing programs are COBOL 
applications more than five years old. 

In this article, there is a term I use, when I refer to several programs all together 
which are used as part of a complete solution to a problem. I call this 
combination an "application group." While there may be independent programs 
in the group that stand alone, these programs often pass information to and 
from each other and usually share files). 

Here are the points to be made: 

1. Most programmers - my personal estimate is 90% - will spend 75% of their 
time maintaining "legacy applications", e.g. the old programs that are in use by 
companies that are the "crown jewels" of the organization. 

Where a company has a financial application system - payroll, accounts 
payable, and accounts receivable, along with perhaps other programs - the 
company may have a large chunk of their people doing nothing but maintenance 
on that application group. 

If they have, say, ten people doing maintenance on that particular application 
group, and have been doing so for perhaps ten years, based on salaries and 
costs, they have more than five million dollars tied up in that package. Further, if 
it has 10 people working on it, chances are you would need that many MORE 
people if you wanted to create a new one to do the same thing. 

And if 10 people are working on this one application group, that's probably half 
of the programming staff (remember, this one application group is the lifeblood 
of the company, if it was unavailable the company would probably go bankrupt 
in a matter of weeks (if even that long)). Therefore adding 10 more people 
(assuming you could find them), would be a major shock to the programming 
staff (as any place that suddenly had a 25% increase in personnel), perhaps 
causing people to move elsewhere! 

Take the numbers any way you want, whether it's 10 people or 40 (as Yourdon 
gives in one example), most of the people in the office are busy doing "life 
support", usually centering on the care and feeding on that critical application 
group that keeps the company alive. 

Further, unless you want a shoddy piece of junk that is just as bad as the 
application group that is there, there needs to be quality built into it. That means 
a new set of applications to replace the current ones would take a while. If it 
took, say, two years to create a replacement for the current application group, 
we may be looking at, in effect, paying ten people for two years before they 
produce any actual work which is usable by the company. I doubt that very 
many companies can justify a 3/4 million dollar investment to replace something 
that already works and still spend the same amount keeping the old system 
alive until the new one is finished. 

Oh, yes, if they do replace modules as they create them there might be some 
improved functionality, but can anyone see doubling the staff working on an 
application so that eventually, down the line, the new staff can be eliminated and 
the old staff reduced in size because less maintenance is required? Beyond the 
fact that people are still needing things to be done in the interim? Or that a 
manager would spend money on more people to rewrite the applications to 
enable the company to reduce the amount of unpaid overtime? (Too many 
places rely on 'Spanish Prisoner' accounting of programmers, e.g. they take into 
account in costs of programmers the regular and chronic unpaid overtime they 
put in.) 

We often refer to these legacy applications as "old COBOL dinosaurs" (or old 
FORTRAN dinosaurs, but most places that have significant maintenance issues 
are in business applications. If places still had a lot of RSTS/E systems around, 
we might talk about old BASIC dinosaurs). 

But this sort of mudslinging is a disservice: these applications still do useful 
work, they are critical to the functioning of the organization which probably 
literally depends for its life on the applications group, and the organization 
CANNOT AFFORD to replace them. Further, these large application groups - 
perhaps a dozen main programs and hundreds of modules, consisting of 
perhaps 2 million lines of code - are usually so complicated that nobody really 
knows how they work anymore; rewriting them is out of the question when you 
don't even know what they do. 

Therefore, what we need - what is despirately needed in the real world - are 
better tools to perform maintenance on existing applications. 

2. Do you know how much money a programmer with a college degree and C 
programming experience makes in China? About $180 a month. And this is not 
"slave wages" - I understand it's about the equivalent of a minister in a cabinet 
post there, and as such, maintenance programmers in the U.S. today - and 
possibly in other Western nations - are very close to the exact position of U.S. 
auto workers in the 1960s or 1970s, before Japan came along and cleaned our 
clock for us. 

Let's not forget that India, is doing a lot of transshipment of programmers here, 
where they can do better quality work than we do for less money. I won't argue 
over whether this is good or bad; the fact is, it is happening now. Even if there 
wasn't a single imported programmer allowed into the country, software is not a 
product that is capital intensive; the people don't have to be where the work is. 

Which leads to the next step: sending the specifications overseas and having a 
shop there write the code, then bringing it back here to have local programmers 
adjust it for local functionality (e.g. to ensure the commas are in the right place, 
etc.). The cost for to do work like this is probably an order of magnitude less 
than having it done entirely within the U.S. 

Don't be too smug if you're in Europe. India has had 350 years of Britsh Rule; a 
lot of people there speak English well and have had extensive education which 
was developed by England. How can you tell whether a programmer who wrote 
a program did so from a terminal in Cambridge or one in Calcutta? Especially if 
the program is published by an EC-based company with a London address. 

But don't think cost is everything: if labor cost was the only consideration of the 
creation of a product, Haiti would have had almost no unemployment. 

Do you know why someone working on a shop floor in Detroit makes ten times 
as much money as someone doing the identical work on a shop floor in Mexico? 
Because the American has the education and tools to make him ten times as 
productive. 

Western programmers have not had a "Japanese Import" problem yet to shake 
them up into improving the way they create programs. A lot of people doing 
COBOL coding in shops, who haven't taken a programming course in ten years, 
are marked men, waiting to be cut down by the same thing that forced layoffs in 
Detroit: foreign imports of better quality that cost less. 

Did anyone notice that the premier graphics package, Corel Draw!, was created 
by a company in Canada? The game "Tetris" was developed by two 
programmers in Moscow. Minor inroads, but they are the hints of future 
developments. 

If we continue the way things are, eventually, as Japan did to the auto industry 
in the 1970s/1980s, some hungry foreign country is going to eat our lunch in 
software development. If we change now, it will be easier. If we wait until we are 
forced to do so, it will mean the same gut-wrenching changes - and programmer 
unemployment - will hit the software industry as struck Detroit. 

We can change this. And those who develop the tools to help todays 
programmers stay competitive can make money hand over fist. 

To ensure that we are worth the high wages we are getting, we have to be much 
more productive. Most people who are programming are already overworked as 
it is. They do not need to work harder; what they need is to work smarter. 

- We need better tools, and ways to make maintenance - which is still 70% or 
more of most people's work - easier to accomplish. 

- We need to increase the amount of code which is reused. From the 
programming courses on, copying from other people has been frowned upon; 
people who write programs by borrowing other code get the Rodney Dangerfield 
treatment (which is why maintenance programmers are held in such low 
esteem). Yet the best shops are able to reuse 80% of their code. Most shops 
are lucky to do 20% reuse. Does anyone seriously think that rewriting the 
COBOL overhead - four divisions and various statements - every single time a 
program is created makes any sense? No, and most people have a skeleton 
frame of the program to start with. Yet that practice in and of itself shows that 
having usable pre-written code to pick from makes people more productive. 

- We need to get better CASE tools. Computers can manipulate text quite well; 
it's time to develop better program generators and precompilers. Who is more 
productive? Someone who uses a full screen painter like Borland Resource 
Workshop to create MS-Windows panels, or someone who codes them as text 
statements? 

Why then, can't we go further and allow people to pick functions and create a 
program graphically? Yes, I know there are some applications out there that do 
provide this, but in many cases they are only of use to you if you are creating 
new work, not maintaining old work. And they often don't provide enough 
functionality; many times you still have to go in and edit the generated source to 
get the results right; and they usually do not support people adding their own 
statements. If I manually edit an .RC file and add a new item, the Borland 
resource workshop will create the on-screen window, dialog box and controls to 
match the specifications. Such capability does not often obtain with program 
generators. 

- We need to develop better repositories to store source code, and the other 
things that go along with it, such as documentation. And full-screen browsing 
with good dictionary and definition specifications. Nobody is going to want to 
look for a routine in a 3,000 page listing of routines; on-line browsing has got to 
be available. 

- Good cross-reference and indexing tools are needed. When was the last time 
you saw a cross-reference tool for DBASE or Pascal, or even saw a PC-Based 
compiler for any language that created cross reference or variable usage 
tables? Probably the best cross reference tool I've ever seen is the FORMAT 
program which was written by someone in Germany (the code is in Pascal; the 
comments are in German). It's a Pascal cross-reference, pretty printer and 
indexer all in one. 

It does one very nice thing that I've not seen in some mainframe COBOL 
compilers. For each procedure, it lists the procedures that it calls by line 
numbers, and also lists the name and line number of every procedure that calls 
it. Listings like this are CRUCIAL for maintenance of a program, where you are 
somewhere in a program and trying to figure out how it got there. 

Do you (or your company) want to make some money and provide something 
despirately needed for 70% of the work done? Stop thinking about writing the 
next YACC and consider the needs of the poor maintenance programmer out 
there. 

- Create a good "macro" type library for COBOL or FORTRAN or BASIC or any 
of the older languages that people will be continuing to do maintenance in 
twenty years from now. Even if it's only a preprocessor, it will help in doing 
maintenance on existing applications, by allowing heavier use of pre-written 
routines. 

C has a fairly good macro language with parameter substitution. COBOL has, at 
best, some COPY constructs that allow some changing of prior values, and 
usually all people use it for is to copy declarations of variables. We need to 
encourage people to be able to copy procedures and even inline code 
segments. 

- We need good "smart" compilers and linkers as well as support for handling 
the overhead of compilation by the machine. The first time I ever saw a "make" 
routine and how it was smart enough to know what had been edited and needed 
to be recompiled, what had been recompiled and needed to be relinked, blew 
me away. I had been doing this sort of thing manually on mainframes. Also, 
Borland's compilers strip unused procedures, and for objects, unused methods, 
automatically. 

- Create better checkout and merge capability for applications which are worked 
on by multiple people. Checkout facilities for mainframes and (now appearing) 
for PCs do help, but they are still weak in giving good inclusion capability for 
procedures and code fragments. And they usually don't have facilities for tying 
documentation files to program sources. 

- Integrate these functions so that recompiling a program triggers a rerun of the 
cross-reference, which replaces the old cross reference file if it is stored in the 
archive, and also replaces old binaries. 

- Support archive members at the compiler level; it is easy to encourage people 
to keep hundreds of 500 byte or smaller files if they can store them in a .ZIP, 
.ZOO or .ARC archive for subsequent extraction and thus keep all the related 
files together (and save space) but not if these small files are stored as single 
files using 4K or 8K each. 

- Start creating libraries of pre-written, tested procedures and code segments 
that people can use when writing applications or when doing maintenance on 
existing ones. Sure, the usual library routines supplied with a compiler provide 
some of these, but people often need source because they want a specific 
function, but they want it to do less than the prewritten one does, or less 
combined with other functionality. 

For example, I might have a small table, say 600 entries of 15 bytes each. I read 
this in from either another program or supplied by an individual. I get better 
performance doing searches by putting it in order. I do not want to order the 
person supplying the information to alphabetize it (and it might be coming from 
another program which cannot be told to do so), and further I might be using 
only part of the data passed on in a file that is yet passed on to yet another 
program, which expects the file a certain way, so I can't change the input to 
pre-sort it. 

In this case, I do not need (and probably don't want to invoke) a full-blown 
disk-based sort for a table this small, that might only be 10K in size; what I need 
is a reasonably good in-memory sort routine. Yet for a table this small, even a 
dictionary sort is sufficient, since even a worst case is only going to be a second 
or so of running time, insignificant if this is, for example, the initialization of a 
program that runs for minutes or hours. A reasonable dictionary sort requires 
two loops and about 5-10 lines of code. 

What usually happens in a case like this is that the programmer spends time 
rewriting a dictionary sort because there is nothing available to give him this 
functionality. And if he needs to do some work on the table while sorting, even if 
there is a built-in simple sort, he can't use it because he can't change the 
process. Where he might just need a 10-line sort to insert into a 20-line 
procedure, he wastes considerable time writing a simple sort because the 
feature he needs isn't there. If it is there, is there a way he can find it? To find it, 
he needs well-indexed libraries, and he needs on-line search capability. 

- Make cross-compiling easier. With the increase in processor speed and size of 
disks and memory, it's only a matter of time until 370 emulators start bringing 
those old COBOL programs onto the new "mainframe" which is the size of a 
Tower microcomputer. If people can move from MVS COBOL to MS or Ryan 
McFarlane COBOL, it will make their job easier, moreso if the program will run in 
exactly the same way as the original program, without the user having to rewrite 
any standard construct. 

Also, there should be support for changing what was VSAM files into the PC 
Equivalent, B-Trees, or into data files compatible with standard files, such as 
DBASE, Oracle, SQL, or any other environment which is being made available 
on PCs. Don't forget record locking on Novell to replace the standard ENQ/DEQ 
on Mainframes. 

Also, if he's got an inquiry program for CICS, he needs to develop a way to 
change his screens that were painted so that he can take the original IBM 
Assembler specification and translate that into a panel in MS-Windows or OS/2, 
or even a DOS text-mode screen. 

- If someone is debugging a program, they should be able to use full-screen 
debugging of the source language, not debugging in assembler. The debugger 
should support the data structures in the output file and allow their analysis in 
the same way as the source language does, so that I don't have to say 
3e48:1023 and see 3000, instead I should be able to reference 
"CURRENT-PAY" and if it's COMP-1, see 480. If that's not unique, of course, 
then I have to say "CURRENT-PAY in PAY-RECORD". 

- We need tools like FORMAT for other languages. With object oriented 
languages referencing procedures indirectly through access to variables, "CALL 
TO" and "CALL BY" listings are badly needed. And they need to support 
multi-module 

Yourdon also mentions one other thing that is going to "blow the socks off" your 
average programmer: Object Oriented Cobol. The specifications (in 1992 when 
his book was released) were just then being formulated. I try to keep up on the 
literature, applications and new developments, and yet I still don't understand 
Object Orientation that well; I shudder to think what this will do to someone who 
hasn't read a textbook in five years. 

Like it or dislike it, COBOL is not going to wither away any time soon; there's 
probably some $50 billion in programming assets tied up in it. Like the difference 
between C and C++ or Objective C, you may not recognize it by the time they 
get finished with it, but I suspect it will still be around twenty years from now 
unless every one of those large companies are able to move to micros and that 
their COBOL programs get translated into other languages. 

Look at what has happened to BASIC, it's the macro language for MS Word. 

Paul Robinson - Paul@TDR.COM 

[Yourdon's book is well worth reading. It's not specifically about compilers but 
has a lot to say about the way that programmers do and don't use the tools they 
have available.-John] 

Send compilers articles to compilers@iecc.com or {ima | spdcc | 
world}!iecc!compilers. Meta-mail to compilers-request@iecc.com. 

[Ed. note: This article was submitted for publication in the ModulaTor by the 
autor, in 16-Mar-1994.] 

________________________________________________________________


IMPRESSUM: The ModulaTor is an unrefereed journal. Technical papers are to be taken as working papers and personal rather than organizational statements. Items are printed at the discretion of the Editor based upon his judgement on the interest and relevancy to the readership. Letters, announcements, and other items of professional interest are selected on the same basis. Office of publication: The Editor of The ModulaTor is Guenter Dotzel; he can be reached by tel/fax: [removed due to abuse] or by mailto:[email deleted due to spam]
  ModulaWare home page   The ModulaTor download    [Any browser]

Webdesign by www.otolo.com/webworx, 14-Jul-1998