comp.lang.ada
 help / color / mirror / Atom feed
* Q: on redefinition of "=
@ 1996-03-30  0:00 david scott gibson
  1996-04-01  0:00 ` Robert A Duff
  1996-04-01  0:00 ` Tucker Taft
  0 siblings, 2 replies; 16+ messages in thread
From: david scott gibson @ 1996-03-30  0:00 UTC (permalink / raw)


Hi.  I'm overloading the = operation to return a non-boolean value for
a non-limited private type.  Is there any way in Ada95 to "hide" the
automatically defined = returning a boolean value?  Redefining =
returning a boolean type in the private section didn't seem to help.

Dave
--
dgibson@cis.ohio-state.edu





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

* Re: Q: on redefinition of "=
  1996-04-01  0:00 ` Tucker Taft
@ 1996-04-01  0:00   ` david scott gibson
  1996-04-01  0:00     ` Robert Dewar
  0 siblings, 1 reply; 16+ messages in thread
From: david scott gibson @ 1996-04-01  0:00 UTC (permalink / raw)


In article <Dp6wAp.6w5.0.-s@inmet.camb.inmet.com>,
Tucker Taft <stt@henning.camb.inmet.com> wrote:
>david scott gibson (dgibson@aleutian.cis.ohio-state.edu) wrote:
>
>: Hi.  I'm overloading the = operation to return a non-boolean value for
>: a non-limited private type.  Is there any way in Ada95 to "hide" the
>: automatically defined = returning a boolean value?  Redefining =
>: returning a boolean type in the private section didn't seem to help.
>
>Presuming your private type is not a tagged type, you could
>override the predefined "=" operator with one declared as "abstract."
>For tagged types, this is only allowed if the type is itself abstract.
>But for untagged types, you can use "abstract" as a way of overriding
>a primitive operation in a way that makes it illegal to call it.

Yes.  Unfortunately it is a tagged type.

>On the other hand, it might be simpler to provide some definition 
>for "=" that returns Boolean, perhaps in terms of the one that 
>returns the non-boolean value (are you using tri-state logic?).

Actually, I would like to use the Boolean = and automatically defined
/= to privately implement my non-Boolean = and /=.  It's not tri-state
logic and, believe me, you really don't want to know about it :-).
Anyway, in the design I'm currently working with all types must
support automatic initialization and finalization (and thus are
controlled types) and have the primitive operation Swap.  Since I'd
like to be able to import Swap implicitly for all types, I'm deriving
all types from a common controlled base type with Swap as an abstract
primitive.  With this strategy, Ada's built-in scalars are not
composable and thus in place of Boolean, I'm offering up the
controlled type Bool (many apologies).  Bool is the alternative return
type here.  Ideally Bool would be a limited type, but then I can't
provide equivalents of the standard Boolean operations which must
return a non-limited type and := is convenient here.  (I'm painfully
aware of some of the negative implications of this stategy.)  Letting
the Boolean = show through the interface is a reasonable option, but
has a few negative consequences.  At this point I'm just trying to see
if there is a way to hide the Boolean =.  I'm beginning to suspect
not.

--
Dave
dgibson@cis.ohio-state.edu




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

* Re: Q: on redefinition of "=
  1996-04-01  0:00   ` david scott gibson
@ 1996-04-01  0:00     ` Robert A Duff
  0 siblings, 0 replies; 16+ messages in thread
From: Robert A Duff @ 1996-04-01  0:00 UTC (permalink / raw)


In article <4joui6INNqej@snoopy.cis.ohio-state.edu>,
david scott gibson <dgibson@snoopy.cis.ohio-state.edu> wrote:
>Thanks for the suggestion.  However, I should have mentioned that the
>type for which I'm redefining equality (My_Type above) is indeed a
>tagged type.

Oh, sorry.

How about:

function "="(X, Y: My_Type'Class) return Boolean is abstract;
                          ^^^^^^

This does not override the predefined "=" for My_Type, but it will make
most calls of "=" ambiguous, and thus illegal.  The error message from
your compiler might not be as friendly as you would like, if you do
this.

And you still have to worry about reemergence of predefined "=",
which has been discussed at length in this newsgroup.

You could re-define the primitive "=" to raise an exception.  Then you
get run-time checking, which isn't quite as nice as compile-time
checking, but at least you get checking.  And, for tagged types,
predefined "=" doesn't "reemerge", which is nice.  I guess you could do
*both*.

>...  According to RM3.9.3(3), I believe I can only define an
>abstract subprogram as a primitive operation of a tagged type if the
>taggged type itself is abstract.

Correct.

>...  Thus this strategy doesn't seem to
>work.

Correct.

>...Admittedly what I'm trying to do is a bit strange, but I
>thought the rules for redefining the equality operator were intended
>to make something like this possible.  Perhaps this sort of thing was
>only intended for limited types.   Any other ideas anyone?

Making the type limited is often a good idea.  Do you *really* want ":="
on this type?  Would it not be better to have a Copy or Clone
subprogram, or some such thing?

- Bob




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

* Re: Q: on redefinition of "=
  1996-04-01  0:00   ` david scott gibson
@ 1996-04-01  0:00     ` Robert Dewar
  1996-04-02  0:00       ` Mike Young
  0 siblings, 1 reply; 16+ messages in thread
From: Robert Dewar @ 1996-04-01  0:00 UTC (permalink / raw)


"Anyway, in the design I'm currently working with all types must
support automatic initialization and finalization (and thus are
controlled types)"

This sounds truly awful. I wonder if whoever devised this approach has
any idea how much overhead this approach introduces, not to mention
complexity in the generated code.





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

* Re: Q: on redefinition of "=
  1996-03-30  0:00 Q: on redefinition of "= david scott gibson
@ 1996-04-01  0:00 ` Robert A Duff
  1996-04-01  0:00   ` david scott gibson
  1996-04-01  0:00 ` Tucker Taft
  1 sibling, 1 reply; 16+ messages in thread
From: Robert A Duff @ 1996-04-01  0:00 UTC (permalink / raw)


In article <4jkj5sINN8d3@aleutian.cis.ohio-state.edu>,
david scott gibson <dgibson@aleutian.cis.ohio-state.edu> wrote:
>Hi.  I'm overloading the = operation to return a non-boolean value for
>a non-limited private type.  Is there any way in Ada95 to "hide" the
>automatically defined = returning a boolean value?  Redefining =
>returning a boolean type in the private section didn't seem to help.

function "="(X, Y: My_Type) return Boolean is abstract;

This overrides the predefined "=" with an abstract version.
It's illegal to call this abstract version, since calls to
abstract function have to be dispatching calls, and there are
no tagged operands, so there's no way to write a dispatching call.
(I'm assuming My_Type is not tagged, here.)

- Bob





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

* Re: Q: on redefinition of "=
  1996-03-30  0:00 Q: on redefinition of "= david scott gibson
  1996-04-01  0:00 ` Robert A Duff
@ 1996-04-01  0:00 ` Tucker Taft
  1996-04-01  0:00   ` david scott gibson
  1 sibling, 1 reply; 16+ messages in thread
From: Tucker Taft @ 1996-04-01  0:00 UTC (permalink / raw)


david scott gibson (dgibson@aleutian.cis.ohio-state.edu) wrote:

: Hi.  I'm overloading the = operation to return a non-boolean value for
: a non-limited private type.  Is there any way in Ada95 to "hide" the
: automatically defined = returning a boolean value?  Redefining =
: returning a boolean type in the private section didn't seem to help.

Presuming your private type is not a tagged type, you could
override the predefined "=" operator with one declared as "abstract."
For tagged types, this is only allowed if the type is itself abstract.
But for untagged types, you can use "abstract" as a way of overriding
a primitive operation in a way that makes it illegal to call it.

On the other hand, it might be simpler to provide some definition 
for "=" that returns Boolean, perhaps in terms of the one that 
returns the non-boolean value (are you using tri-state logic?).

: Dave
: --
: dgibson@cis.ohio-state.edu

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




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

* Re: Q: on redefinition of "=
  1996-04-01  0:00 ` Robert A Duff
@ 1996-04-01  0:00   ` david scott gibson
  1996-04-01  0:00     ` Robert A Duff
  0 siblings, 1 reply; 16+ messages in thread
From: david scott gibson @ 1996-04-01  0:00 UTC (permalink / raw)


In article <Dp6q2B.Ay4@world.std.com>,
Robert A Duff <bobduff@world.std.com> wrote:
>In article <4jkj5sINN8d3@aleutian.cis.ohio-state.edu>,
>david scott gibson <dgibson@aleutian.cis.ohio-state.edu> wrote:
>>Hi.  I'm overloading the = operation to return a non-boolean value for
>>a non-limited private type.  Is there any way in Ada95 to "hide" the
>>automatically defined = returning a boolean value?  Redefining =
>>returning a boolean type in the private section didn't seem to help.
>
>function "="(X, Y: My_Type) return Boolean is abstract;
>
>This overrides the predefined "=" with an abstract version.
>It's illegal to call this abstract version, since calls to
>abstract function have to be dispatching calls, and there are
>no tagged operands, so there's no way to write a dispatching call.
>(I'm assuming My_Type is not tagged, here.)

Thanks for the suggestion.  However, I should have mentioned that the
type for which I'm redefining equality (My_Type above) is indeed a
tagged type.  According to RM3.9.3(3), I believe I can only define an
abstract subprogram as a primitive operation of a tagged type if the
taggged type itself is abstract.  Thus this strategy doesn't seem to
work.  Admittedly what I'm trying to do is a bit strange, but I
thought the rules for redefining the equality operator were intended
to make something like this possible.  Perhaps this sort of thing was
only intended for limited types.   Any other ideas anyone?

Dave








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

* Re: Q: on redefinition of "=
  1996-04-02  0:00             ` Robert A Duff
@ 1996-04-02  0:00               ` david scott gibson
  1996-04-02  0:00                 ` Robert A Duff
  0 siblings, 1 reply; 16+ messages in thread
From: david scott gibson @ 1996-04-02  0:00 UTC (permalink / raw)


In article <Dp8wn3.B1x@world.std.com>,
Robert A Duff <bobduff@world.std.com> wrote:
>In article <4jrlluINN15b@thalamus.cis.ohio-state.edu>,
>david scott gibson <dgibson@thalamus.cis.ohio-state.edu> wrote:
>>As I mentioned in my post, I'm painfully aware of the negative
>>implications of this strategy.  Unfortunately there is a mismatch
>>between Ada and the language I'm trying to map to Ada.  When I import
>>some type as a generic parameter, I need to know that the instance
>>gets a valid representation of that type.  With Ada's scalars, this is
>>impossible.
>
>You seem to imply that you want initialization, but not necessarily
>finalization.

For all static types like scalars this is the case since the language
ensures sufficient finalization automatically. 

>It seems to me that it wouldn't be hard for an implementation to
>special-case those controlled types that have initialization, but not
>finalization.  Most of the cost comes from the finalization support.

The strategy I'm currently working with uses null-bodied Initialize
and Finalize routines for wrapped scalars.  I provide an initial value
with a record component initialization.  The lack of a valid
representation is the problem, however, not the lack of a specific
initial value for scalars.  Since the representations don't have any
controlled sub-components, I'm assuming that the Initialize and
Finalize calls for wrapped scalars can be optimized away.  I realize
the tagged types will require more storage, but does GNAT's
implementation entail an additional performance penalty in this
situation?

>Also, a plain old (non-controlled) record type can have automatic
>initialization for its components.

Yes, I've still got this implementation around.  It suffers from all
of the same type conversion annoyances and requires explicit
importation of Swap everywhere.  However, it should be more efficient.
Once GNAT is compiling everything, I'll do some performance
comparisons and get an idea of just how costly the tagged scalars
implementation is.

--
Dave
dgibson@cis.ohio-state.edu







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

* Re: Q: on redefinition of "=
  1996-04-02  0:00               ` david scott gibson
@ 1996-04-02  0:00                 ` Robert A Duff
  1996-04-02  0:00                   ` david scott gibson
  0 siblings, 1 reply; 16+ messages in thread
From: Robert A Duff @ 1996-04-02  0:00 UTC (permalink / raw)


In article <4jrsumINN9m0@snoopy.cis.ohio-state.edu>,
david scott gibson <dgibson@snoopy.cis.ohio-state.edu> wrote:
>The strategy I'm currently working with uses null-bodied Initialize
>and Finalize routines for wrapped scalars.  I provide an initial value
>with a record component initialization.

So why use a controlled type?  Perhaps because *some* of your types need
Initialize or Finalize, and you want to inherit from a single root type
which has Swap.  Well, I wonder if you could have a non-controlled root
type with Swap, and extend it with controlled components in the cases
where you need that functionality?

>...  The lack of a valid
>representation is the problem, however, not the lack of a specific
>initial value for scalars.  Since the representations don't have any
>controlled sub-components, I'm assuming that the Initialize and
>Finalize calls for wrapped scalars can be optimized away.

They can, so long as you don't have class-wide stuff.  But I doubt if
they *are*, in a typical compiler.

>...I realize
>the tagged types will require more storage, but does GNAT's
>implementation entail an additional performance penalty in this
>situation?

I believe so.  Every controlled object will be hooked onto a chain
(doubly-linked, I think), of controlled objects.

>>Also, a plain old (non-controlled) record type can have automatic
>>initialization for its components.
>
>Yes, I've still got this implementation around.  It suffers from all
>of the same type conversion annoyances and requires explicit
>importation of Swap everywhere.

...or use "is <>" default for Swap.

>...  However, it should be more efficient.
>Once GNAT is compiling everything, I'll do some performance
>comparisons and get an idea of just how costly the tagged scalars
>implementation is.

- Bob




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

* Re: Q: on redefinition of "=
  1996-04-02  0:00                 ` Robert A Duff
@ 1996-04-02  0:00                   ` david scott gibson
  0 siblings, 0 replies; 16+ messages in thread
From: david scott gibson @ 1996-04-02  0:00 UTC (permalink / raw)


In article <Dp92G6.KI5@world.std.com>,
Robert A Duff <bobduff@world.std.com> wrote:
>So why use a controlled type?  Perhaps because *some* of your types need
>Initialize or Finalize, and you want to inherit from a single root type
>which has Swap.  Well, I wonder if you could have a non-controlled root
>type with Swap, and extend it with controlled components in the cases
>where you need that functionality?

That's an interesting idea.  I may need to fake multiple inheritance for
this since my representation types are already derived from an abstract
type (which may have non-controlled implementations).  It's not clear to
me how everything will work out with non-controlled components layered on
top of controlled components, but it might work.  Thanks very much for
the suggestion!

--
Dave
dgibson@cis.ohio-state.edu






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

* Re: Q: on redefinition of "=
  1996-04-02  0:00           ` david scott gibson
  1996-04-02  0:00             ` Robert A Duff
@ 1996-04-02  0:00             ` Robert Dewar
  1996-04-03  0:00             ` Tucker Taft
  2 siblings, 0 replies; 16+ messages in thread
From: Robert Dewar @ 1996-04-02  0:00 UTC (permalink / raw)


David Gibson said

"While I certaily see how this is useful for performance critial
applications, I'm not convinced that this is a particularly good
characteristic for a "software engineering" language.  Ada supports
abstraction nicely in many ways.  The notion that a programmer needs
to be thinking in terms of how language constructs are implemented
seems less than ideal."

Maybe, but if you break the connection, you tend to find people doing
completely off the wall things (like having all types be controlled :-)





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

* Re: Q: on redefinition of "=
  1996-04-01  0:00     ` Robert Dewar
@ 1996-04-02  0:00       ` Mike Young
  1996-04-02  0:00         ` Robert Dewar
  0 siblings, 1 reply; 16+ messages in thread
From: Mike Young @ 1996-04-02  0:00 UTC (permalink / raw)


Robert Dewar wrote:
> 
> "Anyway, in the design I'm currently working with all types must
> support automatic initialization and finalization (and thus are
> controlled types)"
> 
> This sounds truly awful. I wonder if whoever devised this approach has
> any idea how much overhead this approach introduces, not to mention
> complexity in the generated code.

==========
Would this be the equivalent of constructors/destructors in C++? I 
apologize for not seeing the problems. What is going on that would make 
this such a horrible approach?

Mike.




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

* Re: Q: on redefinition of "=
  1996-04-02  0:00       ` Mike Young
@ 1996-04-02  0:00         ` Robert Dewar
  1996-04-02  0:00           ` david scott gibson
  0 siblings, 1 reply; 16+ messages in thread
From: Robert Dewar @ 1996-04-02  0:00 UTC (permalink / raw)


Mike said

"Robert Dewar wrote:
>
> "Anyway, in the design I'm currently working with all types must
> support automatic initialization and finalization (and thus are
> controlled types)"
>
> This sounds truly awful. I wonder if whoever devised this approach has
> any idea how much overhead this approach introduces, not to mention
> complexity in the generated code.

==========
Would this be the equivalent of constructors/destructors in C++? I
apologize for not seeing the problems. What is going on that would make
this such a horrible approach?"

Mostly Ada is a low level language in the sense that what you write is
pretty closely tied to the semantics of the machine, so you have soe
reasonable idea of the underlying execution semantics.

Controlled types (or destructors in C++) are an exception. THe use of 
either generates a lot of extra baggage in time and space. They are
useful features when used where necessary or really useful, but
the idea of making ALL types controlled is to me a design idea
that has run completely amok.

Mike, if you are using GNAT, try using the -gnatdg switch on your code
to get some idea of what you are generating. Certainly GNAT does not
do an optimal job of handling finalization, that is an area in which
we have improvements to make, but there is no way of doing finalization
free!





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

* Re: Q: on redefinition of "=
  1996-04-02  0:00         ` Robert Dewar
@ 1996-04-02  0:00           ` david scott gibson
  1996-04-02  0:00             ` Robert A Duff
                               ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: david scott gibson @ 1996-04-02  0:00 UTC (permalink / raw)


I wrote:
>> "Anyway, in the design I'm currently working with all types must
>> support automatic initialization and finalization (and thus are
>> controlled types)"

Robert Dewar wrote:
> This sounds truly awful. I wonder if whoever devised this approach has
> any idea how much overhead this approach introduces, not to mention
> complexity in the generated code.

As I mentioned in my post, I'm painfully aware of the negative
implications of this strategy.  Unfortunately there is a mismatch
between Ada and the language I'm trying to map to Ada.  When I import
some type as a generic parameter, I need to know that the instance
gets a valid representation of that type.  With Ada's scalars, this is
impossible.

>Mostly Ada is a low level language in the sense that what you write is
>pretty closely tied to the semantics of the machine, so you have soe
>reasonable idea of the underlying execution semantics.

While I certaily see how this is useful for performance critial
applications, I'm not convinced that this is a particularly good
characteristic for a "software engineering" language.  Ada supports
abstraction nicely in many ways.  The notion that a programmer needs
to be thinking in terms of how language constructs are implemented
seems less than ideal.

--
Dave
dgibson@cis.ohio-state.edu












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

* Re: Q: on redefinition of "=
  1996-04-02  0:00           ` david scott gibson
@ 1996-04-02  0:00             ` Robert A Duff
  1996-04-02  0:00               ` david scott gibson
  1996-04-02  0:00             ` Robert Dewar
  1996-04-03  0:00             ` Tucker Taft
  2 siblings, 1 reply; 16+ messages in thread
From: Robert A Duff @ 1996-04-02  0:00 UTC (permalink / raw)


In article <4jrlluINN15b@thalamus.cis.ohio-state.edu>,
david scott gibson <dgibson@thalamus.cis.ohio-state.edu> wrote:
>As I mentioned in my post, I'm painfully aware of the negative
>implications of this strategy.  Unfortunately there is a mismatch
>between Ada and the language I'm trying to map to Ada.  When I import
>some type as a generic parameter, I need to know that the instance
>gets a valid representation of that type.  With Ada's scalars, this is
>impossible.

You seem to imply that you want initialization, but not necessarily
finalization.

It seems to me that it wouldn't be hard for an implementation to
special-case those controlled types that have initialization, but not
finalization.  Most of the cost comes from the finalization support.
Of course, that doesn't imply that this optimization is worthwhile --
I'm not sure how many controlled types, outside your application, would
benefit.

Also, a plain old (non-controlled) record type can have automatic
initialization for its components.

- Bob




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

* Re: Q: on redefinition of "=
  1996-04-02  0:00           ` david scott gibson
  1996-04-02  0:00             ` Robert A Duff
  1996-04-02  0:00             ` Robert Dewar
@ 1996-04-03  0:00             ` Tucker Taft
  2 siblings, 0 replies; 16+ messages in thread
From: Tucker Taft @ 1996-04-03  0:00 UTC (permalink / raw)


david scott gibson (dgibson@thalamus.cis.ohio-state.edu) wrote:

: ...
: While I certaily see how this is useful for performance critial
: applications, I'm not convinced that this is a particularly good
: characteristic for a "software engineering" language.  Ada supports
: abstraction nicely in many ways.  The notion that a programmer needs
: to be thinking in terms of how language constructs are implemented
: seems less than ideal.

During the Ada 9X revision process, we had to make a conscious choice
about what kind of language was Ada.  Our conclusion was that
Ada was primarily a "systems implementation language," where programmers
care deeply about the time and space performance of their programs.

Of course you can use a language any way you want, but when
designing the language, we felt it was important to have a clear
design philosophy which could guide tough decisions.

So Ada 95 was designed primarily for programmers who care how 
things are implemented.  Programmers who don't care have it easy, 
of course.  For those who do, it is important to understand, almost
to the point of "intuition," the relative expense of various
language features.  

The ideal (in my view) is that all "primitive" features of the 
language be extremely efficiently implementable, and the sources of
inefficiency all be those of the programmer's own making.  
However, even with the best of intentions, certain features (or 
interactions, such as exceptions+finalization) do end up inducing 
more overhead.  For those features, it is important for the unlucky 
programmers who *do* care about space/time performance that they be 
aware of this overhead.

As one final comment, I personally believe that a *big* part of
software engineering is satisfying the time/space requirements.
Perhaps we have all gone soft in an era of rapidly increasing
hardware speed and RAM, but in my experience, customers still
care deeply about time/space performance, and if the hardware
gets faster, they want their code to run faster too, not just
bloat out to take up all the extra MIPS/MBytes.

Sorry to sound so "preachy" here, but too often I hear this
notion that you can ignore performance issues during "software
engineering" and tune the code when you are done.  In any big
system, I have *never* found this to be the case.  If you want
the system to be fast, you have to design in high speed and a small
(virtual) memory foot print.  You can't just "tune" it.  The old 90/10
rule is misleading in my experience, because the 10% of the code
in which you spend 90% of the time, or consume 90% of the space,
is spread all over the place, and after even a little "tuning," 
no single routine consumes more than 5% of the time/space.

: Dave
: dgibson@cis.ohio-state.edu

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




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

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

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-03-30  0:00 Q: on redefinition of "= david scott gibson
1996-04-01  0:00 ` Robert A Duff
1996-04-01  0:00   ` david scott gibson
1996-04-01  0:00     ` Robert A Duff
1996-04-01  0:00 ` Tucker Taft
1996-04-01  0:00   ` david scott gibson
1996-04-01  0:00     ` Robert Dewar
1996-04-02  0:00       ` Mike Young
1996-04-02  0:00         ` Robert Dewar
1996-04-02  0:00           ` david scott gibson
1996-04-02  0:00             ` Robert A Duff
1996-04-02  0:00               ` david scott gibson
1996-04-02  0:00                 ` Robert A Duff
1996-04-02  0:00                   ` david scott gibson
1996-04-02  0:00             ` Robert Dewar
1996-04-03  0:00             ` Tucker Taft

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