comp.lang.ada
 help / color / mirror / Atom feed
* How to test object hierarchy
@ 2003-12-18 18:24 Pierre Favier
  2003-12-19  0:15 ` Stephen Leake
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Pierre Favier @ 2003-12-18 18:24 UTC (permalink / raw)


I am wondering how to test for two objects which types both derive from a
common root type if one of them derives from the other. In short, I am trying
to run something like the following code which does not compile because
the Class attribute applies to types or subtypes but not to objects:

   procedure Test_Hierarchy (Obj1 : in Root_Object'Class;
                             Obj2 : in Root_Object'Class) is
   begin

      if Obj1 in Obj2'Class then

         -- Do something

      else

         -- Do something else

      end if;

   end Test_Hierarchy;

Any suggestions on how to achieve the intended effect?



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

* Re: How to test object hierarchy
  2003-12-18 18:24 How to test object hierarchy Pierre Favier
@ 2003-12-19  0:15 ` Stephen Leake
  2003-12-19  7:45   ` Pierre Favier
  2003-12-19 10:53 ` Dmitry A. Kazakov
  2003-12-19 17:24 ` Nick Roberts
  2 siblings, 1 reply; 19+ messages in thread
From: Stephen Leake @ 2003-12-19  0:15 UTC (permalink / raw)
  To: comp.lang.ada

favierp@sofreavia.fr (Pierre Favier) writes:

> I am wondering how to test for two objects which types both derive from a
> common root type if one of them derives from the other. 

Interesting. Here's one way:

with Ada.Strings.Unbounded;
package Objects is

   type Root_Object is abstract tagged record
      Name : Ada.Strings.Unbounded.Unbounded_String;
   end record;

   type Object_1 is new Root_Object with record
      I : Integer;
   end record;

   type Object_1_1 is new Object_1 with record
      J : Integer;
   end record;

end Objects;

with Objects;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Tags;
with Ada.Strings.Fixed;
with Ada.Strings.Unbounded;
procedure Test_Hierarchy is

   function "+" (Item : in String) return Ada.Strings.Unbounded.Unbounded_String
     renames Ada.Strings.Unbounded.To_Unbounded_String;

   function "+" (Item : in Ada.Strings.Unbounded.Unbounded_String) return String
     renames Ada.Strings.Unbounded.To_String;

   procedure Test
     (Obj1 : in Objects.Root_Object'Class;
      Obj2 : in Objects.Root_Object'Class)
   is
      Obj1_Type_Name : constant String := Ada.Tags.Expanded_Name (Obj1'Tag);
      Obj2_Type_Name : constant String := Ada.Tags.Expanded_Name (Obj2'Tag);
   begin

      if 0 /= Ada.Strings.Fixed.Index (Source => Obj1_Type_Name, Pattern => Obj2_Type_Name) then

         Put_Line (+Obj1.Name & " is in " & (+Obj2.Name));

      else

         Put_Line (+Obj1.Name & " is not in " & (+Obj2.Name));

      end if;
   end Test;

   Obj1 : Objects.Object_1 := (+"higher", 1);
   Obj2 : Objects.Object_1_1 := (+"lower", 2, 3);
begin

   Test (Obj1, Obj2);
   Test (Obj2, Obj1);

end Test_Hierarchy;


make -r test_hierarchy.run
gnatmake -k -O3 -gnatn -gnatwa -I.. test_hierarchy -largs   -bargs  -cargs 
gcc -c -I./ -O3 -gnatn -gnatwa -I.. -I- ..\test_hierarchy.adb
gnatbind -aO./ -I.. -I- -x test_hierarchy.ali
gnatlink test_hierarchy.ali
./test_hierarchy.exe 
higher is not in lower
lower is in higher


It does seem like you aught to be able to do this without string operations.

-- 
-- Stephe




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

* Re: How to test object hierarchy
  2003-12-19  0:15 ` Stephen Leake
@ 2003-12-19  7:45   ` Pierre Favier
  0 siblings, 0 replies; 19+ messages in thread
From: Pierre Favier @ 2003-12-19  7:45 UTC (permalink / raw)


Stephen Leake <stephen_leake@acm.org> wrote in message news:<mailman.138.1071792945.31149.comp.lang.ada@ada-france.org>...
> favierp@sofreavia.fr (Pierre Favier) writes:
> 
> > I am wondering how to test for two objects which types both derive from a
> > common root type if one of them derives from the other. 
> 
> Interesting. Here's one way:
> 
> ......
>
> It does seem like you aught to be able to do this without string operations.

Yes. I had thought of using tag's Expanded_Name like you suggested but was
wondering whether there was a language feature that I was overlooking.

If you look at spec of package Ada.Tags in GNAT you see the following
function in the private part of the spec:

   function CW_Membership (Obj_Tag : Tag; Typ_Tag : Tag) return Boolean;
   --  Given the tag of an object and the tag associated to a type, return
   --  true if Obj is in Typ'Class.

which could be used as is for two object tags instead of an object tag and
a type tag. 

Why not make it public? Is any addition of this sort planned for Ada 200X?



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

* Re: How to test object hierarchy
  2003-12-18 18:24 How to test object hierarchy Pierre Favier
  2003-12-19  0:15 ` Stephen Leake
@ 2003-12-19 10:53 ` Dmitry A. Kazakov
  2003-12-19 14:35   ` Hyman Rosen
  2003-12-19 17:25   ` Georg Bauhaus
  2003-12-19 17:24 ` Nick Roberts
  2 siblings, 2 replies; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-19 10:53 UTC (permalink / raw)


Pierre Favier wrote:

> I am wondering how to test for two objects which types both derive from a
> common root type if one of them derives from the other. In short, I am
> trying to run something like the following code which does not compile
> because the Class attribute applies to types or subtypes but not to
> objects:
> 
>    procedure Test_Hierarchy (Obj1 : in Root_Object'Class;
>                              Obj2 : in Root_Object'Class) is
>    begin
> 
>       if Obj1 in Obj2'Class then
> 
>          -- Do something
> 
>       else
> 
>          -- Do something else
> 
>       end if;
> 
>    end Test_Hierarchy;
> 
> Any suggestions on how to achieve the intended effect?

Unfortunately tags have no "<" defined. Otherwise, one could simply write
Obj1'Tag < Obj2'Tag (in the sense Obj1 <: Obj2).

However there is a trick to achieve what you want using dispatching. The
idea is to emulate multiple dispatch and so you go as follows:

procedure Do_It -- Obj1 :>= Obj2
(  Obj1 : in Root_Object'Class;
   Obj2 : in Root_Object'Class
);

procedure Test_Hierarchy
(  Obj1 : in Root_Object; -- Dispatches in this argument
   Obj2 : in Root_Object'Class;
   Recursion : Boolean := False
)  is
begin
   if Recursion or else Obj2 not in Root_Object'Class then
      Do_It (Obj1, Obj2); -- Deal with Obj1 :>= Obj2
   else
      Test_Hierarchy (Obj2, Obj1, True); -- Dispatch again
   end if;
end Test_Hierarchy;

type Derived_Object is new Root_Object with ...;
procedure Test_Hierarchy
(  Obj1 : in Derived_Object;
   Obj2 : in Root_Object'Class;
   Recursion : Boolean := False
)  is
begin
   if Recursion
      or else Obj2 not in Derived_Object'Class
      or else Obj2 in Derived_Object
   then
      Do_It (Obj1, Obj2); -- Deal with Obj1 :>= Obj2
   else
      Test_Hierarchy (Obj2, Obj1, True); -- Dispatch again
   end if;
end Test_Hierarchy;

You have to override Test_Hierarchy for each new type, but I suppose that
"do something" in your code is dispatching anyway. When Test_Hierarchy is
not commutative it gets a bit more complicated, but I think you have got
the idea.

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: How to test object hierarchy
  2003-12-19 10:53 ` Dmitry A. Kazakov
@ 2003-12-19 14:35   ` Hyman Rosen
  2003-12-19 17:07     ` Dmitry A. Kazakov
  2003-12-19 23:26     ` Robert A Duff
  2003-12-19 17:25   ` Georg Bauhaus
  1 sibling, 2 replies; 19+ messages in thread
From: Hyman Rosen @ 2003-12-19 14:35 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> You have to override Test_Hierarchy for each new type

Which brings a question to my non Ada-knowing mind.
I know that for a subprogram to be dispatching, it
must be defined in the same package (or immediately
after?) as the tagged type upon which it dispatches.
Can an instantiation of a generic be dispatching in
this way? Could I do (pardon the syntax errors)
     procedure Test_Hierarchy is new
	Generic_Test_Hierarchy(Type1=>Derived_Object);
rather than copy the code each time?




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

* Re: How to test object hierarchy
  2003-12-19 14:35   ` Hyman Rosen
@ 2003-12-19 17:07     ` Dmitry A. Kazakov
  2003-12-19 23:26     ` Robert A Duff
  1 sibling, 0 replies; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-19 17:07 UTC (permalink / raw)


Hyman Rosen wrote:

> Dmitry A. Kazakov wrote:
>> You have to override Test_Hierarchy for each new type
> 
> Which brings a question to my non Ada-knowing mind.
> I know that for a subprogram to be dispatching, it
> must be defined in the same package (or immediately
> after?) as the tagged type upon which it dispatches.

Before the freezing point, which is informally at the first "non-trivial"
use of the type before the package specification end.

> Can an instantiation of a generic be dispatching in
> this way? Could I do (pardon the syntax errors)
>      procedure Test_Hierarchy is new
> Generic_Test_Hierarchy(Type1=>Derived_Object);
> rather than copy the code each time?

Aside, it is actually what inheritance is for! The problem is that there is
no [proper] multiple dispatch in Ada.

Well, an implementation of a dispatching subprogram through instantiation of
a generic one is not allowed in either Ada or C++. One step up. A generic
primitive operation is also not allowed in both. Another step up. Generic
types do exist in C++, but not in Ada, where same effect is achieved using
generic packages.

A strategic question is, whether one realy should exploit all possible
combinations of inheritance [and all other language things] and generics.
You know my opinion, down with generics! And there will be no question
anymore! (:-))

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: How to test object hierarchy
  2003-12-18 18:24 How to test object hierarchy Pierre Favier
  2003-12-19  0:15 ` Stephen Leake
  2003-12-19 10:53 ` Dmitry A. Kazakov
@ 2003-12-19 17:24 ` Nick Roberts
  2 siblings, 0 replies; 19+ messages in thread
From: Nick Roberts @ 2003-12-19 17:24 UTC (permalink / raw)


Pierre Favier wrote:

> I am wondering how to test for two objects which types both derive from 
> a common root type if one of them derives from the other. In short, I am
> trying to run something like the following code which does not compile
> because the Class attribute applies to types or subtypes but not to
> objects ...
> 
> Any suggestions on how to achieve the intended effect?

I feel this is a bit like someone asking how to scratch his ear with his
foot. I suspect the most sensible answer might be "Don't do that."

Since, within the procedure Test_Hierarchy, the only operations available
for either Obj1 or Obj2 are the operations of the type Root_Object, how can
it be of any significance to the code inside this procedure what relation
(deeper in the hierarchy) the objects have to each other? Surely the code
inside the procedure sees only two objects which obey the interface of
Root_Object?

I would guess, therefore, that there is an error of logic (or perhaps of
style) in your program, but if you think not then by all means please give
more details of what you are really trying to do.

-- 
Nick Roberts
  __________________________________________________________
|  Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/  |
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




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

* Re: How to test object hierarchy
  2003-12-19 10:53 ` Dmitry A. Kazakov
  2003-12-19 14:35   ` Hyman Rosen
@ 2003-12-19 17:25   ` Georg Bauhaus
  2003-12-20 11:13     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 19+ messages in thread
From: Georg Bauhaus @ 2003-12-19 17:25 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
: type Derived_Object is new Root_Object with ...;
: procedure Test_Hierarchy
: (  Obj1 : in Derived_Object;
:   Obj2 : in Root_Object'Class;
:   Recursion : Boolean := False
: )  is
: begin
:   if Recursion
:      or else Obj2 not in Derived_Object'Class
:      or else Obj2 in Derived_Object
:   then
:      Do_It (Obj1, Obj2); -- Deal with Obj1 :>= Obj2
:   else
:      Test_Hierarchy (Obj2, Obj1, True); -- Dispatch again
:   end if;
: end Test_Hierarchy;
: 
: You have to override Test_Hierarchy for each new type, but I suppose that
: "do something" in your code is dispatching anyway. When Test_Hierarchy is
: not commutative it gets a bit more complicated, but I think you have got
: the idea.

Whenever I see an "if" testing for types I'm wondering whether
these ifs should be turned "to the outside" into what they mean
in the solution domain, but using language means. Is it really
advantageous or necessary to have to do manual dispatching in
your program?

And I have the same question that Hyman has asked about generics,
plus, should "with type" be mentioned in this context?


-- Georg



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

* Re: How to test object hierarchy
  2003-12-19 14:35   ` Hyman Rosen
  2003-12-19 17:07     ` Dmitry A. Kazakov
@ 2003-12-19 23:26     ` Robert A Duff
  2003-12-20 18:20       ` Robert I. Eachus
  1 sibling, 1 reply; 19+ messages in thread
From: Robert A Duff @ 2003-12-19 23:26 UTC (permalink / raw)


Hyman Rosen <hyrosen@mail.com> writes:

> Dmitry A. Kazakov wrote:
> > You have to override Test_Hierarchy for each new type
> 
> Which brings a question to my non Ada-knowing mind.
> I know that for a subprogram to be dispatching, it
> must be defined in the same package (or immediately
> after?) as the tagged type upon which it dispatches.

It must defined in the same package *spec* (visible part or private
part).

One obscure point is that if you override an inherited subprogram, it is
dispatching.  It has to be declared in the same declarative region in
that case.

> Can an instantiation of a generic be dispatching in
> this way?

Yes, it can be instance.  It can also be a renaming.

>... Could I do (pardon the syntax errors)
>      procedure Test_Hierarchy is new
> 	Generic_Test_Hierarchy(Type1=>Derived_Object);
> rather than copy the code each time?

I didn't follow the entire discussion, but yes, I think that could work.

- Bob



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

* Re: How to test object hierarchy
  2003-12-19 17:25   ` Georg Bauhaus
@ 2003-12-20 11:13     ` Dmitry A. Kazakov
  2003-12-21  4:34       ` Georg Bauhaus
  0 siblings, 1 reply; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-20 11:13 UTC (permalink / raw)


Georg Bauhaus wrote:

> Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
> : type Derived_Object is new Root_Object with ...;
> : procedure Test_Hierarchy
> : (  Obj1 : in Derived_Object;
> :   Obj2 : in Root_Object'Class;
> :   Recursion : Boolean := False
> : )  is
> : begin
> :   if Recursion
> :      or else Obj2 not in Derived_Object'Class
> :      or else Obj2 in Derived_Object
> :   then
> :      Do_It (Obj1, Obj2); -- Deal with Obj1 :>= Obj2
> :   else
> :      Test_Hierarchy (Obj2, Obj1, True); -- Dispatch again
> :   end if;
> : end Test_Hierarchy;
> : 
> : You have to override Test_Hierarchy for each new type, but I suppose
> : that "do something" in your code is dispatching anyway. When
> : Test_Hierarchy is not commutative it gets a bit more complicated, but I
> : think you have got the idea.
> 
> Whenever I see an "if" testing for types I'm wondering whether
> these ifs should be turned "to the outside" into what they mean
> in the solution domain, but using language means. Is it really
> advantageous or necessary to have to do manual dispatching in
> your program?

R-r-right. The rest is easy, just to write an AI for multiple dispatch in
Ada! (:-))

Ideally, the language should allow to program without any explicit
testing/casting for types. I remember a fierce discussion in comp.object on
this topic. The result, as always, was unsettled.

Then not always types do reflect the solution domain. In some cases the
language rules (limitations) force developer to create helper types. There
are also semi-domain types, like pointers, handles, interators etc. 

> And I have the same question that Hyman has asked about generics,
> plus,

Should we emulate inheritance using generics?

> should "with type" be mentioned in this context?

Interesting, why do you thing it should?

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: How to test object hierarchy
  2003-12-19 23:26     ` Robert A Duff
@ 2003-12-20 18:20       ` Robert I. Eachus
  0 siblings, 0 replies; 19+ messages in thread
From: Robert I. Eachus @ 2003-12-20 18:20 UTC (permalink / raw)


Robert A Duff wrote:

> Yes, it can be instance.  It can also be a renaming.
...
> I didn't follow the entire discussion, but yes, I think that could work.

Before somebody gets bent all out of shape trying to implement the idea, 
there is a subtle gotcha here that has to be avoided.  It is often 
difficult (but not impossible) to define the generic you want before the 
freezing point.

There are two workarounds, which often occur naturally.  The first is to 
make the signature of the subprogram dispatching.  Then in the body, 
implement the subprogram as a generic instance.  Or you can make the 
generic an operation of a parent type, so that the generic instantiation 
can appear before the freezing point of the child type, but after the 
freezing point of the parent.

As I said, you may naturally not run into a problem.  Depends on how you 
define the generic and other things.  But if you do have a problem, move 
the instantiation to the body of the package that defines the type.

-- 
                                           Robert I. Eachus

"The war on terror is a different kind of war, waged capture by capture, 
cell by cell, and victory by victory. Our security is assured by our 
perseverance and by our sure belief in the success of liberty." -- 
George W. Bush




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

* Re: How to test object hierarchy
  2003-12-20 11:13     ` Dmitry A. Kazakov
@ 2003-12-21  4:34       ` Georg Bauhaus
  2003-12-21 13:43         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 19+ messages in thread
From: Georg Bauhaus @ 2003-12-21  4:34 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
: 
:> should "with type" be mentioned in this context?
: 
: Interesting, why do you thing it should?

I'm not really familiar with "with type", but I thought (guessed)
that the OP's procedure could be distributed across pairs of two,
each procedure taking one top level class-wide parameter and
a derived type parameter. If I have

package D is

   type Root is tagged private;

   type Derived_1 is new Root with private;

   procedure Op_1(d: Derived_1; other: Derived_2'Class);
                                       -- too early
   procedure Op_1(d: Derived_2; other: Derived_2'Class);
                  --  too early,       too early

   type Derived_2 is new Root with private;

   procedure Op_2(d: Derived_2; other: Derived_1'Class);
   procedure Op_2(d: Derived_1; other: Derived_1'Class);
                  -- too late

   ...

Will "with type" and package reorganisation help?


-- Georg



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

* Re: How to test object hierarchy
  2003-12-21  4:34       ` Georg Bauhaus
@ 2003-12-21 13:43         ` Dmitry A. Kazakov
  2003-12-21 19:58           ` Dmytry Lavrov
  0 siblings, 1 reply; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-21 13:43 UTC (permalink / raw)


Georg Bauhaus wrote:

> Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
> : 
> :> should "with type" be mentioned in this context?
> : 
> : Interesting, why do you thing it should?
> 
> I'm not really familiar with "with type", but I thought (guessed)
> that the OP's procedure could be distributed across pairs of two,
> each procedure taking one top level class-wide parameter and
> a derived type parameter. If I have
> 
> package D is
> 
>    type Root is tagged private;
> 
>    type Derived_1 is new Root with private;
> 
>    procedure Op_1(d: Derived_1; other: Derived_2'Class);
>                                        -- too early
>    procedure Op_1(d: Derived_2; other: Derived_2'Class);
>                   --  too early,       too early
> 
>    type Derived_2 is new Root with private;
> 
>    procedure Op_2(d: Derived_2; other: Derived_1'Class);
>    procedure Op_2(d: Derived_1; other: Derived_1'Class);
>                   -- too late
> 
>    ...
> 
> Will "with type" and package reorganisation help?

I think that IF Ada should have multiple dispatch on different types then
inevitably we should reconsider the freezing rules. The most useful
implementations of MD appear when types are defined in different packages.
The rationale behind the existing freezing rules is to prevent dispatching
to non-elaborated targets. I believe that for a MD operation the freezing
point could be the last freezing point of all involved types. For example:

package Devices is
   type Device is tagged ...;
   procedure Load (X : in out Device);
end Device; -- No more primitive operations with only Device

with Devices; use Devices;
package Curves is
   type Curve is tagged ...;
   procedure Show (X : in out Device; Y : Curve);
end Curves; -- No more operations with Device and Curve

It is clear that these rules can be very dangerous, if we will not limit use
of non-primitive operations (except the class-wide ones). The first step
could be to make all types "tagged". But even this could be not enough.

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: How to test object hierarchy
  2003-12-21 13:43         ` Dmitry A. Kazakov
@ 2003-12-21 19:58           ` Dmytry Lavrov
  2003-12-22  1:19             ` Robert I. Eachus
  2003-12-22 10:05             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 19+ messages in thread
From: Dmytry Lavrov @ 2003-12-21 19:58 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:<bs47m5$9e9ea$2@ID-77047.news.uni-berlin.de>...
<snip> 
> 
> I think that IF Ada should have multiple dispatch on different types

Wao.That's exactly(multiple dispatch) that i tried to explain to
peoples(very experienced and probably smart too ) who know only
"object.method" notation.
Of course that failed(they even can't understand what it is it),
because that damn "."(like fields in record) left place only for one
object!

i got probably good(and also wild) idea that
method(paramether,paramether,...) are shugar for
method(composed_class_constructor(paramether1,paramether2,...) )

and if thete's multiple inheritance, it's 
method(temporary_child_class_constructor(parent1,parent2,...) );

and also about that it's shugar for
dispatch(in paramether1[, in paramether2....]).method(in out
paramether1[,in out paramether2....]);
- it can be implemented without changing the language at all,but need
lots of stupid work with "procedural variables".

Maybe that could give someone here any good idea.

(it was about problem with overloading math operators for classes-
double dispathing was required - different methods for matrix by
matrix,matrix by scalar,matrix by vector,vector by matrix,etc,in all
combinations including complex number stuff ,etc. )


> then
> inevitably we should reconsider the freezing rules. The most useful
> implementations of MD appear when types are defined in different packages.
> The rationale behind the existing freezing rules is to prevent dispatching
> to non-elaborated targets. I believe that for a MD operation the freezing
> point could be the last freezing point of all involved types. For example:
> 
> package Devices is
>    type Device is tagged ...;
>    procedure Load (X : in out Device);
> end Device; -- No more primitive operations with only Device
> 
> with Devices; use Devices;
> package Curves is
>    type Curve is tagged ...;
>    procedure Show (X : in out Device; Y : Curve);
> end Curves; -- No more operations with Device and Curve
> 
> It is clear that these rules can be very dangerous, if we will not limit use
> of non-primitive operations (except the class-wide ones). The first step
> could be to make all types "tagged". But even this could be not enough.

Main problem that compiler will no longer detect some errors,right?

Regards,

Dmytry Lavrov.



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

* Re: How to test object hierarchy
  2003-12-21 19:58           ` Dmytry Lavrov
@ 2003-12-22  1:19             ` Robert I. Eachus
  2003-12-22 10:09               ` Dmitry A. Kazakov
  2003-12-22 10:05             ` Dmitry A. Kazakov
  1 sibling, 1 reply; 19+ messages in thread
From: Robert I. Eachus @ 2003-12-22  1:19 UTC (permalink / raw)


Dmytry Lavrov wrote:

>>I think that IF Ada should have multiple dispatch on different types...

In Ada, if and where you need it, you can get multiple dispatching. 
There are of course many different patterns that correspond to multiple 
dispatching, and if you want the most general pattern:

function "+" (L, R: Object) return Object;

Where unlike normal Ada, L, R and the return value can be different 
specific types.  This can be done, but you actually have to do some 
extra work "under the covers."

Normally you would declare the visible "+" as:

function "+" (L: Object; R: Object'Class) return Object'Class;

Then in the private part you would have a function which is called by 
the visible "+" but dispatches on the second parameter, and result type:

function Add (L: Object'Class; R: Object) return Object;

Or L may be of some general representation type.  But from experience, 
doing all this is a lot of work, and you don't want to even think about 
extending Object beyond the initial set of specific types.  You don't 
have to rethink the entire structure when you do that, but it may be the 
only way to produce something that is understandable to humans.

The Multics PL/I compiler has (had?) a horrible example of this.  PL/I 
has implicit conversions between types and all sorts of conversions you 
wouldn't expect are defined.  Including various flavors of literals, the 
PL/I compiler front end had 17 different cases to deal with. Well, 
actually, that was for each parameter.  So there were really 289 cases 
that could come up.  In practice only about 60 were implemented 
specificly, the rest were defaulted by using an "any-to-any" conversion 
routine on one or the other operand.  Most of the defaulted cases 
involved adding (or whatever operation you were implementing) two 
literals, so everything could be done at compile time anyway.

So can you do something like this in Ada.  Sure.  Can you maintain your 
sanity while doing it?  Questionable whether you are doing it in Ada, 
PL/I, assembler, or whatever.  The polynomial explosion of cases may be 
capable of being handled by quite clever code, but you still end up 
slogging through testing all those bizarre cases anyway.  (And in PL/I, 
you don't have to spend much time dreaming up test cases for adding bit 
strings to decimal numbers, or adding booleans to character strings 
before you start screaming. ;-)


The much, much, more common, and much easier to deal with case is where 
you want to dispact separately on two or more independent parameters. 
I've actually used that.

-- 
                                           Robert I. Eachus

"The war on terror is a different kind of war, waged capture by capture, 
cell by cell, and victory by victory. Our security is assured by our 
perseverance and by our sure belief in the success of liberty." -- 
George W. Bush




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

* Re: How to test object hierarchy
  2003-12-21 19:58           ` Dmytry Lavrov
  2003-12-22  1:19             ` Robert I. Eachus
@ 2003-12-22 10:05             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-22 10:05 UTC (permalink / raw)


Dmytry Lavrov wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:<bs47m5$9e9ea$2@ID-77047.news.uni-berlin.de>... <snip>
>> 
>> I think that IF Ada should have multiple dispatch on different types
> 
> Wao.That's exactly(multiple dispatch) that i tried to explain to
> peoples(very experienced and probably smart too ) who know only
> "object.method" notation.
> Of course that failed(they even can't understand what it is it),
> because that damn "."(like fields in record) left place only for one
> object!
> 
> i got probably good(and also wild) idea that
> method(paramether,paramether,...) are shugar for
> method(composed_class_constructor(paramether1,paramether2,...) )
> 
> and if thete's multiple inheritance, it's
> method(temporary_child_class_constructor(parent1,parent2,...) );
> 
> and also about that it's shugar for
> dispatch(in paramether1[, in paramether2....]).method(in out
> paramether1[,in out paramether2....]);
> - it can be implemented without changing the language at all,but need
> lots of stupid work with "procedural variables".
> 
> Maybe that could give someone here any good idea.
> 
> (it was about problem with overloading math operators for classes-
> double dispathing was required - different methods for matrix by
> matrix,matrix by scalar,matrix by vector,vector by matrix,etc,in all
> combinations including complex number stuff ,etc. )

The case you are describing is multiple dispatch on same type. It is a bit
easier, especially because the existing freezing rules are OK and because
it still allows C++ appoach of having virtual table pointer buried in
objects. I have posted an example how to deal with it. You can also take a
look at

http://www.dmitry-kazakov.de/ada/components.htm

where it is used for "=", "<" operations.

But the pet idea of many OOPLs that methods belong to object is absolutely
wrong. So the prefix notation. The pressure is so high that there is an AI
to introduce it in Ada! (It already exists for tasks and protected objects)

>> then
>> inevitably we should reconsider the freezing rules. The most useful
>> implementations of MD appear when types are defined in different
>> packages. The rationale behind the existing freezing rules is to prevent
>> dispatching to non-elaborated targets. I believe that for a MD operation
>> the freezing point could be the last freezing point of all involved
>> types. For example:
>> 
>> package Devices is
>>    type Device is tagged ...;
>>    procedure Load (X : in out Device);
>> end Device; -- No more primitive operations with only Device
>> 
>> with Devices; use Devices;
>> package Curves is
>>    type Curve is tagged ...;
>>    procedure Show (X : in out Device; Y : Curve);
>> end Curves; -- No more operations with Device and Curve
>> 
>> It is clear that these rules can be very dangerous, if we will not limit
>> use of non-primitive operations (except the class-wide ones). The first
>> step could be to make all types "tagged". But even this could be not
>> enough.
> 
> Main problem that compiler will no longer detect some errors,right?

Errors, undesired overloadings, where overriding was meant, backward
compatibility all that things.

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: How to test object hierarchy
  2003-12-22  1:19             ` Robert I. Eachus
@ 2003-12-22 10:09               ` Dmitry A. Kazakov
  2003-12-22 17:33                 ` Robert I. Eachus
  0 siblings, 1 reply; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-22 10:09 UTC (permalink / raw)


Robert I. Eachus wrote:

> Dmytry Lavrov wrote:
> 
>>>I think that IF Ada should have multiple dispatch on different types...
> 
> In Ada, if and where you need it, you can get multiple dispatching.
> There are of course many different patterns that correspond to multiple
> dispatching, and if you want the most general pattern:
> 
> function "+" (L, R: Object) return Object;
> 
> Where unlike normal Ada, L, R and the return value can be different
> specific types.  This can be done, but you actually have to do some
> extra work "under the covers."
> 
> Normally you would declare the visible "+" as:
> 
> function "+" (L: Object; R: Object'Class) return Object'Class;
> 
> Then in the private part you would have a function which is called by
> the visible "+" but dispatches on the second parameter, and result type:
> 
> function Add (L: Object'Class; R: Object) return Object;
> 
> Or L may be of some general representation type.  But from experience,
> doing all this is a lot of work, and you don't want to even think about
> extending Object beyond the initial set of specific types.  You don't
> have to rethink the entire structure when you do that, but it may be the
> only way to produce something that is understandable to humans.

This is an argument in favor of implementing MD in Ada, I suppose (:-))

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

* Re: How to test object hierarchy
  2003-12-22 10:09               ` Dmitry A. Kazakov
@ 2003-12-22 17:33                 ` Robert I. Eachus
  2003-12-23 10:49                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 19+ messages in thread
From: Robert I. Eachus @ 2003-12-22 17:33 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> This is an argument in favor of implementing MD in Ada, I suppose (:-))

No, it is an argument that current Ada rules are just fine.  You can do 
multiple dispatching in Ada, and the sort of casual dispatching where 
the author of the code doesn't even know that multiple dispatch is 
involves works just fine.  For example, instantiate a generic with a 
classwide type or two as an actual type parameter.  The resulting 
executable may have nested dispatching, but there is no real need to 
anticipate that case when writing the generic.

As for cases where you really NEED to understand the code in multiple 
dispatching terms, these are no harder to program in Ada than in other 
languages--and no easier.  And they really are that hard to wrap the 
mind around.  There are cases which are worth the effort, but precious few.

Another more prosaic example would be a general graphic file format 
converter.  I can design such a tool as a combination of a reader and a 
writer with a standard intermediate representation:

...
declare
   Temp: Intermediate_Format := Read(Input_File);
begin
   Write(Temp, Output_File);
end;

Of course I can rewrite this as:

Write(Read(Input_File), Output_File);

Later I might want to add a graphics format that doesn't work well with 
the "standard" intermediate format.  To do this, I can restructure the 
existing code with a multiple dispatch format:

procedure Process(Input: in Graphics_Format; out Graphics_Format'Class);
   or
function Process(Input: Graphics_Format) return Graphics_Format'Class;

Now I can provide a body which normally uses the old approach with 
Intermediate_Format, but first checks for the special cases and handles 
them with other routines.

THAT is when it starts to get difficult to use multiple dispatch.  It is 
not the process of doing what I call 'casual' multiple dispatch in Ada, 
that is easy.  The problem is going through on an N**2 case by case 
basis (or N**3 or N*M or whatever) and insuring that the approach that 
is dynamically selected for that particular case is, in some sense, the 
right one.  And when the set of possibilities grows, adding one new 
format means considering 2N-1 new cases.

-- 
                                           Robert I. Eachus

"The war on terror is a different kind of war, waged capture by capture, 
cell by cell, and victory by victory. Our security is assured by our 
perseverance and by our sure belief in the success of liberty." -- 
George W. Bush




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

* Re: How to test object hierarchy
  2003-12-22 17:33                 ` Robert I. Eachus
@ 2003-12-23 10:49                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 19+ messages in thread
From: Dmitry A. Kazakov @ 2003-12-23 10:49 UTC (permalink / raw)


Robert I. Eachus wrote:

> Dmitry A. Kazakov wrote:
> 
>> This is an argument in favor of implementing MD in Ada, I suppose (:-))
> 
> No, it is an argument that current Ada rules are just fine.  You can do
> multiple dispatching in Ada, and the sort of casual dispatching where
> the author of the code doesn't even know that multiple dispatch is
> involves works just fine.  For example, instantiate a generic with a
> classwide type or two as an actual type parameter.  The resulting
> executable may have nested dispatching, but there is no real need to
> anticipate that case when writing the generic.

These cases are not cases of MD. Anything that can be written using
"cascading" dispatch is in fact single dispatch in one argument and
class-wide in another. What is not MD, is not.

> As for cases where you really NEED to understand the code in multiple
> dispatching terms, these are no harder to program in Ada than in other
> languages--and no easier.  And they really are that hard to wrap the
> mind around.  There are cases which are worth the effort, but precious
> few.

The point is that MD is a *natural* view on any subprogam having many
parameters. All other views are in fact kludges, hard to understand and
very error-prone. Note that if the language is aware of MD, it can enforce
necessary overridings, because it knows that they should be. Otherwise, a
developer is exposed to a geometric explosion of variants, which he might
be even unaware of, especially if he derives from a library type.

> Another more prosaic example would be a general graphic file format
> converter.  I can design such a tool as a combination of a reader and a
> writer with a standard intermediate representation:
> 
> ...
> declare
>    Temp: Intermediate_Format := Read(Input_File);
> begin
>    Write(Temp, Output_File);
> end;
> 
> Of course I can rewrite this as:
> 
> Write(Read(Input_File), Output_File);
> 
> Later I might want to add a graphics format that doesn't work well with
> the "standard" intermediate format.  To do this, I can restructure the
> existing code with a multiple dispatch format:
> 
> procedure Process(Input: in Graphics_Format; out Graphics_Format'Class);
>    or
> function Process(Input: Graphics_Format) return Graphics_Format'Class;
> 
> Now I can provide a body which normally uses the old approach with
> Intermediate_Format, but first checks for the special cases and handles
> them with other routines.
> 
> THAT is when it starts to get difficult to use multiple dispatch.  It is
> not the process of doing what I call 'casual' multiple dispatch in Ada,
> that is easy.  The problem is going through on an N**2 case by case
> basis (or N**3 or N*M or whatever) and insuring that the approach that
> is dynamically selected for that particular case is, in some sense, the
> right one.  And when the set of possibilities grows, adding one new
> format means considering 2N-1 new cases.

Right, therefore it has to be supported by the compiler! And in this case,
MD on same type hierarchy, it is pretty easy to do. The compiler shall
simply check that if one of 2N-1 possible overridings happens, others have
to be explicitly overridden too. Also I really wish some language support
for commutative operations, which would reduce the number of variants in
twice.

But the real problem with MD is the case of different type hierarchies. For
example, stream attributes. Present implementation is obviously
inconsistent. S'Write should know all stream types because it is class-wide
in the Stream argument. How a developer of a type can foresee all possible
streams? What if it is a library type? It is clear to me that consistency
should be enforced by the language. The great problem is how.

-- 
Regards,
Dmitry A. Kazakov
www.dmitry-kazakov.de



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

end of thread, other threads:[~2003-12-23 10:49 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-18 18:24 How to test object hierarchy Pierre Favier
2003-12-19  0:15 ` Stephen Leake
2003-12-19  7:45   ` Pierre Favier
2003-12-19 10:53 ` Dmitry A. Kazakov
2003-12-19 14:35   ` Hyman Rosen
2003-12-19 17:07     ` Dmitry A. Kazakov
2003-12-19 23:26     ` Robert A Duff
2003-12-20 18:20       ` Robert I. Eachus
2003-12-19 17:25   ` Georg Bauhaus
2003-12-20 11:13     ` Dmitry A. Kazakov
2003-12-21  4:34       ` Georg Bauhaus
2003-12-21 13:43         ` Dmitry A. Kazakov
2003-12-21 19:58           ` Dmytry Lavrov
2003-12-22  1:19             ` Robert I. Eachus
2003-12-22 10:09               ` Dmitry A. Kazakov
2003-12-22 17:33                 ` Robert I. Eachus
2003-12-23 10:49                   ` Dmitry A. Kazakov
2003-12-22 10:05             ` Dmitry A. Kazakov
2003-12-19 17:24 ` Nick Roberts

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