comp.lang.ada
 help / color / mirror / Atom feed
* Membership test problem
@ 1996-10-03  0:00 Joel VanLaven
  1996-10-04  0:00 ` Robert A Duff
  1996-10-04  0:00 ` Brian R. Hanson
  0 siblings, 2 replies; 8+ messages in thread
From: Joel VanLaven @ 1996-10-03  0:00 UTC (permalink / raw)



  I ran into an interesting behavior, only to find that it seems to be
part of the LRM.  This is code that illustrates the problem :

package test1 is
   type tag1 is tagged null record;
   function is_tag1 (object : in tag1) return boolean;
end test1;

package body test1 is
   function is_tag1 (object : in tag1) return boolean is
   begin
      return object in tag1;
   end is_tag1;
end test1;

with test1; use test1;
package test2 is
   type tag2 is new tag1 with null record;
end test2;

with text_io; use text_io;
with test2; use test2;
procedure testit is
   obj : tag2;
begin
   if is_tag1(obj) then
      put_line("obj is tag1? I think not");          -- this happens
   else
      put_line("obj is NOT tag1, as it should be."); -- this doesn't
   end if;
end testit;


  The function is_tag1 is a primitive function of tag1, and so gets
inherited when tag2 is declared.  When called with an object of type
tag2, is_tag1 does a membership test that returns a true (!).  This
is because of 4.5.2:30 which says: (bracketed is mine)

  The tested type is not scalar, [it is] and the value of the
simple_expression satisfies an constraints of the named subtype,
[there are none], and, if the type of the simple_expression is class-wide,
[it is not] the value has a tag that identifies a type covered by the
tested type.

  The problem is that because the function is inherited, object can be
of any type derived from tag1, ie any element of tag1'class.  So, I
think that the meaning of the test should be preserved in this case as
being a tag check.  This would only have to be for inherited subprograms
of course.  Perhaps primitive functions should in part be considered to
operate on tag_t'class (internally) rather than on tag_t as that is really
what they are doing.
-- 
-- Joel VanLaven




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

* Re: Membership test problem
@ 1996-10-04  0:00 Chris Sparks
  1996-10-05  0:00 ` Robert A Duff
  0 siblings, 1 reply; 8+ messages in thread
From: Chris Sparks @ 1996-10-04  0:00 UTC (permalink / raw)



Bob Duff wrote:

> If you want tag1'class, then say so.  What's the problem?

When you replace Joel VanLaven's code

  return object in tag1;

with

  return object in tag1'class;

as he suggests, the result noticed by Joel still happens.

If an object is of type tag2, and tag2 is part of the class for tag1,
then isn't this object in tag1's class?

The solution I found that yields the result that Joel is expecting is
to do the following (All of the code here):

  package test1 is
     type tag1 is tagged null record;
     function is_tag1 (object : in tag1) return boolean;
  end test1;

  package body test1 is
     function is_tag1 (object : in tag1) return boolean is
     begin
        return object in tag1'class;
     end is_tag1;
  end test1;

  with test1; use test1;
  package test2 is
     type tag2 is new tag1 with null record;
     function is_tag1 (object : in tag2) return boolean; <<< ADDED THIS
  end test2;

  with Ada.Tags;
  use type Ada.Tags.Tag;

  package body test2 is                                    <<< ADDED
THIS
     function is_tag1 (object : in tag2) return boolean is <<< ADDED
THIS
     begin                                                 <<< ADDED
THIS
       return object'tag = tag1'tag;                       <<< ADDED
THIS >>>
     end is_tag1;                                          <<< ADDED
THIS
  end test2;                                               <<< ADDED
THIS

  with text_io; use text_io;
  with test2; use test2;
  procedure testit is
     obj : tag2;
  begin
     if is_tag1(obj) then
        put_line("obj is tag1? I think not");          -- this happens
     else
        put_line("obj is NOT tag1, as it should be."); -- this doesn't
     end if;
  end testit;

This seems to work.  If Joel wants to have a subprogram that rejects
objects that aren't of tag1 type explicitly, then he should do the
above.




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

* Re: Membership test problem
  1996-10-03  0:00 Joel VanLaven
@ 1996-10-04  0:00 ` Robert A Duff
  1996-10-04  0:00 ` Brian R. Hanson
  1 sibling, 0 replies; 8+ messages in thread
From: Robert A Duff @ 1996-10-04  0:00 UTC (permalink / raw)



In article <1996Oct3.181107.34729@ocsystems.com>,
Joel VanLaven <jvl@ocsystems.com> wrote:
>      return object in tag1;

If you want tag1'class, then say so.  What's the problem?

- Bob





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

* Re: Membership test problem
  1996-10-03  0:00 Joel VanLaven
  1996-10-04  0:00 ` Robert A Duff
@ 1996-10-04  0:00 ` Brian R. Hanson
  1 sibling, 0 replies; 8+ messages in thread
From: Brian R. Hanson @ 1996-10-04  0:00 UTC (permalink / raw)



Joel VanLaven wrote: 
> package body test1 is
>    function is_tag1 (object : in tag1) return boolean is
>    begin
>       return object in tag1;
>    end is_tag1;
> end test1;

You should have written 
	return tag1'class(object) in tag1;
otherwise object is treated as its declaration in the function header.

-- Brian Hanson
-- brh@cray.com




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

* Re: Membership test problem
  1996-10-04  0:00 Membership test problem Chris Sparks
@ 1996-10-05  0:00 ` Robert A Duff
  1996-10-06  0:00   ` Joel VanLaven
  0 siblings, 1 reply; 8+ messages in thread
From: Robert A Duff @ 1996-10-05  0:00 UTC (permalink / raw)



In article <32551CAB.4910@aisf.com>, Chris Sparks  <sparks@AISF.COM> wrote:
>This seems to work.  If Joel wants to have a subprogram that rejects
>objects that aren't of tag1 type explicitly, then he should do the
>above.

Is *that* what Joel wants?  If so, why not this:

    function Is_Tag1(X: Tag1'Class) return Boolean is
    begin
        return X in Tag1;
    end Is_Tag1;

?  No need for dispatching operations, and overriding, and so forth.

- Bob




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

* Re: Membership test problem
  1996-10-05  0:00 ` Robert A Duff
@ 1996-10-06  0:00   ` Joel VanLaven
  1996-10-07  0:00     ` Tucker Taft
  0 siblings, 1 reply; 8+ messages in thread
From: Joel VanLaven @ 1996-10-06  0:00 UTC (permalink / raw)



Robert A Duff (bobduff@world.std.com) wrote:
: In article <32551CAB.4910@aisf.com>, Chris Sparks  <sparks@AISF.COM> wrote:
: >This seems to work.  If Joel wants to have a subprogram that rejects
: >objects that aren't of tag1 type explicitly, then he should do the
: >above.

: Is *that* what Joel wants?  If so, why not this:

  Sorry for the confusion about what I wanted, and also for my silence on the
issue that I have obviously missed (newsfeed problems).  I already know a
number of rather easy solutions to my "problem" such as:
replace X in Tag1 with Tag1'class(X) in Tag1 or use an explicit tag check ala
X'tag = Tag1'tag.  Thank you for the suggestions, but I fear I did not
express myself properly.  I was confused by the rule because it seems to
interfere with the meaning of the test rather than help enforce it.  The
rule not to do a tag check seems to me to simply be an optimization.  After
all, in non-inherited, cases if the type is a specific type, then the tag
check can be statically shown to work (As far as I know).  I can't see how
the enforcement of a semantics-changing optimization makes sense.  This is
a case where an error might occur and be hidden from the programmer.  It
caught me, I can't explain why it is the way it is, and I would either like
for it to be considered as a defect in the language, or for an explanation
of why I am wrong.  What I want to do can be done other ways.  According to
the LRM, what I did has no meaning whatsoever, X in tag is statically
evaluated to false.  So, I think making it either illegal or giving a
warning would be in order.  Note that if you "try this at home" on GNAT
3.04a at least, it will incorrectly behave as I suggest :)

  Again, sorry for the confusion.
-- 
-- Joel VanLaven




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

* Re: Membership test problem
  1996-10-06  0:00   ` Joel VanLaven
@ 1996-10-07  0:00     ` Tucker Taft
  1996-10-09  0:00       ` Joel VanLaven
  0 siblings, 1 reply; 8+ messages in thread
From: Tucker Taft @ 1996-10-07  0:00 UTC (permalink / raw)



Joel VanLaven (jvl@ocsystems.com) wrote:

: ... I already know a
: number of rather easy solutions to my "problem" such as:
: replace X in Tag1 with Tag1'class(X) in Tag1 or use an explicit tag check ala
: X'tag = Tag1'tag.  Thank you for the suggestions, but I fear I did not
: express myself properly.  I was confused by the rule because it seems to
: interfere with the meaning of the test rather than help enforce it.  The
: rule not to do a tag check seems to me to simply be an optimization.  

The conceptual model is that an expression of a "specific" type does
not have a "Tag" attribute (RM95 3.9(17-18); AARM 3.9(18.a)); a conversion 
to a class-wide type is required to make the Tag visible.  This was 
carried over to membership testing, where an expression of a specific type 
is only tested against the constraints of the tested type; there
is no consideration of the tag.  Optimization concerns have nothing
to do with it.

Similarly, you can't convert an expression of a specific type directly to 
some extension of the type; you must first convert to its class-wide type
to open up the possibility that it might actually "underneath" be
an object of the extended type.

Finally, when you call a dispatching operation, if the controlling 
operand(s) are of a specific type, then the underlying tag of those
operands is irrelevant -- the call is statically bound based on the
specific (compile-time) type of the operand(s).

Hence, as long as you have an expression of a specific type, you
are basically following Ada 83 rules, and tags are irrelevant.
The only way you can reveal the underlying tag is to convert
(explicitly or implicitly) to the class-wide type.

This is a pretty important principle in the Ada 95 model.
One side-effect of this model is that if there are no conversions
to class-wide types anywhere, then tags need not be stored anywhere,
even if you have type extensions.  Again, this is not an optimization,
rather part of the basic conceptual model distinguishing specific
types from class-wide types.

: ... This is
: a case where an error might occur and be hidden from the programmer.  It
: caught me, I can't explain why it is the way it is, and I would either like
: for it to be considered as a defect in the language, or for an explanation
: of why I am wrong.  What I want to do can be done other ways.  According to
: the LRM, what I did has no meaning whatsoever, X in tag is statically
: evaluated to false.  

I don't understand that.  I have lost your original example, so I don't
know whether X was of specific type "tag".  If it was, then "X in tag"
is statically true (presuming tag doesn't have constrained discriminants).
If X is not of specific type "tag", then the membership test is illegal,
since the type of X neither covers nor is covered by "tag" (4.5.2(3)).

Perhaps GNAT has a bug here, if it is allowing "X in tag" when X
is of a specific type that is not the specific type "tag".

: ... So, I think making it either illegal or giving a
: warning would be in order.  

Again, I missed your original note, but it sounds like it might
already be illegal, and GNAT just has a bug.

: ... Note that if you "try this at home" on GNAT
: 3.04a at least, it will incorrectly behave as I suggest :)

Could you repost the original example if you reply to this?

:   Again, sorry for the confusion.
: -- 
: -- Joel VanLaven

-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Cambridge, MA  USA




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

* Re: Membership test problem
  1996-10-07  0:00     ` Tucker Taft
@ 1996-10-09  0:00       ` Joel VanLaven
  0 siblings, 0 replies; 8+ messages in thread
From: Joel VanLaven @ 1996-10-09  0:00 UTC (permalink / raw)



Tucker Taft (stt@houdini.camb.inmet.com) wrote:
[snip]
: The conceptual model is that an expression of a "specific" type does
: not have a "Tag" attribute (RM95 3.9(17-18); AARM 3.9(18.a)); a conversion 
: to a class-wide type is required to make the Tag visible.  This was 
: carried over to membership testing, where an expression of a specific type 
: is only tested against the constraints of the tested type; there
: is no consideration of the tag.  Optimization concerns have nothing
: to do with it.

: Similarly, you can't convert an expression of a specific type directly to 
: some extension of the type; you must first convert to its class-wide type
: to open up the possibility that it might actually "underneath" be
: an object of the extended type.

: Finally, when you call a dispatching operation, if the controlling 
: operand(s) are of a specific type, then the underlying tag of those
: operands is irrelevant -- the call is statically bound based on the
: specific (compile-time) type of the operand(s).

: Hence, as long as you have an expression of a specific type, you
: are basically following Ada 83 rules, and tags are irrelevant.
: The only way you can reveal the underlying tag is to convert
: (explicitly or implicitly) to the class-wide type.

: This is a pretty important principle in the Ada 95 model.
: One side-effect of this model is that if there are no conversions
: to class-wide types anywhere, then tags need not be stored anywhere,
: even if you have type extensions.  Again, this is not an optimization,
: rather part of the basic conceptual model distinguishing specific
: types from class-wide types.

  Interesting.  I missed this whole conceptual framework completely...
The concept seems central to OOP in Ada95 but I guess I either missed
some explanation somewhere or noone told me.  This changes the way I
need to think about object-oriented programming in Ada95.  Is the
intention to make me have to explicitly indicate that I want OO type
things going on like dispatching?  I had previously thought that all
I needed to do to indicate that was declare the type to be tagged.
Now it looks like I need to do that AND put 'class on a large number
of things.  I suppose that makes sense from the point of view of
minimizing the impact of OOP on traditional programmers.  The question
is if this makes sense from the point of view of transferring the
benefits that Ada83 gives to traditional programming to OOP.  Perhaps
it does but for me at least, the question is as yet unanswered.

: : ... This is
: : a case where an error might occur and be hidden from the programmer.  It
: : caught me, I can't explain why it is the way it is, and I would either like
: : for it to be considered as a defect in the language, or for an explanation
: : of why I am wrong.  What I want to do can be done other ways.  According to
: : the LRM, what I did has no meaning whatsoever, X in tag is statically
: : evaluated to false.  

: I don't understand that.  I have lost your original example, so I don't
: know whether X was of specific type "tag".  If it was, then "X in tag"
: is statically true (presuming tag doesn't have constrained discriminants).
: If X is not of specific type "tag", then the membership test is illegal,
: since the type of X neither covers nor is covered by "tag" (4.5.2(3)).

  Sorry, I mis"spoke"... I meant statically evaluated to true.  Consider
it a really bad typo.

[snip]
: Could you repost the original example if you reply to this?

  Ok, for what it's worth, here it is.

package test1 is
   type tag1 is tagged null record;
   function is_tag1 (object : in tag1) return boolean;
end test1;

package body test1 is
   function is_tag1 (object : in tag1)return boolean is
   begin
      return object in tag1;
   end is_tag1;
end test1;

with test1; use test1;
package test2 is
   type tag2 is new tag1 with null record;
end test2;

with text_io; use text_io;
with test2; use test2;
procedure main is
  obj:tag2;
begin
  if is_tag1(obj) then
     put_line("Failed");
  else
     put_line("Passed");
  end if;
end main;

BTW, thank you for the info, it was very helpful and interesting.
-- 
-- Joel VanLaven




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

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

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-10-04  0:00 Membership test problem Chris Sparks
1996-10-05  0:00 ` Robert A Duff
1996-10-06  0:00   ` Joel VanLaven
1996-10-07  0:00     ` Tucker Taft
1996-10-09  0:00       ` Joel VanLaven
  -- strict thread matches above, loose matches on Subject: below --
1996-10-03  0:00 Joel VanLaven
1996-10-04  0:00 ` Robert A Duff
1996-10-04  0:00 ` Brian R. Hanson

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