[comp.lang.ada] Use of "is separate" and compilatio

stt@inmet.inmet.com (11/28/89)

We have built a number of very large Ada systems at Intermetrics,
and our customers have built some even bigger ones.
As a result of this we have built up a very strong
prejudice *against* the use of subunits (aka "is separates").
Instead, we try to structure our system as a series
of medium size packages (about 500-2500 lines each),
using either a functional or object-oriented structuring.

Ideally, each of these packages represents a well-defined,
relatively self-contained component of the system.
When making a change or trying to understand a particular
feature of the system, it is generally only necessary to
look at the single medium-size package which implements it.
Furthermore, most of the candidates for low-level, small-chunk-of-code
reuse, are within a single package.

Subunits foul up this structure in a number of ways:
First and foremost, a single subunit is in no way "self-contained."
It has unlimited visibility into its parent unit, representing
a very "broad" interface (the worst kind).

Secondly, when editing a subunit, other related code is
not immediately available, so we have found that programmers
working on a heavily "subunited" program tend to reinvent the
wheel repeatedly, rather than noticing a similar sequence
of code in another subprogram of the same package, and
separating off that logic as a local shared subprogram
of the package.

Thirdly, subunits cause havoc with sophisticated optimizers,
especially subunits within subprograms.  When calling a separately-compiled
subunit the compiler must assume the worst: that the subunit
accesses and/or updates all objects it can see, meaning that
all local variables visible to the subunit must be stored back
into memory from registers before the call, and reloaded afterward.

Finally, they tend to allow single library units to grow
without bound.  Often when a subsystem grows too big, it
is wise to split it up into a number of packages, each with
a narrower purpose.  When using subunits, the tendency
is to instead just keep adding more and more functionality
into a single package.

As far as recompilation, subunits are also bad news, since
almost all compilers will recompile *all* subunits when
any change is made to the enclosing parent unit, including
just the addition of another subunit.  Of course, the total
amount of code is no greater than if the package had not
been "subunited" (presuming you resisted the growth-without-bound
phenomenon), but most compilers will compile a single 2500-line
package much faster than 50 50-line subunits.
Of course you win when the only change to be made was in a single
subunit, but in our experience, that incentive causes many
of the problems with subunits -- the avoidance of restructuring
of the package.  Many bugs can best be fixed by modest
restructuring of the implementation of a package.  
Any attempt at restructuring in the presence of subunits
causes them all to be recompiled again.

I should mention that reasonable people differ
on this whole "subunit" issue, and there are
selected places where a subunit can be extremely useful,
to, for instance, isolate a very small bit of host-dependent
code.  However, on balance, I would regard them almost
as bad as a goto -- to be used only when all other 
avenues have been exhausted.

As Lori Clarke, et al, said in their classic critique of
Ada subunits long ago, "nesting in Ada is for the birds."

S. Tucker Taft
Intermetrics, Inc.
Cambridge, MA  02138

edm@vrdxhq.verdix.com (Ed Matthews) (11/29/89)

I pretty much agree with Tucker.  I used to really like separate subunits,
but now that I have switched to the compiler development side of the
world, it's easy to see that separate subunits is one of those issues
that gives compiler and optimizer writers nightmares.

In article <20600021@inmet> stt@inmet.inmet.com writes:

>When making a change or trying to understand a particular
>feature of the system, it is generally only necessary to
>look at the single medium-size package which implements it.

On the whole, Tuck makes some persuasive arguments, but I disagree here.
This argument is an artifact of the editors of the past.  With modern
editor technology and windowing, the entirety of a package, whether it
be one package of 2500 lines, or 25 subunits of 100 lines, can be 
easily viewed.  Further, in editors with syntactic and semantic
navigation, understanding a unit is equally easy no matter how the
program is structured.

>Furthermore, most of the candidates for low-level, small-chunk-of-code
>reuse, are within a single package.

I agree here -- reuse at the small-chunk-of-code level may be obscured
by subunits.  This is another another topic, but I wonder how much value
small-chunk-of-code reuse represents on the reuse continuum.  I do a lot
of reuse at this level.

>Thirdly, subunits cause havoc with sophisticated optimizers,
>especially subunits within subprograms.  When calling a separately-compiled
>subunit the compiler must assume the worst: that the subunit
>accesses and/or updates all objects it can see, meaning that
>all local variables visible to the subunit must be stored back
>into memory from registers before the call, and reloaded afterward.

Furthermore, the compiler has to assume that the subunit may contain tasks
and then it has to generate code to check for task termination etc.

Two guidelines to think about when using separate subunits:

1. Separate subunits should be declared in package bodies, not in
subprograms.

2. Nest subunits only one layer deep.  A reasonable relaxation might
allow separate package bodies inside separate package bodies.
-- 

Ed Matthews                                                edm@verdix.com
Verdix Corporation Headquarters                            (703) 378-7600
Chantilly, Virginia

stt@inmet.inmet.com (11/30/89)

Ed Matthews (edm@verdix.com) points out that fancy editors
can improve the situation w.r.t. subunits:
> 
> . . . With modern
> editor technology and windowing, the entirety of a package, whether it
> be one package of 2500 lines, or 25 subunits of 100 lines, can be 
> easily viewed.  Further, in editors with syntactic and semantic
> navigation, understanding a unit is equally easy no matter how the
> program is structured.
> 
I can't argue with this since I haven't got one of these fancy editors!
("Tags" with vi helps a little, but has real trouble with overloading
and the multi-level namespace.)

In any case, even though I do have a multi-window workstation on my desk,
I still find I like to look at good old hard-copy listings
now and then, and hyper-text just hasn't arrived on our line printer
(nor even our laser printer!) yet.  Lots of subunits make any
kind of paper and pencil work a royal pain.

S. Tucker Taft
Intermetrics, Inc.
Cambridge, MA  02138

arny@cbnewsl.ATT.COM (arny.b.engelson) (11/30/89)

In article <20600021@inmet> stt@inmet.inmet.com writes:
>We have built a number of very large Ada systems at Intermetrics,
>and our customers have built some even bigger ones.
>As a result of this we have built up a very strong
>prejudice *against* the use of subunits (aka "is separates").
>Instead, we try to structure our system as a series
>of medium size packages (about 500-2500 lines each),
>using either a functional or object-oriented structuring.
>
>Ideally, each of these packages represents a well-defined,
>relatively self-contained component of the system.
>When making a change or trying to understand a particular
>feature of the system, it is generally only necessary to
>look at the single medium-size package which implements it.
>Furthermore, most of the candidates for low-level, small-chunk-of-code
>reuse, are within a single package.

My personal experience has been working mostly on somewhat smaller
efforts (single person, 20000 - 30000 lines of code programs), and
I don't agree with this philosophy for those types of programs.

Generally, I have several "medium" size packages, but with most of
these having a few small (about 50-200 lines) subunits.  Each subunit
implements a single requirement (for lack of a better term).  Usually,
when a change is required, it is to a single subunit (not always, but
usually).  I believe this is due to a combination of the nature of the
application and a good design/program structure on my part.  Occasionally
it is necessary to restructure the parent package, but not often.

>Subunits foul up this structure in a number of ways:
>First and foremost, a single subunit is in no way "self-contained."
>It has unlimited visibility into its parent unit, representing
>a very "broad" interface (the worst kind).

The visibility of the subunit doesn't change by integrating it into
the parent.  If proper scoping of declarations is done (i.e. only what
really should be visible is visible), I don't see the problem.

>Secondly, when editing a subunit, other related code is
>not immediately available, so we have found that programmers
>working on a heavily "subunited" program tend to reinvent the
>wheel repeatedly, rather than noticing a similar sequence
>of code in another subprogram of the same package, and
>separating off that logic as a local shared subprogram
>of the package.

Isn't this a problem of the programmers not having enough knowledge of
the program, rather than a problem of the program structure itself?
If the programmer really knows the existing code, s/he will know enough
not to reinvent the wheel.  In my case, since I developed the entire
program, I know when I can reuse an existing piece of code.  Maybe your
anti-subunits stance should be limited to very large systems with
many programmers working on it.

>Thirdly, subunits cause havoc with sophisticated optimizers,
>especially subunits within subprograms.  When calling a separately-compiled
>subunit the compiler must assume the worst: that the subunit
>accesses and/or updates all objects it can see, meaning that
>all local variables visible to the subunit must be stored back
>into memory from registers before the call, and reloaded afterward.

Again, if proper scope is maintained for variables, there should be very
few that to which this would apply.

>Finally, they tend to allow single library units to grow
>without bound.  Often when a subsystem grows too big, it
>is wise to split it up into a number of packages, each with
>a narrower purpose.  When using subunits, the tendency
>is to instead just keep adding more and more functionality
>into a single package.

This is a very real risk, but is again a fault of the programmer.  A
good programmer should recognize that a subsystem needs to be split
regardless of whether there are subunits; a less qualified programmer
will let a single package grow to several thousand lines, containing
many unrelated subprograms, regardless of whether or not subunits are
employed.

>As far as recompilation, subunits are also bad news, since
>almost all compilers will recompile *all* subunits when
>any change is made to the enclosing parent unit, including

One of my goals in using subunits is to reduce the scope of changes.
Fewer changes should involve the parent.

>just the addition of another subunit.  Of course, the total
>amount of code is no greater than if the package had not
>been "subunited" (presuming you resisted the growth-without-bound

In other words (my words), the amount of code recompiled is the same,
and there is no real difference.

>phenomenon), but most compilers will compile a single 2500-line
>package much faster than 50 50-line subunits.

So what?  I don't think this amount of reduced compilation time is a
strong argument for changing your program structure.  But, if the change
is only to one subunit, compilation time can be reduced substantially.
This has actually saved me a very substantial amount of time when adding
a new feature as a subunit.  I can repeatedly recompile and debug this
very quickly.

>Of course you win when the only change to be made was in a single
>subunit, but in our experience, that incentive causes many
>of the problems with subunits -- the avoidance of restructuring
>of the package.  Many bugs can best be fixed by modest
>restructuring of the implementation of a package.  

Maybe and maybe not -- it depends on the bug.  As far as avoiding the
restructuring of a package because of subunits, I think this is again
a fault of the programmer.  I restructure when necessary, what's the
big deal?  Changing the documentation may be a different story, but that
depends on your documentation, and how it is maintained.

>Any attempt at restructuring in the presence of subunits
>causes them all to be recompiled again.

Even if they weren't subunits they would be getting recompiled anyway.
It's easier to see what areas are untouched by a change when the code
is in different files.

>I should mention that reasonable people differ
>on this whole "subunit" issue, and there are
>selected places where a subunit can be extremely useful,
>to, for instance, isolate a very small bit of host-dependent
>code.  However, on balance, I would regard them almost
>as bad as a goto -- to be used only when all other 
>avenues have been exhausted.

I think this view is a bit extreme, and its validity varies with each
type of application and with the size of the application.  Besides the
arguments I presented above, as a result of my work environment I have
saved a lot of time by using subunits.  I have saved time on recompilation
(on my sometimes overloaded system), on disk space (which we are always
running out of), on printouts (they are smaller), and on debugging time
(in many cases).  Your mileage may (rather, will) vary.

>As Lori Clarke, et al, said in their classic critique of
>Ada subunits long ago, "nesting in Ada is for the birds."

Tweet, tweet.  :-)

>S. Tucker Taft
>Intermetrics, Inc.
>Cambridge, MA  02138

Arny Engelson
AT&T Bell Laboratories
Whippany, NJ 07981
att!wayback!arny

len@array.UUCP (Leonard Vanek) (12/02/89)

In article <3076@cbnewsl.ATT.COM> arny@cbnewsl.ATT.COM (arny.b.engelson,wh,) writes:
>In article <20600021@inmet> stt@inmet.inmet.com writes:

>The visibility of the subunit doesn't change by integrating it into
>the parent.  If proper scoping of declarations is done (i.e. only what
>really should be visible is visible), I don't see the problem.

>>     subunits cause havoc with sophisticated optimizers,
>>especially subunits within subprograms.
>
>Again, if proper scope is maintained for variables, there should be very
>few that to which this would apply.

If "proper name scoping" is used to avoid the potential pitfalls of
subunits, how does the subunit differ substantially from a package?
I think that the alternative to subunits in this case is not to place
them in-line in the parent procedure or package, but to make them
packages in their own right. Why do we need to use the "is separate"
mechanism?
--------------------------------------------------------------------
Leonard Vanek                  UUCP: ... uunet!attcan!lsuc!array!len
Array Systems Computing Inc.    or ... utzoo!dciem!array!len
5000 Dufferin St. Suite 200     or lsuc!array!len@ai.toronto.edu
Downsview, Ont. M3H 5T5        Phone: (416) 736-0900
Canada                         FAX:   (416) 736-4715

schwartz@dinl.uucp (Michael Schwartz) (12/05/89)

> why do we need 'is separate'

This is just another tool to break up long files (and thus reduce
the burden of changes for recompilation).

Imagine a package with a task embedded in the body (easy to
imagine).  Imagine the task is substantial.  The task spec can
appear in the body, while the task body 'is separate'.
-- 
-----------------------
schwartz@pogo.den.mmc.com "Expect everything ... 
mschwartz@mmc.com                   and the unexpected never happens." 
ncar!dinl!schwartz                               --the phantom tollbooth

DISCLAIMER:  The opinions expressesed are not necessarily those of my 
	     employer or myself.

walsh@stdc01.UUCP (Mike Walsh) (12/06/89)

In article <1501@dinl.mmc.UUCP> schwartz@dinl.UUCP (Michael Schwartz) writes:
>
>> why do we need 'is separate'
>
'is seperate' is useful for extracting certain procedures from a package.
I once wrote a package that had a classified algorithm in it.  By making the
one procedure separate, I could print out the file, and not have to worry
about having a classified document laying around.  Just an example ...


Mike Walsh
Star Technologies - Graphicon Products Division
Research Triangle Park, NC

walsh@stdc01    {...uunet!mcnc!rti!stdc01!walsh}

stluka@software.org (Fred Stluka) (12/08/89)

In article <60@array.UUCP> len@array.UUCP (Leonard Vanek) writes:
> If "proper name scoping" is used to avoid the potential pitfalls of
> subunits, how does the subunit differ substantially from a package?
> I think that the alternative to subunits in this case is not to place
> them in-line in the parent procedure or package, but to make them
> packages in their own right. Why do we need to use the "is separate"
> mechanism?


Subunits are similar to library units in being allowed to have "with"
clauses.

However, they are different in not being able to be "with"ed by other 
units.  They are visible only to their parents.

Subunits are the only choice when you want to only a small portion of 
a large package to have visibility into other library units without 
allowing other units to have visibility into the small portion.  

--Fred
--
Fred Stluka                          CSNET:   stluka@software.org
Software Productivity Consortium     ARPANET: stluka%software.org@RELAY.CS.NET
2214 Rock Hill Rd, Herndon VA 22070  UUNET:   ...!uunet!sunny!stluka