comp.lang.ada
 help / color / mirror / Atom feed
* automatic tag conversion?
@ 2003-05-23 23:04 Stephan Heinemann
  2003-05-23 23:57 ` Stephan Heinemann
  0 siblings, 1 reply; 8+ messages in thread
From: Stephan Heinemann @ 2003-05-23 23:04 UTC (permalink / raw)


I would like to convert a Subtype of a tagged Supertype stored in a
variable of Supertype into a variable of Subtype. I do not want to
use the following:

if supervar'Tag = "Subtype" then
	polymorphic(Subtype(supervar));
elsif ...
else ...
end if;

Isn't there anything like:

t: Tag;
subvar: Subtype;
...
t := supervar'Tag;
subvar := t'convert(supervar); -- convert(t, supervar)
polymorphic(subvar);

?

It is because I would like to extend the Supertype and use dynamic
binding / polymorphism for the appropriate variable of Subtype without
having to do this String mess.

Thanks in advance,
Stephan



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

* Re: automatic tag conversion?
  2003-05-23 23:04 automatic tag conversion? Stephan Heinemann
@ 2003-05-23 23:57 ` Stephan Heinemann
  2003-05-24 17:39   ` Georg Bauhaus
  0 siblings, 1 reply; 8+ messages in thread
From: Stephan Heinemann @ 2003-05-23 23:57 UTC (permalink / raw)


Stephan Heinemann <zombie@cs.tu-berlin.de> wrote:

> t: Tag;
> subvar: Subtype;
> ...
> t := supervar'Tag;
> subvar := t'convert(supervar); -- convert(t, supervar)
> polymorphic(subvar);

Of course I don't know what the concrete Subtype is and I don't wanna
know. Therefore the code snippet is wrong. I meant:

polymorphic(t'convert(supervar))

or better and safer (because t may describe a Type not within Supertype)

polymorphic(supervar'TagType)

It is not my lazyness, but I'd like to extend my code without updating
conditionals on Strings. For every new Subtype of Supertype I not only
need to overload the polymorphic procedure but also a String comparation.

Thanks,
Stephan



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

* Re: automatic tag conversion?
  2003-05-23 23:57 ` Stephan Heinemann
@ 2003-05-24 17:39   ` Georg Bauhaus
  2003-05-25 20:59     ` Stephan Heinemann
  0 siblings, 1 reply; 8+ messages in thread
From: Georg Bauhaus @ 2003-05-24 17:39 UTC (permalink / raw)


Stephan Heinemann <zombie@cs.tu-berlin.de> wrote:
: Stephan Heinemann <zombie@cs.tu-berlin.de> wrote:
: 
:> t: Tag;
:> subvar: Subtype;
:> ...
:> t := supervar'Tag;
:> subvar := t'convert(supervar); -- convert(t, supervar)
:> polymorphic(subvar);
: 
: Of course I don't know what the concrete Subtype is and I don't wanna
: know. Therefore the code snippet is wrong. I meant:

If I understand your wording correctly (in Ada, a subtype is
different from a derived type (subtypes add value constraints,
they do not extend)), it might be simpler.
I hope i don't tell matters of course, as I might have missed the
intent of your question.

Consider this small hierarchy.

package R is

   -- a tagged type

   type T is
     tagged record
        null;
     end record;

   function About(it: T) return String;



   type Switch_State is (on, off);
   -- an ad hoc Boolean type, used in the derived type TT

   -- a derived type, extended version of T (what you have called
   -- a subtype, I believe)

   type TT is new T
     with record
        toggle: Switch_State;
     end record;

   function About(it: TT) return String;

end R;

Then, for a variable to be able to represent objects of any type
in this hierarchy, it must either be class-wide, or it
must be an access type (pointer, or reference).

I have tried to make this distintion in the following
snippet:


with R; use R;

procedure U is

   VV: TT;  -- an instance of extended type TT


begin

objects:  -- as opposed to object pointers

    declare
       Current: T := T(VV);
       -- upward conversion, some VV-components gone!
    begin
       -- therefore, the next line doesn't compile, because
       -- it would mean a downward conversion (with missing
       -- TT-components):
       VV := TT(Current);


       -- however, these do compile, because there is a match for every
       -- component needed in a TT instance.

       VV := (Current with toggle => on);
       VV := TT'(Current with toggle => on);
    end objects;


object_pointers:

    declare
       type Poly is access T'class;
       -- Poly values may refer to T-objects or to TT-objects

       a_tt: Poly := new TT;
       a_t: Poly := new T;
    begin
       --  attempts to copy assumed TT values into vv
       vv := TT(a_tt.all);
       vv := TT(a_t.all);  -- tag check will fail at run time
    end object_pointers;

class_wide:    -- (this is probably a very incomplete overview)

    declare
       any1: T'class := TT'(toggle => off);
       any2: T'Class := T'(null record)
    begin
       any1 := any2;  -- run time exception (objects copied, not pointers)
       VV := TT(any1);
    end class_wide;

end U;


HTH,
georg



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

* Re: automatic tag conversion?
  2003-05-24 17:39   ` Georg Bauhaus
@ 2003-05-25 20:59     ` Stephan Heinemann
  2003-05-26  8:29       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 8+ messages in thread
From: Stephan Heinemann @ 2003-05-25 20:59 UTC (permalink / raw)


Georg,

first of all, you are quite right: I should have used the term
"derived type" instead of "subtype". Further I did not explain what
the problem really is forcing you to write a lot of code - sorry
for that.

I actually was not talking about tagged types, access to tagged
types or even class-wide types but about access to all class-wide
types with a given type-identifier.
The problem for which I do not have a good solution until now is
the following:

I am using generic sets like this one:

generic

    type Element is private;

package CNAda.Utils.Sets is

    type Set is private;
    type LookProcedure is access procedure (e: in Element);
    type MapProcedure is access procedure (e: in out Element);

    procedure empty(s: in out Set);
    procedure insert(e: in Element; s: in out Set);
    procedure remove(e: in Element; s: in out Set);

    procedure look(lookp: in LookProcedure; s: in Set);
    procedure map(mapp: in MapProcedure; s: in Set);

private

    type SetElement is
        record
            content: Element;
            prev: Set;
            next: Set;
        end record;

    type Set is access SetElement;

end CNAda.Utils.Sets;

I use the following for instantiation of this package.

    type Node is abstract new Component with private;
    type NodeClassAccess is access all Node'Class;

package NodeClassAccessSets is new CNAda.Utils.Sets(NodeClassAccess);

NodeClassAccessSets.Set is a component within another tagged (record) 
type - a Net.
There are various derived types of Node like Transition, Place and
further Operation, Socket, Port and so on....

I want to apply a LookProcedure on the set for example to
print all elements of this set. There is a primitive operation print
defined on the types within the hierarchy:

procedure print(n: access Node) is abstract;
procedure print(t: access Transition);
procedure print(p: access Place);

...and so on. I want the system to dispatch to the most special variant
of the procedure for the apropriate derived type like:

NodeClassAccessSets.look(print'Access, s);

It is clearly possible to pass in a NodeClassAccess variable with any 
derived *ClassAccess value into a print procedure defined as above even if
the print procedure was not overridden by the new derived type.
The system would always dispatch the most special case, am I right?

But my compiler (gnat 3.13p) does not accept the last statement saying:
cnada-cnets-components.adb:43:38: expected type "LookProcedure" defined at 
cnada-utils-sets.ads:8, instance at cnada-cnets-components.ads:94
cnada-cnets-components.adb:43:38: found type access to "print" defined at 
line 43

So I changed the print procedures to:

procedure print(n: in NodeClassAccess);
procedure print(t: in TransitionClassAccess);
procedure print(p: in PlaceClassAccess);

Now the problematic statement compiles. The first procedure cannot
be abstract anymore because it is the procedure passed as the
LookProcedure. Now the problem is the following: Always the procedure
for the approprate local pointer type of the passed in actual parameter
is taken now.

(1) If I passed in a TransitionClassAccess actual parameter with a derived 
*ClassAccess value the procedure of the former is taken.

(2)
Further I could not pass in a derived *ClassAccess actual parameter 
without having defined a more special print procedure.

(1) forces me to always use the exact *ClassAccess variable for which
I want to apply a procedure. Further it forces me to implement the
procedure for NodeClassAccess which can be used as type for the passed 
in actual parameter (having to ask 'Tag for what is the appropriate
procedure because Node is still abstract and shall be - that was the
problem of my former posting).

(2) forces me to always overide the procedure I want to use.

There will be procedures for which the appropriate variant is much more
important than for print and it would be much less work. 

What can I do to get out of this mess?

Thanks,
Stephan



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

* Re: automatic tag conversion?
  2003-05-25 20:59     ` Stephan Heinemann
@ 2003-05-26  8:29       ` Dmitry A. Kazakov
  2003-05-26 18:16         ` Georg Bauhaus
  0 siblings, 1 reply; 8+ messages in thread
From: Dmitry A. Kazakov @ 2003-05-26  8:29 UTC (permalink / raw)


Stephan Heinemann wrote:

> I am using generic sets like this one:
> 
> generic
>     type Element is private;
> package CNAda.Utils.Sets is
> 
>     type Set is private;
>     type LookProcedure is access procedure (e: in Element);
>     type MapProcedure is access procedure (e: in out Element);
> 
>     procedure empty(s: in out Set);
>     procedure insert(e: in Element; s: in out Set);
>     procedure remove(e: in Element; s: in out Set);
> 
>     procedure look(lookp: in LookProcedure; s: in Set);
>     procedure map(mapp: in MapProcedure; s: in Set);
[...]
> I use the following for instantiation of this package.
> 
>     type Node is abstract new Component with private;
>     type NodeClassAccess is access all Node'Class;
> 
> package NodeClassAccessSets is new CNAda.Utils.Sets(NodeClassAccess);
> 
> NodeClassAccessSets.Set is a component within another tagged (record)
> type - a Net.
> There are various derived types of Node like Transition, Place and
> further Operation, Socket, Port and so on....
> 
> I want to apply a LookProcedure on the set for example to
> print all elements of this set. There is a primitive operation print
> defined on the types within the hierarchy:
> 
> procedure print(n: access Node) is abstract;
> procedure print(t: access Transition);
> procedure print(p: access Place);
> 
> ...and so on. I want the system to dispatch to the most special variant
> of the procedure for the apropriate derived type like:
> 
> NodeClassAccessSets.look(print'Access, s);
> 
> It is clearly possible to pass in a NodeClassAccess variable with any
> derived *ClassAccess value into a print procedure defined as above even if
> the print procedure was not overridden by the new derived type.
> The system would always dispatch the most special case, am I right?

No, Element is of NodeClassAccess which is different from anonymous "access 
Node" (that will dispatch). Thus LookProcedure.all is not dispatching at 
all. However it will be sort of "class-wide" when NodeClassAccess is 
class-wide, as it is. So you practically have everything to make it 
working. Just define a wrapper in the same package, where Node is defined:

procedure Print_Any (Ptr : NodeClassAccess) is
begin
   Print (Ptr); -- Dispatches
end Print_Any;

Then

NodeClassAccessSets.look (Print_Any'Access, s);

should work as expected.

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



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

* Re: automatic tag conversion?
  2003-05-26  8:29       ` Dmitry A. Kazakov
@ 2003-05-26 18:16         ` Georg Bauhaus
  2003-05-26 18:27           ` Georg Bauhaus
  0 siblings, 1 reply; 8+ messages in thread
From: Georg Bauhaus @ 2003-05-26 18:16 UTC (permalink / raw)


Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> wrote:
:> The system would always dispatch the most special case, am I right?
: 
: No, Element is of NodeClassAccess which is different from anonymous "access 
: Node" (that will dispatch). Thus LookProcedure.all is not dispatching at 
: all. However it will be sort of "class-wide" when NodeClassAccess is 
: class-wide, as it is. So you practically have everything to make it 
: working. Just define a wrapper in the same package, where Node is defined:
: 
: procedure Print_Any (Ptr : NodeClassAccess) is
: begin
:   Print (Ptr); -- Dispatches
: end Print_Any;

Yes. I've made something similar, using a slightly modified set with
a generic "look" function,

    generic
       with procedure accessor(e: in Element);
    procedure look(s: in Set);

(and also deriving Node from a Printable abstract tagged type,

   type Printable is abstract tagged private;
   procedure print(p: access Printable) is abstract;
)
Maybe both the Booch components and the Charles library
might provide some ideas (in addition to code :)
of how iteration can be done.

The slight change results in

with Sets;
with nodes; use nodes;

procedure run is  -- testing

   package Node_Sets is new Sets(Element => Node_ptr);

   net: Node_sets.Set;

   procedure print_any(n: Node_ptr) is
   begin
      print(n.all'access);
   end print_any;

   procedure print_all is
      new node_sets.look(accessor => print_any);

begin
   node_sets.insert(new Transition, net);
   node_sets.insert(new Place, net);
   node_sets.insert(new Transition, net);
   node_sets.insert(new Transition, net);
   print_all(net);
end run;

$ ./run
a transition
a transition
a place
a transition
$


Georg



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

* Re: automatic tag conversion?
  2003-05-26 18:16         ` Georg Bauhaus
@ 2003-05-26 18:27           ` Georg Bauhaus
  2003-05-26 20:49             ` Stephan Heinemann
  0 siblings, 1 reply; 8+ messages in thread
From: Georg Bauhaus @ 2003-05-26 18:27 UTC (permalink / raw)


Georg Bauhaus <sb463ba@d2-hrz.uni-duisburg.de> wrote:
: 
:   procedure print_any(n: Node_ptr) is
:   begin
:      print(n.all'access);
:   end print_any;

That should be

       print(n);


:   procedure print_all is
:      new node_sets.look(accessor => print_any);
: 
: begin
:   node_sets.insert(new Transition, net);
:   node_sets.insert(new Place, net);
And maybe: (Hyperway derived from Transition, not overriding print)
   node_sets.insert(new Hyperway, net);
:   node_sets.insert(new Transition, net);
:   print_all(net);
: end run;
 
Still:
: $ ./run
: a transition
: a transition
: a place
: a transition
: $



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

* Re: automatic tag conversion?
  2003-05-26 18:27           ` Georg Bauhaus
@ 2003-05-26 20:49             ` Stephan Heinemann
  0 siblings, 0 replies; 8+ messages in thread
From: Stephan Heinemann @ 2003-05-26 20:49 UTC (permalink / raw)


Thank you Dmitry and Georg! That was exactly what I needed.



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

end of thread, other threads:[~2003-05-26 20:49 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-23 23:04 automatic tag conversion? Stephan Heinemann
2003-05-23 23:57 ` Stephan Heinemann
2003-05-24 17:39   ` Georg Bauhaus
2003-05-25 20:59     ` Stephan Heinemann
2003-05-26  8:29       ` Dmitry A. Kazakov
2003-05-26 18:16         ` Georg Bauhaus
2003-05-26 18:27           ` Georg Bauhaus
2003-05-26 20:49             ` Stephan Heinemann

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