comp.lang.ada
 help / color / mirror / Atom feed
* Re: run-time type identification
  1998-09-03  0:00 run-time type identification Bob Fletcher
  1998-09-03  0:00 ` Steve Sabljak
  1998-09-03  0:00 ` Matthew Heaney
@ 1998-09-03  0:00 ` Tucker Taft
  1998-09-03  0:00 ` Samuel Tardieu
  3 siblings, 0 replies; 13+ messages in thread
From: Tucker Taft @ 1998-09-03  0:00 UTC (permalink / raw)


Bob Fletcher (bob@radge.globalnet.co.uk) wrote:

: Is there any equivalent in Ada 95 to the C++ "dynamic_cast" operator?

Absolutely (we had it before they did ;-).  Both the membership
test and type conversion were generalized to provide this
capability in a pretty intuitive (and safe) way.  Any text on Ada 95 OOP 
should explain this pretty thoroughly.  RM95 defines this in 4.5.2(3,4,30) 
and 4.6(23,40).

: For example, say you have a class A, and a derived class A2.
: In the package for class A there is also:
: 	type A_Ptr is access A'Class;
: You can assign an access to an object of class A2 to a variable of type
: A_Ptr, but, as far as I know, cannot then de-reference the A_Ptr in such a
: way that the extra bits of class A2 are accessible.

Given X : A_Ptr, you can convert X.all to A2 and get the extra bits.  E.g.:

   A2(X.all).extra_bits.  

You can also convert X to an access-to-A2 and then dereference 
(implicitly or explicitly).  E.g.:

   A2_Ptr(X).all.extra_bits  
 or 
   A2_Ptr(X).extra_bits

Prior to any of these conversions, you might want to find out
whether X designates an object that has all the desired extra bits.
This is done by:

   if X.all in A2'Class then ...

If it doesn't, and you go ahead and do the conversion, you will
get a Constraint_Error due to the failure of the Tag_Check.

: It seems to me that this is something that would make a lot of sense when
: dealing with class-wide access types, which can easily be used to go up the
: object heirarchy, but not, as far as I know, to go back down, (without
: messing about with unchecked_conversion).

See above and RM95 paragraphs 4.5.2(3,4,30) and 4.6(23,42).  
No need for any messy unchecked_conversions. ;-)

: Bob Fletcher
: bob@radge.globalnet.co.uk

--
-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Burlington, MA  USA
An AverStar Company




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

* run-time type identification
@ 1998-09-03  0:00 Bob Fletcher
  1998-09-03  0:00 ` Steve Sabljak
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Bob Fletcher @ 1998-09-03  0:00 UTC (permalink / raw)


Is there any equivalent in Ada 95 to the C++ "dynamic_cast" operator?

For example, say you have a class A, and a derived class A2.
In the package for class A there is also:
	type A_Ptr is access A'Class;
You can assign an access to an object of class A2 to a variable of type
A_Ptr, but, as far as I know, cannot then de-reference the A_Ptr in such a
way that the extra bits of class A2 are accessible.

It seems to me that this is something that would make a lot of sense when
dealing with class-wide access types, which can easily be used to go up the
object heirarchy, but not, as far as I know, to go back down, (without
messing about with unchecked_conversion).

Bob Fletcher
bob@radge.globalnet.co.uk




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

* Re: run-time type identification
  1998-09-03  0:00 run-time type identification Bob Fletcher
                   ` (2 preceding siblings ...)
  1998-09-03  0:00 ` Tucker Taft
@ 1998-09-03  0:00 ` Samuel Tardieu
  1998-09-03  0:00   ` Bob Fletcher
  3 siblings, 1 reply; 13+ messages in thread
From: Samuel Tardieu @ 1998-09-03  0:00 UTC (permalink / raw)
  To: Bob Fletcher

>>>>> "Bob" == Bob Fletcher <bob@radge.globalnet.co.uk> writes:

Bob> It seems to me that this is something that would make a lot of
Bob> sense when dealing with class-wide access types, which can easily
Bob> be used to go up the object heirarchy, but not, as far as I know,
Bob> to go back down, (without messing about with
Bob> unchecked_conversion).

You can do it in Ada: (pseudo-code that compiles but is obviously incorrect)

package T is
   type A is tagged null record;
   type A2 is new A with null record;
   type A_Ptr is access all A'Class;
   Z : A_Ptr;
   Y : constant A2 := A2 (Z.all);
end T;

Of course, Constraint_Error will be raised if Z.all does not belong to 
A2'Class.

  Sam
-- 
Samuel Tardieu -- sam@ada.eu.org




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

* Re: run-time type identification
  1998-09-03  0:00 ` Samuel Tardieu
@ 1998-09-03  0:00   ` Bob Fletcher
  1998-09-03  0:00     ` Matthew Heaney
  1998-09-03  0:00     ` Fergus Henderson
  0 siblings, 2 replies; 13+ messages in thread
From: Bob Fletcher @ 1998-09-03  0:00 UTC (permalink / raw)


Yeah, this is the problem, there's no way of ensuring the safety of the
operation.

Also, in the code you give, are you certain that any record fields specific
to the class A2 would be copied by the assignment to the constant? It seems
likely to me that they would be lost. (I'll have a try when I get home from
work, as I don't have a compiler here). I imagine that invoking Z.All, in
your example, will return only the class A part of the object, regardless
of whether it is in fact an object of class A2.

As you rightly say, there will be problems if you try to do this in a
situation where you don't know whether the object in question is of the
base class or one of it's derived classes, which is what would really be
useful. The C++ dynamic_cast operator returns a zero (null) pointer if the
object being pointed to is not of the correct class.

Bob Fletcher
bob@radge.globalnet.co.uk
http://www.users.globalnet.co.uk/~radge/

Samuel Tardieu <sam@ada.eu.org> wrote in article 
> 
> You can do it in Ada: (pseudo-code that compiles but is obviously
incorrect)
> 
> package T is
>    type A is tagged null record;
>    type A2 is new A with null record;
>    type A_Ptr is access all A'Class;
>    Z : A_Ptr;
>    Y : constant A2 := A2 (Z.all);
> end T;
> 
> Of course, Constraint_Error will be raised if Z.all does not belong to 
> A2'Class.
> 





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

* Re: run-time type identification
  1998-09-03  0:00 run-time type identification Bob Fletcher
  1998-09-03  0:00 ` Steve Sabljak
@ 1998-09-03  0:00 ` Matthew Heaney
  1998-09-03  0:00   ` Bob Fletcher
  1998-09-03  0:00 ` Tucker Taft
  1998-09-03  0:00 ` Samuel Tardieu
  3 siblings, 1 reply; 13+ messages in thread
From: Matthew Heaney @ 1998-09-03  0:00 UTC (permalink / raw)


"Bob Fletcher" <bob@radge.globalnet.co.uk> writes:

> Is there any equivalent in Ada 95 to the C++ "dynamic_cast" operator?
> 
> For example, say you have a class A, and a derived class A2.
> In the package for class A there is also:
> 	type A_Ptr is access A'Class;
> You can assign an access to an object of class A2 to a variable of type
> A_Ptr, but, as far as I know, cannot then de-reference the A_Ptr in such a
> way that the extra bits of class A2 are accessible.

The syntax is just a normal type cast:

procedure Op (O : A_Ptr) is
 
   O2 : A2 renames A2 (O.all);
begin

This is called a "view conversion."  It gives you an A2 view of object
O.  Of course, if O's type isn't in A2'Class, then you'll get
Constraint_Error.

If you call operations on O2, you'll be calling the primitive
operations for the specific type A2.

However, you probably want to the operations to dispatch.  After all,
the object might be of a specific type that derives from A2:

procedure Op (O : A_Ptr) is

   O2 : A2'Class renames A2'Class (O.all);
begin

This is a view conversion to the class-wide type A2'Class.


You always have membership test available to you:

if O.all in A2 then ...;


if O.all in A2'Class then ...;

> It seems to me that this is something that would make a lot of sense when
> dealing with class-wide access types, which can easily be used to go up the
> object heirarchy, but not, as far as I know, to go back down, (without
> messing about with unchecked_conversion).

A downcast from a class-wide type nearer the root to a type (specific or
class-wide) more away from the root is perfectly legal in Ada95.  No
Unchecked_Conversion is necessary.




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

* Re: run-time type identification
  1998-09-03  0:00   ` Bob Fletcher
  1998-09-03  0:00     ` Matthew Heaney
@ 1998-09-03  0:00     ` Fergus Henderson
  1 sibling, 0 replies; 13+ messages in thread
From: Fergus Henderson @ 1998-09-03  0:00 UTC (permalink / raw)


"Bob Fletcher" <bob@radge.globalnet.co.uk> writes:

>Yeah, this is the problem, there's no way of ensuring the safety of the
>operation.

What's wrong with trying the operation, and catching the exception
if it fails?

>The C++ dynamic_cast operator returns a zero (null) pointer if the
>object being pointed to is not of the correct class.

That's only half the story.  In C++, if you use `dynamic_cast' to
cast to a pointer type, it will return a null pointer if the
cast fails.  But if you use `dynamic_cast' to cast to a reference
type, it will throw an exception (of type `std::bad_cast') if
the cast fails.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3        |     -- the last words of T. S. Garp.




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

* Re: run-time type identification
  1998-09-03  0:00   ` Bob Fletcher
@ 1998-09-03  0:00     ` Matthew Heaney
  1998-09-06  0:00       ` Samuel Tardieu
  1998-09-03  0:00     ` Fergus Henderson
  1 sibling, 1 reply; 13+ messages in thread
From: Matthew Heaney @ 1998-09-03  0:00 UTC (permalink / raw)


"Bob Fletcher" <bob@radge.globalnet.co.uk> writes:

> Yeah, this is the problem, there's no way of ensuring the safety of the
> operation.

No.  If the actual type isn't in A2'Class, then you'll get
Constraint_Error.

> Also, in the code you give, are you certain that any record fields specific
> to the class A2 would be copied by the assignment to the constant? It seems
> likely to me that they would be lost. 

No.

> I imagine that invoking Z.All, in your example, will return only the
> class A part of the object, regardless of whether it is in fact an
> object of class A2.

No.  The type cast to A2 gives you an A2 view of the object.  If O
really is of type A2 (or its descendent), then you'll get all the
fields.

The thing I don't like about Samuel's example is that it makes a copy of
the object:

>    Y : constant A2 := A2 (Z.all);

There is no need for a copy.  Just do a "view conversion":

   Y : A2 renames A2 (Z.all);

or better

   Y : A2'Class renames A2'Class (Z.all);


> As you rightly say, there will be problems if you try to do this in a
> situation where you don't know whether the object in question is of the
> base class or one of it's derived classes, which is what would really be
> useful. The C++ dynamic_cast operator returns a zero (null) pointer if the
> object being pointed to is not of the correct class.

No, there will be _no_ problems.  This is Ada.  If the actual type of
Z.all isn't in A2'Class, then you'll get Constraint_Error.





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

* Re: run-time type identification
  1998-09-03  0:00 ` Matthew Heaney
@ 1998-09-03  0:00   ` Bob Fletcher
  1998-09-03  0:00     ` Matthew Heaney
  0 siblings, 1 reply; 13+ messages in thread
From: Bob Fletcher @ 1998-09-03  0:00 UTC (permalink / raw)


Don't you lose the extra values associated with the derived class though?
Maybe I'm wrong, but I thought that's what would happen.

Matthew Heaney <matthew_heaney@acm.org> wrote in article 
> 
> A downcast from a class-wide type nearer the root to a type (specific or
> class-wide) more away from the root is perfectly legal in Ada95.  No
> Unchecked_Conversion is necessary.
> 




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

* Re: run-time type identification
  1998-09-03  0:00 ` Steve Sabljak
@ 1998-09-03  0:00   ` Matthew Heaney
  1998-09-03  0:00   ` Steve Sabljak
  1 sibling, 0 replies; 13+ messages in thread
From: Matthew Heaney @ 1998-09-03  0:00 UTC (permalink / raw)


sabljak@cs.rmit.edu.au (Steve Sabljak) writes:

> You can do run-time type identification like this
> 
> with Ada.Tags; use Ada.Tags;
> with A;        use A;
> 
> procedure Tag_Test is
> 
>    Generalised   : A_Ptr;   
>    Specialised   : A2_Ptr;   
>    Specialised_2 : A2_Ptr;   
> 
> begin
>    Specialised := new A2'(X => 1, Y => 2);
>    Generalised := Specialised;
>    if Generalised'Tag = A2'Tag then
> 	   Specialised_2 := A2_Ptr(Generalised);
>    end if;
> end Tag_Test;

I prefer to just use a membership test.

To test for membership in the specific type A2:

   if Generalized.all in A2 then

To test for membership in the class-wide type A2'Class:

   if Generalized.all in A2'Class then


Don't bother with the Tag attribute or the package Ada.Tags.

You don't really need the tag test to do the type cast.  If the actual
type of the source object (Generalized.all) isn't in A2'Class, then the
type cast "A2_Ptr(Generalized)" will raise Constraint_Error:












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

* Re: run-time type identification
  1998-09-03  0:00   ` Bob Fletcher
@ 1998-09-03  0:00     ` Matthew Heaney
  0 siblings, 0 replies; 13+ messages in thread
From: Matthew Heaney @ 1998-09-03  0:00 UTC (permalink / raw)


"Bob Fletcher" <bob@radge.globalnet.co.uk> writes:

> Matthew Heaney <matthew_heaney@acm.org> wrote in article 
> > 
> > A downcast from a class-wide type nearer the root to a type (specific or
> > class-wide) more away from the root is perfectly legal in Ada95.  No
> > Unchecked_Conversion is necessary.
> > 
> Don't you lose the extra values associated with the derived class though?
> Maybe I'm wrong, but I thought that's what would happen.

No.  You'd only "lose values" if you chose to view a type as a type
nearer the root.

procedure Op (O : A_Ptr) is 

This is the case here.  If the actual type of O is A2, then you can't
access the A2-specific fields of O, because you're viewing it as a
member of A'Class.
  
The only time data is "lost" is if you make a copy of the object:

procedure Op (O : A_Ptr) is  

   C : constant A := A (O.all);
begin

This is like taking a slice in C++: you get the A-specific part of
object O.all.

That's the reason why I like to use a view conversion instead.  You
always keep all the data, but chose how much of it you like to view.

The declaration

   C : A renames O.all;

gives an A-view of O.

The declaration 

   C : A2 renames A2 (O.all);

gives you an A2-view of O, if O in A2'Class (Constraint_Error
otherwise).




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

* Re: run-time type identification
  1998-09-03  0:00 run-time type identification Bob Fletcher
@ 1998-09-03  0:00 ` Steve Sabljak
  1998-09-03  0:00   ` Matthew Heaney
  1998-09-03  0:00   ` Steve Sabljak
  1998-09-03  0:00 ` Matthew Heaney
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 13+ messages in thread
From: Steve Sabljak @ 1998-09-03  0:00 UTC (permalink / raw)


"Bob Fletcher" <bob@radge.globalnet.co.uk> writes:

>Is there any equivalent in Ada 95 to the C++ "dynamic_cast" operator?

>For example, say you have a class A, and a derived class A2.
>In the package for class A there is also:
>	type A_Ptr is access A'Class;
>You can assign an access to an object of class A2 to a variable of type
>A_Ptr, but, as far as I know, cannot then de-reference the A_Ptr in such a
>way that the extra bits of class A2 are accessible.

>It seems to me that this is something that would make a lot of sense when
>dealing with class-wide access types, which can easily be used to go up the
>object heirarchy, but not, as far as I know, to go back down, (without
>messing about with unchecked_conversion).

You can do run-time type identification like this

with Ada.Tags; use Ada.Tags;
with A;        use A;

procedure Tag_Test is

   Generalised   : A_Ptr;   
   Specialised   : A2_Ptr;   
   Specialised_2 : A2_Ptr;   

begin
   Specialised := new A2'(X => 1, Y => 2);
   Generalised := Specialised;
   if Generalised'Tag = A2'Tag then
	   Specialised_2 := A2_Ptr(Generalised);
   end if;
end Tag_Test;

cheers
-Steve
--
Steve Sabljak - RMIT - 3rd Year Computer Science  
e-mail: sabljak@cs.rmit.edu.au            
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




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

* Re: run-time type identification
  1998-09-03  0:00 ` Steve Sabljak
  1998-09-03  0:00   ` Matthew Heaney
@ 1998-09-03  0:00   ` Steve Sabljak
  1 sibling, 0 replies; 13+ messages in thread
From: Steve Sabljak @ 1998-09-03  0:00 UTC (permalink / raw)


sabljak@cs.rmit.edu.au (Steve Sabljak) writes:

>"Bob Fletcher" <bob@radge.globalnet.co.uk> writes:

>>Is there any equivalent in Ada 95 to the C++ "dynamic_cast" operator?

>>For example, say you have a class A, and a derived class A2.
>>In the package for class A there is also:
>>	type A_Ptr is access A'Class;
>>You can assign an access to an object of class A2 to a variable of type
>>A_Ptr, but, as far as I know, cannot then de-reference the A_Ptr in such a
>>way that the extra bits of class A2 are accessible.

>>It seems to me that this is something that would make a lot of sense when
>>dealing with class-wide access types, which can easily be used to go up the
>>object heirarchy, but not, as far as I know, to go back down, (without
>>messing about with unchecked_conversion).

>You can do run-time type identification like this

>with Ada.Tags; use Ada.Tags;
>with A;        use A;

>procedure Tag_Test is

>   Generalised   : A_Ptr;   
>   Specialised   : A2_Ptr;   
>   Specialised_2 : A2_Ptr;   

>begin
>   Specialised := new A2'(X => 1, Y => 2);
>   Generalised := Specialised;
>   if Generalised'Tag = A2'Tag then
>	   Specialised_2 := A2_Ptr(Generalised);
>   end if;
>end Tag_Test;

Or even

begin
   Specialised := new A2'(X => 1, Y => 2);
   Generalised := Specialised;
   if Generalised.all in A2 then
	   Specialised_2 := A2_Ptr(Generalised);
   end if;
end Tag_Test;

cheers
-Steve
--
Steve Sabljak - RMIT - 3rd Year Computer Science  
e-mail: sabljak@cs.rmit.edu.au            
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




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

* Re: run-time type identification
  1998-09-03  0:00     ` Matthew Heaney
@ 1998-09-06  0:00       ` Samuel Tardieu
  0 siblings, 0 replies; 13+ messages in thread
From: Samuel Tardieu @ 1998-09-06  0:00 UTC (permalink / raw)


>>>>> "Matthew" == Matthew Heaney <matthew_heaney@acm.org> writes:

Matthew> There is no need for a copy.  Just do a "view conversion":

Of course, I was just pointing out that this was feasible :-) My
example was not valid anyway, the pointer was set to null.

  Sam
-- 
Samuel Tardieu -- sam@ada.eu.org




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

end of thread, other threads:[~1998-09-06  0:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-09-03  0:00 run-time type identification Bob Fletcher
1998-09-03  0:00 ` Steve Sabljak
1998-09-03  0:00   ` Matthew Heaney
1998-09-03  0:00   ` Steve Sabljak
1998-09-03  0:00 ` Matthew Heaney
1998-09-03  0:00   ` Bob Fletcher
1998-09-03  0:00     ` Matthew Heaney
1998-09-03  0:00 ` Tucker Taft
1998-09-03  0:00 ` Samuel Tardieu
1998-09-03  0:00   ` Bob Fletcher
1998-09-03  0:00     ` Matthew Heaney
1998-09-06  0:00       ` Samuel Tardieu
1998-09-03  0:00     ` Fergus Henderson

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