comp.lang.ada
 help / color / mirror / Atom feed
* Abstract Operations On A Tagged Record
@ 2004-10-30 13:04 Marin David Condic
  2004-10-30 14:34 ` Dmitry A. Kazakov
  2004-10-30 16:07 ` Nick Roberts
  0 siblings, 2 replies; 7+ messages in thread
From: Marin David Condic @ 2004-10-30 13:04 UTC (permalink / raw)


Can someone clarify my understanding (perhaps again) on abstract 
operations and the implications as a class heierarchy is being 
constructed? Specifically, what I want is something like this:

A base class has an abstract operation, but I may not yet know the data 
types of the parameters - or possibly even the number of parameters. 
Let's say what I want is like this:

procedure Some_Op (<TBD Parameter List>) is abstract ;

When I get to the child class, what I really need is:

procedure Some_Op (Some_Param1 : in Integer; Some_Param2 : in Float) ;

For a different child class I may want:

procedure Some_Op (Some_Param1 : in Integer; Some_Param2 : in Character; 
Some_Param3 : in Boolean) ;

The base class wants to express the basic necessity of "Some_Op" but it 
really doesn't know if it will have 1, 2 or N parameters or of what 
type. My understanding is that if I express that as an abstract 
operation, when I get to the child class, I'll have to supply a real 
operation of the same name and same parameter profile. (Or can I use a 
different parameter profile & satisfy the need for a concrete 
implementation of the abstract op? My recollection is the compiler 
whines about it or creates an overloading. Is this correct?)

I realize I can make another procedure "Some_Op" with a different 
parameter list and that overloading will take care of me, but then I 
didn't really need the abstract procedure in the first place, did I? It 
becomes unnecessary baggage that you have to fill in just because its 
there, but you have no intention of using it.

Do I understand this correctly? Is there away around it? Keep in mind 
that what I want to express is the notion in a base class that Operation 
X needs to be present, but the precise parameters to X will be 
determined by the child class. I'm interested *specifically* in how this 
works with an abstract tagged record and the inheritance heierarchy that 
goes with it, so please don't suggest that I'm going about it all wrong 
and I really need to do something with a generic, etc... If my 
understanding is correct and it can't be done then we just trash that 
notion and go to other techniques, but I want to know how this 
capability works. Thanks.

MDC

-- 
======================================================================
Marin David Condic
I work for: http://www.belcan.com/
My project is: http://www.jsf.mil/NSFrames.htm

Send Replies To: m   o   d   c @ a   m   o   g
                    c   n   i       c   .   r

     "Power corrupts.  Absolute power is kind of neat"
         -- John Lehman, Secretary of the Navy 1981-1987
======================================================================



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

* Re: Abstract Operations On A Tagged Record
  2004-10-30 13:04 Abstract Operations On A Tagged Record Marin David Condic
@ 2004-10-30 14:34 ` Dmitry A. Kazakov
  2004-10-30 16:07 ` Nick Roberts
  1 sibling, 0 replies; 7+ messages in thread
From: Dmitry A. Kazakov @ 2004-10-30 14:34 UTC (permalink / raw)


On Sat, 30 Oct 2004 13:04:37 GMT, Marin David Condic wrote:

> Can someone clarify my understanding (perhaps again) on abstract 
> operations and the implications as a class heierarchy is being 
> constructed? Specifically, what I want is something like this:
> 
> A base class has an abstract operation, but I may not yet know the data 
> types of the parameters - or possibly even the number of parameters. 
> Let's say what I want is like this:
> 
> procedure Some_Op (<TBD Parameter List>) is abstract ;

The first question is what is the class you are talking about. When class
refers a package to be extended by other packages etc, then it is far away
from Ada, tagged types and not very clear at all. So I assume that class
refers here types, and more specifically a hierarchy of types. If so, then
Some_Op should be an operation of that type.

> When I get to the child class, what I really need is:
> 
> procedure Some_Op (Some_Param1 : in Integer; Some_Param2 : in Float) ;
> 
> For a different child class I may want:
> 
> procedure Some_Op (Some_Param1 : in Integer; Some_Param2 : in Character; 
> Some_Param3 : in Boolean) ;
> 
> The base class wants to express the basic necessity of "Some_Op" but it 
> really doesn't know if it will have 1, 2 or N parameters or of what 
> type.

But it *has* to have a parameter of its own type, the parameter of the
class. Some_Op is an operation of the "class". This is how clients become
aware of it. They (the clients) are in the class so they have this
operation too. There are only two ways to have an operation defined on
class:

1. class-wide: Some_Op (Object : in out T'Class);

2. primitive operation: Some_Op (Object : in out T);

A primitive operation is defined on the class, but it is implemented
"piecewise" by overriding (implementing) its parts in derived types.

> My understanding is that if I express that as an abstract 
> operation, when I get to the child class, I'll have to supply a real 
> operation of the same name and same parameter profile. (Or can I use a 
> different parameter profile & satisfy the need for a concrete 
> implementation of the abstract op? My recollection is the compiler 
> whines about it or creates an overloading. Is this correct?)

Yes, it is the case 2, so it is in fact one operation and thus it has one
parameter profile. It is merely syntax sugar and an ability to call an
override directly, without dispatch, that makes us believe that it has a
"different" profile.

A primitive operation is abstract when it is not implemented for some of
the class types. It is safe to do so because these types will be then
abstract and so will have no instances. But any concrete derived type
should implement it for itself (by either overriding or inheriting from the
[concrete] base).

> I realize I can make another procedure "Some_Op" with a different 
> parameter list and that overloading will take care of me, but then I 
> didn't really need the abstract procedure in the first place, did I? It 
> becomes unnecessary baggage that you have to fill in just because its 
> there, but you have no intention of using it.

Yes, because overloaded operations have nothing in common except the name.
The idea of abstract primitive operation is to define an operation on the
class. The class is needed only to write programs in terms of that class.
One cannot write programs in terms of names without any semantics. For this
there would be enough to have a text editor with cut/paste and substitute
or a preprocessor (or C++ templates (:-)).

> Do I understand this correctly? Is there away around it? Keep in mind 
> that what I want to express is the notion in a base class that Operation 
> X needs to be present, but the precise parameters to X will be 
> determined by the child class.

Why this is needed? How this class might be used? Consider the most general
case, I have an instance of some class member:

procedure Foo (Object : in out T'Class) is
begin
   X (Object, ?);

Now I am going to apply X to Object. How do I know the parameter profile?
There is no way to determine it. What cannot be used with class is not of
the class.

So X with varying parameter profile cannot be an operation of the class,
unless you bring that variance under one roof. One way to do it is to pack
all possible actual profiles into values of one other type P or P'Class:

type P is abstract tagged ...; -- All possible parameters
type T is abstract tagged ...; -- The type
procedure X (Object : in out T; Parameters : P'Class) is abstract;

A client have to override X. It can also derive from P its own set of
parameters. BTW, this is the typical case where multiple dispatch would be
appropriate and more safe:

procedure X (Object : in out T; Parameters : P) is abstract;

Like in:

Print (Output : in out Device; Object : Thing) is abstract;

Without multiple dispatch each client should take care of selecting an
appropriate way of dealing with all possible parameters that may occur in
P'Class.

Here we come to another problem. You can say, OK, but each client has its
own unique set of parameters. Why should I care about the cross-variants
coming from other clients? This is the problem of parallel type
hierarchies. When you derive from T you want either to automatically derive
or to force a deriving from P. These pairs of derived types have to be
bound. In terms of multiple dispatch it is the case when the joint dispatch
table has to be diagonal. The most famous examples are Object-Container_Of,
Object-Handle types pairs. When you derive a new object, you also want to
have a specialized handle type (or access type) to it. AFAIK, this problem
is not solved in either Ada or any other OO language I know.

> I'm interested *specifically* in how this 
> works with an abstract tagged record and the inheritance heierarchy that 
> goes with it, so please don't suggest that I'm going about it all wrong 
> and I really need to do something with a generic, etc... If my 
> understanding is correct and it can't be done then we just trash that 
> notion and go to other techniques, but I want to know how this 
> capability works. Thanks.

And so we return to the very first question, why there should be a class?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



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

* Re: Abstract Operations On A Tagged Record
  2004-10-30 13:04 Abstract Operations On A Tagged Record Marin David Condic
  2004-10-30 14:34 ` Dmitry A. Kazakov
@ 2004-10-30 16:07 ` Nick Roberts
  2004-11-01 12:58   ` Marin David Condic
  1 sibling, 1 reply; 7+ messages in thread
From: Nick Roberts @ 2004-10-30 16:07 UTC (permalink / raw)


Marin David Condic wrote:

> Can someone clarify my understanding (perhaps again) on abstract 
> operations and the implications as a class heierarchy is being 
> constructed? Specifically, what I want is something like this:
> 
> A base class has an abstract operation, but I may not yet know the data 
> types of the parameters - or possibly even the number of parameters. 
> ...
> The base class wants to express the basic necessity of "Some_Op" but it 
> really doesn't know if it will have 1, 2 or N parameters or of what 
> type. My understanding is that if I express that as an abstract 
> operation, when I get to the child class, I'll have to supply a real 
> operation of the same name and same parameter profile.

Correct.

> (Or can I use a 
> different parameter profile & satisfy the need for a concrete 
> implementation of the abstract op? 

No.

> My recollection is the compiler 
> whines about it or creates an overloading. Is this correct?

Correct. (The compiler whines ;-)

> I realize I can make another procedure "Some_Op" with a different 
> parameter list and that overloading will take care of me, but then I 
> didn't really need the abstract procedure in the first place, did I? It 
> becomes unnecessary baggage that you have to fill in just because its 
> there, but you have no intention of using it.

Worse than that, you have no dynamic dispatching, which is the whole
point of using a tagged type in the first place. Disaster.

> Do I understand this correctly? Is there away around it?

The solution is simple, Marin. You use /two/ type hierarchies, one to
represent the primary objects, and a secondary one to represent the
detailed parameters of the primitive operation in question.

For example, suppose we have a primary hierarchy of shapes, and we
want a primitive operation transforming a shape according to a set
of parameters that depends on the shape (and the kind of
transformation):

   type Root_Shape_Type is abstract tagged private;

   type Transformation_Spec is abstract tagged private;

   function Transform (Shape: in Root_Shape_Type;
                       Spec:  in Transformation_Spec'Class)
         return Root_Shape_Type'Class is abstract;

   Transformation_Error: exception;

Note carefully that Transform is a primitive operation of the primary
type Root_Shape_Type. The Spec parameter is of a class wide type, and so
is the result (since a transformation might produce a different kind of
shape).

We could then declare some transformations, such as:

   type Rotation is new Transformation_Spec with
      record
         Angle: Radians;
      end record;

   type Translation is new Transformation_Spec with
      record
         Offset: Surface_Offset;
      end record;

and we might declare a polygon, say, as follows:

   type Polygonal_Shape is new Root_Shape_Type with private;

   function Points (Shape: in Polygonal_Shape) return Point_Vector;

   ... -- other polygon operations

   function Transform (Shape: in Polygonal_Shape;
                       Spec:  in Transformation_Spec'Class)
         return Root_Shape_Type'Class;

The body of the Transform function for polygons would have to test the
actual type of the Spec parameter to determine which tranformation to
perform:

   function Transform (Shape: in Polygonal_Shape;
                       Spec:  in Transformation_Spec'Class)
         return Root_Shape_Type'Class is
   begin
      if Spec in Rotation then
         declare
            Rot_Spec:   constant Rotation := Rotation(Spec);
            Center:     constant Point := Centerpoint(Shape);
            Old_Points: constant Point_Vector := Points(Shape);
            New_Points: Point_Triple(Old_Points'Range);
         begin
            for P in Old_Points'Range loop
               New_Points(P) :=
                  Rotate( Old_Points(P), Center, Rot_Spec.Angle );
            end loop;
            return To_Polygon(New_Points);
         end;
      elsif Spec in Translation then
         ...
      else
         raise Transformation_Error; -- unrecognized transformation
      end if;
   end Transform;

I think it is interesting to note that some languages, such as Cecil,
provide a way to select an operation's implementation (body) on two or
more parameters, rather than just one. Cecil is a very interesting
language (but not yet mature enough for real use, I think).

Nevertheless, Ada's lowly single selection still permits new shapes to
be added to a program without having to worry about how this affects
other parts of the program (in general), and this could be very useful.

Note also that you might possibly wish to swap the roles of shape and
transformation, so that Transform becomes a primitive operation of
Transformation_Spec (instead of Root_Shape_Type), and bodies of the
function have to test for different shapes. This would allow you to
add new transformations in a very independent manner.

HTH

-- 
Nick Roberts



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

* Re: Abstract Operations On A Tagged Record
  2004-10-30 16:07 ` Nick Roberts
@ 2004-11-01 12:58   ` Marin David Condic
  2004-11-01 18:09     ` Nick Roberts
  0 siblings, 1 reply; 7+ messages in thread
From: Marin David Condic @ 2004-11-01 12:58 UTC (permalink / raw)


Thanks for the response. As both you and Dimitry observed, I rather 
neglected to toss in the class parameter. I should have put in an 
example with a base class operation that looked like:

procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class) is abstract ;

Then the intent was to discuss the need to have child operations with 
different parameter profiles:

procedure Some_Op (The_Thing : in out Some_Tagged_Type_Child1 ; Parm1 : 
in Integer) is abstract ;

procedure Some_Op (The_Thing : in out Some_Tagged_Type_Child2 ; Parm1 : 
in Boolean; Parm_2 : in Float) is abstract ;

My understanding from your explanation is that I can't really get around 
having to fill in *something* for:

procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class) is abstract ;

but that overloading takes care of the other cases. I was hoping to 
avoid having a useless operation dangling around like that.

However, I had thought of the case you mention wherein I could provide 
another tagged type for the parameter list and do something like this in 
the base class:

procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class; Its_Parms 
: in Another_Tagged_Type'Class) is abstract ;

That sounds like a reasonable answer to the abstraction problem I had. I 
can identify the need for some parameters down the line without having 
to specify what they are in the base class. It keeps me from 
proliferating operations all over the place while allowing me to insist 
that a certain operation must be provided from anything inherited from 
the base class.

Thanks for the help.

MDC



Nick Roberts wrote:
> Marin David Condic wrote:
> 
>> Can someone clarify my understanding (perhaps again) on abstract 
>> operations and the implications as a class heierarchy is being 
>> constructed? Specifically, what I want is something like this:
>>
>> A base class has an abstract operation, but I may not yet know the 
>> data types of the parameters - or possibly even the number of 
>> parameters. ...
>> The base class wants to express the basic necessity of "Some_Op" but 
>> it really doesn't know if it will have 1, 2 or N parameters or of what 
>> type. My understanding is that if I express that as an abstract 
>> operation, when I get to the child class, I'll have to supply a real 
>> operation of the same name and same parameter profile.
> 
> 
> Correct.
> 
>> (Or can I use a different parameter profile & satisfy the need for a 
>> concrete implementation of the abstract op? 
> 
> 
> No.
> 
>> My recollection is the compiler whines about it or creates an 
>> overloading. Is this correct?
> 
> 
> Correct. (The compiler whines ;-)
> 
>> I realize I can make another procedure "Some_Op" with a different 
>> parameter list and that overloading will take care of me, but then I 
>> didn't really need the abstract procedure in the first place, did I? 
>> It becomes unnecessary baggage that you have to fill in just because 
>> its there, but you have no intention of using it.
> 
> 
> Worse than that, you have no dynamic dispatching, which is the whole
> point of using a tagged type in the first place. Disaster.
> 
>> Do I understand this correctly? Is there away around it?
> 
> 
> The solution is simple, Marin. You use /two/ type hierarchies, one to
> represent the primary objects, and a secondary one to represent the
> detailed parameters of the primitive operation in question.
> 
> For example, suppose we have a primary hierarchy of shapes, and we
> want a primitive operation transforming a shape according to a set
> of parameters that depends on the shape (and the kind of
> transformation):
> 
>   type Root_Shape_Type is abstract tagged private;
> 
>   type Transformation_Spec is abstract tagged private;
> 
>   function Transform (Shape: in Root_Shape_Type;
>                       Spec:  in Transformation_Spec'Class)
>         return Root_Shape_Type'Class is abstract;
> 
>   Transformation_Error: exception;
> 
> Note carefully that Transform is a primitive operation of the primary
> type Root_Shape_Type. The Spec parameter is of a class wide type, and so
> is the result (since a transformation might produce a different kind of
> shape).
> 
> We could then declare some transformations, such as:
> 
>   type Rotation is new Transformation_Spec with
>      record
>         Angle: Radians;
>      end record;
> 
>   type Translation is new Transformation_Spec with
>      record
>         Offset: Surface_Offset;
>      end record;
> 
> and we might declare a polygon, say, as follows:
> 
>   type Polygonal_Shape is new Root_Shape_Type with private;
> 
>   function Points (Shape: in Polygonal_Shape) return Point_Vector;
> 
>   ... -- other polygon operations
> 
>   function Transform (Shape: in Polygonal_Shape;
>                       Spec:  in Transformation_Spec'Class)
>         return Root_Shape_Type'Class;
> 
> The body of the Transform function for polygons would have to test the
> actual type of the Spec parameter to determine which tranformation to
> perform:
> 
>   function Transform (Shape: in Polygonal_Shape;
>                       Spec:  in Transformation_Spec'Class)
>         return Root_Shape_Type'Class is
>   begin
>      if Spec in Rotation then
>         declare
>            Rot_Spec:   constant Rotation := Rotation(Spec);
>            Center:     constant Point := Centerpoint(Shape);
>            Old_Points: constant Point_Vector := Points(Shape);
>            New_Points: Point_Triple(Old_Points'Range);
>         begin
>            for P in Old_Points'Range loop
>               New_Points(P) :=
>                  Rotate( Old_Points(P), Center, Rot_Spec.Angle );
>            end loop;
>            return To_Polygon(New_Points);
>         end;
>      elsif Spec in Translation then
>         ...
>      else
>         raise Transformation_Error; -- unrecognized transformation
>      end if;
>   end Transform;
> 
> I think it is interesting to note that some languages, such as Cecil,
> provide a way to select an operation's implementation (body) on two or
> more parameters, rather than just one. Cecil is a very interesting
> language (but not yet mature enough for real use, I think).
> 
> Nevertheless, Ada's lowly single selection still permits new shapes to
> be added to a program without having to worry about how this affects
> other parts of the program (in general), and this could be very useful.
> 
> Note also that you might possibly wish to swap the roles of shape and
> transformation, so that Transform becomes a primitive operation of
> Transformation_Spec (instead of Root_Shape_Type), and bodies of the
> function have to test for different shapes. This would allow you to
> add new transformations in a very independent manner.
> 
> HTH
> 

-- 
======================================================================
Marin David Condic
I work for: http://www.belcan.com/
My project is: http://www.jsf.mil/NSFrames.htm

Send Replies To: m   o   d   c @ a   m   o   g
                    c   n   i       c   .   r

     "Power corrupts.  Absolute power is kind of neat"
         -- John Lehman, Secretary of the Navy 1981-1987
======================================================================



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

* Re: Abstract Operations On A Tagged Record
  2004-11-01 12:58   ` Marin David Condic
@ 2004-11-01 18:09     ` Nick Roberts
  2004-11-01 22:27       ` Marin David Condic
  2004-11-06 13:17       ` Marin David Condic
  0 siblings, 2 replies; 7+ messages in thread
From: Nick Roberts @ 2004-11-01 18:09 UTC (permalink / raw)


Marin David Condic wrote:

> Thanks for the response. As both you and Dimitry observed, I rather 
> neglected to toss in the class parameter. I should have put in an 
> example with a base class operation that looked like:
> 
> procedure Some_Op (The_Thing : in out Some_Tagged_Type'Class)
>       is abstract ;

Although this declaration isn't actually illegal, it probably isn't
what you intended, Marin. Since Some_Op is not a primitive operation of
any named type, it cannot be inherited, and so cannot be overridden. It
therefore does not ensure that an operation is implemented by any
derived type.

I'm fairly certain that you require something like:

   procedure Some_Op (The_Thing : in out Some_Tagged_Type;
                      The_Params: in     Some_Parameter_Type'Class)
                                                          is abstract ;

where Some_Parameter_Type is a tagged type (it could also be abstract)
from which you derive types to specify particular variations and their
specific parameter values, just as I (and Dmitry) illustrated.

At the point where you /call/ Some_Op, you may well provide a class wide
actual parameter, for The_Thing, for The_Params, or both, e.g.:

   declare
      This_Thing:   constant Some_Tagged_Type'Class := From_Outer_Space;
      These_Params: constant Some_Parameter_Type'Class := What_To_Do;
   begin
      Some_Op( This_Thing, These_Params );

The call of Some_Op, in this example, will dispatch on the actual type
of the class wide object This_Thing. Because it dispatches, it will call
an concrete (non-abstract) overriding of Some_Op, for a concrete actual
type (derived from Some_Tagged_Type).

Does this make sense?

-- 
Nick Roberts



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

* Re: Abstract Operations On A Tagged Record
  2004-11-01 18:09     ` Nick Roberts
@ 2004-11-01 22:27       ` Marin David Condic
  2004-11-06 13:17       ` Marin David Condic
  1 sibling, 0 replies; 7+ messages in thread
From: Marin David Condic @ 2004-11-01 22:27 UTC (permalink / raw)


Yes. I was originally tossing something out as "This is what I desire 
even if the language doesn't accommodate me..." I understand that 
without the parameters tacked on, the original base class operation 
isn't going to do anything useful for me. (Other than remind me I need 
to make something that *does* do the job later...) I think the best 
answer is to include another tagged type for the variable parameter 
content that is to come in the child classes. Thanks.

MDC


Nick Roberts wrote:

> 
> Does this make sense?
> 

-- 
======================================================================
Marin David Condic
I work for: http://www.belcan.com/
My project is: http://www.jsf.mil/NSFrames.htm

Send Replies To: m   o   d   c @ a   m   o   g
                    c   n   i       c   .   r

     "Power corrupts.  Absolute power is kind of neat"
         -- John Lehman, Secretary of the Navy 1981-1987
======================================================================



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

* Re: Abstract Operations On A Tagged Record
  2004-11-01 18:09     ` Nick Roberts
  2004-11-01 22:27       ` Marin David Condic
@ 2004-11-06 13:17       ` Marin David Condic
  1 sibling, 0 replies; 7+ messages in thread
From: Marin David Condic @ 2004-11-06 13:17 UTC (permalink / raw)


BTW: I've been mucking around with this for the last few days and, after 
much struggling, have concluded that attempting to do this (while it may 
indeed work) started becoming entirely too unwieldy. Trying to keep 
stalling off the problems with more and more layers of indirection 
started becoming painful.

What I'm doing is basically leaving those operations out of the base 
class and (where it makes sense) I'm creating layer(s) of intermediate 
classes that get more and more specific about what the required 
parameter types are. Its still rather "heavy" (you have to keep 
isolating things in more packages and creating more branches in the 
class tree) but it seemed less painful than trying to find all the 
necessary abstractions & provide all the needed operations on the 
parameter class.

Sometimes you just have to bite the bullet and say "here's a version 
that deals with a float and here's a version that deals with a boolean 
and its just not worth the pain of trying to make them both be the same 
thing..." But at least I got a better understanding of what I'm dealing 
with, eh?

MDC



Nick Roberts wrote:
> 
> I'm fairly certain that you require something like:
> 
>   procedure Some_Op (The_Thing : in out Some_Tagged_Type;
>                      The_Params: in     Some_Parameter_Type'Class)
>                                                          is abstract ;
> 


-- 
======================================================================
Marin David Condic
I work for: http://www.belcan.com/
My project is: http://www.jsf.mil/NSFrames.htm

Send Replies To: m   o   d   c @ a   m   o   g
                    c   n   i       c   .   r

     "Power corrupts.  Absolute power is kind of neat"
         -- John Lehman, Secretary of the Navy 1981-1987
======================================================================



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

end of thread, other threads:[~2004-11-06 13:17 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-10-30 13:04 Abstract Operations On A Tagged Record Marin David Condic
2004-10-30 14:34 ` Dmitry A. Kazakov
2004-10-30 16:07 ` Nick Roberts
2004-11-01 12:58   ` Marin David Condic
2004-11-01 18:09     ` Nick Roberts
2004-11-01 22:27       ` Marin David Condic
2004-11-06 13:17       ` Marin David Condic

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