* 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-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
* 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
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