comp.lang.ada
 help / color / mirror / Atom feed
* Re: Choice of OO primitives in Ada95
       [not found] <4fmrhk$7k3@erinews.ericsson.se>
@ 1996-02-19  0:00 ` Richard A. O'Keefe
  0 siblings, 0 replies; 16+ messages in thread
From: Richard A. O'Keefe @ 1996-02-19  0:00 UTC (permalink / raw)


ehsjony@ehs.ericsson.se (Jonas Nygren) writes:
>A possible syntax could be outlined as:

>	class type Class_Name [extends Super] is ...
>	
>then we would not have the difficult to master freezing rules
>and controlling operand rules.

I for one am very happy with the Ada 95 model.
It really says a lot for the Ada 83 design that OOP could be grafted
in so cleanly.

The freezing rules are pretty intuitive (note that C also has rules about
when a type must be completed).

>One would simply prefix with
>the 'controlling operand' as for task and protected types.

This is not a simplification.  It is a complexification, because it
forces every operation to have only one controlling operand.  Set
operations are the classic example when you have two operands of the
same type (union, and so on).

Dynamic dispatching is still a form of procedure call; why impose new
syntax when we already have comprehensible syntax that works fine?

Having used Pop-2, where
	f(x)
	x.f
	x, f()
	x, f.apply
and so on all did the same thing, I can no longer get too enthusiastic
about minor differences in syntax.  See a recent discussion in
comp.lang.dylan (which allows both dotted and dotless method calls)
for why dotless might be preferred.

-- 
Election time; but how to get Labour _out_ without letting Liberal _in_?
Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-19  0:00     ` Don Harrison
@ 1996-02-19  0:00       ` Norman H. Cohen
  1996-02-19  0:00       ` Robert A Duff
  1996-02-21  0:00       ` Robert I. Eachus
  2 siblings, 0 replies; 16+ messages in thread
From: Norman H. Cohen @ 1996-02-19  0:00 UTC (permalink / raw)


In article <Dn0FqH.8Cw@assip.csasyd.oz>, donh@syd.csa.com.au (Don Harrison)
writes: 

|> I don't question the value of packages for non-OO encapsulation. I am interested
|> to know what is the perceived flexibility wrt OO. Did Tucker meant flexibility
|> wrt non-OO encapsulation?

I can't speak for Tucker, but my argument is as follows: 

      Packages, private parts, and package bodies are an appropriate
      mechanism for non-OO encapsulation that can be used in precisely
      the same way for OO encapsulation, equally appropriately.
      Therefore, a second, quite different mechanism for OO encapsulation
      would be redundant.

|> :2. It allows data abstractions involving two or more intimately linked
|> :   types to be encapsulated together.  For example: 
[my family-tree example deleted]
|>
|> This is an example of what I mean by tight-coupling of abstractions - you are
|> forced to encapsulate both abstractions into a single module.

No, I wasn't forced to do so, I chose to do so, because Marriage_Type and
Person_Type are part of a single recursive data structure and the
family-tree data abstraction has many operations that are most
efficiently implemented by referring to both the Marriage_Type and
Person_Type parts of this data structure.

Other applications entail mutually dependent types that are not
"initimately linked" in this way, and in such cases separate packages are
more appropriate.  A programmer whose encapsulation mechanism is a
package has the freedom to choose whether or not the two types should be
encapsulated together.  A programmer whose encapsulation mechanism is the
class does not.

|> :|> As far as symmetry between operands is concerned, the benefits seem to be more
|> :|> theoretical than practical.
|> : 
|> :The ability to use natural notation has the very practical advantage of
|> :making programs easier to read and understand.
|>
|> I would say the opposite is true - forcing a whole bunch of different abstractions
|> into the one module creates an amorphous mess that the developer has to sift
|> through to see which operations relate to which abstractions.

This is a non sequitur.  Your original remark about symmetry being of
only theoretical interest referred to the ability to define truly
symmetric binary dispatching operations.  I replied that this ability
provides a practical rather than theoretical advantage in terms of
program understandability.  You reply with a false and in any event
irrelevant suggestion that packages "force" different abstractions into
one module.

|> An example might best illustrate what I mean. Extending your example and assuming
|> each type is tagged, we might have: 
|>
|> package X is
|>   type MARRIAGE is tagged ...
|>   type PERSON is tagged ...
|>   type UNIVERSITY is tagged ...
|>   type GOVERNMENT is tagged ...
|>   type ELECTORATE is tagged ...
|>   type ADDRESS is tagged ...
|>
|>   procedure Enrol (Student : in out PERSON; Uni : in out UNIVERSITY);
|>   procedure Award_Grant (Polies : in out GOVERNMENT; Uni : in out UNIVERSITY);
|>   procedure Make_Gerrymander (Polies : in out GOVERNMENT; Elect : in out ELECTORATE);
|>   function Office_Address (Elect : in ELECTORATE) return ADDRESS;
|>
|> end X;
|>
|> Each abstraction is related to the previous one but isn't necessarily related
|> to any other. As I understand it, the language rules dictate that each of these
|> abstractions must be in the same package.

You understand it incorrectly!

|>                                           But many of them have nothing to do with
|> each other. They are tightly-coupled even though they should be distinct and this
|> has been forced by the language rules.

There are several solutions for writing data abstractions that have
mutually dependent interfaces, but independent implementations, in
separate packages.  John Volan and I have debated two such approaches in
this newsgroup ad nauseum.

Ada packages give you the CHOICE of packaging two types together or
separately.  In the family-tree example, the two types are different
aspects of the same abstraction, with a shared implementation, and a
single package is appropriate.  (Other examples:  A package providing a
type for linked lists and a type for cursors representing positions in
linked lists; a package providing a type for points on a time line and a
type for lengths of intervals on a time line; a package providing a type
for machine addresses and a type for offsets between machine addresses;
a package providing a type for sparse matrices, a type identifying a row
of such a sparse matrix, and a type identifying a column of a sparse
matrix; etc.)

When it is not appropriate to package two mutually dependent types
together, Ada packages give you the CHOICE to encapsulate them
separately.

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




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-19  0:00     ` Don Harrison
  1996-02-19  0:00       ` Norman H. Cohen
@ 1996-02-19  0:00       ` Robert A Duff
  1996-02-20  0:00         ` Don Harrison
  1996-02-21  0:00       ` Robert I. Eachus
  2 siblings, 1 reply; 16+ messages in thread
From: Robert A Duff @ 1996-02-19  0:00 UTC (permalink / raw)


In article <Dn0FqH.8Cw@assip.csasyd.oz>,
Don Harrison <donh@syd.csa.com.au> wrote:
>package X is
>  type MARRIAGE is tagged ...
>  type PERSON is tagged ...
>  type UNIVERSITY is tagged ...
>  type GOVERNMENT is tagged ...
>  type ELECTORATE is tagged ...
>  type ADDRESS is tagged ...
>
>  procedure Enrol (Student : in out PERSON; Uni : in out UNIVERSITY);
>  procedure Award_Grant (Polies : in out GOVERNMENT; Uni : in out UNIVERSITY);
>  procedure Make_Gerrymander (Polies : in out GOVERNMENT; Elect : in out ELECTORATE);
>  function Office_Address (Elect : in ELECTORATE) return ADDRESS;
>
>end X;
>
>Each abstraction is related to the previous one but isn't necessarily related
>to any other. As I understand it, the language rules dictate that each of these 
>abstractions must be in the same package.

No, they don't have to be in the same package (and as you say, probably
should not be).  Could you explain what you mean -- why do you think
that all of the above types have to be in the same package?

(By the way, the above code is illegal, by 3.9.2(12).)

>I can't make any comment on C++ as I'm unfamiliar with it (must be the only
>one in the world). The Eiffel equivalent of static members are probably 'once'
>attributes which may optionally be exported (visible or private).

No, static members in C++ are not quite the same thing as Eiffel's
'once' attributes.  A static member is just a function that is inside
the class for visibility/encapsulation purposes, but isn't attached to
any particular object.  In other words, there's no "self" or "this" when
you call a static member.  A once attribute is a function that gets
executed just once, and the result gets saved -- when you call it again,
you get the saved value.  In Ada, you would just use a constant for that
purpose, in most cases.

>... This issue
>is language war flame bait and I don't intend to defend the pure OO position
>here :-)

Once attributes are flame bait?  Not sure why anybody would get too hot
about that issue.  OK, if you say so.

- Bob




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
       [not found]   ` <4g2f8v$15lc@watnews1.watson.ibm.com>
@ 1996-02-19  0:00     ` Don Harrison
  1996-02-19  0:00       ` Norman H. Cohen
                         ` (2 more replies)
  1996-02-21  0:00     ` John DiCamillo
  1 sibling, 3 replies; 16+ messages in thread
From: Don Harrison @ 1996-02-19  0:00 UTC (permalink / raw)


Norman H. Cohen) wrote:

:|In article <DMu9yw.5ts@assip.csasyd.oz>, donh@syd.csa.com.au (Don Harrison)
:|writes: 
:
:|> Tucker Taft wrote: 
:|>
:|> [...]
:|>
:|> : ...  The orthogonality of
:|> : types and modules in Ada 95 can be a major advantage,
:|> : gives the programmer more flexibility in structuring their system
:|>
:|> What flexibility does this approach offer over conventionally encapsulated classes?
:
:1. It allows other forms of encapsulation and packaging, not involving
:   classes.  We could have a package providing a nonextendible private
:   type for complex numbers, deferred constants zero, one, and i, and a
:   set of arithmetic operations.  We could have a package providing a set
:   of constants.  We could have a package providing a set of
:   higher-level auxiliary routines operating on a type provided by
:   another package, building on the primitive operations provided by that
:   package.  I've seen people try to use C++ classes with no nonstatic
:   members for these other forms of encapsulation and packaging, and the
:   result is strained.  That's one reason C++ has added namespaces, which
:   are like Ada packages.  But once the full generality of Ada-like
:   packages is available, the class program unit as an encapsulation
:   mechanism is redundant.

I don't question the value of packages for non-OO encapsulation. I am interested
to know what is the perceived flexibility wrt OO. Did Tucker meant flexibility
wrt non-OO encapsulation?

:2. It allows data abstractions involving two or more intimately linked
:   types to be encapsulated together.  For example: 
:
:   with Dates; use Dates;
:   package Family_Trees is
:
:      type Marriage_Type is private;
:      type Person_Type is private;
:
:      function New_Person
:         (Name       : String;
:          Birth_Date : Date_Type;
:          Death_Date : Date_Type := No_Date);
:
:      procedure Wed
:         (Husband       : in out Person_Type;
:          Wife          : in out Person_Type;
:          Marriage_Date : in Date_Type;
:          Divorce_Date  : in Date_Type := No_Date;
:          Marriage      : out Marriage_Type);
:
:      procedure Add_Offspring
:         (Marriage: in out Marriage_Type; Child: in out Person_Type);
:
:      function Husband (Marriage: in Marriage_Type) return Person_Type;
:      function Wife (Marriage: in Marriage_Type) return Person_Type;
:      function Marriage_Of (Spouse: in Person_Type) return Marriage_Type;
:      function Parents (Child: in Person_Type) return Marriage_Type;
:
:      generic
:         with procedure Process_One_Child (Child: in Person_Type);
:      procedure Process_All_Children (Marriage: in Marriage_Type);
:
:      generic
:         with procedure Process_One_Marriage (Marriage: in Marriage_Type);
:      procedure Process_All_Marriages (Spouse: in Person_Type);
:
:   private
:
:      ...
:
:   end Family_Trees;

This is an example of what I mean by tight-coupling of abstractions - you are
forced to encapsulate both abstractions into a single module.

:|> As far as symmetry between operands is concerned, the benefits seem to be more
:|> theoretical than practical.
:
:The ability to use natural notation has the very practical advantage of
:making programs easier to read and understand.

I would say the opposite is true - forcing a whole bunch of different abstractions
into the one module creates an amorphous mess that the developer has to sift
through to see which operations relate to which abstractions.

:|>                             Indeed, encapsulating classes has the practical
:|> advantage of cleaner interfaces to classes. Cleaner interfaces facilitate easier
:|> debugging, maintenance, reuse etc. The Ada 95 model works against this principle
:|> by forcing designers to create tightly-coupled classes because parts of their
:|> interfaces are shared.
:
:Ada does not "force" designers to do any such thing.  Indeed, the
:language encourages the use of encapsulated, loosely coupled data
:abstractions.

An example might best illustrate what I mean. Extending your example and assuming
each type is tagged, we might have:

package X is
  type MARRIAGE is tagged ...
  type PERSON is tagged ...
  type UNIVERSITY is tagged ...
  type GOVERNMENT is tagged ...
  type ELECTORATE is tagged ...
  type ADDRESS is tagged ...

  procedure Enrol (Student : in out PERSON; Uni : in out UNIVERSITY);
  procedure Award_Grant (Polies : in out GOVERNMENT; Uni : in out UNIVERSITY);
  procedure Make_Gerrymander (Polies : in out GOVERNMENT; Elect : in out ELECTORATE);
  function Office_Address (Elect : in ELECTORATE) return ADDRESS;

end X;

Each abstraction is related to the previous one but isn't necessarily related
to any other. As I understand it, the language rules dictate that each of these 
abstractions must be in the same package. But many of them have nothing to do with
each other. They are tightly-coupled even though they should be distinct and this
has been forced by the language rules.

:|> Forcing ownership of operations by particular classes is entirely consistent with
:|> the pattern established in Ada 83 for packages: the components of a package OWN
:|> their components (attributes, operations, etc.). Therfore, mapping classes onto
:|> packages giving package classes follows quite naturally as shown by my model.
:
:Ada certainly recognizes a close relationship among packages, types, and
:operations:  If a package provides both a type and subprograms with
:parameters or results of that type, those subprograms "belong" to the
:type.  (In the technical jargon, they are "primitive operations" of the
:type.)
:
:But a package is a module, not a type.  The unnatural modeling of
:one-per-class data items as static "members" in C++ comes from an attempt
:to force-fit the two concepts into a single construct.  In Ada, a
:singleton data item is simply a variable declared inside a
:package--encapsulated in the package body if it is to be hidden (like a
:C++ private static data member).  There is no pretense that the variable
:is in any way a COMPONENT of any type that happens to be encapsulated in
:the same package as the variable.

I can't make any comment on C++ as I'm unfamiliar with it (must be the only
one in the world). The Eiffel equivalent of static members are probably 'once'
attributes which may optionally be exported (visible or private). This issue
is language war flame bait and I don't intend to defend the pure OO position
here :-)
 
:
:--
:Norman H. Cohen    ncohen@watson.ibm.com

Don.







^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-20  0:00         ` Don Harrison
@ 1996-02-20  0:00           ` Jon S Anthony
  1996-02-20  0:00           ` Ray Toal
  1996-02-23  0:00           ` Robert A Duff
  2 siblings, 0 replies; 16+ messages in thread
From: Jon S Anthony @ 1996-02-20  0:00 UTC (permalink / raw)


In article <Dn22M0.G0D@assip.csasyd.oz> donh@syd.csa.com.au (Don Harrison) writes:
> Robert A Duff writes:
> 
> :In article <Dn0FqH.8Cw@assip.csasyd.oz>,
> :Don Harrison <donh@syd.csa.com.au> wrote:
> :>package X is
> :>  type MARRIAGE is tagged ...
> :>  type PERSON is tagged ...
> :>  type UNIVERSITY is tagged ...
> :>  type GOVERNMENT is tagged ...
> :>  type ELECTORATE is tagged ...
> :>  type ADDRESS is tagged ...
> :>
> :>...
> :>end X;
> :>

> :>Each abstraction is related to the previous one but isn't necessarily
> :>related to any other. As I understand it, the language rules dictate
> :>that each of these abstractions must be in the same package.
> :
> :No, they don't have to be in the same package (and as you say, probably
> :should not be).  Could you explain what you mean -- why do you think
> :that all of the above types have to be in the same package?
>
>  I don't have an RM available but quoting you (25.1.96) on the
> subject of dispatching operations in response to Arcadio A. Sincero:
> 
> > >As a matter of fact, the only indication that TPerson's Walk "belongs to
> > >it" is that TPerson's Walk has a TPerson parameter.
> 
> > That, plus the fact that it's in the same package.
> 
> So, if you want all of the operations to be dispatching (primitive), then the
> tagged types must also be in the same package.

What in this in anyway could even _possibly_ be construed in the
course of even the most tortuous path of illogic to be saying _all_
the types _together_ need to be in the _same_ package?  Hmmmmmm????


>  In the same thread, Jon S Anthony went on to say that
> non-dispatching operations using tagged types were those defined in
> different packages to those types:
> 
> > Just to add one more bit (completely beating it to death...), it is also
> > legal to have a subprogram with operands of both types as long as it is
> > not in the package where the two types are declared.  Of course such a
> > subprogram is not primitive and will never dispatch (assuming it has no
> > other controlling operands).

See above (possibly even more so).


>  Dispatching or not dispatching depending on where an operation is
> defined is not what you would call consistent.

Why not?  Seems pretty simple really.  And it allows for non
dispatching operations to be constructed if they have a closer match
to the desired semantics.  And why should operations that are closely
tied to the semantics of a type (basically the intent of primitive
operations) be definable anywhere?  That sort of thing leads pretty
quickly to inscrutable structures.  (I believe that Dylan does allow
this sort of thing, but there has been disagreement on how "wonderful"
it is.)


> A couple of other gripes:

>  1) Why should you have to specify that a type is 'tagged'? Can't
> the compiler work that out for itself? eg. by seeing whether the
> type is extended elsewhere. The developer is forced to worry about
> what should be an implementation issue.

Ahhh, the ol' clairvoyant compiler.  You are on a roll.  What if the
type is not extended?  This sort of comment might make sense if you
were discussing a language where the only kinds of types available
were "classes" (actually, it would not even make sense there as then
it would be irrelevant).  But you aren't.  Of course you can decry
this fact, but that is another matter altogether and irrelevant given
the current context.  Also, given the context, it is very much the
case that "tagged" is _not_ simply an implementation issue.  Flagging
a particular type as one which is extensible and supportive of dynamic
polymorphism can be argued to be a "good engineering" tradeoff.


> 2) Similarly, why should the developer have to specify that an
> operation dispatches (classwide operations)? Presumably, you're
> aiming for quicker execution, but compilers could perform a certain
> degree of optimisation eg. If it knows the type is not extended
> anywhere, there is no need to dispatch. There would also be
> situations where the specific variant of an inherited type is known
> eg. following an explicit assignment from an entity of that type.

This is just plain wrong - on several accounts.  First class wide
operations do not dispatch (they have uses more akin to a "generic
method" in CLOS, though clearly more restricted).  Second, _all_
primitive operations are dispatching operations.  The "developer" does
_not_ specify that an operation dispatches (other than simply
including it as a primitive operation of a tagged type).  Third,
optimization is irrelevant _to the semantics_ of whether any actual
_invocation_ dispatches.  Sans optimizations a primitive operation
dispatches iff it has class-wide actuals for the operation's
controlling parameters - the compiler _always_ knows when a particular
call of an operation dispatches.  Fourth, optimization is also
(mostly) irrelevant for making the design choice of keeping instances
of dynamic polymorphism a local rather than global issue.

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

617.484.3383
jsa@organon.com





^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-19  0:00       ` Robert A Duff
@ 1996-02-20  0:00         ` Don Harrison
  1996-02-20  0:00           ` Jon S Anthony
                             ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Don Harrison @ 1996-02-20  0:00 UTC (permalink / raw)


Robert A Duff writes:

:In article <Dn0FqH.8Cw@assip.csasyd.oz>,
:Don Harrison <donh@syd.csa.com.au> wrote:
:>package X is
:>  type MARRIAGE is tagged ...
:>  type PERSON is tagged ...
:>  type UNIVERSITY is tagged ...
:>  type GOVERNMENT is tagged ...
:>  type ELECTORATE is tagged ...
:>  type ADDRESS is tagged ...
:>
:>  procedure Enrol (Student : in out PERSON; Uni : in out UNIVERSITY);
:>  procedure Award_Grant (Polies : in out GOVERNMENT; Uni : in out UNIVERSITY);
:>  procedure Make_Gerrymander (Polies : in out GOVERNMENT; Elect : in out ELECTORATE);
:>  function Office_Address (Elect : in ELECTORATE) return ADDRESS;
:>
:>end X;
:>
:>Each abstraction is related to the previous one but isn't necessarily related
:>to any other. As I understand it, the language rules dictate that each of these 
:>abstractions must be in the same package.
:
:No, they don't have to be in the same package (and as you say, probably
:should not be).  Could you explain what you mean -- why do you think
:that all of the above types have to be in the same package?

I don't have an RM available but quoting you (25.1.96) on the subject of dispatching
operations in response to Arcadio A. Sincero:

> >As a matter of fact, the only indication that TPerson's Walk "belongs to
> >it" is that TPerson's Walk has a TPerson parameter.

> That, plus the fact that it's in the same package.

So, if you want all of the operations to be dispatching (primitive), then the
tagged types must also be in the same package.

In the same thread, Jon S Anthony went on to say that non-dispatching operations
using tagged types were those defined in different packages to those types:

> Just to add one more bit (completely beating it to death...), it is also
> legal to have a subprogram with operands of both types as long as it is
> not in the package where the two types are declared.  Of course such a
> subprogram is not primitive and will never dispatch (assuming it has no
> other controlling operands).

Dispatching or not dispatching depending on where an operation is defined is not
what you would call consistent.

A couple of other gripes:

1) Why should you have to specify that a type is 'tagged'? Can't the compiler work
that out for itself? eg. by seeing whether the type is extended elsewhere. The
developer is forced to worry about what should be an implementation issue.

2) Similarly, why should the developer have to specify that an operation dispatches
(classwide operations)? Presumably, you're aiming for quicker execution, but
compilers could perform a certain degree of optimisation eg. If it knows the type
is not extended anywhere, there is no need to dispatch. There would also be
situations where the specific variant of an inherited type is known eg. following
an explicit assignment from an entity of that type.
 
[...]

:- Bob

Don.









^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-20  0:00         ` Don Harrison
  1996-02-20  0:00           ` Jon S Anthony
@ 1996-02-20  0:00           ` Ray Toal
  1996-02-21  0:00             ` Don Harrison
  1996-02-22  0:00             ` Bernd Holzmueller
  1996-02-23  0:00           ` Robert A Duff
  2 siblings, 2 replies; 16+ messages in thread
From: Ray Toal @ 1996-02-20  0:00 UTC (permalink / raw)


donh@syd.csa.com.au (Don Harrison) wrote:

>1) Why should you have to specify that a type is 'tagged'? Can't the compiler work
>that out for itself? eg. by seeing whether the type is extended elsewhere. The
>developer is forced to worry about what should be an implementation issue.

Requiring 'tagged' is a GOOD THING!  Inheritance weakens encapsulation.
The default case (no tagged) is that you design a type, and you
provide all and only those operations that work on the type and you
don't make any details available to anyone else - in short you
fully control the type.  Now if your intent is to ALLOW derivation
then you must mark it tagged.  This alerts the reader that this
type may be derived from.  Imagine a language in which you could
inherit from any type you wanted to! :-)  Whether or not a type
should be tagged is a DESIGN decision; I totally disagree that it
should be an implementation decision.  By the way a compiler can not
in general determine if the "type is extended elsewhere" since in
Ada extensions can appear in other compilation units.


>2) Similarly, why should the developer have to specify that an operation dispatches
>(classwide operations)? Presumably, you're aiming for quicker execution, but
>compilers could perform a certain degree of optimisation eg. If it knows the type
>is not extended anywhere, there is no need to dispatch. There would also be
>situations where the specific variant of an inherited type is known eg. following
>an explicit assignment from an entity of that type.

The reason you need to specify whether or not an operation dispatches
is that you can write code like

  procedure P (X: T) is begin R(X); end P;
  procedure Q (X: T'Class) is begin R(X); end Q;

which behave differently.

Ray Toal






^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-19  0:00     ` Don Harrison
  1996-02-19  0:00       ` Norman H. Cohen
  1996-02-19  0:00       ` Robert A Duff
@ 1996-02-21  0:00       ` Robert I. Eachus
  2 siblings, 0 replies; 16+ messages in thread
From: Robert I. Eachus @ 1996-02-21  0:00 UTC (permalink / raw)



In article <Dn0FqH.8Cw@assip.csasyd.oz> donh@syd.csa.com.au (Don Harrison) writes:

  > This is an example of what I mean by tight-coupling of
  > abstractions - you are forced to encapsulate both abstractions
  > into a single module.

   Not FORCED to, choose to.

  > An example might best illustrate what I mean. Extending your
  > example and assuming each type is tagged, we might have:

  > package X is
  >   type MARRIAGE is tagged ...
  >   type PERSON is tagged ...
  >   type UNIVERSITY is tagged ...
  >   type GOVERNMENT is tagged ...
  >   type ELECTORATE is tagged ...
  >   type ADDRESS is tagged ...

  >    procedure Enrol (Student : in out PERSON; Uni : in out UNIVERSITY);
  >    procedure Award_Grant (Polies : in out GOVERNMENT; Uni : in out UNIVERSITY);
  >    procedure Make_Gerrymander (Polies : in out GOVERNMENT; Elect : in out ELECTORATE);
  >    function Office_Address (Elect : in ELECTORATE) return ADDRESS;

  > end X;

  > Each abstraction is related to the previous one but isn't
  > necessarily related to any other. As I understand it, the language
  > rules dictate that each of these abstractions must be in the same
  > package. But many of them have nothing to do with each other. They
  > are tightly-coupled even though they should be distinct and this
  > has been forced by the language rules.

    What language rules say this?  The only thing remotely close is
that when you have two types where you want primitive operations of
one with operands of the other, you have to chose one of several
approaches.  ONE of those approaches is to package the types together,
and if they are closely related, it is usually the right choice.
Other choices include using child packages, making the operations on
one type class-wide operations using a parent of the other type,
treating the relation between the two types as its own class,
generics, etc...

    But how would you attack this "problem" in C++?  The "solutions" I
have seen all have the same semantic effect as the Ada solution shown
even though the file layout is usually different.  (The mingling of
the types is via #includes.)

--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
       [not found]   ` <4g2f8v$15lc@watnews1.watson.ibm.com>
  1996-02-19  0:00     ` Don Harrison
@ 1996-02-21  0:00     ` John DiCamillo
  1996-02-22  0:00       ` Don Harrison
  1 sibling, 1 reply; 16+ messages in thread
From: John DiCamillo @ 1996-02-21  0:00 UTC (permalink / raw)


ncohen@watson.ibm.com (Norman H. Cohen) writes:
>|> Tucker Taft wrote: 
>|> : ...  The orthogonality of
>|> : types and modules in Ada 95 can be a major advantage,
>|> : gives the programmer more flexibility in structuring their system

But Cardelli and Wegner [CW85] showed that the opposite is
true: providing package types through existential quantification
is *more* flexible than having typeless package values as
Ada provides.  It also simplifies and unifies the concept of Ada
generic packages, which are almost package types, and allows
package values to be treated as first-class values.

To be sure, C&W based their analysis on a type system supporting
first class functional values (not present in Ada), so their
conclusions may not hold for Ada.  However, I find it difficult
to believe that the converse is actually true.

>|> What flexibility does this approach offer over conventionally encapsulated classes?

>1. It allows other forms of encapsulation and packaging, not involving
>   classes.  We could have a package providing a nonextendible private
>   type for complex numbers, deferred constants zero, one, and i, and a
>   set of arithmetic operations.  We could have a package providing a set
>   of constants.  We could have a package providing a set of
>   higher-level auxiliary routines operating on a type provided by
>   another package, building on the primitive operations provided by that
>   package.  I've seen people try to use C++ classes with no nonstatic
>   members for these other forms of encapsulation and packaging, and the
>   result is strained.

"Strained" in what way?  _D&E_ [Stroustrup94] mentions several
minor problems with this approach, but seems to be considering
using classes to wrap already existing global declarations.
(btw, i'm not disagreeing, just asking for clarification)

>   That's one reason C++ has added namespaces, which
>   are like Ada packages.

Sort of... Namespaces simply control name visibility, they are
not an abstraction mechanism.  Namespaces do not have private
parts.  Namespaces may be extended by multiple declarations.

>   But once the full generality of Ada-like
>   packages is available, the class program unit as an encapsulation
>   mechanism is redundant.

Again, sort of.  Why talk of adding a separate class program unit?
Why not just extend packages to provide package types?  That way,
you have only one mechanism for encapsulation (the package) and
packages become first class values, allowing for more flexible
package declarations and increased code-reuse.

[big snip]

>Ada certainly recognizes a close relationship among packages, types, and
>operations:  If a package provides both a type and subprograms with
>parameters or results of that type, those subprograms "belong" to the
>type.  (In the technical jargon, they are "primitive operations" of the
>type.)

>But a package is a module, not a type.

Which is the whole problem, despite what the rationale tries to
claim, IMHO.  Ada, despite being a very type-centric programming
language, has too limited a concept of types.

>The unnatural modeling of
>one-per-class data items as static "members" in C++ comes from an attempt
>to force-fit the two concepts into a single construct.

Not at all.  The unnatural modeling comes from a lack of class
values in C++.  This same problem causes the awkward semantics
of constructors and destructors.  In other words, static members
are a C++ problem, not a class problem.

>--
>Norman H. Cohen    ncohen@watson.ibm.com

-- 
    ciao,
    milo
================================================================
    John DiCamillo                         Fiery the Angels Fell 
    milod@netcom.com       Deep thunder rode around their shores




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-20  0:00           ` Ray Toal
@ 1996-02-21  0:00             ` Don Harrison
  1996-02-23  0:00               ` Robert A Duff
  1996-02-22  0:00             ` Bernd Holzmueller
  1 sibling, 1 reply; 16+ messages in thread
From: Don Harrison @ 1996-02-21  0:00 UTC (permalink / raw)


Ray Toal wrote:

:donh@syd.csa.com.au (Don Harrison) wrote:
:
:>1) Why should you have to specify that a type is 'tagged'? Can't the compiler work
:>that out for itself? eg. by seeing whether the type is extended elsewhere. The
:>developer is forced to worry about what should be an implementation issue.
:
:Requiring 'tagged' is a GOOD THING!  Inheritance weakens encapsulation.

Not sure what you mean by this. Inheritance is no weaker or stronger in languages
(such as Eiffel) which map classes onto the encapsulation mechanism.

:The default case (no tagged) is that you design a type, and you
:provide all and only those operations that work on the type and you
:don't make any details available to anyone else - in short you
:fully control the type.  Now if your intent is to ALLOW derivation
:then you must mark it tagged.  This alerts the reader that this
:type may be derived from.  Imagine a language in which you could
:inherit from any type you wanted to! :-)

Yes, it's called Eiffel and it's great having such flexibility! :-). One aspect
of that flexibility is that, if, one sunny day, you decide you need to extend a
type you go right in and do it and don't have to touch the original. In Ada, you
have to go back and redefine the type to make it tagged. The impact of this may
be limited to that - don't know, haven't thought about it - but you shouldn't have
to redefine something to reuse it.

:                                            Whether or not a type
:should be tagged is a DESIGN decision; I totally disagree that it
:should be an implementation decision.  By the way a compiler can not
:in general determine if the "type is extended elsewhere" since in
:Ada extensions can appear in other compilation units.

I can't think offhand of a suitable way of dealing with this but that isn't to
say it's impossible. 

:>2) Similarly, why should the developer have to specify that an operation dispatches
:>(classwide operations)? Presumably, you're aiming for quicker execution, but
:>compilers could perform a certain degree of optimisation eg. If it knows the type
:>is not extended anywhere, there is no need to dispatch. There would also be
:>situations where the specific variant of an inherited type is known eg. following
:>an explicit assignment from an entity of that type.
:
:The reason you need to specify whether or not an operation dispatches
:is that you can write code like
:
:  procedure P (X: T) is begin R(X); end P;
:  procedure Q (X: T'Class) is begin R(X); end Q;
:
:which behave differently.

You don't have to do it that way. You can use (for example) a synonym construct like

  procedure P, Q (X: T) is begin R(X); end P, Q;

and redefine Q for extensions of X.

:
:Ray Toal
:
:

Don.









^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-20  0:00           ` Ray Toal
  1996-02-21  0:00             ` Don Harrison
@ 1996-02-22  0:00             ` Bernd Holzmueller
  1996-02-23  0:00               ` Robert A Duff
  1 sibling, 1 reply; 16+ messages in thread
From: Bernd Holzmueller @ 1996-02-22  0:00 UTC (permalink / raw)


Ray Toal wrote:
> 
> donh@syd.csa.com.au (Don Harrison) wrote:
> 
> >1) Why should you have to specify that a type is 'tagged'? Can't the compiler work
> >that out for itself? eg. by seeing whether the type is extended elsewhere. The
> >developer is forced to worry about what should be an implementation issue.
> 
> Requiring 'tagged' is a GOOD THING!  Inheritance weakens encapsulation.
> The default case (no tagged) is that you design a type, and you
> provide all and only those operations that work on the type and you
> don't make any details available to anyone else - in short you
> fully control the type.  Now if your intent is to ALLOW derivation
> then you must mark it tagged.  This alerts the reader that this
> type may be derived from.  Imagine a language in which you could
> inherit from any type you wanted to! :-)  Whether or not a type
> should be tagged is a DESIGN decision; I totally disagree that it
> should be an implementation decision.  By the way a compiler can not
> in general determine if the "type is extended elsewhere" since in
> Ada extensions can appear in other compilation units.

Actually, the compiler _can_ work out if a tag is necessary. This is the case only if 
a type is used polymorphically, i.e., class-wide in Ada 95 terminology (and has 
_nothing_ to do with type-extension). A different implementation model than is given 
in the LRM would create a tag only in these cases, which would allow 'normal' 
(monomorphic) uses of a tagged type be as efficient as the use of an untagged type. 
The consequence is that a special kind of "tagged types" is not necessary if 
efficiency is of concern. This is discussed in more detail in a paper at Ada-Europe 96.

Regarding the requirement to mark a type tagged to control type extension: I cannot 
see any advantage in restricting the flexibility (in the sense of potential reuse) 
of the language without gaining anything. Whether or not a programmer is going to 
use a type for type extension is not relevant for the author of the original type 
and should therefore not explicitly prohibitable by him. It could be of interest 
for a _user_ of the original type because dispatching can be a concern, but not 
necessarily because he may wish to use this type only monomorphically, and thus 
no dispatching will ever occur.

Bernd

-- 
 -----------------------------------------------------------------------------
 Bernd Holzmueller,
 Institute of Computer Science, University of Stuttgart      
 email : holzmuel@informatik.uni-stuttgart.de
 http://www.informatik.uni-stuttgart.de/ifi/ps/bernd.html
 -----------------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-21  0:00     ` John DiCamillo
@ 1996-02-22  0:00       ` Don Harrison
  1996-02-24  0:00         ` Robert A Duff
  0 siblings, 1 reply; 16+ messages in thread
From: Don Harrison @ 1996-02-22  0:00 UTC (permalink / raw)


John DiCamillo wrote:

[objective arguments about class encapsulation]

Thank you. I was beginning to wonder whether there was anyone else in this forum
willing to discard their preconceived ideas and able to think objectively on
this subject.

Don.


 







^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-20  0:00         ` Don Harrison
  1996-02-20  0:00           ` Jon S Anthony
  1996-02-20  0:00           ` Ray Toal
@ 1996-02-23  0:00           ` Robert A Duff
  2 siblings, 0 replies; 16+ messages in thread
From: Robert A Duff @ 1996-02-23  0:00 UTC (permalink / raw)


In article <Dn22M0.G0D@assip.csasyd.oz>,
Don Harrison <donh@syd.csa.com.au> wrote:
>Robert A Duff writes:
>:No, they don't have to be in the same package (and as you say, probably
>:should not be).  Could you explain what you mean -- why do you think
>:that all of the above types have to be in the same package?
>
>I don't have an RM available but quoting you (25.1.96) on the subject of dispatching
>operations in response to Arcadio A. Sincero:
>
>> >As a matter of fact, the only indication that TPerson's Walk "belongs to
>> >it" is that TPerson's Walk has a TPerson parameter.
>
>> That, plus the fact that it's in the same package.
>
>So, if you want all of the operations to be dispatching (primitive), then the
>tagged types must also be in the same package.

Sorry, you misunderstood me.  In Ada, a procedure can only be
dispatching on *one* type.  It can have several parameters of that type,
and a result of that type (if it's a function).  But there is a run-time
check that all of those parameters have the same type tag.  Ada does not
have multi-dispatching, like CLOS does.  But neither to any of the
languages (such as Eiffel) that use the prefix notation.

Now a procedure that's dispatching on type T can have other parameters
of other types.  It does not need to be in the same package as those
other types.  Same thing in Eiffel -- the operation is inside one class,
and is dispatching (only) on that class, but can have parameters of some
other class.

So, typically, you put exactly one type in a package, and put its
primitive (dispatching) operations in that same package.  You can put
operations that don't dispatch on that type in some other package.

The one case where this doesn't work too well is when you have two types
that are defined in terms of each other (e.g. T1 contains a pointer to
T2, and T2 contains a pointer to T1).  When this happens, you are forced
to put both types in the same package, or use one of the slightly ugly
workarounds that have been discussed here recently.  I admit that is a
language design flaw.  But don't generalize that to say that all types
in your entire program have to get sucked into the same package!

>In the same thread, Jon S Anthony went on to say that non-dispatching operations
>using tagged types were those defined in different packages to those types:
>
>> Just to add one more bit (completely beating it to death...), it is also
>> legal to have a subprogram with operands of both types as long as it is
>> not in the package where the two types are declared.  Of course such a
>> subprogram is not primitive and will never dispatch (assuming it has no
>> other controlling operands).
>
>Dispatching or not dispatching depending on where an operation is defined is not
>what you would call consistent.

Heh?  I thought you were arguing in favor of the class-based languages,
which do exactly that.  In Eiffel, an operation is dispatching based on
which class it's in.

In CLOS, you can have dispatching operations that are declared whereever
you want.  That can lead to some rather disorganized code, but I suppose
it's necessary if you're going to have multi-methods.  Anyway, I think
it's best to gather the dispatching operations together with the type
(either inside it, as in Eiffel, or in the same package, as in Ada).

Note also that in Eiffel you can declare that a given operation cannot
be further overridden ("frozen", or something like that?).  That's a
very similar feature to what you complain about here -- in part, it is a
hint to the compiler that calling that function won't dispatch to
someplace else, and in part, it's a help in understanding the program,
because you can know exactly which function is being called.

>A couple of other gripes:
>
>1) Why should you have to specify that a type is 'tagged'? Can't the compiler work
>that out for itself? eg. by seeing whether the type is extended elsewhere. The
>developer is forced to worry about what should be an implementation issue.

No, the compiler cannot tell, because of separate compilation.  It can't
tell in the Eiffel case, either, for the same reason.  But in Eiffel,
everything's dispatching.  If you're willing to do extra work at link
time, then you can optimize away the tag field.  But not at compile
time.

Note that C++ has essentially the same thing -- the "virtual" keyword.
If there are no virtual functions in a class, then no tag field is
necessary.  In Ada, if there is no "tagged" keyword, then no tag field
is necessary.  (One difference between Ada and C++ is that in Ada you
cannot extend an untagged type with extra record components, whereas as
you *can* do that in C++ (i.e. you can extend a class that has no
virtual functions.  There was a big fight about that during the design
of Ada 9X.  I don't like the way it turned out).

So, you're pretty much correct that "tagged" is not a logical necessity.
It is, in fact, an efficiency hack.

>2) Similarly, why should the developer have to specify that an operation dispatches
>(classwide operations)? Presumably, you're aiming for quicker execution, but
>compilers could perform a certain degree of optimisation eg. If it knows the type
>is not extended anywhere, there is no need to dispatch. There would also be
>situations where the specific variant of an inherited type is known eg. following
>an explicit assignment from an entity of that type.

The reason for this is to avoid what is sometimes called the "fragile
base class" problem that occurs in many large OO programs.  If
*everything* is potentially dispatching, it's much harder to understand
the program.  Better to do something special if you want dispatching.

Another reason is of course upward compatibility.  Ada 83 subprograms
did not do dispatching, and of course you don't want all your Ada 83
programs to drastically change their behavior when compiled by an Ada 95
compiler.

I suppose quicker execution is part of the reason, but it's not the main
thing.

Another point about the design of Ada's OOP: It was essential that there
be little or no distributed overhead.  That is, if you don't use the
feature, your program should not be slowed down by the mere existence of
the feature.  And if you recompile an Ada 83 program with an Ada 95
compiler, it shouldn't get slower (assuming the Ada 95 compiler is as
high quality as the Ada 83 one).  If dispatching always happened, there
would be distributed overhead (both space and time), that could not be
eliminated without link-time optimizations.

- Bob




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-21  0:00             ` Don Harrison
@ 1996-02-23  0:00               ` Robert A Duff
  0 siblings, 0 replies; 16+ messages in thread
From: Robert A Duff @ 1996-02-23  0:00 UTC (permalink / raw)


In article <Dn42C3.21u@assip.csasyd.oz>,
Don Harrison <donh@syd.csa.com.au> wrote:
>Ray Toal wrote:
>:Requiring 'tagged' is a GOOD THING!  Inheritance weakens encapsulation.
>
>Not sure what you mean by this. Inheritance is no weaker or stronger in languages
>(such as Eiffel) which map classes onto the encapsulation mechanism.

He didn't say "inheritance" is weaker, he said "encapsulation" is
weaker.  That's clearly true -- when you see a function call that cannot
dispatch, you know for sure exactly what it does.  When you see a
dispatching call, it might go off and do something you've never heard
of.  If there's no dispatching, then a single abstraction is completely
encapsulated, whereas with dispatching, an overriding function can sneak
in and do buggy things.  Dispatching is a powerful feature, but it has
this cost.  If you use dispatching when you don't need it, you are
paying that cost without getting any benefit.  Therefore, it makes sense
to give the programmer the choice.  Note that Eiffel seems to agree with
this, to some extent -- otherwise, the "frozen" (or whatever it's
called) thing wouldn't exist.

Of course, the counter-argument is that you don't always know ahead of
time when you might need dispatching.

I'm not sure I agree with Ray Toal, though, that requiring "tagged" is a
Good Thing.  Even without that rule, Ada still gives you control over
whether things dispatch, on a call-by-call basis.  So, I view "tagged"
as simply an efficiency hack.  Efficiency is a Good Thing, too, though.

>Yes, it's called Eiffel and it's great having such flexibility! :-). One aspect
>of that flexibility is that, if, one sunny day, you decide you need to extend a
>type you go right in and do it and don't have to touch the original.

Well, that's not *really* true.  You quite often have to go back and
change the original, because you're doing something new that conflicts
with assumptions made by the original.

>... In Ada, you
>have to go back and redefine the type to make it tagged. The impact of this may
>be limited to that - don't know, haven't thought about it - but you shouldn't have
>to redefine something to reuse it.

I pretty much agree with that.  You can, of course, make all your types
tagged in the first place, and then you won't have that problem.

>:                                            Whether or not a type
>:should be tagged is a DESIGN decision; I totally disagree that it
>:should be an implementation decision.  By the way a compiler can not
>:in general determine if the "type is extended elsewhere" since in
>:Ada extensions can appear in other compilation units.
>
>I can't think offhand of a suitable way of dealing with this but that isn't to
>say it's impossible. 

It is clearly possible to do at link time, and clearly impossible at
compile time, given separate compilation.

>You don't have to do it that way. You can use (for example) a synonym construct like
>
>  procedure P, Q (X: T) is begin R(X); end P, Q;
>
>and redefine Q for extensions of X.

Yes, that's another reasonable way to do it.

- Bob




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-22  0:00             ` Bernd Holzmueller
@ 1996-02-23  0:00               ` Robert A Duff
  0 siblings, 0 replies; 16+ messages in thread
From: Robert A Duff @ 1996-02-23  0:00 UTC (permalink / raw)


In article <312C236B.2344@informatik.uni-stuttgart.de>,
Bernd Holzmueller  <holzmuel@informatik.uni-stuttgart.de> wrote:
>Actually, the compiler _can_ work out if a tag is necessary. ...

Are you saying that if I have a program that contains no dispatching at
all (i.e. nothing is ever converted to a class-wide type), then it is
possible for the compiler to avoid ever storing tags?  I don't see how
that can be true, because of re-dispatching.  Consider:

    package P1 is
       type T1 is tagged null record;
       procedure P(X: T1);
       procedure Q(X: T1);
    end P1;

    with P1; use P1;
    package P2 is
       type T2 is new T1 with null record;
       -- Override Q, but not P:
       procedure Q(X: T2);
    end P2;

    with P1; use P1;
    with P2; use P2;
    procedure Client is
       Object: T2;
    begin
       P(T1(X)); -- This is *not* a dispatching call.
    end Client;

I claim that the tag of Object (namely the tag representing type T2)
must be made available to procedure P1.P.  The tag could be stored as a
hidden component of Object, or it could be passed as an extra parameter
to P.  Either way, there is some overhead in doing this.  Now, suppose
there's no dispatching anywhere in the program.  For example, P might
look like this:

    procedure P(X: T1) is
    begin
       Q(X); -- This is *not* a dispatching call.
    end P;

Then we've wasted some time and space by making that tag available to P.
Distributed overhead.

So, what if we eliminate that tag?  Well, then if P looks like this:

    procedure P(X: T1) is
    begin
       Q(T1'Class(X)); -- This *is* a dispatching call.
    end P;

it won't work, because the above call is supposed to call the version of
Q for T2.

But the compiler cannot know, at compile time of Client, what the body
of P looks like.  Therefore, it *must* pass that information to P, just
*in case* P does a dispatching call.

QED.

Unless, of course, you're willing to generate code at link time.

- Bob




^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Choice of OO primitives in Ada95
  1996-02-22  0:00       ` Don Harrison
@ 1996-02-24  0:00         ` Robert A Duff
  0 siblings, 0 replies; 16+ messages in thread
From: Robert A Duff @ 1996-02-24  0:00 UTC (permalink / raw)


In article <Dn5K6K.8zI@assip.csasyd.oz>,
Don Harrison <donh@syd.csa.com.au> wrote:
>John DiCamillo wrote:
>
>[objective arguments about class encapsulation]
>
>Thank you. I was beginning to wonder whether there was anyone else in this forum
>willing to discard their preconceived ideas and able to think objectively on
>this subject.

Now, now.  We were having a nice technical discussion, and then you go
and insult everybody who happens to disagree with you.  Yes, it *is*
insulting to say that because I disagree with you, I'm stuck on
preconceived ideas, and I am unable to think objectively.  Grr.
Is this whole thing just a troll, as somebody else suggested elsewhere
in this thread?  Do you want it to devolve into the usual religious
language flame war, complete with ad-hominem arguments?  If so, I don't
particularly want to participate.

- Bob




^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~1996-02-24  0:00 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <4fmrhk$7k3@erinews.ericsson.se>
1996-02-19  0:00 ` Choice of OO primitives in Ada95 Richard A. O'Keefe
     [not found] <DMqHqF.9F1.0.-s@inmet.camb.inmet.com>
     [not found] ` <DMu9yw.5ts@assip.csasyd.oz>
     [not found]   ` <4g2f8v$15lc@watnews1.watson.ibm.com>
1996-02-19  0:00     ` Don Harrison
1996-02-19  0:00       ` Norman H. Cohen
1996-02-19  0:00       ` Robert A Duff
1996-02-20  0:00         ` Don Harrison
1996-02-20  0:00           ` Jon S Anthony
1996-02-20  0:00           ` Ray Toal
1996-02-21  0:00             ` Don Harrison
1996-02-23  0:00               ` Robert A Duff
1996-02-22  0:00             ` Bernd Holzmueller
1996-02-23  0:00               ` Robert A Duff
1996-02-23  0:00           ` Robert A Duff
1996-02-21  0:00       ` Robert I. Eachus
1996-02-21  0:00     ` John DiCamillo
1996-02-22  0:00       ` Don Harrison
1996-02-24  0:00         ` Robert A Duff

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox