comp.lang.ada
 help / color / mirror / Atom feed
* Q: Endless loop by dispatching
@ 2003-07-11  8:22 Michael Erdmann
  2003-07-11  9:46 ` Jean-Pierre Rosen
                   ` (2 more replies)
  0 siblings, 3 replies; 35+ messages in thread
From: Michael Erdmann @ 2003-07-11  8:22 UTC (permalink / raw)


Dear all,

i got a problem with the following code fragment below. The Idea is that 
the procedure Serialize defines the strategy how to display object which
are derived from A.Object. Searialize simply dispatches into the class
by calling a procedure Write, which does the job for the class.

package A is

    type Object is tagged record
          P1 : Natural := 1;
          P2 : Natural := 2;
       end record;


    procedure Write(
       This : in Object );

    procedure Serialize(
       This : in Object'Class );

end A;


package body A is

    procedure Serialize(
       This : in Object'Class ) is
    begin
       Write( This );
    end Serialize;

    procedure Write(
       This : in Object ) is
    begin
       Put_Line( "P1 =" & Natural'Image( This.P1 ) );
       Put_Line( "P2 =" & Natural'Image( This.P2 ) );
    end Write;

end A;

In the following fragment i am defining a package B with an
derived objec B.Object as below. When an instance of B.Object
shall be serialized, the element of the super class (A.Object)
shall be serialzed as well. The code looks nice and compiles
but does not work, since the Serialize dispatches again with
Object.B even ther was a a case given  A.Object( This ).

package B is

    type Object is new A.Object with record
          Q : Natural := 2;
       end record;

    procedure Write(
       This : in Object );

end B;

..........
package body B is

    procedure Write(
       This : in Object ) is
    begin
       A.Serialize( A.Object( This ) );
       Put_Line( "Q =" & Natural'Image(This.Q));
    end Write;

end B;

Does any body know, what this loop causes?! I am not sure
if this is a bug or simply i missed the point.

Michael






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

* Re: Endless loop by dispatching
  2003-07-11  8:22 Q: Endless loop by dispatching Michael Erdmann
@ 2003-07-11  9:46 ` Jean-Pierre Rosen
  2003-07-11 15:19   ` Michael Erdmann
  2003-07-11 10:01 ` Q: " Dmitry A. Kazakov
  2003-07-11 16:27 ` T. Kurt Bond
  2 siblings, 1 reply; 35+ messages in thread
From: Jean-Pierre Rosen @ 2003-07-11  9:46 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1033 bytes --]


"Michael Erdmann" <michael.erdmann@snafu.de> a �crit dans le message de news:un82u-4kb.ln1@boavista.snafu.de...
[SNIP]
> Does any body know, what this loop causes?! I am not sure
> if this is a bug or simply i missed the point.
>
You missed the point :-)

Serialize is a general entry point, which dispatches to Write. If you call it again from Write, it will redispatch
to Write, hence the loop.

Now do you think that Write of B is really Serialize of A, plus something else?
Isn't it *Write* of A, plus something else? If you change your package to

package body B is

    procedure Write(
       This : in Object ) is
    begin
       A.Write( A.Object( This ) );
       Put_Line( "Q =" & Natural'Image(This.Q));
    end Write;

end B;

It will be OK.

Oh, by the way, why do you need Serialize at all? Since all it does is call Write, why don't you
call Write directly?

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr





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

* Re: Q: Endless loop by dispatching
  2003-07-11  8:22 Q: Endless loop by dispatching Michael Erdmann
  2003-07-11  9:46 ` Jean-Pierre Rosen
@ 2003-07-11 10:01 ` Dmitry A. Kazakov
  2003-07-11 15:07   ` Michael Erdmann
  2003-07-11 16:27 ` T. Kurt Bond
  2 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-11 10:01 UTC (permalink / raw)


On Fri, 11 Jul 2003 10:22:54 +0200, Michael Erdmann
<michael.erdmann@snafu.de> wrote:

>i got a problem with the following code fragment below. The Idea is that 
>the procedure Serialize defines the strategy how to display object which
>are derived from A.Object. Searialize simply dispatches into the class
>by calling a procedure Write, which does the job for the class.

[...]

>In the following fragment i am defining a package B with an
>derived objec B.Object as below. When an instance of B.Object
>shall be serialized, the element of the super class (A.Object)
>shall be serialzed as well. The code looks nice and compiles
>but does not work, since the Serialize dispatches again with
>Object.B even ther was a a case given  A.Object( This ).

[...]

>Does any body know, what this loop causes?! I am not sure
>if this is a bug or simply i missed the point.

Serialize is class-wide and a view conversion does not change the
tag..I.e. you have a re-dispatching case. Re-dispatching is a
dangerous thing. [I would like it removed from Ada]

So Serialize re-dispatches to B.Write which again calls Serialize.
From design point of view, one should never call class-wide routines
from specific ones, this warranties that dispatch happens only once.

I suppose that you want sort of procedure expansion instead of
complete overriding, if so, then you should explicitly call parent's
Write, similarly as one does it for Initialize/Finalize:

package body B is
...
procedure Write (This : in Object) is
begin
--       A.Serialize( A.Object( This ) );
   A.Write (A.Object (This)); -- Write parent's things
   Put_Line( "Q =" & Natural'Image(This.Q));
end Write;

BTW, why do not you use Ada.Streams? It is for things like this.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-11 10:01 ` Q: " Dmitry A. Kazakov
@ 2003-07-11 15:07   ` Michael Erdmann
  2003-07-12  1:41     ` Jeffrey Carter
  2003-07-14  8:48     ` Dmitry A. Kazakov
  0 siblings, 2 replies; 35+ messages in thread
From: Michael Erdmann @ 2003-07-11 15:07 UTC (permalink / raw)
  To: Dmitry A. Kazakov

Dmitry A. Kazakov wrote:

>>Does any body know, what this loop causes?! I am not sure
>>if this is a bug or simply i missed the point.
> 
> 
> Serialize is class-wide and a view conversion does not change the
> tag..I.e. you have a re-dispatching case. Re-dispatching is a
> dangerous thing. [I would like it removed from Ada]
> 
> So Serialize re-dispatches to B.Write which again calls Serialize.
> From design point of view, one should never call class-wide routines
> from specific ones, this warranties that dispatch happens only once.
> 
> I suppose that you want sort of procedure expansion instead of
> complete overriding, if so, then you should explicitly call parent's
> Write, similarly as one does it for Initialize/Finalize:
> 
Unfortuantly this was not the complete code. The Serialize was itended
to do a  more complex job, which i have to replicate any where i want
to serialize an object. The original serialize code looks some what
like this:

procedure Serialize( This : in Object'Class ) is
   ........
    a := next(Attributes(This'Tag))
    while a /= null loop
        Write( this.all, a.id );
        a := next(....);
    end loop;

end;

The procedure write is a procedures which  writes out a selected 
attribute of an object. The procedure Serialize the complete
object. I would have been great when i could write something
like this in ada:

procedure Serialize( This : in Object'Class ) is

    Serialize( Super( This ) );

    a := next(Attributes(This'Tag))
    while a /= null loop
        Write( this.all, a.id );
        a := next(....);
    end loop;

end;


I think something like this does not exist in Ada!?


> package body B is
> ...
> procedure Write (This : in Object) is
> begin
> --       A.Serialize( A.Object( This ) );
>    A.Write (A.Object (This)); -- Write parent's things
>    Put_Line( "Q =" & Natural'Image(This.Q));
> end Write;
> 
> BTW, why do not you use Ada.Streams? It is for things like this.

I fact i am using Ada.Stream, but as i have written above the code was
simply a consended version.
> 
> ---
> Regards,
> Dmitry Kazakov
> www.dmitry-kazakov.de




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

* Re: Endless loop by dispatching
  2003-07-11  9:46 ` Jean-Pierre Rosen
@ 2003-07-11 15:19   ` Michael Erdmann
  0 siblings, 0 replies; 35+ messages in thread
From: Michael Erdmann @ 2003-07-11 15:19 UTC (permalink / raw)
  To: Jean-Pierre Rosen

Jean-Pierre Rosen wrote:

> 
> You missed the point :-)
>
I understood this mean while. It seems that the case A.Object(This) does
not change the tag. I have checked the RM but i found nothing, but this
seems to be accepted as normal behaviour in the community.


> Serialize is a general entry point, which dispatches to Write. If you call it again from Write, it will redispatch
> to Write, hence the loop.
> 
> Now do you think that Write of B is really Serialize of A, plus something else?
> Isn't it *Write* of A, plus something else? If you change your package to
> 
> package body B is
> 
>     procedure Write(
>        This : in Object ) is
>     begin
>        A.Write( A.Object( This ) );
>        Put_Line( "Q =" & Natural'Image(This.Q));
>     end Write;
> 
> end B;
> 
> It will be OK.


> 
> Oh, by the way, why do you need Serialize at all? Since all it does is call Write, why don't you
> call Write directly?
> 

Maybe the conseded code i have sent was missleading. Since the
procedure Serialize is intended to do more then just i put it
here as pseudocode:

procedure Serialze( this : in Object'Class ) is

     Serialize( Super( This ) );

     F := Get( Attribute( this'Tag ) )
     while F /= null loop
        Unbounded_String'Output( S, F.Name );
        Write( This, F.Id );
        F := Next(...);
     end loop;

end Serialize:

Using write directly is possible but then i have to put the code of
serialze everwhere were i want to do the trick. I there would be 
something like the Super operation yielding the references to the
super class then everthing would be fine, i guess!

Michael





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

* Re: Q: Endless loop by dispatching
  2003-07-11  8:22 Q: Endless loop by dispatching Michael Erdmann
  2003-07-11  9:46 ` Jean-Pierre Rosen
  2003-07-11 10:01 ` Q: " Dmitry A. Kazakov
@ 2003-07-11 16:27 ` T. Kurt Bond
  2003-07-12  8:37   ` Michael Erdmann
  2 siblings, 1 reply; 35+ messages in thread
From: T. Kurt Bond @ 2003-07-11 16:27 UTC (permalink / raw)


-- Michael Erdmann <michael.erdmann@snafu.de> asked in message 
-- news:<un82u-4kb.ln1@boavista.snafu.de> about redispatching on 'Class types,
-- which was causing his program to loop endlessly.
--
-- Here's a program that includes his example code and does what (I think) 
-- he wants.
--
with Ada.Text_IO; use Ada.Text_IO;
procedure Test is
   --  From: Michael Erdmann <michael.erdmann@snafu.de>
   --  Subject: Q: Endless loop by dispatching
   --  Newsgroups: comp.lang.ada
   --  Date: Fri, 11 Jul 2003 10:22:54 +0200
   --  Organization: [Posted via] Inter.net Germany GmbH

   --  Dear all,

   --  i got a problem with the following code fragment below. The Idea is
   --  that the procedure Serialize defines the strategy how to display
   --  object which
   --  are derived from A.Object. Searialize simply dispatches into the class
   --  by calling a procedure Write, which does the job for the class.
   package A is
      type Object is tagged record
	 P1 : Natural := 1;
	 P2 : Natural := 2;
      end record;
      type Class_Access is access Object'Class;	         --  added for example.

      procedure Write(This : in Object );
      procedure Serialize(This : in Object'Class );
   end A;

   package body A is
      procedure Serialize(This : in Object'Class ) is
      begin
	 Put_Line ("Serialize (Object'Class) called:");	  --  added for example
	 Write( A.Object (This) );	             --  changed for example!!!
	   -- Since "This" is at Object'Class, "Write (This)" would dispatch
           -- on the actual tag of "This", calling "B.Write" for objects of 
	   -- type "B.Object", which would call "A.Serialize" again, 
	   -- looping forever.  To always call A.Write, construct
	   -- a *view* of the object as being of type "A.object" by using the 
	   -- *view conversion* "A.Object(This)".
      end Serialize;

      procedure Write(This : in Object ) is
      begin
	 Put_Line ("Write (A.Object) called:");	          --  added for example
	 Put_Line( "P1 =" & Natural'Image( This.P1 ) );
	 Put_Line( "P2 =" & Natural'Image( This.P2 ) );
      end Write;
   end A;

   --  In the following fragment i am defining a package B with an
   --  derived objec B.Object as below. When an instance of B.Object
   --  shall be serialized, the element of the super class (A.Object)
   --  shall be serialzed as well. The code looks nice and compiles
   --  but does not work, since the Serialize dispatches again with
   --  Object.B even ther was a a case given  A.Object( This ).

   package B is
      type Object is new A.Object with record
	 Q : Natural := 2;
      end record;

      procedure Write(This : in Object );
   end B;
   -- ..........
   package body B is
      procedure Write(This : in Object ) is
      begin
	 Put_Line ("Write (B.Object) called:");
	 A.Serialize( A.Object( This ) );
	 Put_Line( "Q =" & Natural'Image(This.Q));
      end Write;
   end B;

   --  Does any body know, what this loop causes?! I am not sure
   --  if this is a bug or simply i missed the point.

   --  Michael

   Aobj : A.Object;
   Bobj : B.Object;
   Objs : array (1 .. 4) of A.Class_Access := 
     (new A.Object, new B.Object, new A.Object, new B.Object);
begin
   Put_Line ("Write A");
   A.Write (Aobj);
   New_Line;
   Put_Line ("Write B");
   B.Write (Bobj);
   New_Line;
   Put_Line ("Dispatching calls:");
   for I in Objs'Range loop
      Put_Line ("A.Write (Objs(" & Integer'Image (I) & "))");
      -- This will dispatch, so B.Write will actually be called 
      -- for Objs(2) and Objs(3)
      A.Write (Objs (I).all);
   end loop;
end Test;

-- The preceding program produces the following output when run:
--  Write A
--  Write (A.Object) called:
--  P1 = 1
--  P2 = 2
--
--  Write B
--  Write (B.Object) called:
--  Serialize (Object'Class) called:
--  Write (A.Object) called:
--  P1 = 1
--  P2 = 2
--  Q = 2
--
--  Dispatching calls:
--  A.Write (Objs( 1))
--  Write (A.Object) called:
--  P1 = 1
--  P2 = 2
--  A.Write (Objs( 2))
--  Write (B.Object) called:
--  Serialize (Object'Class) called:
--  Write (A.Object) called:
--  P1 = 1
--  P2 = 2
--  Q = 2
--  A.Write (Objs( 3))
--  Write (A.Object) called:
--  P1 = 1
--  P2 = 2
--  A.Write (Objs( 4))
--  Write (B.Object) called:
--  Serialize (Object'Class) called:
--  Write (A.Object) called:
--  P1 = 1
--  P2 = 2
--  Q = 2



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

* Re: Q: Endless loop by dispatching
  2003-07-11 15:07   ` Michael Erdmann
@ 2003-07-12  1:41     ` Jeffrey Carter
  2003-07-14  8:48     ` Dmitry A. Kazakov
  1 sibling, 0 replies; 35+ messages in thread
From: Jeffrey Carter @ 2003-07-12  1:41 UTC (permalink / raw)


Michael Erdmann wrote:
> 
>    a := next(Attributes(This'Tag))
>    while a /= null loop
>        Write( this.all, a.id );
>        a := next(....);
>    end loop;

When you're in the habit of using "while" loops, you often write code 
like this. When you avoid them, you tend to write

loop
    A := Next (Attributes (This'Tag) );

    exit when a = null;

    Write (This.all, A.ID);
end loop;

which avoids the often dangerous code duplication required by using "while".

-- 
Jeff Carter
"I blow my nose on you."
Monty Python & the Holy Grail




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

* Re: Q: Endless loop by dispatching
  2003-07-11 16:27 ` T. Kurt Bond
@ 2003-07-12  8:37   ` Michael Erdmann
  2003-07-15  7:11     ` Kenneth Almquist
  0 siblings, 1 reply; 35+ messages in thread
From: Michael Erdmann @ 2003-07-12  8:37 UTC (permalink / raw)
  To: T. Kurt Bond

T. Kurt Bond wrote:

Thanks. In fact i have now selected this aproach. Each package
derives from the base type (A.Object) is forced to implement
a procedure Serialize by definint it in A as abstract.

The bad thing about it, is that i wanted to add some code
which is common to all implementation of A.Object in the
Central Serialize procedure (e.g. writing the attrbiute
name if ront of every field of B.Object) Now i have to duplicate
this code in all implementations of A.Object.

Some time i am realy wondering if there is something like

     Serialize( Super(This) ...)

is missing, which is realy the tag of the superclass of
B.Object.

Thanks
    Michael



> -- Michael Erdmann <michael.erdmann@snafu.de> asked in message 
> -- news:<un82u-4kb.ln1@boavista.snafu.de> about redispatching on 'Class types,
> -- which was causing his program to loop endlessly.
> --
> -- Here's a program that includes his example code and does what (I think) 
> -- he wants.
> --
> with Ada.Text_IO; use Ada.Text_IO;
> procedure Test is
>    --  From: Michael Erdmann <michael.erdmann@snafu.de>
>    --  Subject: Q: Endless loop by dispatching
>    --  Newsgroups: comp.lang.ada
>    --  Date: Fri, 11 Jul 2003 10:22:54 +0200
>    --  Organization: [Posted via] Inter.net Germany GmbH
> 
>    --  Dear all,
> 
>    --  i got a problem with the following code fragment below. The Idea is
>    --  that the procedure Serialize defines the strategy how to display
>    --  object which
>    --  are derived from A.Object. Searialize simply dispatches into the class
>    --  by calling a procedure Write, which does the job for the class.
>    package A is
>       type Object is tagged record
> 	 P1 : Natural := 1;
> 	 P2 : Natural := 2;
>       end record;
>       type Class_Access is access Object'Class;	         --  added for example.
> 
>       procedure Write(This : in Object );
>       procedure Serialize(This : in Object'Class );
>    end A;
> 
>    package body A is
>       procedure Serialize(This : in Object'Class ) is
>       begin
> 	 Put_Line ("Serialize (Object'Class) called:");	  --  added for example
> 	 Write( A.Object (This) );	             --  changed for example!!!
> 	   -- Since "This" is at Object'Class, "Write (This)" would dispatch
>            -- on the actual tag of "This", calling "B.Write" for objects of 
> 	   -- type "B.Object", which would call "A.Serialize" again, 
> 	   -- looping forever.  To always call A.Write, construct
> 	   -- a *view* of the object as being of type "A.object" by using the 
> 	   -- *view conversion* "A.Object(This)".
>       end Serialize;
> 
>       procedure Write(This : in Object ) is
>       begin
> 	 Put_Line ("Write (A.Object) called:");	          --  added for example
> 	 Put_Line( "P1 =" & Natural'Image( This.P1 ) );
> 	 Put_Line( "P2 =" & Natural'Image( This.P2 ) );
>       end Write;
>    end A;
> 
>    --  In the following fragment i am defining a package B with an
>    --  derived objec B.Object as below. When an instance of B.Object
>    --  shall be serialized, the element of the super class (A.Object)
>    --  shall be serialzed as well. The code looks nice and compiles
>    --  but does not work, since the Serialize dispatches again with
>    --  Object.B even ther was a a case given  A.Object( This ).
> 
>    package B is
>       type Object is new A.Object with record
> 	 Q : Natural := 2;
>       end record;
> 
>       procedure Write(This : in Object );
>    end B;
>    -- ..........
>    package body B is
>       procedure Write(This : in Object ) is
>       begin
> 	 Put_Line ("Write (B.Object) called:");
> 	 A.Serialize( A.Object( This ) );
> 	 Put_Line( "Q =" & Natural'Image(This.Q));
>       end Write;
>    end B;
> 
>    --  Does any body know, what this loop causes?! I am not sure
>    --  if this is a bug or simply i missed the point.
> 
>    --  Michael
> 
>    Aobj : A.Object;
>    Bobj : B.Object;
>    Objs : array (1 .. 4) of A.Class_Access := 
>      (new A.Object, new B.Object, new A.Object, new B.Object);
> begin
>    Put_Line ("Write A");
>    A.Write (Aobj);
>    New_Line;
>    Put_Line ("Write B");
>    B.Write (Bobj);
>    New_Line;
>    Put_Line ("Dispatching calls:");
>    for I in Objs'Range loop
>       Put_Line ("A.Write (Objs(" & Integer'Image (I) & "))");
>       -- This will dispatch, so B.Write will actually be called 
>       -- for Objs(2) and Objs(3)
>       A.Write (Objs (I).all);
>    end loop;
> end Test;
> 
> -- The preceding program produces the following output when run:
> --  Write A
> --  Write (A.Object) called:
> --  P1 = 1
> --  P2 = 2
> --
> --  Write B
> --  Write (B.Object) called:
> --  Serialize (Object'Class) called:
> --  Write (A.Object) called:
> --  P1 = 1
> --  P2 = 2
> --  Q = 2
> --
> --  Dispatching calls:
> --  A.Write (Objs( 1))
> --  Write (A.Object) called:
> --  P1 = 1
> --  P2 = 2
> --  A.Write (Objs( 2))
> --  Write (B.Object) called:
> --  Serialize (Object'Class) called:
> --  Write (A.Object) called:
> --  P1 = 1
> --  P2 = 2
> --  Q = 2
> --  A.Write (Objs( 3))
> --  Write (A.Object) called:
> --  P1 = 1
> --  P2 = 2
> --  A.Write (Objs( 4))
> --  Write (B.Object) called:
> --  Serialize (Object'Class) called:
> --  Write (A.Object) called:
> --  P1 = 1
> --  P2 = 2
> --  Q = 2




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

* Re: Q: Endless loop by dispatching
  2003-07-11 15:07   ` Michael Erdmann
  2003-07-12  1:41     ` Jeffrey Carter
@ 2003-07-14  8:48     ` Dmitry A. Kazakov
  2003-07-14 18:38       ` Randy Brukardt
  1 sibling, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-14  8:48 UTC (permalink / raw)


On Fri, 11 Jul 2003 17:07:52 +0200, Michael Erdmann
<michael.erdmann@snafu.de> wrote:

>Dmitry A. Kazakov wrote:
>
>>>Does any body know, what this loop causes?! I am not sure
>>>if this is a bug or simply i missed the point.
>> 
>> Serialize is class-wide and a view conversion does not change the
>> tag..I.e. you have a re-dispatching case. Re-dispatching is a
>> dangerous thing. [I would like it removed from Ada]
>> 
>> So Serialize re-dispatches to B.Write which again calls Serialize.
>> From design point of view, one should never call class-wide routines
>> from specific ones, this warranties that dispatch happens only once.
>> 
>> I suppose that you want sort of procedure expansion instead of
>> complete overriding, if so, then you should explicitly call parent's
>> Write, similarly as one does it for Initialize/Finalize:
>> 
>Unfortuantly this was not the complete code. The Serialize was itended
>to do a  more complex job, which i have to replicate any where i want
>to serialize an object. The original serialize code looks some what
>like this:
>
>procedure Serialize( This : in Object'Class ) is
>   ........
>    a := next(Attributes(This'Tag))
>    while a /= null loop
>        Write( this.all, a.id );
>        a := next(....);
>    end loop;
>
>end;
>
>The procedure write is a procedures which  writes out a selected 
>attribute of an object. The procedure Serialize the complete
>object.

Thus from design point of view Write should never call Serialize.

>I would have been great when i could write something
>like this in ada:
>
>procedure Serialize( This : in Object'Class ) is
>
>    Serialize( Super( This ) );
>
>    a := next(Attributes(This'Tag))
>    while a /= null loop
>        Write( this.all, a.id );
>        a := next(....);
>    end loop;
>
>end;

It is a somewhat contradictory code. Serialize is either class-wide,
or not. If it is then it should work for all Object'Class. Then it
should not call itself. If it differs for different types then it has
to be declared as a "normal" subroutine. I would split it in two:

procedure Do_Serialize (This : Object'Class; As_If : Tag) is
begin
   loop
      a := next (Attributes (As_If));
      exit when a = null;
      Write (This, a.id); 
   end loop;
end Do_Serialize;

procedure Serialize (This : in Some_Object) is
begin
   Do_Serialize (This, Parent_Object'Tag);
   Do_Serialize (This, Some_Object'Tag);
end Serialize;

Though it is still a strange thing. Why parent's attributes cannot be
extracted from an object using next? In other words, why do you want
to extend Serialize? Why the following might be insufficient:

procedure Serialize (This : Object'Class) is
begin
   for Attribute in 1..Get_Number_Of_Attributes (This) loop
      Write (This, Attribute); 
   end loop;
end Serialize;

>I think something like this does not exist in Ada!?

Yes it does not.

[Remote things]

I wished Ada's OO be modified,

1. To have stricter contracts. Your case indicates an importance of
contracts. When you write

   Object : constant Parent'Class := Create_Child;
begin
   Foo (Parent (Object)); -- I am not what you think!

you rightfully expect that the result be of Parent. But tagged types
shamelessly break this. The result is not of Parent. It is still of
Child because the conversion does not change the type tag. It is a
clear contract violation, which leads to nasty surprises when later,
in Foo, a re-dispatch happens. The source of the problem is that tag
is a part of the object, so you cannot change it. OO-speaking the
object has an identity which cannot be changed. It might be (and is) a
great problem in other OOPL, but not in Ada which has T and T'Class
different. So one might consistently state that T objects have no
identity at all, while T'Class ones have it (through tag). And note,
that nothing would be lost, because Rosen's trick would still allow
you to add identity at your own risk. Alas, it wasn't made.

If all types will become someday 'tagged', this should be changed. For
present tagged types I would either forbid misleading view conversions
to specific types or at least make them raising Constraint_Error if
the source is not exactly of the target type:

   Parent (Object)
      -- Either illegal or Constraint_Error if not Parent
   Parent'Class (Object)
      -- Legal, and no surpises expected

2. To have an ability to refer the immediate parent [and visible
ancestor] types. However, this feature should be carefully designed to
keep a way free to multiple inheritance. Something like this:

if X in S'Class then X'Super (S) is the most specific ancestor type in
S'Class. For single inheritance case, it is abbreviated to S'Super.

For tags 'Pred and 'Succ attributes should be defined to get tags
along a derivation path:

T'Pred (S) is the tag of a base type in S'Class, T'Succ (S) is the tag
of a derived type in 'not S'Class or S' (all ancestors of S including
S). Constraint_Error if the result does not exist or is ambiguous.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-14  8:48     ` Dmitry A. Kazakov
@ 2003-07-14 18:38       ` Randy Brukardt
  2003-07-15  8:47         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Randy Brukardt @ 2003-07-14 18:38 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:erm4hvsg533tp2hkhsj86tftu0s8i0ot9j@4ax.com...
> 2. To have an ability to refer the immediate parent [and visible
> ancestor] types. However, this feature should be carefully designed to
> keep a way free to multiple inheritance. Something like this:
>
> if X in S'Class then X'Super (S) is the most specific ancestor type in
> S'Class. For single inheritance case, it is abbreviated to S'Super.
>
> For tags 'Pred and 'Succ attributes should be defined to get tags
> along a derivation path:
>
> T'Pred (S) is the tag of a base type in S'Class, T'Succ (S) is the tag
> of a derived type in 'not S'Class or S' (all ancestors of S including
> S). Constraint_Error if the result does not exist or is ambiguous.

We discussed something like this when we were discussing controlling
dispatching. However, there is a significant problem in that a type can have
two (related) parents:

     package P is
        type NT is new T1 with private;
     private
        type NT is new T2 with private;
     end P;

     with P;
     procedure Q is
     begin
            NT'Parent -- ???

Does NT'Parent refer to T1 or T2? If it returns T2, we're breaking
privateness (with all of the methodlogical and implementation problems that
entails). If it returns T1, we're not really getting the right answer, and
moreover, the result changes with visibility (yuck!).

Thus, we haven't really moved forward on this.

                  Randy.






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

* Re: Q: Endless loop by dispatching
  2003-07-12  8:37   ` Michael Erdmann
@ 2003-07-15  7:11     ` Kenneth Almquist
  0 siblings, 0 replies; 35+ messages in thread
From: Kenneth Almquist @ 2003-07-15  7:11 UTC (permalink / raw)


Michael Erdmann <michael.erdmann@snafu.de> wrote:
> Thanks. In fact i have now selected this aproach. Each package
> derives from the base type (A.Object) is forced to implement
> a procedure Serialize by definint it in A as abstract.
>
> The bad thing about it, is that i wanted to add some code
> which is common to all implementation of A.Object in the
> Central Serialize procedure (e.g. writing the attrbiute
> name if ront of every field of B.Object) Now i have to duplicate
> this code in all implementations of A.Object.

The way to avoid duplicate code is to place the code in a generic
procedure which is instantiated for each type.  Something along
the line of:

    package A is

        type Object is tagged private;

        -- Write out all of the attributes of an object.
        procedure Serialize(This : Object);

        -- Write the value of a single attribute.
        procedure Write(This : Object; Attribute : Attribute_Id);

	-- Serialize_Extension for type T writes the attributes
	-- which appear in T type but not in the parent of type T.
	generic
	    type T is new Object with private;
	    Attributes : in Attribute_Array;
	    with procedure Write(This : Object; Attribute : Integer) is <>;
	procedure Serialize_Extension(This : Object);

    end A;


    package B is

        type Object is new A.Object with private;

        -- Write out all of the attributes of an object.
        procedure Serialize(This : Object);

        -- Write the value of a single attribute.
        procedure Write(This : Object; Attribute : Attribute_Id);

    end B;

    package body B is

        My_Attributes : constant Attribute_Array := (...);

        procedure Serialize(This : Object) is
            procedure SE is new Serialize_Extension(Object, My_Attributes);
        begin
            Serialize(A.Object(This));
            SE(This);
        end Serialize;

        procedure Write(This : Object; Attribute : Attribute_Id) is ...;

    end B;


Kenneth Almquist



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

* Re: Q: Endless loop by dispatching
  2003-07-14 18:38       ` Randy Brukardt
@ 2003-07-15  8:47         ` Dmitry A. Kazakov
  2003-07-15 17:23           ` Randy Brukardt
  0 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-15  8:47 UTC (permalink / raw)


On Mon, 14 Jul 2003 13:38:14 -0500, "Randy Brukardt"
<randy@rrsoftware.com> wrote:

>"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>news:erm4hvsg533tp2hkhsj86tftu0s8i0ot9j@4ax.com...
>> 2. To have an ability to refer the immediate parent [and visible
>> ancestor] types. However, this feature should be carefully designed to
>> keep a way free to multiple inheritance. Something like this:
>>
>> if X in S'Class then X'Super (S) is the most specific ancestor type in
>> S'Class. For single inheritance case, it is abbreviated to S'Super.
>>
>> For tags 'Pred and 'Succ attributes should be defined to get tags
>> along a derivation path:
>>
>> T'Pred (S) is the tag of a base type in S'Class, T'Succ (S) is the tag
>> of a derived type in 'not S'Class or S' (all ancestors of S including
>> S). Constraint_Error if the result does not exist or is ambiguous.
>
>We discussed something like this when we were discussing controlling
>dispatching. However, there is a significant problem in that a type can have
>two (related) parents:
>
>     package P is
>        type NT is new T1 with private;
>     private
>        type NT is new T2 with private;
>     end P;
>
>     with P;
>     procedure Q is
>     begin
>            NT'Parent -- ???
>
>Does NT'Parent refer to T1 or T2? If it returns T2, we're breaking
>privateness (with all of the methodlogical and implementation problems that
>entails). If it returns T1, we're not really getting the right answer, and
>moreover, the result changes with visibility (yuck!).
>
>Thus, we haven't really moved forward on this.

Ah, you mean this:

package A is
   type X is tagged null record;
   type XX is new X with null record;
end A;

with A;  use A;
package B is
   type Y is new X with private;
private
   type Y is new XX with null record;
end B;

It is an interesting case. Though I see little harm if Y'Parent would
give different answers depending on scope. It would be indeed nasty if
somebody would try to call Y'Parent.Finalize, but why should one wish
a thing like that? Anyway if he would using explicit type
specification, then he could get nothing better than Y'Parent would
offer. But I agree that it is unattractive.

Probably it is worth to think how to eliminate any need in Y'Parent?
For example one could provide some sort of overriding by extension.
I.e. the bodies which would implicitly call the overriden body, as it
is manually made in Initialize/Finalize.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-15  8:47         ` Dmitry A. Kazakov
@ 2003-07-15 17:23           ` Randy Brukardt
  2003-07-16  8:08             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Randy Brukardt @ 2003-07-15 17:23 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:h5c7hvgol0sscrnaj98qp071903m9hoh5c@4ax.com...
> Probably it is worth to think how to eliminate any need in Y'Parent?
> For example one could provide some sort of overriding by extension.
> I.e. the bodies which would implicitly call the overriden body, as it
> is manually made in Initialize/Finalize.

Interesting idea, but you'd need some way to specify when the overridden
body is called. For instance, you usually call the overridden body first for
Initialize (so the parent components are Initialized before you do anything)
and last for Finalize (so the parent components still exist while you are
writing your code). I've even had a few cases where I had to do it in the
middle (with operations before an after it).

                      Randy.






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

* Re: Q: Endless loop by dispatching
  2003-07-15 17:23           ` Randy Brukardt
@ 2003-07-16  8:08             ` Dmitry A. Kazakov
  2003-07-16 17:44               ` Robert I. Eachus
  2003-07-17  1:57               ` Robert A Duff
  0 siblings, 2 replies; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-16  8:08 UTC (permalink / raw)


On Tue, 15 Jul 2003 12:23:29 -0500, "Randy Brukardt"
<randy@rrsoftware.com> wrote:

>"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>news:h5c7hvgol0sscrnaj98qp071903m9hoh5c@4ax.com...
>> Probably it is worth to think how to eliminate any need in Y'Parent?
>> For example one could provide some sort of overriding by extension.
>> I.e. the bodies which would implicitly call the overriden body, as it
>> is manually made in Initialize/Finalize.
>
>Interesting idea, but you'd need some way to specify when the overridden
>body is called. For instance, you usually call the overridden body first for
>Initialize (so the parent components are Initialized before you do anything)
>and last for Finalize (so the parent components still exist while you are
>writing your code). I've even had a few cases where I had to do it in the
>middle (with operations before an after it).

One should invent a good syntax suggar for this. Which is rather
difficult. There are actually two things in it:

1. There should be a way to declare some primitive operation saying
that it cannot be overriden completely. One might wish it for things
like Initialize/Finalize. Then probably there should be a way to say
where an override is allowed to add something.

2. During overriding one should specifiy where the override(s) places
the extension. I think that it should be specified in the body, while
the specification should only say that it gets overridden.

The question is syntax and a good balance between 1. and 2., i.e
between contract and implementation. The most complicated cases would
emerge from things like Adjust, I suppose.

It is also related to an ability to explicitly specify that a
subroutine is an overriding, not overloading, to avoid undesired
overloading in case ot typo errors. I do not know whether there is an
AI on that. If yes, they should be considered together.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-16  8:08             ` Dmitry A. Kazakov
@ 2003-07-16 17:44               ` Robert I. Eachus
  2003-07-17  1:57               ` Robert A Duff
  1 sibling, 0 replies; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-16 17:44 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> One should invent a good syntax suggar for this. Which is rather
> difficult. There are actually two things in it:

That is putting it VERY mildly.

> 1. There should be a way to declare some primitive operation saying
> that it cannot be overriden completely. One might wish it for things
> like Initialize/Finalize. Then probably there should be a way to say
> where an override is allowed to add something.
> 
> 2. During overriding one should specifiy where the override(s) places
> the extension. I think that it should be specified in the body, while
> the specification should only say that it gets overridden.
> 
> The question is syntax and a good balance between 1. and 2., i.e
> between contract and implementation. The most complicated cases would
> emerge from things like Adjust, I suppose.

 > It is also related to an ability to explicitly specify that a
 > subroutine is an overriding, not overloading, to avoid undesired
 > overloading in case ot typo errors. I do not know whether there is an
 > AI on that. If yes, they should be considered together.


There is an AI on this  (AI-218).  If you try to follow the discussion, 
you eyes will quickly glaze over.  It needs to be fixed, it probably 
will be fixed, but there is a slight problem.  There can be multiple 
views of a subprogram declaration, and in some views it will be 
overriding, while in others it is not.  This is both why a "confirming" 
keyword is currently the leading candidate for Ada0Y, and why it is so 
hard. We don't want a solution that requires a programmer to explicitly 
confirm the wrong view:

package P is

    type T is tagged private;

private

    type T is new Ada.Finalization.Controlled with...;

end P;

package P.Q is

   type NT is new T;

   procedure Initialize(X: in out NT); -- overriding?  Not here.

private
   -- but it is here.

   procedure Finalize(X: in out NT); -- overriding?  Yes, and here.

end P.Q;

I favor the pragma solution, because you can put the pragma at the point 
where it says "but it is here," and not confuse anyone.  Most ARG 
members seem to prefer the keyword solution, which requires an "extra" 
declaration at that point just to use the keyword.

Note that 90% of the potential uses are simple.  The other 10% are cases 
where the compiler will probably end up providing education to Ada 
programmers.  Getting that education as painless as possible is the real 
problem.

-- 

                                                        Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-16  8:08             ` Dmitry A. Kazakov
  2003-07-16 17:44               ` Robert I. Eachus
@ 2003-07-17  1:57               ` Robert A Duff
  2003-07-18  9:10                 ` Dale Stanbrough
  1 sibling, 1 reply; 35+ messages in thread
From: Robert A Duff @ 2003-07-17  1:57 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes:

> One should invent a good syntax suggar for this. Which is rather
> difficult. There are actually two things in it:
> 
> 1. There should be a way to declare some primitive operation saying
> that it cannot be overriden completely. One might wish it for things
> like Initialize/Finalize. Then probably there should be a way to say
> where an override is allowed to add something.
> 
> 2. During overriding one should specifiy where the override(s) places
> the extension. I think that it should be specified in the body, while
> the specification should only say that it gets overridden.

Common Lisp (CLOS) has some stuff like this.

> The question is syntax and a good balance between 1. and 2., i.e
> between contract and implementation. The most complicated cases would
> emerge from things like Adjust, I suppose.
> 
> It is also related to an ability to explicitly specify that a
> subroutine is an overriding, not overloading, to avoid undesired
> overloading in case ot typo errors. I do not know whether there is an
> AI on that. If yes, they should be considered together.

Yes, there is such an AI.

- Bob



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

* Re: Q: Endless loop by dispatching
  2003-07-17  1:57               ` Robert A Duff
@ 2003-07-18  9:10                 ` Dale Stanbrough
  2003-07-18 20:26                   ` Robert I. Eachus
  0 siblings, 1 reply; 35+ messages in thread
From: Dale Stanbrough @ 2003-07-18  9:10 UTC (permalink / raw)


Robert A Duff <bobduff@shell01.TheWorld.com> wrote:


> > It is also related to an ability to explicitly specify that a
> > subroutine is an overriding, not overloading, to avoid undesired
> > overloading in case ot typo errors. I do not know whether there is an
> > AI on that. If yes, they should be considered together.
> 
> Yes, there is such an AI.

Does it cover the opposite where due to a typo you haven't overridden a 
subprogram?

Dale



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

* Re: Q: Endless loop by dispatching
  2003-07-18  9:10                 ` Dale Stanbrough
@ 2003-07-18 20:26                   ` Robert I. Eachus
  2003-07-18 21:35                     ` tmoran
  2003-07-19 14:44                     ` Chad R. Meiners
  0 siblings, 2 replies; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-18 20:26 UTC (permalink / raw)


Dale Stanbrough wrote:

> Does it cover the opposite where due to a typo you haven't overridden a 
> subprogram?

That is the major impetus behind it.  If you think you are overriding, 
and the compiler doesn't, there is an error.  It can be in your 
understanding of the situation, the compiler's understanding, or just be 
a typo.

The problem is, as I said is WHERE the declaration is overriding. I 
created an example:
--------------------------------------------------------------------------

Now my head really hurts!  Are you saying that the original derived 
Finalize declaration really can't be overridden and that in this case 
(or in this case with Finalize spelled right) dispatching still calls 
the implicit operation?  I hope not, and that this is just semantics.

Let me create a better example (in current Ada):

  with Ada.Finalization;
  package Root is
    type Root_Type is tagged private;
    function Value (Object : Root_Type) return Integer;
    procedure Set (Object : in out Root_Type; Value: in Integer);
  private
     type Root_Type is new Ada.Finalization.Controlled with record
       Init_Case: Integer := 3; end record;
    procedure Initialize (Object : in out Root_Type); -- 1
    -- Finalization hidden in private part to since Controlled is
    -- hidden.
  end Root;

  package body Root is
    function Value (Object : Root_Type) return Integer
    is begin return Object.Init_Case; end Value;

    procedure Set (Object : in out Root_Type; Value: in Integer) is
    begin Object.Init_Case := Value; end Set;

    procedure Initialize (Object : in out Root_Type) is
    begin Object.Init_Case := 1; end Initialize;

  end Root;

  with Root;
  package Leaf is
    type Derived_Type is new Root.Root_Type with null record;
    -- derived type is known to be tagged but not controlled.
    procedure Initialize (Object : in out Derived_Type); -- 2
    -- Tucker says this is not overriding, right?
  end Leaf;

  package body Leaf is
    procedure Initialize (Object : in out Derived_Type)
    is begin Set(Object, 2); end Initialize;
  end Leaf;

  with Leaf;
  with Ada.Text_IO; use Ada.Text_IO;
  procedure Sample is
       Obj : Leaf.Derived_Type; -- Which Initialize gets called?
  begin
    case Leaf.Value(Obj) is
    when 1 => Put_Line(" Root.Initialize Called.");
    when 2 => Put_Line(" Leaf.Initialize Called.");
    when 3 => Put_Line(" No initialization!");
    when others => Put_Line(" I give up!");
    end case;
  end Sample;

E:\Ada\Test\AI-218>sample
  Leaf.Initialize Called.

At least GNAT agrees with me. ;-)  Seriously I think that Tucker may be 
correct, "by the book."  But to not be able to declare Leaf.Initialize 
as overriding defeats the whole point.  Sigh.  So now even if we adopt 
my solution or the new syntax, we still have to change 7.3.1 to get the 
definition of overriding to agree with the (to me) commonsense definition.

------------------------------------------------------------------------

As you will see if you read the whole discussion, other compilers do NOT 
agree with me.  For some reason Tucker's compiler agrees with him. ;-) 
And of course, I haven't submitted this as a bug against GNAT until the 
AI as a whole is resolved.

Incidently I am posting this here to give the spectators a view of what 
is going on.  This is a hard and non-trivial issue.  It might be nice if 
in the final version, declaring Leaf.Initialize to be overriding could 
"pierce the privateness" and cause it to be so.  I went out of my way in 
writing this code, so that there is no location where Leaf.Initialize is 
overriding.  (At least as Tucker and the RM seem to currently define 
overriding.)  But as I say, the (very hard) issue is to come up with a 
way to do add the overriding keyword so that it helps users overall. 
The "little test" of putting the overriding declaration in the right 
place is a potential huge pain to users. (If Leaf was a child of Root, 
then Initialize would be overriding in the body and in the private part 
of Leaf if there was one.  Obviously in that case declaring 
Leaf.Initialize as non-overriding helps no one.)

-- 

                                                        Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-18 20:26                   ` Robert I. Eachus
@ 2003-07-18 21:35                     ` tmoran
  2003-07-19  0:25                       ` Robert I. Eachus
  2003-07-19 14:44                     ` Chad R. Meiners
  1 sibling, 1 reply; 35+ messages in thread
From: tmoran @ 2003-07-18 21:35 UTC (permalink / raw)


  What was programmer of Root trying to accomplish when he said
>   type Root_Type is tagged private;
  It seems to me he was trying to say "If you declare a child type
and procedures Initialize or Finalize or Adjust, don't expect them
to be called as if Root_Type was Controlled.  If he wanted to let
derived types be Controlled, he should have said:
>   type Root_Type is new Ada.Finalization.Controlled with private;

> But to not be able to declare Leaf.Initialize
> as overriding defeats the whole point.
  Defeats what point?



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

* Re: Q: Endless loop by dispatching
  2003-07-18 21:35                     ` tmoran
@ 2003-07-19  0:25                       ` Robert I. Eachus
  2003-07-19  2:30                         ` tmoran
  0 siblings, 1 reply; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-19  0:25 UTC (permalink / raw)


tmoran@acm.org wrote:
>   What was programmer of Root trying to accomplish when he said
> 
>>  type Root_Type is tagged private;

He was trying to demonstrate an obscure point about the current 
definition of overriding.  I typically say that, for most Ada 
programmers 10% of the Reference Manual is relevant, the rest explains 
in gruesome detail what will happen if you try to shoot yourself in the 
foot. The ARG combs through that ninety percent, finds the one percent 
where it is not clear which foot you should hit and worries about it for 
years.  Example programs like this, and like most of the ACATS tests are 
about consistently hitting the same toe when you miss what you are 
aiming at.

Only a small very fun part of the job is adding new features to the 
language.  (But for every new useful feature, there are also at least 
ten new ways to shoot at your feet.   So the big part of the job is 
corralling all those nasal daemons.

>   It seems to me he was trying to say "If you declare a child type
> and procedures Initialize or Finalize or Adjust, don't expect them
> to be called as if Root_Type was Controlled.  If he wanted to let
> derived types be Controlled, he should have said:
> 
>>  type Root_Type is new Ada.Finalization.Controlled with private;

Could have, should have, will learn to.  All irrelevant, as I said, the 
discussion on this starts with the assumptions of gun and foot.  The ARG 
wants to make the foot smaller and the gun harder to point at your own 
body.  But we are only human, the solutions are imperfect, and somewhere 
out there is a bigger fool than I can imagine.  I have to content myself 
with saving those I can hope to understand.

There is another thread about let me find it:

--------- test.ads ---------

with System.Storage_Elements; use System.Storage_Elements;
package Test is
     type A is
	record
	    I: Integer;
	end record;
     B: A;
     J: Integer renames B.I;
     for J'Address use To_Address(0);
end Test;

---------------------------

What was the author of this code TRYING to do?  I have yet to answer 
that one.  If there is a real need here, I should try to find some 
answer other than, "You may be entitled to a better error message."

Does RM 13.3(12) explicitly disallow this case? Yes.

Address may be specified for stand-alone objects and for program units 
via an attribute_definition_clause.

Stand-alone object is a technical term defined in RM 3.3.1(1): "An 
object_declaration declares a stand-alone object with a given nominal 
subtype..."

Since J is declared by a renaming declaration, it is not a stand-alone 
object.

And per 13.3(5), the RM decides where a non-implementation defined 
attribute can appear in an attribute definition clause.

>>But to not be able to declare Leaf.Initialize
>>as overriding defeats the whole point.
> 
>   Defeats what point?

In this case the idea of extending the language to allow the programmer 
to state whether he expects the declaration to be overriding.  Making 
something overriding and only allowing a user to declare it as 
non-overriding clearly defeats that intent.  So most of the discussion 
is about how to allow these declarations to be true.  No, I'm not crazy 
and it is hard.  Remember any changes that affect real software out in 
the world require a huge benefit.  So we want to fix this without 
breaking what exists.

Note that for this particular example I wrote, whatever is decided will 
break it.  But that is fine.  It was written only for exploratory 
reasons, and whatever the final resolution is, ALL compilers will 
produce the same output.

-- 

                                                        Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-19  0:25                       ` Robert I. Eachus
@ 2003-07-19  2:30                         ` tmoran
  2003-07-19  5:48                           ` Robert I. Eachus
  0 siblings, 1 reply; 35+ messages in thread
From: tmoran @ 2003-07-19  2:30 UTC (permalink / raw)


> >   What was programmer of Root trying to accomplish when he said
> >
> >>  type Root_Type is tagged private;
>
> He was trying to demonstrate an obscure point
 ;)
But to rephrase the question: Why would an application programmer write
  type Root_Type is tagged private;
instead of
  type Root_Type is new Ada.Finalization.Controlled with private;
unless he specifically did not want derived types to do their own
Initialize et al.  As I understand:
>     -- derived type is known to be tagged but not controlled.
>     procedure Initialize (Object : in out Derived_Type); -- 2
>     ...
>        Obj : Leaf.Derived_Type; -- Which Initialize gets called?
>   Leaf.Initialize Called.
>
> At least GNAT agrees with me. ;-)
you and Gnat believe that
  type Root_Type is tagged private;
  type Root_Type is new Ada.Finalization.Controlled with private;
should be equivalent, right?  It seems to me that additional ways to
say the same thing are of modest value, while ways to say something
different are of greater value, so I would want those two declarations
to accomplish different, not the same, things.



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

* Re: Q: Endless loop by dispatching
  2003-07-19  2:30                         ` tmoran
@ 2003-07-19  5:48                           ` Robert I. Eachus
  2003-07-21  8:38                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-19  5:48 UTC (permalink / raw)


tmoran@acm.org wrote:

>   type Root_Type is tagged private;
>   type Root_Type is new Ada.Finalization.Controlled with private;
> should be equivalent, right?  It seems to me that additional ways to
> say the same thing are of modest value, while ways to say something
> different are of greater value, so I would want those two declarations
> to accomplish different, not the same, things.

No I believe that having TWO dispatching operations named Initialize, 
and which one is called depends on whether the call is implicit or 
explicit is potentially confusing to users.  The same effect occurs if 
you have two objects with default initializations, and the one in the 
package spec calls one version of Initialize, and the one in the package 
calls a different Initialize.

This as I said was a small program to demonstrate where the people on 
both sides of the discussion weren't "getting it."  I wanted to 
demonstrate that even if everyone did have the identical understanding 
of the overridding rules, these funny cases do exist.  (Remember the 
part about users shooting themselves in the foot.)  And in the worst 
cases, the point at which the overriding occurs does affect run-time 
behavior.

The fact that I tripped over a case where compilers disagree tells us 
(the ARG) two things:

1) There is definitely a problem.
2) If it was a serious problem, users would have already run into it.

I can't testify that users hadn't tripped over it before, but now it is 
definitely out in the open.

Which rule do you prefer:

1) All objects of a type derived from Ada.Finalization.Controlled by 
default call the same version of Initialize?

or

2) Information hiding in effect AT THE PLACE OF THE CALL can determine 
which version of a subprogram is called?

If you vote for 2), I won't argue, I'll take it as data.  The important 
part for the ARG is that in this (foot shooting) case we have to choose. 
  The two alternatives are clearly incompatible, and that is what the 
program was written to demostrate.

-- 

                                                        Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-18 20:26                   ` Robert I. Eachus
  2003-07-18 21:35                     ` tmoran
@ 2003-07-19 14:44                     ` Chad R. Meiners
  2003-07-20 12:36                       ` Robert I. Eachus
  1 sibling, 1 reply; 35+ messages in thread
From: Chad R. Meiners @ 2003-07-19 14:44 UTC (permalink / raw)


"Robert I. Eachus" <rieachus@attbi.com> wrote in message
news:3F1857E4.60702@attbi.com...
> At least GNAT agrees with me. ;-)  Seriously I think that Tucker may be
> correct, "by the book."  But to not be able to declare Leaf.Initialize
> as overriding defeats the whole point.  Sigh.  So now even if we adopt
> my solution or the new syntax, we still have to change 7.3.1 to get the
> definition of overriding to agree with the (to me) commonsense definition.

Well one problem is that some people (as in me) think that Tucker's behavior
is common sense. Although either way, it is best to have the compilers agree
;)

-CRM





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

* Re: Q: Endless loop by dispatching
  2003-07-19 14:44                     ` Chad R. Meiners
@ 2003-07-20 12:36                       ` Robert I. Eachus
  0 siblings, 0 replies; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-20 12:36 UTC (permalink / raw)


Chad R. Meiners wrote:

> Well one problem is that some people (as in me) think that Tucker's behavior
> is common sense. Although either way, it is best to have the compilers agree
> ;)

On most every issue debated in the ARG, the actual decision made is 
almost a detail.  The important parts are to make sure that everyone 
understands the issue, that we don't create new issues when fixing a 
current one, and to cover all cases.

I personally think that the effort needed to allow support two 
dispatching operations of the same name, and which one gets called 
depends on the place in the text of the call is unnecessary overhead. 
(Note that having several dispatching operations with the same name, and 
determining which is called by a view conversion is clearly necessary. 
The surprise in this case is that there is no view conversion needed.)

But again, any case where this comes up is expected to be one where the 
user is unintentionally shooting himself in the foot.  The intent of 
adding pragma Overriding or the overriding keyword is to allow the user 
to detect such cases at compile time.  THAT is the important part of the 
AI.  This particular example arose when I was demonstrating that there 
are cases of overriding where there would be no reasonable place to put 
the pragma or keyword.  It turned out that in this particular case, I 
was right to be wrong.  I understood the rules the way GNAT implements 
them, while others compilers do it differently.

I think that the final resolution will be to read things the way Tuck 
was arguing, with possibly a few "extra" words to insure that the only 
cases where the dual meanings arise are in package specs. I don't think 
we want a Beaujolais-like effect, where adding a with clause can change 
which version gets called.

-- 

                                                        Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-19  5:48                           ` Robert I. Eachus
@ 2003-07-21  8:38                             ` Dmitry A. Kazakov
  2003-07-21 10:08                               ` Robert I. Eachus
  0 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-21  8:38 UTC (permalink / raw)


On Sat, 19 Jul 2003 05:48:23 GMT, "Robert I. Eachus"
<rieachus@attbi.com> wrote:

>1) All objects of a type derived from Ada.Finalization.Controlled by 
>default call the same version of Initialize?

Which one version? How a public part might know that there is a
privately declared Initialize?

>or
>
>2) Information hiding in effect AT THE PLACE OF THE CALL can determine 
>which version of a subprogram is called?

For good or bad, but this was the intention, i.e. to hide Initialize
and here you are.

>If you vote for 2), I won't argue, I'll take it as data.  The important 
>part for the ARG is that in this (foot shooting) case we have to choose. 
>  The two alternatives are clearly incompatible, and that is what the 
>program was written to demostrate.

IMO the problem is that you can have both an overloading in the public
part and an overriding in the private. This is a nasty problem,
because:

1<-->A. if we prohibit this, we would expose something from the
private part;

2<-->B. if we accept this, we have pitfalls as your example shows.

I think that the syntax should clearly distinguish declaring a
primitive (and thus overriding) vs. non-primitive (overloading)
subprogram. Further, no matter how painful it could be, one should
probably outlaw non-primitive subprograms with tagged non-class-wide
arguments. This again would solve little as long as a type can be
publicly non-tagged, being tagged privately. So again I have to repeat
the same old slogan: ALL TYPES BE TAGGED!

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



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

* Re: Q: Endless loop by dispatching
  2003-07-21  8:38                             ` Dmitry A. Kazakov
@ 2003-07-21 10:08                               ` Robert I. Eachus
  2003-07-21 13:21                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-21 10:08 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

>>1) All objects of a type derived from Ada.Finalization.Controlled by 
>>default call the same version of Initialize? 
> 
> Which one version? How a public part might know that there is a
> privately declared Initialize?
> 
>>or
>>
>>2) Information hiding in effect AT THE PLACE OF THE CALL can determine 
>>which version of a subprogram is called?
> 
> For good or bad, but this was the intention, i.e. to hide Initialize
> and here you are.

Yep.

> I think that the syntax should clearly distinguish declaring a
> primitive (and thus overriding) vs. non-primitive (overloading)
> subprogram. Further, no matter how painful it could be, one should
> probably outlaw non-primitive subprograms with tagged non-class-wide
> arguments.

Actually the syntax is such that it is very difficult to have tagged 
types which are not publically tagged.  (I used to drive Tuck crazy, I 
think, during the Ada 9X process with examples using generic 
instantiations to get a type declared as "type Visible is private;" but 
which was actually a tagged type.  But let's leave those cases aside for 
a moment.  The real devilish problem occurs when the public type is tagged:

    type Public is tagged private;

    procedure Initialize(X: in out Public);

and the full declaration:

    type Public is new Ada.Finalization.Controlled with...

results in a subprogram becoming overriding in part of its scope.  That 
is what pushes for choice 1 above.  It is clear that currently 2 is 
intended by the RM, but if anyone finds themselves in this mess the 
likelihood that they will "get it right" is low.  (Remember, not even 
GNAT does.)  Also note that, in the above example, declaring Initialize 
(publicly) non-overriding is actively harmful.

I've suggested a "will override" choice for the pragma or keyword.  But 
as you say, that exposes what the programmer obviously knows is going to 
happen in the private part.  Note that there are cases where you have a 
child package containing a type derived from a private type in the 
parent package, and where you NEED for the "will override" operation to 
be public.  It is not an easy problem.

-- 

                                            Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-21 10:08                               ` Robert I. Eachus
@ 2003-07-21 13:21                                 ` Dmitry A. Kazakov
  2003-07-21 18:51                                   ` Robert I. Eachus
  0 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-21 13:21 UTC (permalink / raw)


On Mon, 21 Jul 2003 10:08:45 GMT, "Robert I. Eachus"
<rieachus@attbi.com> wrote:

>Dmitry A. Kazakov wrote:
>
>>>1) All objects of a type derived from Ada.Finalization.Controlled by 
>>>default call the same version of Initialize? 
>> 
>> Which one version? How a public part might know that there is a
>> privately declared Initialize?
>> 
>>>or
>>>
>>>2) Information hiding in effect AT THE PLACE OF THE CALL can determine 
>>>which version of a subprogram is called?
>> 
>> For good or bad, but this was the intention, i.e. to hide Initialize
>> and here you are.
>
>Yep.
>
>> I think that the syntax should clearly distinguish declaring a
>> primitive (and thus overriding) vs. non-primitive (overloading)
>> subprogram. Further, no matter how painful it could be, one should
>> probably outlaw non-primitive subprograms with tagged non-class-wide
>> arguments.
>
>Actually the syntax is such that it is very difficult to have tagged 
>types which are not publically tagged.  (I used to drive Tuck crazy, I 
>think, during the Ada 9X process with examples using generic 
>instantiations to get a type declared as "type Visible is private;" but 
>which was actually a tagged type.  But let's leave those cases aside for 
>a moment.  The real devilish problem occurs when the public type is tagged:
>
>    type Public is tagged private;
>
>    procedure Initialize(X: in out Public);
>
>and the full declaration:
>
>    type Public is new Ada.Finalization.Controlled with...
>
>results in a subprogram becoming overriding in part of its scope.  That 
>is what pushes for choice 1 above.  It is clear that currently 2 is 
>intended by the RM, but if anyone finds themselves in this mess the 
>likelihood that they will "get it right" is low.  (Remember, not even 
>GNAT does.)  Also note that, in the above example, declaring Initialize 
>(publicly) non-overriding is actively harmful.

Ah, and people are still claiming that multiple inheritance is a bad
thing! Now look at this "single" inheritance. Actually, it is
multiple! You declare, publicly, that X has Initialize, this is the
interface No.1. Then in the private part you derive from
Ada.Finalization.Controlled, but this is the interface No.2. Now you
want to reconcile both having only single [interface] inheritance? It
is a clear contradiction. Should we have solved MI, the above were for
free.

Another evil is that constructors/destructors are exposed as "normal"
operations having some special semantincs attached to them *depending*
on the context. This also won't work. The word "Initialize" suddenly
becomes some very special for the compiler in the private part, being
just a name in the public one. If it were just a procedure Foo, one
could probably live with it.

>I've suggested a "will override" choice for the pragma or keyword.  But 
>as you say, that exposes what the programmer obviously knows is going to 
>happen in the private part.

IMO it should be illegal with any pragma:

package A is
   type Public is tagged private;
   procedure Initialize(X: in out Public);
private
   type Public is new Ada.Finalization.Controlled with...
      -- Error public and private views are incompatible!
end A;

It could be made legal only if primitive operation disallowing were
supported:

package A is
   type Public is tagged private;
   procedure Initialize(X: in out Public);
private
   type Public is new Ada.Finalization.Controlled with...
   procedure Ada.Finalization.Controlled.Initialize
      (X: in out Public) is null; -- Down with it!
   -- Fine, now both views are compatible
end A;

A more interesting case:

package AA is
   type Public is tagged private;
private
   type Public is new Ada.Finalization.Controlled with...
end AA;

with AA;  use AA;
package B is
   type Public_Public is new Public with private;
   procedure Initialize(X: in out Public_Public);
      -- This is legal. B knows nothing about Public's origin
      -- so it cannot misuse it
private
   type Public_Public is new Public with ...
end B

package AA.C is
   type Private_Public is new Public with private;
   procedure Initialize(X: in out Public_Public);
      -- This is an error. C knows Public's private, so
      -- its private part is illegal
private
   type Private_Public is new Public with ...
end AA.C

> Note that there are cases where you have a 
>child package containing a type derived from a private type in the 
>parent package, and where you NEED for the "will override" operation to 
>be public.  It is not an easy problem.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-21 13:21                                 ` Dmitry A. Kazakov
@ 2003-07-21 18:51                                   ` Robert I. Eachus
  2003-07-22  7:41                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Robert I. Eachus @ 2003-07-21 18:51 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> Another evil is that constructors/destructors are exposed as "normal"
> operations having some special semantincs attached to them *depending*
> on the context. This also won't work. The word "Initialize" suddenly
> becomes some very special for the compiler in the private part, being
> just a name in the public one. If it were just a procedure Foo, one
> could probably live with it.

Initialize (and for that matter Ada.Finalization) is just a convenient 
scapegoat to use in examples.  The problems can occur with any 
predefined operations of a tagged type.  (But there is this one package 
in the RM that declares tagged types which is why it tends to get used 
in examples.)

> IMO it should be illegal with any pragma:
> 
> package A is
>    type Public is tagged private;
>    procedure Initialize(X: in out Public);
> private
>    type Public is new Ada.Finalization.Controlled with...
>       -- Error public and private views are incompatible!
> end A;
> 
> It could be made legal only if primitive operation disallowing were
> supported:

That is an interesting approach.  I can't see justifying disallowing it 
entirely, but saying that:

    not overriding procedure Initialize(X: in out Public);
    -- or whatever syntax is chosen

becomes illegal in the private part might be a good idea.  At least it 
prevents the misleading use of the keywords.  If we still have "may 
override" and add my "will override" then the programmer gets to choose 
what to say publicly, which is nice, and still get the advantage of the 
compiler checking his assertions.

> A more interesting case:
> 
> package AA is
>    type Public is tagged private;
> private
>    type Public is new Ada.Finalization.Controlled with...
> end AA;
> 
> with AA;  use AA;
> package B is
>    type Public_Public is new Public with private;
>    procedure Initialize(X: in out Public_Public);
>       -- This is legal. B knows nothing about Public's origin
>       -- so it cannot misuse it
> private
>    type Public_Public is new Public with ...
> end B
> 
> package AA.C is
>    type Private_Public is new Public with private;
>    procedure Initialize(X: in out Public_Public);
>       -- This is an error. C knows Public's private, so
>       -- its private part is illegal
> private
>    type Private_Public is new Public with ...
> end AA.C

Change Private_Public to new Public_Public with private and you will 
begin to understand the problem.  AA.C.Initialize would override 
B.Initialize everywhere, but would only override AA.Initalize, assuming 
that there is one, in some areas of its scope.

-- 

                                                        Robert I. Eachus

�In an ally, considerations of house, clan, planet, race are 
insignificant beside two prime questions, which are: 1. Can he shoot? 2. 
Will he aim at your enemy?� -- from the Laiden novels by Sharon Lee and 
Steve Miller.




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

* Re: Q: Endless loop by dispatching
  2003-07-21 18:51                                   ` Robert I. Eachus
@ 2003-07-22  7:41                                     ` Dmitry A. Kazakov
  2003-07-22 10:36                                       ` Lutz Donnerhacke
  0 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-22  7:41 UTC (permalink / raw)


On Mon, 21 Jul 2003 18:51:34 GMT, "Robert I. Eachus"
<rieachus@attbi.com> wrote:

>Dmitry A. Kazakov wrote:
>
>> Another evil is that constructors/destructors are exposed as "normal"
>> operations having some special semantincs attached to them *depending*
>> on the context. This also won't work. The word "Initialize" suddenly
>> becomes some very special for the compiler in the private part, being
>> just a name in the public one. If it were just a procedure Foo, one
>> could probably live with it.
>
>Initialize (and for that matter Ada.Finalization) is just a convenient 
>scapegoat to use in examples.  The problems can occur with any 
>predefined operations of a tagged type.

Yes, but for Initialize/Finalize the consequences are usually
catastrophic. This is why I would prefer either a special syntax (C++
way), or a more general approach with overriding by extension. Which
can be later well re-used:

1. for user-defined aggregates, if they come;
2. for overriding entry points of tagged tasks, if ...;
3. for overriding operations of tagged protected objects, if ...;

>(But there is this one package 
>in the RM that declares tagged types which is why it tends to get used 
>in examples.)
>
>> IMO it should be illegal with any pragma:
>> 
>> package A is
>>    type Public is tagged private;
>>    procedure Initialize(X: in out Public);
>> private
>>    type Public is new Ada.Finalization.Controlled with...
>>       -- Error public and private views are incompatible!
>> end A;
>> 
>> It could be made legal only if primitive operation disallowing were
>> supported:
>
>That is an interesting approach.  I can't see justifying disallowing it 
>entirely, but saying that:
>
>    not overriding procedure Initialize(X: in out Public);
>    -- or whatever syntax is chosen
>
>becomes illegal in the private part might be a good idea.  At least it 
>prevents the misleading use of the keywords.  If we still have "may 
>override" and add my "will override" then the programmer gets to choose 
>what to say publicly, which is nice, and still get the advantage of the 
>compiler checking his assertions.
>
>> A more interesting case:
>> 
>> package AA is
>>    type Public is tagged private;
>> private
>>    type Public is new Ada.Finalization.Controlled with...
>> end AA;
>> 
>> with AA;  use AA;
>> package B is
>>    type Public_Public is new Public with private;
>>    procedure Initialize(X: in out Public_Public);
>>       -- This is legal. B knows nothing about Public's origin
>>       -- so it cannot misuse it
>> private
>>    type Public_Public is new Public with ...
>> end B
>> 
>> package AA.C is
>>    type Private_Public is new Public with private;
>>    procedure Initialize(X: in out Public_Public);
>>       -- This is an error. C knows Public's private, so
>>       -- its private part is illegal
>> private
>>    type Private_Public is new Public with ...
>> end AA.C
>
>Change Private_Public to new Public_Public with private and you will 
>begin to understand the problem.  AA.C.Initialize would override 
>B.Initialize everywhere, but would only override AA.Initalize, assuming 
>that there is one, in some areas of its scope.

If you mean this:

with B; use B;
package AA.D is
   type Private_Public_Public is new Public_Public with ...;
end AA.D;

then it should be again a compile error, because AA.C "knows" that
Public_Public has a private Initialize which collides with the public
one. The rule is simple - there should be no way to create a context
where both versions of Initialize could be visible.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-22  7:41                                     ` Dmitry A. Kazakov
@ 2003-07-22 10:36                                       ` Lutz Donnerhacke
  2003-07-22 12:11                                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Lutz Donnerhacke @ 2003-07-22 10:36 UTC (permalink / raw)


* Dmitry A Kazakov wrote:
> On Mon, 21 Jul 2003 18:51:34 GMT, "Robert I. Eachus"
>>Initialize (and for that matter Ada.Finalization) is just a convenient
>>scapegoat to use in examples.  The problems can occur with any
>>predefined operations of a tagged type.
> 
> Yes, but for Initialize/Finalize the consequences are usually
> catastrophic. This is why I would prefer either a special syntax (C++
> way), or a more general approach with overriding by extension. Which
> can be later well re-used:
> 
> 1. for user-defined aggregates, if they come;
> 2. for overriding entry points of tagged tasks, if ...;
> 3. for overriding operations of tagged protected objects, if ...;

How about a fixing rule, which applies at the private syntax element?



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

* Re: Q: Endless loop by dispatching
  2003-07-22 10:36                                       ` Lutz Donnerhacke
@ 2003-07-22 12:11                                         ` Dmitry A. Kazakov
  2003-07-22 12:18                                           ` Lutz Donnerhacke
  0 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-22 12:11 UTC (permalink / raw)


On Tue, 22 Jul 2003 10:36:56 +0000 (UTC), Lutz Donnerhacke
<lutz@iks-jena.de> wrote:

>* Dmitry A Kazakov wrote:
>> On Mon, 21 Jul 2003 18:51:34 GMT, "Robert I. Eachus"
>>>Initialize (and for that matter Ada.Finalization) is just a convenient
>>>scapegoat to use in examples.  The problems can occur with any
>>>predefined operations of a tagged type.
>> 
>> Yes, but for Initialize/Finalize the consequences are usually
>> catastrophic. This is why I would prefer either a special syntax (C++
>> way), or a more general approach with overriding by extension. Which
>> can be later well re-used:
>> 
>> 1. for user-defined aggregates, if they come;
>> 2. for overriding entry points of tagged tasks, if ...;
>> 3. for overriding operations of tagged protected objects, if ...;
>
>How about a fixing rule, which applies at the private syntax element?

Which rule do you mean?

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



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

* Re: Q: Endless loop by dispatching
  2003-07-22 12:11                                         ` Dmitry A. Kazakov
@ 2003-07-22 12:18                                           ` Lutz Donnerhacke
  2003-07-22 14:46                                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Lutz Donnerhacke @ 2003-07-22 12:18 UTC (permalink / raw)


* Dmitry A Kazakov wrote:
> On Tue, 22 Jul 2003 10:36:56 +0000 (UTC), Lutz Donnerhacke
>>How about a fixing rule, which applies at the private syntax element?
>
> Which rule do you mean?

If publicly defined tagged types are fixed at the private syntax element,
there is no possibility to define dispatching procedures and functions
afterwards. Of course, it's not a choice, because it will break existing
programs.



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

* Re: Q: Endless loop by dispatching
  2003-07-22 12:18                                           ` Lutz Donnerhacke
@ 2003-07-22 14:46                                             ` Dmitry A. Kazakov
  2003-07-22 15:11                                               ` Lutz Donnerhacke
  0 siblings, 1 reply; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-22 14:46 UTC (permalink / raw)


On Tue, 22 Jul 2003 12:18:57 +0000 (UTC), Lutz Donnerhacke
<lutz@iks-jena.de> wrote:

>* Dmitry A Kazakov wrote:
>> On Tue, 22 Jul 2003 10:36:56 +0000 (UTC), Lutz Donnerhacke
>>>How about a fixing rule, which applies at the private syntax element?
>>
>> Which rule do you mean?
>
>If publicly defined tagged types are fixed at the private syntax element,
>there is no possibility to define dispatching procedures and functions
>afterwards. Of course, it's not a choice, because it will break existing
>programs.

But what if I need to extend the interface by adding some new
primitive operations?

Or do you mean some sort of interface freezing like Java's "final"? It
will face same problems to be solved:

package A is
   type X is tagged ...;
   procedure Foo (Obj : X);
end A;

package B is
   type XX is new X with ...;
   procedure Foo (Obj : XX) is final; -- No more overridings
end B;

package C is
   type Y is new X with private;
   procedure Foo (Obj : Y); -- Going to override, can I?
private
   type Y is new XX with ...;
      -- Oops, I can't!
end C;

I can only repeat my old thesis: either multiple inheritance allows a
reasonable implementation, or there should be no inheritance at all.

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



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

* Re: Q: Endless loop by dispatching
  2003-07-22 14:46                                             ` Dmitry A. Kazakov
@ 2003-07-22 15:11                                               ` Lutz Donnerhacke
  2003-07-23  8:12                                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 35+ messages in thread
From: Lutz Donnerhacke @ 2003-07-22 15:11 UTC (permalink / raw)


* Dmitry A Kazakov wrote:
> On Tue, 22 Jul 2003 12:18:57 +0000 (UTC), Lutz Donnerhacke
>>If publicly defined tagged types are fixed at the private syntax element,
>>there is no possibility to define dispatching procedures and functions
>>afterwards. Of course, it's not a choice, because it will break existing
>>programs.
>
> But what if I need to extend the interface by adding some new
> primitive operations?

Not possible in the private part. Plain and simple.

package X is
   type T is tagged private;
   function Foo return T; -- Ok.
private -- fix T
   procedure Bar(o : T); -- Fails.
   type T is new Ada.Finalization.Controlled with null record; -- Fails.
end X;

but

package X is
   type T is tagged private;
   function Foo return T;
private -- fix T
   type T is ...
end X;

with X;
package Y is
   type T is new X.T with private;
   procedure Bar(o : T); -- Ok.
private
   type T is new X.T with null record;
end Y;

with X;
package Z is
   [...]
private
   type T is new X.T with null record;
   procedure Bar(o : T); -- Ok.
end Z;



> Or do you mean some sort of interface freezing like Java's "final"?

No.



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

* Re: Q: Endless loop by dispatching
  2003-07-22 15:11                                               ` Lutz Donnerhacke
@ 2003-07-23  8:12                                                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 35+ messages in thread
From: Dmitry A. Kazakov @ 2003-07-23  8:12 UTC (permalink / raw)


On Tue, 22 Jul 2003 15:11:15 +0000 (UTC), Lutz Donnerhacke
<lutz@iks-jena.de> wrote:

>* Dmitry A Kazakov wrote:
>> On Tue, 22 Jul 2003 12:18:57 +0000 (UTC), Lutz Donnerhacke
>>>If publicly defined tagged types are fixed at the private syntax element,
>>>there is no possibility to define dispatching procedures and functions
>>>afterwards. Of course, it's not a choice, because it will break existing
>>>programs.
>>
>> But what if I need to extend the interface by adding some new
>> primitive operations?
>
>Not possible in the private part. Plain and simple.
>
>package X is
>   type T is tagged private;
>   function Foo return T; -- Ok.
>private -- fix T
>   procedure Bar(o : T); -- Fails.
>   type T is new Ada.Finalization.Controlled with null record; -- Fails.
>end X;

But I do need private primitive operations to implement T and note, to
reuse them while implementing the types derived from T. This proposal
in effect would make impossible to have both public and private
operations. This will force a type designer to publish everything
breaking information hiding.

Just ask the question, why

   type T is new Ada.Finalization.Controlled with null record;

was made private? The only answer is: to hide Initialize/Finalize! To
my taste even 3.9.3(10) is too limiting. It should be possible to
declare a private abstract primitive subprogram! For example:

   type T is private abstract tagged private; -- (:-))
private
   type T is abstract tagged ...;
   procedure Write_etc_passwd (This : T) is abstract;

You can derive from T only in a child package. The public declaration
of T shall specify this fact, of course.

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



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

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

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-11  8:22 Q: Endless loop by dispatching Michael Erdmann
2003-07-11  9:46 ` Jean-Pierre Rosen
2003-07-11 15:19   ` Michael Erdmann
2003-07-11 10:01 ` Q: " Dmitry A. Kazakov
2003-07-11 15:07   ` Michael Erdmann
2003-07-12  1:41     ` Jeffrey Carter
2003-07-14  8:48     ` Dmitry A. Kazakov
2003-07-14 18:38       ` Randy Brukardt
2003-07-15  8:47         ` Dmitry A. Kazakov
2003-07-15 17:23           ` Randy Brukardt
2003-07-16  8:08             ` Dmitry A. Kazakov
2003-07-16 17:44               ` Robert I. Eachus
2003-07-17  1:57               ` Robert A Duff
2003-07-18  9:10                 ` Dale Stanbrough
2003-07-18 20:26                   ` Robert I. Eachus
2003-07-18 21:35                     ` tmoran
2003-07-19  0:25                       ` Robert I. Eachus
2003-07-19  2:30                         ` tmoran
2003-07-19  5:48                           ` Robert I. Eachus
2003-07-21  8:38                             ` Dmitry A. Kazakov
2003-07-21 10:08                               ` Robert I. Eachus
2003-07-21 13:21                                 ` Dmitry A. Kazakov
2003-07-21 18:51                                   ` Robert I. Eachus
2003-07-22  7:41                                     ` Dmitry A. Kazakov
2003-07-22 10:36                                       ` Lutz Donnerhacke
2003-07-22 12:11                                         ` Dmitry A. Kazakov
2003-07-22 12:18                                           ` Lutz Donnerhacke
2003-07-22 14:46                                             ` Dmitry A. Kazakov
2003-07-22 15:11                                               ` Lutz Donnerhacke
2003-07-23  8:12                                                 ` Dmitry A. Kazakov
2003-07-19 14:44                     ` Chad R. Meiners
2003-07-20 12:36                       ` Robert I. Eachus
2003-07-11 16:27 ` T. Kurt Bond
2003-07-12  8:37   ` Michael Erdmann
2003-07-15  7:11     ` Kenneth Almquist

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