Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A comparison of Ada and Modula 3

39 views
Skip to first unread message

Kenneth Almquist

unread,
Feb 5, 1996, 3:00:00 AM2/5/96
to
1. Introduction

Ada and Modula 3 have many things in common, but they differ in a
number of significant ways. Here are some notes I've written up
comparing on the similarities and differences of the two lan-
guages.

Ideally, language comparisons should be written by people who are
experienced in both languages being compared. I have used both
Ada and Modula 3, but I only know Ada well. These notes should
be read with that qualification in mind.


2. External Issues

2.1 History and Purpose

Ada was developed under contract to the U.S. Department of De-
fense, with the intent that it become a common high order lan-
guage for systems development.

Modula 3 was developed by the Systems Research Center at DEC, and
was used to implement the TAOS system. One goal of the Modula 3
effort was to produce a reasonably simple language. The develop-
ers set and achieved a language that could be described in 60
pages.

2.2 Language Standards

The current version of the language is Ada 95, which is an ISO
standard. Modula 3 has not been standardized, but a language
specification has been written by DEC. Both specifications are
available for free on the Internet.

2.3 Other Issues

Ada has the backing of the US DoD, which is generally considered
to have done a poor job of promoting the language. Never the
less, Ada is more widely used than Modula 3, particularly in the
commercial world. Both languages have been used with reported
success as a first language in Computer Science curricula.

Free compilers for both languages are also available on the net.
GNAT and SRC Modula 3 both use the GCC back end.


3. Packages/Modules

3.1 Basics

Both Ada and Modula 3 provide an encapsulation construct. The
only definitions which are visible outside the package/module are
those provided in the "interface" (Modula 3 terminology) or the
"package specification" (Ada terminology).

Ada 95 supports child packages. A package named "X.Y" is a child
of the package named "X". Child packages are useful for managing
the name space of large systems and for sharing information be-
tween packages without making the information generally avail-
able. As an example of the first use, most of the packages de-
fined by the Ada 95 standard are children of "Ada". The package
"Ada" contains no definitions; it simply serves as a place to put
other definitions. Child packages can be declared to be "pri-
vate", meaning that only other children of the same parent can
use them. For example, if you wanted to implement Ada.Text_IO
and Ada.Sequential_IO in terms of a common abstraction, but
didn't want to cast the interface in concrete, you could place
the common abstraction in a private child of Ada.

Modula 3 allows a module to have more than one interface. In
Ada, each package has a single interface, but child packages can
be used to provide the equivalent of multiple interfaces.

Both Ada and Modula 3 provide the ability to export a type via an
interface without revealing all of the details of the type. This
will be covered under the discussion of data types.


3.2 IMPORT/with

The Modula 3 declaration "IMPORT Interface;" and the Ada declara-
tion "with Interface;" are essentially equivalent. In Modula 3,
writing

FROM Interface IMPORT name1, name2, name3;

allows you to refer to the specified names directly rather than
writing Interface.name1. In Ada, writing

use Interface;

allows you to refer to all of the names in Interface directly.
This means that adding names to an interface in Ada can cause
previously working clients to no longer compile (although this is
not common in practice). In constrast, adding new names to a
Modula 3 interface cannot break clients.


3.3 Generics

Both Ada and Modula 3 support generics, which are similar in con-
cept to C++ templates.

Ada supports both generic packages and generic procedures. In
Ada a generic has a specification which determines what parame-
ters can be used to instantiate it. For example, the generic pa-
rameter

type T is range <>;

will match any integer type. Attempting to instantiate the
generic with a record type will result in a compile time error.
This checking can be performed even before the implementation of
the generic is written.

Modula 3 supports generic modules. The parameters to the generic
are other interfaces. (In contrast, Ada also allows variables,
constants, types, subroutines to be used as parameters.) The
language does not include a way to specify what interfaces are
appropriate for use with a particular generic; as a result an in-
correct instantiation may result in an error message relating to
code buried in the body of the generic module. However, instan-
tiations are fully checked at compile time.


4. Data Types

4.1 Data Type Equivalence

Modula 3 uses structural equivalence for types. The means that
if you have two types with the same structure, they can be used
interchangeably.

This raises the possibility of two unrelated types which just
happen to have the same structure being confused by the program-
mer without the compiler detecting it. Two things make this un-
likely. First, the names of fields in records are considered to
be part of the type. so that
RECORD
seconds: INTEGER;
milliseconds: INTEGER;
END;
and
RECORD
x: INTEGER;
y: INTEGER;
END;
are different types. Second, it is possible to "BRAND" reference
types in order to make them distinct. A "brand" is simply a text
string which is compared when checking for structural equiva-
lence; if two reference types have different brands then they are
not equivalent types. If the keyword "BRAND" is used without
specifying a brand, the compiler generates a string which is
guaranteed to be unique. Branding only applies to reference
types.

Ada 95 uses name equivalence. This means that each type defini-
tion defines a new type. Ada 95 also includes subtype defin-
tions, which define a type which can be used interchangeably with
the parent type except that the range of possible values may be
restricted.

subtype Size is Integer range 1 .. 1000;

defines a type which is compatible with type Integer but whose
range is restricted.

An example of the use of name equivalence in Ada is the defini-
tion of a process exit status, which appears in Ada.Command_Line:

type Exit_Status is range 0 .. 255;

This creates a new type (which inherits the integer literals and
operators from some integer type selected by the compiler). Ac-
cidentally using an integer in place of an exit status value will
typically be caught by the compiler. If it is actually necessary
to assign an Integer value to and Exit_Status variable, this can
be done using an explicit type conversion.


4.2 Basic Data Types

Ada and Modula 3 both provide integer, floating point, enumerat-
ed, array, record, and pointer types.

Modula 3 provides a set type. Ada does not, although a similar
effect can be achieved using an array of boolean.

Ada provides variant records. Modula 3 does not, but object
types (similar to tagged types in Ada 95) can be used to achieve
a similar effect.

Ada and Modula 3 both allow the ranges of integer types to be
specified. In Modula 3 integer types are always subtypes of IN-
TEGER, whereas in Ada a compiler may allow integer types with a
range larger than Integer. This means that large integer ranges
are difficult to support under Modula 3.

Ada 95 includes modular types, which provide modular arithmetic
and bit operations on unsigned integers. Modula 3 includes an
interface named WORD, which defines an unsigned integer type.

Modula 3 provides three floating point types: REAL, LONGREAL,
and EXTENDED. It also provides packages containing constants
which describe these types. (Precision is specified; accuracy is
not.) Ada 95 allows you to declare a floating point type by
specifying a minimum accuracy. It also supports fixed point
types.


4.3 Opaque/private types

In Ada, a type in an interface can be declared to be "limited
private." The full definition of the type is then given in a
portion of the package which is labeled "private." The only op-
erations available for the type are the operations specified in
the interface. A type can also be declared to be "private",
which is similar to "limited private" except that the assignment
and comparison for equality are allowed.

The corresponding feature in Modula 3 is the opaque type. An
opaque type is always a pointer (and is always branded). The
least informative declaration of an opaque type is

TYPE T <: REFANY;

which specifies that t is some subtype of REFANY (which is the
class of all pointer types). The type of t must be specified
somewhere using a REVEAL statement:

REVEAL T = Xtype;

Partial revelations provide more limited information about an
opaque type. (Typically this is useful with objects, discussed
in the next section.)

Revelations can occur anywhere. A client using the interface
defining T could write the partial revelation

REVEAL T <: Xtype;

Following this definition, the client could use T as an Xtype,
thereby violating the "opaqueness" of the type. This can be pre-
vented by encapsulating the definition of Xtype in the body of a
module where the client cannot access it. If T is an object (see
the next section), the problem is not so easily solved because
the client can also gain (partial) access to the implementation
of T by revealing it to be any of the parent types of Xtype.

Since opaque types are pointers, there is always the possibility
of them being NIL. For example, both Modula 3 and Ada 95 have an
unbounded length string type defined in their standard libraries.
In Modula 3, operations on the unbounded string type may fail be-
cause they are passed NIL rather than an unbounded string. In
Ada 95, this error is not possible.


4.4 Objects

In Ada and Modula 3, encapsulation is provided by mod-
ules/packages and opaque/private types rather than being limited
to "objects." Ada 95 and Modula 3 both provide additional con-
structs to support single inheritance and polymorphism.

In Modula 3, objects are declared using OBJECT declarations,
which specify the fields and methods associated with the object.
Objects may only be allocated on the heap. An object type actu-
ally refers to a pointer to the object rather than the object it-
self.

The methods associated with a Modula 3 object are listed as part
of the object declaration. Overrides of existing methods are
listed separately from the addition of new methods. This means
that if you attempt to redefine a method but misspell the name
you will get a compile time error. (In contrast, Ada 95 will
cheerfully accept the misspelled name, treating it as a new
method.)

The Ada 95 equivalent to an object is a tagged type. In contrast
to Modula 3, Ada 95 tagged types are not restricted to the heap.
Defining a tagged type actually defines two types: a specific
type and a class-wide type. The class-wide type can refer to the
specific type or to any type derived from the specific type.
Dispatching calls are only performed when class-wide types are
used.

In Ada 95, you can override a method but not delete it. This
means that dispatching calls can be checked at compile time. In
contrast, Modula 3 allows you to override a method by setting it
to NIL. Calling NIL is a run time error.


4.5 Pointer types

In Modula 3, all heap objects have a type tag associated with
them, so that the type can be determined at run time. There is
also a general pointer type (REFANY) which is a pointer to an ob-
ject of an unspecified type. Pointers can only point to object
on the heap.

In Ada 95, only tagged object need contain a tag. You can have a
pointer to a local or static variable as long as the variable is
declared to be "aliased".


4.6 Representation Specifications

Modula 3 provides a BITS FOR clause which specifies the size of a
type and prevents the compiler from inserting padding between an
object of the type and any preceding object. Ada 95 provides a
much more complex set of representation clauses.


5. Storage Management

Modula 3 provides automatic garbage collection. Ada permits au-
tomatic garbage collection but does not mandate it, and in prac-
tice it is not generally implemented.

Ada 95 provides controlled types. These have hooks which the
compiler calls when assigning to or destroying an object of the
type. These are typically used for freeing memory. Controlled
types make manual storage management easier that it otherwise
would be, but automatic garbage collection is still easier and
less error prone. Controlled types can also be used to ensure
that resources other than memory are freed; Modula 3 has no
equivalent for this (relatively uncommon) use of controlled
types.

Modula 3 generally requires more heap allocation than Ada, be-
cause Modula 3 requires both objects and arrays whose size is not
known at compile time to be allocated on the heap.

Both languages provide escape mechanisms to perform address
arithmetic when necessary.


6. Statements

Both Ada and Modula 3 provide a standard set of fully bracketed
flow-of-control constructs. Modula 3 provides a REPEAT UNTIL
construct which is a while loop with the test at the bottom; Ada
provides an "exit when" construct which makes it a bit easier to
find the exit condition for a loop with the test in the middle.
The Modula 3 FOR loop allows a step size to be specified.

Ada includes a goto statement, although some coding standards
prohibit its use.


7. Exceptions and run time errors

Both Ada and Modula 3 provide exceptions. A Modula 3 exception
may have a parameter. The value of the parameter is made avail-
able to the exception handler. Ada 95 exceptions do not have pa-
rameters, but an message string is associated with every excep-
tion.

In Ada 95, every run time error (that the compiler is required to
check for) maps into an exception. This is intended to allow
fault tolerant programs to attempt to recover from bugs. In Mod-
ula 3, the method of reporting run time errors is implementation
defined.

The Modula 3 specification doesn't say anything about memory ex-
haustion or arithmetic overflow. The SRC Modula 3 compiler caus-
es programs to abort when they run out of memory, which limits
the ability to construct reliable programs.

Ada includes pragmas which suppress run time checking. These can
be used to improve performance in code which is believed to be
reliable. The Modula 3 specification does not define pragmas to
suppress run time checking, although an implementation could pro-
vide them.

When you declare a Modula 3 procedure, you specify the set of ex-
ceptions which it can raise. It is a run time error for the pro-
cedure to raise an exception not listed.

Modula 3 provides a TRY FINALLY construct which will execute a
set of statements and then execute some cleanup code. The
cleanup code is exited regardless of whether the statements are
exited via an exception, a return statement, an exit statement,
or normal execution. Controlled types provide a similar capabil-
ity in Ada 95.


8. Tasks/threads

Both Ada and Modula 3 suport multiple threads of control in a
single address space. The Ada 95 distributed systems annex
(which is an optional part of the standard) provides support for
distributed programs. Modula 3 uses locks and conditions for
synchronization, while Ada 95 uses rendezvous and protected
types. A complete discussion of these alternatives would require
more time than I'm willing to put into this document.


9. Procedure parameters

Procedure parameters can have default values in both Ada and Mod-
ula 3. A call can use either named or positional notation, or a
combination of the two.

In Ada, parameter modes specify the flow of information. The
modes of a parameter can be "in", "out", or "in out". (Func-
tions, which are procedures which return a value, are restricted
to "in" parameters.) In Modula 3, the possible parameters modes
are VAR, VALUE, and READONLY. The first two correspond to call
by reference and call by value. The last is call by reference if
the actual parameter is a variable, and call by value otherwise.


10. Expressions

10.1 General

Modula 3 allows the result of a procedure which returns a value
to be discarded by writing "EVAL procedure-call". In Ada 95, the
only way to discard an unused result is to assign it to a vari-
able and not use the value of the variable.

Ada 95 includes an exponentiation operator; Modula 3 does not.
Both Ada 95 and Modula 3 include short circuit versions of and
and or; Ada 95 also includes non-short-circuit versions.

Both languages include constructors for aggregates, with both
named and positional notation.


10.2 Overloading and Operator Redefinition

Ada allows procedures, functions, and enumeration values to be
overloaded. Modula 3 does not (beyond the simple overloading of
the predefined operators). Ada also allows operators additional
overloadings to be added to the existing Ada operators, although
new operators cannot be defined.


11. Lexical

Modula 3 is case sensitive; all keywords are in upper case. In
Ada, the distinction between upper and lower case letters is not
significant except in character and string constants.

Ada allows underscores to be inserted in numbers to improve read-
ability; for example 10000000 can be written as 10_000_000.


12. My Conclusions

Ada and Modula 3 have many features in common, and are useful for
many of the same types of problems. Automatic garbage collection
is clearly Modula 3's strong point when compared to Ada 95. I'm
less sure about the weaknesses of Modula 3 since it is often dif-
ficult to distinguish between bad ideas and unfamiliar ideas, but
my biggest concern is with Modula 3's lack of "private" types.
In fact my web browser just pulled up the following comment from
the WeakRef interface:

Please treat this as though it were an opaque type: the only
operations allowed are assignment, equality tests, and the
procedures
in this interface.

In Ada you would simply declare the type private and let the com-
piler enforce this restriction, rather than writing pleading com-
ments.
Kenneth Almquist

Tim Mann

unread,
Feb 5, 1996, 3:00:00 AM2/5/96
to
I'd like to pick a few nits in the M3 side of this comparison.

In article <4f48un$s...@nntpa.cb.att.com>, k...@socrates.hr.att.com (Kenneth Almquist) writes:

>Modula 3 was developed by the Systems Research Center at DEC, and
>was used to implement the TAOS system. One goal of the Modula 3
>effort was to produce a reasonably simple language. The develop-
>ers set and achieved a language that could be described in 60
>pages.

Taos was actually implemented in Modula-2+, a predecessor to Modula-3.
The experience of building Taos did help give direction to the M3 design.

The goal was 50 pages, and they ran slightly over, but came in well
under 60.

>Ada has the backing of the US DoD, which is generally considered
>to have done a poor job of promoting the language. Never the
>less, Ada is more widely used than Modula 3, particularly in the
>commercial world. Both languages have been used with reported
>success as a first language in Computer Science curricula.

Another reason Ada is more widely used is that it was introduced
several years before Modula-3, so it has had more time to catch on.

>Following this definition, the client could use T as an Xtype,
>thereby violating the "opaqueness" of the type. This can be pre-
>vented by encapsulating the definition of Xtype in the body of a
>module where the client cannot access it. If T is an object (see
>the next section), the problem is not so easily solved because
>the client can also gain (partial) access to the implementation
>of T by revealing it to be any of the parent types of Xtype.

What problem? Opaqueness is not a security feature like passwords or
encryption. Opaqueness simply lets an interface designer hide
information that clients shouldn't use, by putting it in a separate
interface or module that they don't have to import or look at. If
clients insist on looking under the covers by importing private
interfaces or writing their own REVEAL statements, they can do so.
The point is that no one is going to do this by mistake. (Contrast
this with C++, where one is practically forced to put all kinds of
information in .H files that clients should not use and should not
have to look at.) I don't know whether Ada's "private" mechanism is
better or worse than M3's opaques; it seems rather similar in power
from your description.

>In Ada 95, you can override a method but not delete it. This
>means that dispatching calls can be checked at compile time. In
>contrast, Modula 3 allows you to override a method by setting it
>to NIL. Calling NIL is a run time error.

Overriding a method with NIL is not intended to mean that you are
deleting it from the type signature. In particular, if you take a
type that has a NIL method and subtype it, you can override the NIL
with a real method again. If the NIL were deleting the method, there
would be nothing to override. NIL is nothing more than shorthand for
a method that always raises a run-time error if you call it. You can
write such a method in any object-oriented language; you just don't
get the shorthand of calling it NIL in most. So M3 and Ada are
basically the same on this point.

Note that no form of method override (including override with NIL)
occurs at runtime; method override can occur only in a type
declaration.

>Ada 95 provides controlled types. These have hooks which the
>compiler calls when assigning to or destroying an object of the

>type. ... Controlled types can also be used to ensure


>that resources other than memory are freed; Modula 3 has no
>equivalent for this (relatively uncommon) use of controlled
>types.

The WeakRef interface in M3 provides a rather similar facility. It
lets you get control when the garbage collector wants to throw
something away, and it lets certain references (e.g., from a cache you
are maintaining) be considered as "weak" and not considered by the
collector.

>cleanup code is exited regardless of whether the statements are

"exited" should read "executed", of course

>my biggest concern is with Modula 3's lack of "private" types.
>In fact my web browser just pulled up the following comment from
>the WeakRef interface:
>
> Please treat this as though it were an opaque type: the only
> operations allowed are assignment, equality tests, and the
>procedures
> in this interface.
>
>In Ada you would simply declare the type private and let the com-
>piler enforce this restriction,

The problem here is that the WeakRef type wants to be opaque, but it
isn't an object or REF type. Modula-2+ had opaque word types, but
they were little-used, so the feature was left out of M3. The vast
majority of types that need to be opaque in M3 programs are object or
REF types.

In this particular case, no one is really likely to do anything with a
WeakRef that the comments forbid, so the lack of opacity seems harmless.

> rather than writing pleading comments.

Would you have liked the comment better if it didn't say "please"? :-)

--Tim

Olaf Wagner

unread,
Feb 5, 1996, 3:00:00 AM2/5/96
to

I just thought somebody might be interested in the HTML version of
the language comparision by Kenneth Almquist I just produced.

To save space, it's a gzip'ed uuencoded file.


begin 664 m3-vs-ada.html.gz
<uuencoded_portion_removed>
,VQ#S7TJ'%O5%6@``
`
end

--
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ Olaf Wagner at Logware GmbH Schwedenstrasse 9 \
\ ol...@logware.de (work) 13359 Berlin \
\ wag...@luthien.in-berlin.de (private) Germany / Deutschland \
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Farshad Nayeri

unread,
Feb 6, 1996, 3:00:00 AM2/6/96
to

I must admit that I think feature-by-feature comparison of Ada95 with
Modula-3 is like that of a Jaguar and an MG. (I am probably being nice
to both languages here. ;-) Nevertheless, it is nice to see some an
Ada programmer's view of Modula-3! Now, if we could get a Modula-3
programmer to read the Ada95 reference manual and try programming in
it...

My basic point is:

When reviewing design tradeoffs of any artifact, I think it is always
a good question to ask "At what cost?". I think we should also ask
this question in review of Ada95 and Modula-3's designs. At what costs
do they achieve their results?

If a design is simple, we must ask, at what cost have the designers
achieved this? Does the design miss some important uses to be expected
from the artifact? Does the design specify enough?

If a design incorporates many features, then we must ask again, at
what cost was this achieved? How many pages are the specifications?
How compliant are the implementations to the full specification? Is
the design overspecified?

Looking at the design for Modula-3, I'd say that the designers aimed
at simplicity, safety, and completeness in *that order*. From what I
know about Ada, its design tends to follow the opposite order. I think
the difference in the languages reflects this point more than anything
else: Modula-3 achieves Ada95's (or C++'s) power with a definition
that is about *an order of magnitude* simpler.

(*) With the *major* but sad exception that Ada95 doesn't have garbage
collection. I was hoping to see C++ as the popular last language
design which didn't support garbage collection!

-- Farshad

Disclaimer: I am biased!
--
Farshad Nayeri
nay...@gte.com

Brian Rogoff

unread,
Feb 6, 1996, 3:00:00 AM2/6/96
to
nay...@gte.com (Farshad Nayeri) writes:
I must admit that I think feature-by-feature comparison of Ada95 with
Modula-3 is like that of a Jaguar and an MG. (I am probably being nice
to both languages here. ;-)

Both languages seem pretty nice, though I think I'd miss overloading, and
the more complex generics of Ada in Modula 3. GC is the single most important
advantage over Ada that M3, and my personal favorite, Sather, have.

If a design is simple, we must ask, at what cost have the designers
achieved this? Does the design miss some important uses to be expected
from the artifact? Does the design specify enough?

I think we should define "simplicity", or use a more specific terminology,
before we use it as a metric. I assume here that you are using the size
of the reference manual to measure simplicity.

Looking at the design for Modula-3, I'd say that the designers aimed
at simplicity, safety, and completeness in *that order*. From what I
know about Ada, its design tends to follow the opposite order. I think
the difference in the languages reflects this point more than anything
else: Modula-3 achieves Ada95's (or C++'s) power with a definition
that is about *an order of magnitude* simpler.

I can't say because I don't know M3 well (I read a few articles about it), but
I seem to remember that all user created M3 types get heap allocated. If this is
so, then I kind of doubt that I'd want to write complex matrix types for
numerical programming in M3. In Ada, stack allocated ("value") objects are the
default and you use references (access types) to make heap allocated objects.
For an "OOP"language, I'd prefer that ref was the default, and special syntax
added to handle value types (a-la Sather). Is anyone using M3 for CPU intensive
numerical work? Any measurements on how it would stack up (;-)) against Ada/Sather/C++
for this?

(*) With the *major* but sad exception that Ada95 doesn't have garbage
collection. I was hoping to see C++ as the popular last language
design which didn't support garbage collection!

I agree 100%! Maybe the new Ada-Java stuff will lead to GC sneaking into Ada.

-- Farshad

-- Brian


Laurent Guerby

unread,
Feb 6, 1996, 3:00:00 AM2/6/96
to
Robert A Duff writes
[discussion about abstraction deleted]
: Of course, there's a cost to allowing different sizes -- in Ada, if you
: change the record type that completes a private type, you have to
: recompile all clients, even though those clients are not supposed to
: "know" what that record looks like.

Is there a cost when it ends in an incomplete type declaration ?

type T is private;
private
type Internal;
type T is access Internal;
-- Full definition of internal in the body.

In this case I think there's no recompilation cost, but you may
pay something each time you access the type (I don't know what
GNAT does).

: - Bob

-- Laurent Guerby, student at Telecom Bretagne (FRANCE), Team Ada
-- mailto:Laurent...@enst-bretagne.fr
-- http://www-eleves.enst-bretagne.fr/~guerby/
-- Try GNAT, the GNU Ada 95 compiler (ftp://cs.nyu.edu/pub/gnat)

Robert A Duff

unread,
Feb 6, 1996, 3:00:00 AM2/6/96
to
In article <4f5phe$3...@src-news.pa.dec.com>, Tim Mann <ma...@pa.dec.com> wrote:
>>In Ada 95, you can override a method but not delete it. This
>>means that dispatching calls can be checked at compile time. In
>>contrast, Modula 3 allows you to override a method by setting it
>>to NIL. Calling NIL is a run time error.
>
>Overriding a method with NIL is not intended to mean that you are
>deleting it from the type signature. In particular, if you take a
>type that has a NIL method and subtype it, you can override the NIL
>with a real method again. If the NIL were deleting the method, there
>would be nothing to override. NIL is nothing more than shorthand for
>a method that always raises a run-time error if you call it. You can
>write such a method in any object-oriented language; you just don't
>get the shorthand of calling it NIL in most. So M3 and Ada are
>basically the same on this point.

Does M3 have abstract types? In Ada you can declare a method as
abstract (whether it's overriding something or not), and then further
type derivations can override it with a non-abstract version. The nice
thing about this is that the rules ensure at compile time that the
abstract thing is never called -- you can't create an object that would
cause it to be called via run-time dispatching, for example.

As you say, if you want run-time checking instead, you can simply write
an overriding that raises an exception. That's the same as NIL, except
that there's no short-hand.

>The problem here is that the WeakRef type wants to be opaque, but it
>isn't an object or REF type. Modula-2+ had opaque word types, but
>they were little-used, so the feature was left out of M3. The vast
>majority of types that need to be opaque in M3 programs are object or
>REF types.

That's compared to a language that allowed word types in addition, but
not just *any* type. In Ada, the vast majority of private types end up
being implemented as record types, not pointer types or word types. I'm
not familiar with Modula-2+, but in Modula-2, the issue was one of size
-- the compiler assumed that an opaque type, if not a pointer, was
exactly the same *size* as a pointer, which of course rules out most
records.

Of course, there's a cost to allowing different sizes -- in Ada, if you
change the record type that completes a private type, you have to
recompile all clients, even though those clients are not supposed to
"know" what that record looks like.

- Bob

Robert A Duff

unread,
Feb 7, 1996, 3:00:00 AM2/7/96
to
In article <4xn36wt...@fermat.enst-bretagne.fr>,

Laurent Guerby <Laurent...@enst-bretagne.fr> wrote:
>Is there a cost when it ends in an incomplete type declaration ?
>
> type T is private;
>private
> type Internal;
> type T is access Internal;
> -- Full definition of internal in the body.
>
>In this case I think there's no recompilation cost, but you may
>pay something each time you access the type (I don't know what
>GNAT does).

That's right. By using an incomplete type, completing it in the package
body, you end up making the private type be a pointer. The advantage is
that you don't have to recompile clients when the record fields change.
The disadvantage is that the generated code is less efficient, since
there's an extra level of indirection. And that you need to manage
storage allocation (controlled types make sense for that). Essentially,
you've moved the cost from compile time to run time, which is often a
good idea.

This kind of thing is essentially the same as Modula-3's opaque types,
where the type has to be implemented as a pointer.

- Bob

Louis-Dominique Dubeau

unread,
Feb 7, 1996, 3:00:00 AM2/7/96
to
Kenneth Almquist wrote:

> Ada 95 provides controlled types. These have hooks which the
> compiler calls when assigning to or destroying an object of the
> type. These are typically used for freeing memory. Controlled
> types make manual storage management easier that it otherwise
> would be, but automatic garbage collection is still easier and
> less error prone. Controlled types can also be used to ensure
> that resources other than memory are freed; Modula 3 has no
> equivalent for this (relatively uncommon) use of controlled
> types.

I beleive weak references in M3 might do the trick.

> In Ada you would simply declare the type private and let the com-
> piler enforce this restriction, rather than writing pleading com-
> ments.

In M3 you can only do this with a reference.

ldd

-- Louis-Dominique Dubeau == Home page: http://step.polymtl.ca/~ldd/ --

Norman H. Cohen

unread,
Feb 7, 1996, 3:00:00 AM2/7/96
to
In article <NAYERI.96...@tahoe.gte.com>, nay...@gte.com
(Farshad Nayeri) writes:

|> Ada spec is about =800= pages. Modula-3 spec is about =50= pages.
|> Add to the M3 spec, the "standard portable library" (100 or so pages)
|> and Network Objects (another 50 or so pages.) you get about 200-250
|> pages for a whole system to do portable, reliable, distributed
|> programming with some support for persistence. What would be the Ada
|> equivalent?

This discussion is badly in need of some facts. The Ada 95 Reference
Manual is 543 pages long, including an extraordinarily complete index,
a syntax cross-reference, and other redundant but useful reference
material. Roughly half of the RM is devoted to language rules,
explanatory notes, and examples; the other half is a description of
predefined facilities--standard libraries. (When it comes to standard
libraries, size is an asset, not a liability.) The Ada language rules
are expressed with formalistic rigor and precision; a less rigorous
presentation, leaving more questions unanswered--say on the level of
Wirth's in the Modula-2 RM--would have led to a substantially shorter
Ada RM.

There is no denying that Ada 95 is a more complex language than Modula-3.
However, Ada 95 is not the behemoth you are picturing. The Modula-3 RM
is not an order of magnitude smaller, and Modula-3 is not an order of
magnitude simpler.

The subset test you mention earlier in your note--

|> Yes, reference manual may be a measure. Another is: what susbset of
|> the system do I have to know about to start to be productive? Number
|> of concepts that a programmer needs to keep in mind at all times in
|> order to be productive.

--is a good one. Ada is highly orthogonal. Writers of single-task
programs need not be concerned with the multitasking facilities; writers
of high-level program components need not be concerned with the
facilities for low-level programming and control of data representation.
Programmers can instantiate generic units without first learning how to
write them. They can use their own compilers without worrying about all
the options laid out in the standard for alternative models of the
compilation environment. A general-purpose "starter set" of Ada features
could be described completely in a few dozen pages.

--
Norman H. Cohen nco...@watson.ibm.com

Bob Kitzberger

unread,
Feb 7, 1996, 3:00:00 AM2/7/96
to
Congratulations and thank you to the contributors to this thread
for producing a useful and reasoned comparison between two languages!
Not a whisper of a language war!

Farshad Nayeri

unread,
Feb 7, 1996, 3:00:00 AM2/7/96
to

> Both languages seem pretty nice, though I think I'd miss
> overloading, and the more complex generics of Ada in Modula 3. GC is
> the single most important advantage over Ada that M3, and my
> personal favorite, Sather, have.

Certainly Modula-3 generics could've been more sophisticated, but I'd
say two things about them: (a) they are there and (b) they are clean
and easy to understand (sometimes too easy, I guess.) I think language
designers tried to be conservative because they didn't have enough
experience with them. (I recall that at the first Modula-3 BOF there
was a proposal for a different generic language.)

I actually like the lack of overloading. I find that it makes for
programs to be much more clear. Though I can see why they'd be useful
for numerical programming.

I guess I'd give up both of these for GC. In fact, if someone gave me
the choice of GC vs. objects, I'd still pick GC. You can always
"emulate" objects, and work around generics, but "emulating" GC is
quite hard.


> I think we should define "simplicity", or use a more specific
> terminology, before we use it as a metric. I assume here that you
> are using the size of the reference manual to measure simplicity.

I didn't mean it as a "metric", but more as a wholistic design goal.


Yes, reference manual may be a measure. Another is: what susbset of
the system do I have to know about to start to be productive? Number
of concepts that a programmer needs to keep in mind at all times in
order to be productive.

Ada spec is about =800= pages. Modula-3 spec is about =50= pages.


Add to the M3 spec, the "standard portable library" (100 or so pages)
and Network Objects (another 50 or so pages.) you get about 200-250
pages for a whole system to do portable, reliable, distributed
programming with some support for persistence. What would be the Ada
equivalent?

Here is what I like about programming in Modula-3 (again, hard to capture in a metric:)

When you run into a problem in some Modula-3 code, most of the time
you can isolate it locally quite easily. That is, looking at a
statement in some program, it is not too hard to tell precisely what
it is doing. Things like operator overloading, copy constructors,
destructors, controlled types, etc., make this a lot harder to do in
other languages. Modula-3 style also encourages you to use
fully-qualified references to other modules, which also makes things
simpler.

Another metric: are your programmers often pulling their hair out
trying to figure out what a piece of code does that they got from
someone else?

> [...] I don't know M3 well [...] but I seem to remember that all user


> created M3 types get heap allocated. If this is so, then I kind of
> doubt that I'd want to write complex matrix types for numerical
> programming in M3.

It is not so. User-defined types in M3 can be stack
allocated. Modula-3 provides RECORD types which can get allocated on
the stack just like C structs. Normal arrays are also stack allocated,
however, you can have a REF ARRAY type which is obviously heap
allocated.

> For an "OOP"language, I'd prefer that ref was the default, and
> special syntax added to handle value types (a-la Sather).

In Modula-3, you can choose OBJECT types which are heap allocated in
most implementations or RECORDs which are stack allocated. You can
have also have either a REF RECORD (traced by default, so it is
garbage collected) or UNTRACED REF RECORD (not traced, good for
systems programming.)

> Is anyone using M3 for CPU intensive numerical work? Any measurements
> on how it would stack up (;-)) against Ada/Sather/C++ for this?

We have to be careful to see if we are comparing languages or language
implementations. SRC Modula-3 is not the fastest code you can generate
from Modula-3 (but it is among the most potrable compilers I have seen
for a language of its class...) There are various groups working on
Modula-3 optimizers. For one effort, see Amer Diwan's article in the
latest issue of Threads, http://www.cmass.com/threads. Since the
language is much simpler than others in its class, it may actually be
easier to optimize also.

-- Farshad

--
Farshad Nayeri
nay...@gte.com

Farshad Nayeri

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to

Hi Norman. Thanks for your comments (and the addition of facts to my
rhetorics!)

> The Ada 95 Reference Manual is 543 pages long,

I looked over an 800-or-so-page manual for Ada95 this summer. Perhaps
it was the *annotated* user manual. (I will have to double-check.) Are
you also including in the annexes in your count?

> [Ada RM includes] an extraordinarily complete index, a syntax


> cross-reference, and other redundant but useful reference material.

This is certainly nice, but if the Ada spec had been shorter and
simpler, it may not have required support of a complicated index, and
all this redundant information, wouldn't you say? (Though it could've
been the ISO RFP requirements.)

Here is another question: if you throw away all the annexes, the
index, *everything* but the "bare bones" required libraries for Ada95,
how many pages of a spec. do you have?

> Roughly half of the RM is devoted to language rules, explanatory
> notes, and examples; the other half is a description of predefined
> facilities--standard libraries.

Based on your comments, we have:

M3 Ada95

The Language: 40p 200p (200p is roughly half of 543 pages)
The Library: 100p 250p (there are few "required" libraries in the M3
Index, etc. 20p 50p spec which are redefined in the library)

So this leaves the Ada language definition 5 times larger than
Modula-3's. Note that the Modula-3 spec does include some explanation
and small examples, also, though it is not meant as a source for a
novice to learn the language.

> (When it comes to standard libraries, size is an asset, not a
> liability.)

I tend to disagree. Functionality and ease of use of standard
libraries count as assets. Library size (in terms of number of
functions or lines, or kilobytes) is not as much an asset, and perhaps
a liability. (Believe me, having a multi-million-lines library as the
default for the SRC Modula-3 distribution has hurt it a lot more than
helping it!)

In terms of functionality, we can ask what is covered by the Ada RM
that is not covered by Modula-3 "Some Useful Interfaces" or "Network
Objects" manuals.

> The Ada language rules are expressed with formalistic rigor and
> precision; a less rigorous presentation, leaving more questions
> unanswered--say on the level of Wirth's in the Modula-2 RM--would
> have led to a substantially shorter Ada RM.

This may be true about Modula-2 (which I know very little about), but
I personally find the Modula-*3* spec to be among the most rigorous
but practical language specs around. (I would like to hear your
comments regarding the spec.) It is also backed by strong theory and
actual experience with Modula-2+ features that were popular, safe, and
useful, and tries to avoid ones that weren't. The language was
implemented simultanously by two independent teams emphasizing
different aspects of the implementation. The language (and the
implementations) were initally released for a year, and at the end the
language was slightly modified. (The "12 changes" added the
"OVERRIDES" keyword for example which Ada95 is still missing.) In many
ways, this is as good a process as it can get for langauge design. Too
bad DEC never got around making it into a product... (Then again,
maybe that's a _good_ thing! :-)

> There is no denying that Ada 95 is a more complex language than
> Modula-3. However, Ada 95 is not the behemoth you are picturing.

> The Modula-3 RM is not an order of magnitude smaller, and Modula-3
> is not an order of magnitude simpler.

So then in your opinion,how much simpler a language is Modula-3?
y


> The subset test you mention earlier in your note--
>

> |> Yes, reference manual may be a measure. Another is: what susbset of
> |> the system do I have to know about to start to be productive? Number
> |> of concepts that a programmer needs to keep in mind at all times in
> |> order to be productive.
>

> --is a good one. Ada is highly orthogonal.

I agree that in the "large scale", Ada's design is highly
orthogonal. I am not entirely sure about the orthogonality of more
detailed feature interactions, like tagged, controlled, and other
modifiers for types.

> writers of high-level program components need not be concerned with
> the facilities for low-level programming and control of data
> representation.

I am curious--how can representation-independence be achieved without
garbage collection? Are you assuming that the parties are using
controlled types? I find it very difficult to "forget about data
representation" of a data structure if I have to deal with managing
memory.

I also question the "look but don't touch" style of the Ada private
types. I'd much prefer the "you can use what you see" attitude of most
Modula-3 interfaces. (And yes, there are a few exceptions.) I can see
that the Ada compiler needs to know the size of private fields and
hence needs to see their types. But I think this was part of the
motivation of having only private/opaque *reference* types in
Modula-3.

> A general-purpose "starter set" of Ada features could be described
> completely in a few dozen pages.

Well, I think what we need to consider is a "general purpose" starter
set of features of Ada or Modula-3 which allow for a *complete* and
*robust* program or library to be written that does something
useful. Here is a more concrete and factual direction for a
comparison: It would be interesting to compare the implementations of
a simple, but concurrent, and extensible HTTP server written using
various languages. Maybe this is too simple, but it is more realistic
than Hello World and more concrete than comparing language
specifications. It'd be interesting to study safety in the resulting
program, etc. A different comparison is for that of HTTP servers in
various languages that have already been written (which may deal with
different trade-offs.)

Also, I am curious--any ideas how many lines of Ada *95* code is out
there in production today? I know there is much Ada code in
production, but what about Ada95?

Farshad Nayeri

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to

In article <DMDA6...@world.std.com> bob...@world.std.com (Robert A Duff) writes:

>
> That's compared to a language that allowed word types in addition,
> but not just *any* type. In Ada, the vast majority of private types
> end up being implemented as record types, not pointer types or word
> types. I'm not familiar with Modula-2+, but in Modula-2, the issue
> was one of size -- the compiler assumed that an opaque type, if not
> a pointer, was exactly the same *size* as a pointer, which of course
> rules out most records.
>
> Of course, there's a cost to allowing different sizes -- in Ada, if
> you change the record type that completes a private type, you have
> to recompile all clients, even though those clients are not supposed
> to "know" what that record looks like.

I think these were similar to reasons as to why Modula-3 only allows
opaque *references*.

Robert A Duff

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
In article <3118C7AE...@step.polymtl.ca>,
Louis-Dominique Dubeau <l...@step.polymtl.ca> wrote:
>Kenneth Almquist wrote:
>
>>...Modula 3 has no

>> equivalent for this (relatively uncommon) use of controlled
>> types.
>
>I beleive weak references in M3 might do the trick.

Two people have said this. I don't understand.

In Ada, controlled types have an Initialize procedure that gets called
automatically when an object of the type is created, and a Finalize
procedure that gets called automatically when the object is destroyed
(even in the presence of exceptions). You can use this to make sure an
open file gets closed, or a database handle gets released, or a
semaphore gets unlocked. I think that's the sort of thing Kenneth
Almquist was talking about. In other words, a garbage collector is
usually specifically for managing memory. Controlled types can manage
various other resources as well. (Of course, memory is probably the
most important resource, and g.c. is more convenient than controlled
types for that.)

I don't understand how weak references would do this -- they seem like a
totally unrelated feature. I thought weak refs were simply pointers
that "don't count" when the garbage collector is deciding whether
something is garbage. Do I misunderstand what weak refs are?

- Bob

Spencer Allain

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
In article <DMGtL...@world.std.com> bob...@world.std.com (Robert A Duff) writes:

In article <3118C7AE...@step.polymtl.ca>,
Louis-Dominique Dubeau <l...@step.polymtl.ca> wrote:
>Kenneth Almquist wrote:
>

>>...Modula 3 has no


>> equivalent for this (relatively uncommon) use of controlled
>> types.
>

>I beleive weak references in M3 might do the trick.

Two people have said this. I don't understand.

In Ada, controlled types have an Initialize procedure that gets called
automatically when an object of the type is created, and a Finalize
procedure that gets called automatically when the object is destroyed
(even in the presence of exceptions). You can use this to make sure an
open file gets closed, or a database handle gets released, or a
semaphore gets unlocked. I think that's the sort of thing Kenneth
Almquist was talking about. In other words, a garbage collector is
usually specifically for managing memory. Controlled types can manage
various other resources as well. (Of course, memory is probably the
most important resource, and g.c. is more convenient than controlled
types for that.)

I don't understand how weak references would do this -- they seem like a
totally unrelated feature. I thought weak refs were simply pointers
that "don't count" when the garbage collector is deciding whether
something is garbage. Do I misunderstand what weak refs are?

- Bob

I'm sure that I'll lose something in the translation :-), but I hope
to shed some light on the subject.

WeakRefs are not a complete mapping of Controlled types. A controlled
type in Ada95 is very much like a constructor/destructor combination
that exists in C++. WeakRefs are only used for finialization
operations.

A WeakRef sorta works _with_ the Garbage Collector, and is _ignored_
by it at the same time :-) Basically what this means is that with a
WeakRef you can register one or more procedures to be called when the
object you created the WeakRef to is about to be collected by the
Garbage Collector. Obviously, if you have a live reference to an
object it can't be collected, so WeakRefs are not counted as live
references for collection purposes.

In a nutshell, WeakRefs allow you to associate one or more finalize
procedures with an object, to clean up non-memory resources when the
object is about to be destroyed (read garbage collected).

-Spencer

----------------------------------------------------------------------
Spencer Allain E-mail: spe...@era.com
Engineering Research Associates Phone : (703) 734-8800 x1414
1595 Spring Hill Road Fax : (703) 827-9411
Vienna, VA 22182-2235

Ask me why _NOT_ to buy anything from Royal Prestige, a Hycite Co.
----------------------------------------------------------------------
<A HREF=http://www.research.digital.com/SRC/modula-3/html/home.html>
Modula-3 Home Page DEC SRC</A>
<A HREF=http://www.vlsi.polymtl.ca/m3/>Modula-3 FAQ, etc. </A>
----------------------------------------------------------------------

Robert A Duff

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
In article <NAYERI.96...@tahoe.gte.com>,

Farshad Nayeri <nay...@gte.com> wrote:
>Ada spec is about =800= pages.

It's big, but not *that* big.

>... Modula-3 spec is about =50= pages.


>Add to the M3 spec, the "standard portable library" (100 or so pages)
>and Network Objects (another 50 or so pages.) you get about 200-250
>pages for a whole system to do portable, reliable, distributed
>programming with some support for persistence. What would be the Ada
>equivalent?

The language spec (chapters 1 to 13) is 255 pages, so that's about 5
times the size of Modula-3's spec, comparing apples to apples. The
standard libraries (annexes A to J) is 207 pages. And there's 92 pages
of reference material (table of contents, index, summary of the syntax,
etc). I'm not sure what this all means, since it depends a lot on the
style of the manual -- how many examples and notes are included in
addition to the bare-bones rules.

It certainly true that Ada is a more complicated language than Modula-3.

>Here is what I like about programming in Modula-3 (again, hard to capture in a metric:)
>
>When you run into a problem in some Modula-3 code, most of the time
>you can isolate it locally quite easily. That is, looking at a
>statement in some program, it is not too hard to tell precisely what
>it is doing. Things like operator overloading, copy constructors,
>destructors, controlled types, etc., make this a lot harder to do in
>other languages.

This is true to an extent, but I still think destructors (for example)
are clearly beneficial. Sure, if you're debugging a piece of code that
declares an object, you have to know that the object might have a
destruction that gets called by magic. But the existence of the
destructor makes the abstraction itself easier to understand -- you can
know something about all objects of the type, without having to look at
how the type is used.

>... Modula-3 style also encourages you to use


>fully-qualified references to other modules, which also makes things
>simpler.

Ada allows fully-qualified references, too. Are you saying "encourages"
because the mechanism for avoiding the qualification is more painful in
Modula-3? (That is, you have to say "FROM Module_Name IMPORT <long list
of names>;", whereas in Ada you just write "use Module_Name;".) Shrug.
Either way, you have to do something explicit if you want to avoid
writing fully-qualified names.

>It is not so. User-defined types in M3 can be stack
>allocated.

But not if the type is opaque, right? That seems like an annoying
trade-off (you can't have information hiding without incurring an extra
run-time cost), although the existence of garbage collection makes it
less troublesome than it would otherwise be.

>...Since the


>language is much simpler than others in its class, it may actually be
>easier to optimize also.

Good point.

- Bob

Kenneth Almquist

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
nay...@gte.com (Farshad Nayeri) comments:

> Ada spec is about =800= pages. Modula-3 spec is about =50= pages.
> Add to the M3 spec, the "standard portable library" (100 or so pages)
> and Network Objects (another 50 or so pages.) you get about 200-250
> pages for a whole system to do portable, reliable, distributed
> programming with some support for persistence. What would be the Ada
> equivalent?

I didn't discuss simplicity in my comparison because I couldn't think
of a way to quantify it. Page counts are not very meaningful. I have
an ASCII version of the Ada 95 standard which contains 43191 lines.
Printing this at 56 lines per page gives 772 pages, or close to your
800 page estimate. On the other hand, according to the table of
contents the index starts at page 190, which means that if you
eliminate the preface, the index and table of contents, and print in
some unspecified font and page size, the Ada 95 standard is only 189
pages. Furthermore, the Modula 3 specification is not an international
standard, and it is not obvious how much it would grow if the loose
ends were nailed down by a standardization process.

It is clear that the definition of Modula 3 is simpler than that of
Ada 95. Some of the more effective ways Modula 3 achieved a simple
definition are:

1. Use of structural equivalence simplifies the type system. A less
obvious effect is that it makes overloading on result (which Modula 3
does not have) less useful. Following the Ada declaration

type Count is new Integer;

the type of the literal 1 can be either Integer or Count. Without
overloading you would have to qualify every use of 1.

2. The lack of generic contracts simplifies the generics considerably.

3. Specifying the size of a type in Modula 3 also eliminates padding
preceding the type. This provides a simple way to specify a
particular layout.

4. Garbage collection is simple conceptually, and makes controlled
types (which are not so simple) mostly unnecessary.

Farshad suggests some other measures of simplicity:


> When you run into a problem in some Modula-3 code, most of the time
> you can isolate it locally quite easily. That is, looking at a
> statement in some program, it is not too hard to tell precisely what
> it is doing. Things like operator overloading, copy constructors,
> destructors, controlled types, etc., make this a lot harder to do in
> other languages. Modula-3 style also encourages you to use
> fully-qualified references to other modules, which also makes things
> simpler.
>
> Another metric: are your programmers often pulling their hair out
> trying to figure out what a piece of code does that they got from
> someone else?

These metrics make counting pages seem simple. :-) I'd say both Ada
and Modula 3 are pretty readable. Operator overloading and controlled
types definitely have the potential to be used to write obfuscated code,
but I haven't heard any stories of them causing problems in practice.
Kenneth Almquist

Richard A. O'Keefe

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
nco...@watson.ibm.com (Norman H. Cohen) writes:
>There is no denying that Ada 95 is a more complex language than Modula-3.
>However, Ada 95 is not the behemoth you are picturing. The Modula-3 RM
>is not an order of magnitude smaller, and Modula-3 is not an order of
>magnitude simpler.

For what it's worth, Dale Stanbrough here wrote a pretty good "Ada Language
notes" to give to students. It's 76 pages, doesn't include OOP, and lacks
an index. However, I would think that any Turbo Pascal programmer, say,
should be able to get started in Ada 95 with just that.

If the section on concurrency and site specific information were dropped,
it would be under 70 pages.
I think a good section on OOP could be provided and still keep the whole
thing under 100 pages.

Just to prove that I'm not tooting RMIT's horn in my praise of this very
handy little document, let me say that it is inexcusable to indent by 8s
instead of a more readable 3, 4, or 5 in Ada code (or any other language).

--
"conventional orthography is ... a near optimal system for the
lexical representation of English words." Chomsky & Halle, S.P.E.
Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.

Robert A Duff

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
In article <NAYERI.96...@tahoe.gte.com>,
Farshad Nayeri <nay...@gte.com> wrote:
>I looked over an 800-or-so-page manual for Ada95 this summer. Perhaps
>it was the *annotated* user manual. (I will have to double-check.) Are
>you also including in the annexes in your count?

The Annotated RM is about 750 pages or so. It contains all kinds of
implementation tricks and weird semantic ramifications. So you
shouldn't take that as the size of the language definition itself.
In *that* style, I could write 10,000 pages, about *any* programming
language.

>This is certainly nice, but if the Ada spec had been shorter and
>simpler, it may not have required support of a complicated index, and
>all this redundant information, wouldn't you say? (Though it could've
>been the ISO RFP requirements.)

No, I disagree. I wrote that index, so maybe I'm biased. But I think a
good index is incredibly useful. I put in anything I could think of. I
don't think that adding stuff to the index makes the language itself
more complex. Of course, a simpler language might require a smaller
index. That doesn't mean a large index implies a complex language.
I've read a lot of books, and only rarely seen a good index.

The "reduntant info" was not required by ISO. It was just considered
useful.

>Here is another question: if you throw away all the annexes, the
>index, *everything* but the "bare bones" required libraries for Ada95,
>how many pages of a spec. do you have?

In another post, I said, 255 pages. Still substantially longer than the
Modula-3 book.

>I also question the "look but don't touch" style of the Ada private
>types. I'd much prefer the "you can use what you see" attitude of most
>Modula-3 interfaces. (And yes, there are a few exceptions.) I can see
>that the Ada compiler needs to know the size of private fields and
>hence needs to see their types. But I think this was part of the
>motivation of having only private/opaque *reference* types in
>Modula-3.

Yeah, it's a trade-off. The Ada way allows private types to be
efficient. The Modula-3 way allows the implementation to be hidden from
the compiler, thus avoiding compile-time costs. (And Ada allows the
Modula-3 way, too -- if your private type *happens* to be a pointer, you
can put the implementation in the package body. This allows the
programmer to make the trade-off, which is nice, but one could argue
that it adds complexity to the language.)

>Also, I am curious--any ideas how many lines of Ada *95* code is out
>there in production today? I know there is much Ada code in
>production, but what about Ada95?

No idea. Ada 95 is even newer than Modula-3, so probably not much, yet.

- Bob

T. Owen O'Malley

unread,
Feb 8, 1996, 3:00:00 AM2/8/96
to
In <DMGtL...@world.std.com> bob...@world.std.com (Robert A Duff) writes:

>In article <3118C7AE...@step.polymtl.ca>,
>Louis-Dominique Dubeau <l...@step.polymtl.ca> wrote:
>>Kenneth Almquist wrote:
>>

>>>...Modula 3 has no equivalent for this (relatively uncommon) use of
>>> controlled types.
>>


>>I beleive weak references in M3 might do the trick.

>I don't understand how weak references would do this -- they seem like a


>totally unrelated feature. I thought weak refs were simply pointers
>that "don't count" when the garbage collector is deciding whether
>something is garbage. Do I misunderstand what weak refs are?

The constructor for weakrefs takes a procedure that will be called
when the target of the weakref would be deallocated by the gc. This
procedure could close files, save data to files or whatever.

Owen O'Malley

Department of ICS | oma...@ics.uci.edu (ARPA)
UC Irvine | http://www.ics.uci.edu/~omalley/ (WWW)
Irvine, CA 92717 | ucbvax!ucivax!omalley (UUCP)


Farshad Nayeri

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to

In article <DMGtL...@world.std.com> bob...@world.std.com (Robert A Duff) writes:

In response to the discussion:

> >> Modula 3 has no equivalent for this (relatively uncommon) use of
> >> controlled types.
> >

> >I beleive weak references in M3 might do the trick.
>

Bob said:

> I don't understand. [...] I thought weak refs were simply pointers


> that "don't count" when the garbage collector is deciding whether
> something is garbage. Do I misunderstand what weak refs are?

Strictly speaking, weak references are references which are not
granted a full guarantee of referencial integrity. Different systems
provide different leves of support for handling this "weakness". The
simplest and most common form of support is what you describe. The
interface WeakRef combines support for weak reference and
finalization. (I agree that the name is misleading, by the way, but
the relationship makes sense once explained.)

Here I include exerpts from the WeakRef interface including an example
that has to do with flushing a writer when there are no more
references to it. For full source, see:

http://www.research.digital.com/SRC/
m3sources/html/weakref/src/WeakRef.i3.html

-- Farshad

INTERFACE WeakRef;

(* Most Modula-3 programs simply let the garbage collector deallocate
storage automatically, but some programs need more control.
For example, if a variable allocated in the traced
heap contains a handle on a resource in the operating system or in
some other address space, then when the variable is garbage-collected
it may be important to deallocate the resource. The "WeakRef"
interface provides this additional control.

A {\it node} is a datum allocated on the traced heap. Thus a node
is either the referent of a variable of a fixed reference type or
the data record of a traced object. Note that a node is not a
Modula-3 reference, but the allocated storage to which a reference
can refer.

A "WeakRef.T" is a data structure that refers to a node
without protecting the node from the garbage collector. If "w" is a
weak reference, we write "nd(w)" to denote the node to which "w"
refers.

We say that a weak reference "w" {\it dies} at the moment that the
garbage collector detects that "nd(w)" is unreachable. A precise
definition of unreachable is given below. Once a weak reference
has died, it remains dead forever, even if the node to which
it refers becomes reachable again.

Associated with each weak reference "w" is a {\it cleanup procedure}
"cp(w)". If the cleanup procedure is not "NIL", the garbage
collector will schedule a call to it when the weak reference
dies. *)

[...]

PROCEDURE FromRef(r: REFANY; p: CleanUpProc := NIL): T;
(* Return a weak reference "w" such that "nd(w) = r" and
"cp(w) = p". It is a checked runtime error if "r" is "NIL".
It is illegal to create more than one weak reference with a
non-nil cleanup to the same node; violations of this rule
may lead to a checked runtime error, or may cause one
of the cleanup actions to be omitted. "FromRef" is not
necessarily functional: it is possible that "nd(w1) = nd(w2)"
but "w1 # w2". *)

PROCEDURE ToRef(w: T): REFANY;
(* Return a reference to "nd(w)", unless "w" is dead, in which
case return "NIL". *)

TYPE CleanUpProc = PROCEDURE(READONLY w: T; r: REFANY);
(* If "cp(w)" is not "NIL", then when "w" dies, the garbage collector
will schedule the call "cp(w)(w, <reference to nd(w)>)". *)

[...]

EXAMPLES

1. Suppose you want writers of the class "WrX.T" to be automatically
flushed and closed if they become unreachable. Then you could write
code like the following in the "WrX" module:

| MODULE WrX; IMPORT WeakRef, Wr, ...;
|
| PROCEDURE New(...): T =
| VAR res := NEW(T); BEGIN
| (* ... initialize res as a WrX.T ... *)
| EVAL WeakRef.FromRef(res, Cleanup);
| RETURN res
| END New;
|
| PROCEDURE Cleanup(READONLY self: WeakRef.T; ref: REFANY) =
| VAR wr: T := ref; BEGIN
| IF NOT Wr.Closed(wr) THEN
| Wr.Flush(wr);
| Wr.Close(wr)
| END
| END Cleanup;
|

There is no danger that another thread could close the writer
after the test "NOT Wr.Closed(wr)" and before the call "Wr.Flush(wr)",
since when "Cleanup" is called, the writer is unreachable. Therefore
the cleanup method has exclusive access to the writer.

--
Farshad Nayeri
nay...@gte.com

Farshad Nayeri

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to

In article <JSA.96Fe...@organon.com> j...@organon.com (Jon S Anthony) writes:

> If you only look at what you describe for Modula-3, then you get
> around 460 pages. With this you get the core language the
> predefined libraries + interfacing to other languages
> (C,Fortran,Cobol), Systems Programming, Real-Time Systems,
> Distributed Systems, Information Systems, Numerics, and Safety and
> Security.
>
> Last I heard Gnat implements most of these and will implement all of
> them.

"Will implement" is too weak for me.

In fact, I heard from Robert Dewar in the Ada GC thread that they had
no requests for GC so he didn't think it will be implemented unless
someone asked (a customer payed?) for it.

So, I guess I am generalizing to:

GNAT will implement all of them if someone is willing to pay for it.

The freely-available SRC Modula-3 has had many of these for the past 6
years and "all" of them for for the past 3 years...

Farshad Nayeri

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to

> How much code has been written in Ada95?

> > No idea. Ada 95 is even newer than Modula-3, so probably not
> > much, yet.

Ada 95 is *a lot* newer than Modula-3, 3-6 years depending on how you
count. Yet, as pointed out by others in this thread, the two languages
give you similar programming power.

Modula-3 language spec has been frozen since 1989, I believe. The
standard libraries and network object interfaces have been virtually
unchanged since 1992 or 1993--I forgot which--and have gotten a lot of
use since then. Most important Modula-3 libraries are crafted for the
full feature set of Modula-3.

To me, this makes Modula-3 the more conservative choice of the two,
even without an ISO standard.

Farshad Nayeri

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to

In article <dewar.823835125@schonberg> de...@cs.nyu.edu (Robert Dewar) writes:

> From: de...@cs.nyu.edu (Robert Dewar)
> Newsgroups: comp.lang.ada,comp.lang.modula3
> Date: 8 Feb 1996 22:08:56 -0500
> Organization: Courant Institute of Mathematical Sciences
>
> ">I also question the "look but don't touch" style of the Ada private
> >types. I'd much prefer the "you can use what you see" attitude of most
> >Modula-3 interfaces. (And yes, there are a few exceptions.) I can see
> >that the Ada compiler needs to know the size of private fields and
> >hence needs to see their types. But I think this was part of the
> >motivation of having only private/opaque *reference* types in
> >Modula-3."
>

> Actually, there is no reason why private parts should be able to be looked
> at if you don't have proper access to them. This is really an implementation
> issue, not a language issue.

I was refering to the *style* of programming. I didn't meant that this
can't be done in an implementatio, just that Ada programmer's
expectations are to be able to see the "private parts". The same is
true about C/C++ and Lisp programmers. The usual expectations of the
Ada programmer is to be able to see a private part but not to be able
to use it.

In Modula-3, at least in its current incarnation, the *style* of
programming is slightly different: you usually don't see any of the
private parts of the modules you are importing at all, and don't
expect to see the private types, etc. either, unless there is an
exceptional situation.

I was really talking about the difference in the "programmer
expectations" not what the tools provided, that's all.

Ada's private types and nested libraries are much better encapsulation
mechanism than C/C++'s headers, for sure!

Robert Dewar

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to
iFarshad said replying to another comment

"> If you only look at what you describe for Modula-3, then you get
> around 460 pages. With this you get the core language the
> predefined libraries + interfacing to other languages
> (C,Fortran,Cobol), Systems Programming, Real-Time Systems,
> Distributed Systems, Information Systems, Numerics, and Safety and
> Security.
>
> Last I heard Gnat implements most of these and will implement all of
> them.

"Will implement" is too weak for me.

In fact, I heard from Robert Dewar in the Ada GC thread that they had
no requests for GC so he didn't think it will be implemented unless
someone asked (a customer payed?) for it.
"

You are confused. GC is not included as a requirement in the Ada RM. GNAT
does indeed implement nearly all of the Ada 95 RM, but not GC, so the
will implement does not include GC, since it is not an RM requirement.

So you are confused, GC is simply not included in the first comment here,
the issue of whether or not or when GNAT will implement GC is an issue
that has nothing to do with implementing the full RM!


Robert Dewar

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to
Farshad said

"In Modula-3, at least in its current incarnation, the *style* of
programming is slightly different: you usually don't see any of the
private parts of the modules you are importing at all, and don't
expect to see the private types, etc. either, unless there is an
exceptional situation."

YOu missed the point, if in an Ada implementation put the visible and
private parts of a package spec in completely separate files, then
it would be operationally similar to what you describe for Modula-3.

Actually, as others have pointed out, if you are willing to settle
for the restriction of modula-3 that only refernce types can be
private, then the full declaration of the private type can be
deferred to the body.

So really here Ada is identical to Modula-3 in capability, but also
allows arbitrary types to be private types. When arbitrary types
are used, the style is a little different, but you can't compare
with M3 at this point, since this is a feature not available in M3.


Geoffrey Wyant - Sun Microsystems Labs BOS

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to m...@src.dec.com
<3118C7AE...@step.polymtl.ca>
<DMGtL...@world.std.com>In-Reply-To: <DMGtL...@world.std.com>
Distribution: world
X-Received: from suneast.East.Sun.COM by East.Sun.COM (5.x/SMI-5.3)
X-Received: by src-mail.pa.dec.com; id AA02009; Fri, 9 Feb 96 06:00:38 -0800
X-Newsgroups: comp.lang.ada,comp.lang.modula3
X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117)
X-Received: from mercury.Sun.COM by mail2.digital.com (5.65 EXP 4/12/95 for V3.2/1.0/WV)
X-Received: by cloyd.East.Sun.COM (SMI-8.6/SMI-SVR4)
X-Received: from East.Sun.COM by mercury.Sun.COM (Sun.COM)
X-Received: by src-news.pa.dec.com; id AA29135; Fri, 9 Feb 96 06:00:38 -0800

Robert A. Duff writes:
> In article <3118C7AE...@step.polymtl.ca>,
> Louis-Dominique Dubeau <l...@step.polymtl.ca> wrote:
> >Kenneth Almquist wrote:
> >

> >>...Modula 3 has no


> >> equivalent for this (relatively uncommon) use of controlled
> >> types.
> >
> >I beleive weak references in M3 might do the trick.
>

> Two people have said this. I don't understand.
>
> In Ada, controlled types have an Initialize procedure that gets called
> automatically when an object of the type is created, and a Finalize
> procedure that gets called automatically when the object is destroyed
> (even in the presence of exceptions). You can use this to make sure an
> open file gets closed, or a database handle gets released, or a
> semaphore gets unlocked. I think that's the sort of thing Kenneth
> Almquist was talking about. In other words, a garbage collector is
> usually specifically for managing memory. Controlled types can manage
> various other resources as well. (Of course, memory is probably the
> most important resource, and g.c. is more convenient than controlled
> types for that.)
>

> I don't understand how weak references would do this -- they seem like a

> totally unrelated feature. I thought weak refs were simply pointers


> that "don't count" when the garbage collector is deciding whether
> something is garbage. Do I misunderstand what weak refs are?
>

Weakref's allow a procedure to register which will get called just
before the storage is deallocated by the garbage collector. So, if the
entity holds a "reference" to an external resource (e.g. X window id,
file descriptor, socket) it has a chance to release the resource, so
it sounds pretty much equivalent to controlled types. However, there
are the following caveats. You can't necessarily gaurantee when the
collector will run, so external resources may be held for arbitrarily
long periods of time. Second, you can't control the order in which
resources are released, so if you need an ordering, you should have
an explicit cleanup regimine defined outside of the garbage
collector.

--geoff

Geoff Wyant
Geoff...@east.sun.com
Sun Microsystems Laboratories

2 Elizabeth Drive
Chelmsford, Ma.
01824

Ted Dennison

unread,
Feb 9, 1996, 3:00:00 AM2/9/96
to
Farshad Nayeri wrote:
>
> In article <JSA.96Fe...@organon.com> j...@organon.com (Jon S Anthony) writes:
>
> > If you only look at what you describe for Modula-3, then you get
> > around 460 pages. With this you get the core language the
> > predefined libraries + interfacing to other languages
> > (C,Fortran,Cobol), Systems Programming, Real-Time Systems,
> > Distributed Systems, Information Systems, Numerics, and Safety and
> > Security.
> >
> > Last I heard Gnat implements most of these and will implement all of
> > them.
...

> In fact, I heard from Robert Dewar in the Ada GC thread that they had
> no requests for GC so he didn't think it will be implemented unless
> someone asked (a customer payed?) for it.

GC is not in the above list.

The sources for Gnat are freely available and user-changable. So if
someone REALLY wanted GC, they could implement it themselves. So far
no-one has wanted to do so.

How tough could it be? :-)


--
T.E.D.
| Work - mailto:denn...@escmail.orl.mmc.com |
| Home - mailto:denn...@iag.net |
| URL - http://www.iag.net/~dennison |

Kenneth Almquist

unread,
Feb 10, 1996, 3:00:00 AM2/10/96
to
nay...@gte.com (Farshad Nayeri) writes:
>> The Ada language rules are expressed with formalistic rigor and
>> precision; a less rigorous presentation, leaving more questions
>> unanswered--say on the level of Wirth's in the Modula-2 RM--would
>> have led to a substantially shorter Ada RM.
>
> This may be true about Modula-2 (which I know very little about), but
> I personally find the Modula-*3* spec to be among the most rigorous
> but practical language specs around. (I would like to hear your

The Modula 3 specification well written, but there are holes in
it.

For example, the NEW operation is required to return a reference
which is distinct from all existing references. I don't think that
the manual explains anywhere what it means for a reference to be
"distinct", so this leaves open the possibility of two calls to NEW
returning references to the same block of memory. If NEW is required
to allocate memory on each call to NEW, then Modula 3 cannot be
implemented on a machine where the amount of storage is finite,
because NEW could be used to allocate more memory than the machine
posesses.

If NEW is used to allocate an open array, the values of the array
must be "arbitrary values of their type." So if you allocate an
open array of type ARRAY OF [1 .. 10], the compiler must generate
code to ensure that the elements of the array don't fall outside of
the range of 1 to 10. Surely this is not intended.

NEW can be used with "untraced references". As I understand it, the
intention here is that this should allocate a piece of memory which is
outside the control of the garbage collector and will remain allocated
until it is explicitly freed using "dispose." But what the specifica-
tion states is very different: "When all traced references to a piece
of allocated storage are gone, the implementation reclaims the
storage."

The sentence quoted in the previous paragraph describes reference
counting semantics for garbage collection. This means that the
programmer must break a link in a circular data structure in order for
the memory to be reclaimed by the system. I suspect that the writers
of the specification did not intend this.

The specification doesn't mention "weak references" at all, but the
posters on this thread seem to feel that they are part of Modula 3.
Weak references create additional complications that any rigorous
description of memory manangement would have to deal with.
Kenneth Almquist

Farshad Nayeri

unread,
Feb 10, 1996, 3:00:00 AM2/10/96
to

In article <DMGyH...@world.std.com> bob...@world.std.com (Robert A Duff) writes:

> >Here is what I like about programming in Modula-3 (again, hard to capture in a metric:)
> >
> >When you run into a problem in some Modula-3 code, most of the time
> >you can isolate it locally quite easily. That is, looking at a
> >statement in some program, it is not too hard to tell precisely
> >what it is doing. Things like operator overloading, copy
> >constructors, destructors, controlled types, etc., make this a lot
> >harder to do in other languages.
>

> This is true to an extent, but I still think destructors (for
> example) are clearly beneficial. Sure, if you're debugging a piece
> of code that declares an object, you have to know that the object
> might have a destruction that gets called by magic. But the

> existence of the adestructor makes the abstraction itself easier to


> understand -- you can know something about all objects of the type,
> without having to look at how the type is used.

This is only true if your object doesn't have pointers into other
objects, right? In presense of pointers, you will have to care about
sharing which is a pain to do. I think destructors are the kind of
things that look easy in the "hello world" example but are quite hard
in any non-trivial application. Otherwise how is it that Purify is
selling so well?

The number one reason why I think garbage collection is important is
that it makes your interfaces to the abstractions simpler and allows
you to concentrate on providing better abstractions.

>
> >... Modula-3 style also encourages you to use


> >fully-qualified references to other modules, which also makes things
> >simpler.
>

> Ada allows fully-qualified references, too. Are you saying "encourages"
> because the mechanism for avoiding the qualification is more painful in
> Modula-3? (That is, you have to say "FROM Module_Name IMPORT <long list
> of names>;", whereas in Ada you just write "use Module_Name;".) Shrug.
> Either way, you have to do something explicit if you want to avoid
> writing fully-qualified names.

In my opinion, Ada's (or Java's) more loose import statements--where
you can import all names from another scope--tend to make it harder to
look at client code. Also, there is possibility of name clashes when
the imported interface changes (which you may have to add overloading
rules to work around.)

If you look at most Modula-3 code, the FROM blah IMPORT foo is not
used much. The language also discourages using it, because you can't
say FROM blah IMPORT *. (This is cumbersome at times, but most of the
time makes for clearer [yet a bit more verbose] code.)

The one exception for this is when you are making interfaces for C
languages, etc, where you may say

FROM Stdio IMPORT stdout, stderr;

to emulate the C style.

>
> >It is not so. User-defined types in M3 can be stack
> >allocated.
>

> But not if the type is opaque, right?

You are right. Opaque types in Modula-3 have to be references.

> That seems like an annoying trade-off (you can't have information
> hiding without incurring an extra run-time cost), although the
> existence of garbage collection makes it less troublesome than it
> would otherwise be.

Actually I would make the case that it is a good design choice *if*
simplicity is a part of your goals. A good design doesn't try to be
all thing to all people. True, there are few data structures which may
need to be user-defined and stack allocated. For those, you lose
polymorphism and opaqueness. But that's not what most programmers will
be doing.

So, the world isn't perfect. Oh well.

Arnt Gulbrandsen

unread,
Feb 10, 1996, 3:00:00 AM2/10/96
to
k...@socrates.hr.att.com (Kenneth Almquist)

> If NEW is used to allocate an open array, the values of the array
> must be "arbitrary values of their type." So if you allocate an
> open array of type ARRAY OF [1 .. 10], the compiler must generate
> code to ensure that the elements of the array don't fall outside of
> the range of 1 to 10. Surely this is not intended.

No? Sounds good to me.

> NEW can be used with "untraced references". As I understand it, the
> intention here is that this should allocate a piece of memory which is
> outside the control of the garbage collector and will remain allocated
> until it is explicitly freed using "dispose." But what the specifica-
> tion states is very different: "When all traced references to a piece
> of allocated storage are gone, the implementation reclaims the
> storage."
>
> The sentence quoted in the previous paragraph describes reference
> counting semantics for garbage collection. This means that the
> programmer must break a link in a circular data structure in order for
> the memory to be reclaimed by the system. I suspect that the writers
> of the specification did not intend this.

I, at least, assumed at once that "traced references" meant paths from
named variables to the piece of allocated storage in question, which
avoids the circular-list problem.

--Arnt

Farshad Nayeri

unread,
Feb 10, 1996, 3:00:00 AM2/10/96
to

Re: destructors, garbage collection, weak references, and finalization

I realized that the TRY FINALLY statement was missing from our
discussions about the need for destructors.

In Modula-3, TRY try-clause FINALLY finally-clause END
will guarantee that finally-clause will run whether or not try
clause raises an exception.

As Kenneth's note mentions, TRY-FINALLY in Modula-3, is often used for
cleanup activities. So you can say:

VAR
file := Open(...);
TRY
write (file,...);
write (file,...);
FINALLY
close(file);
END;

To sum up, I find that the notion of "destructors" is overloaded to
cover at least the following three separate concerns:

(1) reclaiming storage (you know...)
(2) resource management for resources other than memory
(3) running a particular finalization protocol (c.f., Geoff's post)
(4) metaprotocol hooks for attaching code to the unwinding of stack
(so when the stack pops, you can run a piece of code.)

I think this overloading makes things doubly hard because some
concerns conflict with others. For example, the fact that some of the
objects may be in an invalid state due to (1) will create problems for
finalization protocols in (3).

I'd claim that Modula-3's solution goes a long way to provide support
for all three areas that destructors address. By separating these four
concerns, the current SRC Modula-3 make it easier for the programmer
to deal with the kind of things that are quite hard to deal with in
typical C++ and Ada programs.

(1) RECLAIMING STORAGE. Use regular automatic garbage collection.

(2) MANAGING RESOURCES OTHER THAN MEMORY. weak references deal nicely
with resources that don't require fancy finalization protocols,
like files buffers.

(3) FINALIZATION PROTOCOLS. I never understood why people combined
finalization with destruction anyway. For example, it is often
cited that if you have a window class, you may want its destructor
to close all its child windows as well. In a garbage collected
language, you can simply create your own "close" protocol, while
taking advantage of the other mechanisms mentioned. Even in a
language without garbage collection, I'd argue that separating
finalization from destruction protocols may be a good design
choice. (Though I'd love to know why what I say here may not work.)

(4) STACK-BASED METAPROTOCOLS. Stack-allocated objects with fancy
constructor and destructors are used often for hooking up things
to the computation stack. This is often used for dealing with
locks in presense of exceptions, for example, and (as I understand
it) is the basic motivation for auto_ptr (or whatever it is
called) template class. In Modula-3, to hook things up to the
stack pops, you can use the TRY FINALLY clause. In fact, the above
problem with locks in presense of exceptions is nicely dealth with
in Modula-3:

LOCK mu DO lock-clause END

is syntactic sugar for

acquire(mu) TRY lock-clause FINALLY release(mu) END

My understanding is that, to do the same with stack-based objects
or controlled types, I will at least have to create a non-trivial
stack-based object, and use it.

Finally in presense of exceptions, concurrency, and without
garbage collection, preserving invariants in my code is already
quite hard. Adding the complication of stack-allocated objects and
their destructors makes things even more complicated. (See Scott
Meyer's exception paper in October Microsoft Systems Journal for a
scary picture of the ways in which C++ exceptions can cause
problems.)

Have I missed something in this analysis?

Bob Kitzberger

unread,
Feb 11, 1996, 3:00:00 AM2/11/96
to
Farshad Nayeri (nay...@gte.com) wrote:
: I was refering to the *style* of programming. I didn't meant that this

: can't be done in an implementatio, just that Ada programmer's
: expectations are to be able to see the "private parts". The same is
: true about C/C++ and Lisp programmers. The usual expectations of the
: Ada programmer is to be able to see a private part but not to be able
: to use it.

This isn't the case, in my experience. When "private" is encountered,
people know there is no need to keep looking (unless they are simply
curious).

Robert Dewar

unread,
Feb 11, 1996, 3:00:00 AM2/11/96
to
T.E.D. asks regarding implementing GC in GNAT:

How tough could it be? :-)

Our thoughts is that it would not be that hard to have a partial implementation
which applied to a special storage pool, using the controlled mechanism to
make sure that all roots remain identifiable. This would not be terribly
efficient, but it would be workable.

To add general GC, with compression, would be a *very* big job. Even
without compression, locating all the roots would be tricky and require
changes throughout the compiler.

The most efficient way of doing GC in an environment like this is actually
to compile a marking routine for each frame (see Algol-68 literature
for further discussion of this approach). This is very efficient, but is
a LOT of work.


Richard A. O'Keefe

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
bob...@world.std.com (Robert A Duff) writes:

>No, I disagree. I wrote that index, so maybe I'm biased. But I think a
>good index is incredibly useful.

A public THANK-YOU for that. There are even entries like
hidden from all visibility ....
within the declaration itself ...

Was it Mermin who said "there used to be an Index of banned books; perhaps
today we could ban books without an index"? Thank you for that index.

Tucker Taft

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
Farshad Nayeri (nay...@gte.com) wrote:
: ...
: Ada spec is about =800= pages. Modula-3 spec is about =50= pages.

: Add to the M3 spec, the "standard portable library" (100 or so pages)
: and Network Objects (another 50 or so pages.) you get about 200-250
: pages for a whole system to do portable, reliable, distributed
: programming with some support for persistence. What would be the Ada
: equivalent?

Although I will agree that Modula-3 is simpler than Ada 95, I believe the
notion that the Modula-3 50-page "spec" is comparable to the 300 pages of
the Ada *standard* devoted to the language syntax and semantics (as opposed
to the standard libraries) is quite wrong.

Modula-3 is not an international standard, and if it were to want to
become one, the "spec" would have to be turned into a "standard,"
which would be much longer and much more formal. The right comparison
might be against the (forthcoming?) Modula-2 standard, which is
significantly bigger than the Modula-3 "spec" and very foreign to
those not trained in formal semantics. I believe one could write a
"spec" for Ada 95 syntax and semantics in about 100 pages, if one
were aiming at the same level of precision and formality as that
used by the Modula-3 spec.

: Farshad Nayeri
: nay...@gte.com

--
-Tucker Taft s...@inmet.com http://www.inmet.com/~stt/
Intermetrics, Inc. Cambridge, MA USA

Kennel

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
Robert Dewar (de...@cs.nyu.edu) wrote:
> T.E.D. asks regarding implementing GC in GNAT:

> How tough could it be? :-)

> Our thoughts is that it would not be that hard to have a partial implementation
> which applied to a special storage pool, using the controlled mechanism to
> make sure that all roots remain identifiable. This would not be terribly
> efficient, but it would be workable.

> To add general GC, with compression, would be a *very* big job. Even
> without compression, locating all the roots would be tricky and require
> changes throughout the compiler.

This is a good reason why at least a basic GC should have been provided in
the first iteration of GNAT, even without supposed "customer demand".

How much "customer demand" was there for Eiffel before it was invented?

(And that was 85 or 86 for the first version).

Jon S Anthony

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
In article <NAYERI.96...@tahoe.gte.com> nay...@gte.com (Farshad Nayeri) writes:

> I was refering to the *style* of programming. I didn't meant that this
> can't be done in an implementatio, just that Ada programmer's
> expectations are to be able to see the "private parts". The same is
> true about C/C++ and Lisp programmers. The usual expectations of the
> Ada programmer is to be able to see a private part but not to be able
> to use it.

What makes you think this (wrt Ada)? Admittedly all we have is anectdotal
evidence, but in my case I have not seen or heard of such an expectation
among Ada programmers.

(for C, I would tend to agree; for C++ I really don't know; for Lisp, the
issue seems irrelevant...)

/Jon
--
Jon Anthony
Organon Motives, Inc.
1 Williston Road, Suite 4
Belmont, MA 02178

617.484.3383
j...@organon.com


Jon S Anthony

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
In article <NAYERI.96...@tahoe.gte.com> nay...@gte.com (Farshad Nayeri) writes:

>
> In article <JSA.96Fe...@organon.com> j...@organon.com (Jon S Anthony) writes:
>
> > If you only look at what you describe for Modula-3, then you get
> > around 460 pages. With this you get the core language the
> > predefined libraries + interfacing to other languages
> > (C,Fortran,Cobol), Systems Programming, Real-Time Systems,
> > Distributed Systems, Information Systems, Numerics, and Safety and
> > Security.
> >
> > Last I heard Gnat implements most of these and will implement all of
> > them.
>

> "Will implement" is too weak for me.
>

> In fact, I heard from Robert Dewar in the Ada GC thread that they had
> no requests for GC so he didn't think it will be implemented unless
> someone asked (a customer payed?) for it.

You are not reading what I wrote. I didn't mention GC at all so why are
you mentioning it in this particular context?

> So, I guess I am generalizing to:
>
> GNAT will implement all of them if someone is willing to pay for it.

No, that is just not true. The annexes will be implemented. I don't know
what will happen wrt to Gnat and GC.


> The freely-available SRC Modula-3 has had many of these for the past 6
> years and "all" of them for for the past 3 years...

"Many"?, but not "all"? What are you saying?

Robert A Duff

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
In article <NAYERI.96...@tahoe.gte.com>,
Farshad Nayeri <nay...@gte.com> wrote:
>This is only true if your object doesn't have pointers into other
>objects, right? In presense of pointers, you will have to care about
>sharing which is a pain to do.

In the presence of sharing, you have to care about sharing.
*Some* pointers are just there because the size of the thing
needs to change at run time, so you have to implement it as
a pointer.

>... I think destructors are the kind of


>things that look easy in the "hello world" example but are quite hard
>in any non-trivial application. Otherwise how is it that Purify is
>selling so well?

True -- that is, garbage collection is a lot simpler to deal with than
finalization in the complicated cases. Assuming what you interested in
is memory management (as opposed to some other resource).

>The number one reason why I think garbage collection is important is
>that it makes your interfaces to the abstractions simpler and allows
>you to concentrate on providing better abstractions.

Agreed.

>In my opinion, Ada's (or Java's) more loose import statements--where
>you can import all names from another scope--tend to make it harder to
>look at client code.

A lot of Ada folks agree -- to the point where they sometimes have
coding conventions that absolutely forbid use_clauses. That's a bit too
radical for me, but I agree with you that use_clauses can harm
readability.

It's interesting, though, that fully-qualified names is in a sense the
*opposite* of the run-time polymorphism that both M-3 and Ada 95
support. The whole point is that you *don't* want to know what
procedure is being called by looking at the source code.

- Bob

Jon S Anthony

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
In article <d6wzqar...@pentagram.troll.no> Arnt Gulbrandsen <agu...@troll.no> writes:

> k...@socrates.hr.att.com (Kenneth Almquist)


> > NEW can be used with "untraced references". As I understand it, the
> > intention here is that this should allocate a piece of memory which is
> > outside the control of the garbage collector and will remain allocated
> > until it is explicitly freed using "dispose." But what the specifica-
> > tion states is very different: "When all traced references to a piece
> > of allocated storage are gone, the implementation reclaims the
> > storage."
> >
> > The sentence quoted in the previous paragraph describes reference
> > counting semantics for garbage collection. This means that the
> > programmer must break a link in a circular data structure in order for
> > the memory to be reclaimed by the system. I suspect that the writers
> > of the specification did not intend this.
>
> I, at least, assumed at once that "traced references" meant paths from
> named variables to the piece of allocated storage in question, which
> avoids the circular-list problem.

The point is that what you or someone else might "assume" is the problem.
You assume X and I might assume Y (X /= Y). This sort of loose semantics
is just the sort of thing that gets tightened up in a standard.

Jon S Anthony

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
In article <NAYERI.96...@tahoe.gte.com> nay...@gte.com (Farshad Nayeri) writes:

> In article <DMGyH...@world.std.com> bob...@world.std.com (Robert A Duff) writes:
> ...


> > might have a destruction that gets called by magic. But the
> > existence of the adestructor makes the abstraction itself easier to
> > understand -- you can know something about all objects of the type,
> > without having to look at how the type is used.
>

> This is only true if your object doesn't have pointers into other
> objects, right? In presense of pointers, you will have to care about
> sharing which is a pain to do.

I'm not sure what you are getting at here. Certainly if the
destructor is "correctly programmed", the pointers to other objects is
indeed "not a problem" and a client just sees the abstraction and is
done with it. If you are saying that this is a pain for the
_implementor_ of the abstraction to do, well, you're probably more
right than wrong.


> I think destructors are the kind of things that look easy in the
> "hello world" example but are quite hard in any non-trivial
> application. Otherwise how is it that Purify is selling so well?

Depending on what you are doing, I would agree. As for why Purify is
selling well, well, that is because of all the leaky C/C++ code out
there! :-)


> If you look at most Modula-3 code, the FROM blah IMPORT foo is not
> used much. The language also discourages using it, because you can't
> say FROM blah IMPORT *. (This is cumbersome at times, but most of the
> time makes for clearer [yet a bit more verbose] code.)

Yes, and there are "fannatical" anti-use followers in Ada as well.

Keith Thompson

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
In <4flukd$8...@rational.rational.com> r...@rational.com (Bob Kitzberger) writes:
[...]

> This isn't the case, in my experience. When "private" is encountered,
> people know there is no need to keep looking (unless they are simply
> curious).

I agree. A concrete example is Text_IO, probably the single most commonly
used (well, withed) package. How many Ada programmers even know or care
what its private part looks like? Everything you need to know about
how to use a Text_IO.File_Type is in the visible part.

Of course there's nothing wrong with curiosity, but the details of the
private part of Text_IO really aren't relevant 99% of the time.

--
Keith Thompson (The_Other_Keith) k...@thomsoft.com
TeleSoft^H^H^H^H^H^H^H^H Alsys^H^H^H^H^H Thomson Software Products
10251 Vista Sorrento Parkway, Suite 300, San Diego, CA, USA, 92121-2718
"As God is my witness, I thought turkeys could fly." -- Arthur Carlson, WKRP

Hendrik Boom

unread,
Feb 12, 1996, 3:00:00 AM2/12/96
to
Farshad Nayeri (nay...@gte.com) wrote:


: (2) MANAGING RESOURCES OTHER THAN MEMORY. weak references deal nicely


: with resources that don't require fancy finalization protocols,
: like files buffers.

Hava I missed soemthing? What are weak references, and how do they
assist in managing resources?


David Chase

unread,
Feb 13, 1996, 3:00:00 AM2/13/96
to
In article 4...@world.std.com, bob...@world.std.com (Robert A Duff) writes:
> This is true to an extent, but I still think destructors (for example)
> are clearly beneficial.

Destructors are a bit of a pain from the point of view of (not)
overconstraining the garbage collector's specification in the language
specification. For instance, is there any guarantee that the
destructor will run in a timely fashion? Is there any guarantee that
it will run at all? What operations are allowed in a destructor? When
you find a garbage cycle, such that every node in the cycle has a
destructor to be run, which one do you run first? (Are the answers to
these questions compatible with a real-time garbage collector? Are
they compatible with a C-tolerant garbage collector?)

Unpleasant questions like these are a good part of why destructors
are not in the language proper.

> >It is not so. User-defined types in M3 can be stack
> >allocated.
>

> But not if the type is opaque, right? That seems like an annoying


> trade-off (you can't have information hiding without incurring an extra
> run-time cost), although the existence of garbage collection makes it
> less troublesome than it would otherwise be.

In theory (not practice, unfortunately) an optimizing compiler is
supposed to help with problems like these. In practice, I don't quite
think we're there yet, though we're much closer than we were back in 1990.
It also blows away safety if a user can create a REF to stack storage
that is then deallocated. (It also can complicate your garbage collector
implementation, for some styles of garbage collection).

speaking for myself,

David Chase


Gene Ouye

unread,
Feb 13, 1996, 3:00:00 AM2/13/96
to

r...@rational.com (Bob Kitzberger) writes:

[...]

> This isn't the case, in my experience. When "private" is encountered,
> people know there is no need to keep looking (unless they are simply
> curious).

Or unless they are trying to prove that the latest bug they are chasing
is in someone else's code and not in theirs!
;-)

Gene Ouye <ge...@rational.com>


hey...@pa.dec.com

unread,
Feb 14, 1996, 3:00:00 AM2/14/96
to comp.lang.modula3.usenet, comp.lang.ada.usenet, Kenneth Almquist
Kenneth Almquist (k...@socrates.hr.att.com) writes:

> For example, the NEW operation is required to return a reference
> which is distinct from all existing references. I don't think that
> the manual explains anywhere what it means for a reference to be
> "distinct", so this leaves open the possibility of two calls to NEW
> returning references to the same block of memory.

I don't think "distinct" was meant in any technical way; the intended
meaning is "different from". The important word in this specification
is "existing". I interpret the spec to mean that NEW is guaranteed to
return a reference different from any reference I could name in my
program (including local variables, global variables, and all
references reachable from them).

This means that two calls to NEW *can* return identical references
over the life of a program, since once a reference is dead (i.e., no
longer exists by the above definition), the garbage collector can
reclaim it and NEW can allocate the same memory again.

> If NEW is used to allocate an open array, the values of the array
> must be "arbitrary values of their type." So if you allocate an
> open array of type ARRAY OF [1 .. 10], the compiler must generate
> code to ensure that the elements of the array don't fall outside of
> the range of 1 to 10. Surely this is not intended.

Yes, it was intended. This is necessary to guarantee safety. For
example, consider the following code:

VAR
a: ARRAY [1..10] OF BOOLEAN;
x := NEW(REF ARRAY OF [1..10], 5);
BEGIN
a[x[0]] := TRUE;
...

Using x[0] as the index to the array "a" could cause an unchecked
runtime error if the elements of "x" were not initialized to values in
[1..10]. Granted, this code is dangerous because it uses a variable
that has not been explicitly initialized, but it would be very
expensive to require implementations to forbid the use of
uninitialized variables. Instead, the language designers required that
all variables be initialized to an arbitrary value of their type.

> NEW can be used with "untraced references". As I understand it, the
> intention here is that this should allocate a piece of memory which is
> outside the control of the garbage collector and will remain allocated
> until it is explicitly freed using "dispose." But what the specifica-
> tion states is very different: "When all traced references to a piece
> of allocated storage are gone, the implementation reclaims the
> storage."

Nothing more needs to be said about traced references. The operators
for creating and destroying them are defined, and the language provides
no other services related to them. The extra sentence about traced
references is necessary because the language does provide an extra
service for them, namely, garbage collection.

> The sentence quoted in the previous paragraph describes reference
> counting semantics for garbage collection. This means that the
> programmer must break a link in a circular data structure in order for
> the memory to be reclaimed by the system. I suspect that the writers
> of the specification did not intend this.

I agree. It would have been more accurate for them to have written
something like the following instead: "When a piece of allocated
storage becomes unreachable through traced references, the
implementation reclaims the storage."

> The specification doesn't mention "weak references" at all, but the


> posters on this thread seem to feel that they are part of Modula 3.

Weak references are not even mentioned in the Modula-3 language
definition, nor is "WeakRef" a required interface. However, the
"WeakRef" interface is included with the primary Modula-3
implementation, namely SRC Modula-3. I think people are confusing the
Modula-3 language definition with the SRC implementation (which
includes many extra interfaces and libraries not required by the
language).

- Allan

--------------------------------------------------------------------
Allan Heydon Digital Equipment Corporation
hey...@pa.dec.com Systems Research Center
(415) 853-2142 130 Lytton Avenue
(415) 853-2104 (FAX) Palo Alto, CA 94301

Derek Lee Beatty

unread,
Feb 15, 1996, 3:00:00 AM2/15/96
to

This brings to mind one of Adele Goldberg's assertions that one factor in the
success of Smalltalk environments has been that, as almost everything is
implemented in the same language, source-level debugging is available
regardless of what layer of your system you believe you must examine so as to
track down a bug. Having once built a system in a mixture of Scheme and C, I
thought the argument had merit.

How do the debuggers available for GNAT and SRC Modula-3 compare? What about
debugging into calls to a foreign subsystem written in C or (shudder) C++?

--
Derek Lee Beatty _
bea...@netcom.com _| ~-,
Austin, Texas \, * )
\_(

Robert Dewar

unread,
Feb 17, 1996, 3:00:00 AM2/17/96
to
Derek asked

"How do the debuggers available for GNAT and SRC Modula-3 compare? What about
debugging into calls to a foreign subsystem written in C or (shudder) C++?"

gdb is very happy to deal with multi-language programs, it automaticaly
switches its command interpretor personality to match the language you
ar currently debugging (e.g. you type a = b if you are debugging an
Ada unit, and (a == b) if you are debugging a C unit.


AdaWorks

unread,
Feb 20, 1996, 3:00:00 AM2/20/96
to
Kennel (m...@jt3ws1.etd.ornl.gov) wrote:

: Robert Dewar (de...@cs.nyu.edu) wrote:
: > T.E.D. asks regarding implementing GC in GNAT:

: > How tough could it be? :-)

In embedded real-time systems, automatic garbage collection can be
a serious liability. Ada, the language, must work consistently over
a wide-range of applications. Therefore, it is appropriate that GC
not be intrinsic to the language.

On the other hand, Ada 95 takes the very sensible approach of including
a package for Storage Pool management, which, when used with another
package, Ada.Finalization, allows the developer to carefully manage the
garbage collection processs and even make it automatic when necessary
to the design.

Furthermore, the Ada general access type feature eliminates many of the
issues associated with garbage collection one found in Ada 83 because
of the rules related to accessibility and scope.

Langauges that consistently do automatic garbage collection will not
perform correctly in embedded, hard, real-time (HRTS) weapons systems.
They work fine, though, for desk-top systems in which safety is not an
issue.

Richard Riehle
adaw...@netcom.com
--

ric...@adaworks.com
AdaWorks Software Engineering
Suite 27
2555 Park Boulevard
Palo Alto, CA 94306
(415) 328-1815
FAX 328-1112

Jon S Anthony

unread,
Feb 21, 1996, 3:00:00 AM2/21/96
to
In article <adaworksD...@netcom.com> adaw...@netcom.com (AdaWorks) writes:

> In embedded real-time systems, automatic garbage collection can be

> a serious liability...
>...


> Langauges that consistently do automatic garbage collection will not
> perform correctly in embedded, hard, real-time (HRTS) weapons systems.
> They work fine, though, for desk-top systems in which safety is not an
> issue.

I hope you doned your nomex suit before sending this out! :-)

Don Harrison

unread,
Feb 21, 1996, 3:00:00 AM2/21/96
to
Richard Riehle wrote:

[...]

: Langauges that consistently do automatic garbage collection will not
: perform correctly in embedded, hard, real-time (HRTS) weapons systems.
: They work fine, though, for desk-top systems in which safety is not an
: issue.

This is certainly true for single processor architectures. There is a trend
towards parallel architectures (such as SMP - Shared Memory Processing) becoming
more affordable. When they enter mainstream computing sometime in the
not-too-distant future, background processing (such as GC) can be done on a
separate processor from the RT application proper. Then, GC will be a viable proposition for HRTS.

: Richard Riehle
: adaw...@netcom.com

Don.

Mike Douglass

unread,
Feb 25, 1996, 3:00:00 AM2/25/96
to m...@src.dec.com
> Langauges that consistently do automatic garbage collection will not
> perform correctly in embedded, hard, real-time (HRTS) weapons systems.
> They work fine, though, for desk-top systems in which safety is not an
> issue.
>
> Richard Riehle
> adaw...@netcom.com
>

You're confusing particular implementations of a run-time system with the
language specification. I'm sure the SRC run-time system would be
inappropriate for something like an operating system, on the other hand I'm
as sure that over time people will develop run-time systems that are wholly
appropriate.


0 new messages