Newsgroups: comp.lang.c++
Path: utzoo!utgpu!craig
From: craig@gpu.utcs.utoronto.ca (Craig Hubley)
Subject: Re: asking an object for its type
Message-ID: <1991Feb19.211430.12354@gpu.utcs.utoronto.ca>
Organization: Craig Hubley & Associates
References: <23984@netcom.COM> <1190@sheol.UUCP> <1991Feb19.000449.22255@gpu.utcs.utoronto.ca> <1991Feb19.023528.29494@Think.COM>
Date: Tue, 19 Feb 1991 21:14:30 GMT

In article <1991Feb19.023528.29494@Think.COM> barmar@think.com (Barry Margolin) writes:
>In article <1991Feb19.000449.22255@gpu.utcs.utoronto.ca> craig@gpu.utcs.utoronto.ca (Craig Hubley) writes:
>>Arg.  A totally contextual algorithm.  I do NOT want to write a special
>>function for all shapes to respond to this.  What I would really like to
>>do is something like:
>>	"if x.type=circle then if x.diameter > 30 then return x"
>
>Even in languages that provide a way to do that, you probably wouldn't want
>to write it that way, because it doesn't handle derived classes properly.

In languages that support specification inheritance, x.type=circle
would be true for all types descended from circle.  They would be considered
first-class circles.  Not so in C++.

>For instance, if square is derived from regular_polygon and quadrilateral,
>x.type can't be all three.

To find the exact physical type of something an alternate name is often used:
(e.g. .basetype vs. .Mytype in Trellis).  Kind of like oriental family names,
where your first (and most important) name is your surname, and if you care
to qualify that with your given name you can, and then you are talking about
yourself rather than your family.

To stick to the hopefully-emerging-standard terminology, x.TYPE *can* be
all three (i.e. it answers true to "regular_polygon", "quadrilateral", AND
"square") but x.CLASS *can't* be (it is, physically, a "square").

>What you want is something like
>
>	if x.is_circle() ...
>or
>	if x.is_of_type("circle") ...	[craig:  tag this @]

or	if x.is_derived_from("circle") ... if that guarantees a diameter.

However, in C++ it doesn't, and if you change the class or member name it
gets painful.  A better way would be to check directly for the presence
of a diameter before checking it:

	if x.has_member("diameter") ...

>The latter [craig: @] can be implemented by writing something like
>
>int circle::is_of_type(char *type)
>{
>	return (strcmp(type, "circle") == 0) || shape::is_of_type(type);
>}

Yes, although this is painfully redundant (repeating the name of the class,
and all its bases) it will work for the subclasses too.

>int square::is_of_type(char *type)
>{
>	return (strcmp(type, "square") == 0) ||
>	  quadrilateral::is_of_type(type) ||
>	  regular_polygon::is_of_type(type);
>}

If you just build a function that lists its base types into every class,
you could do this with a template.  Similarly, if you build a function that
lists all public members, you could implement x.has_member("...").

The problem with all this, of course, is that now we are managing information
that the compiler already has, and building many dependencies on base types
into our code, although thankfully this avoids dependencies on derived
types.

>Barry Margolin, Thinking Machines Corp.
>
>barmar@think.com
>{uunet,harvard}!think!barmar


-- 
  Craig Hubley   "...get rid of a man as soon as he thinks himself an expert."
  Craig Hubley & Associates------------------------------------Henry Ford Sr.
  craig@gpu.utcs.Utoronto.CA   UUNET!utai!utgpu!craig   craig@utorgpu.BITNET
  craig@gpu.utcs.toronto.EDU   {allegra,bnr-vpa,decvax}!utcsri!utgpu!craig
