Topic: Tagged Pointers
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Thu, 6 Aug 1992 22:03:42 GMT Raw View
In article <1992Aug5.005116.20757@cadsun.corp.mot.com> shang@corp.mot.com writes:
>>
>I'm looking forword to reading your proposal. I just have not time to prepare
>any formal proposals.
>
OK: BRIEF summary: I'm still working on a proper posting.
[NOT yet anywhere near a formal proposal]
Tagged pointers are declared like this:
[T1, T2, T3, ... Tn]* p;
The pointer p is tagged uninitialised here. You can also use the syntax
B[D1, D2, ... Dn]* b;
where D1..Dn are derived from B.
An ordinary pointer can be used to initialise a tagged pointers, or can
be assigned to one.
double *d;
int a;
[double, float, long, int] *number=d, *ap=&a;
When this happens, the tag is set to remember the type. In any such
assignment or initialisation, the static type of the pointer must
convert unambiguously to one of the tag types, otherwise the
compiler generates an error.
A tagged pointer can be assigned to another of a different type
provided EACH type of the source converts unambiguously to a type
of the target. This is called the 'multiplex' overloading rule.
Whenever a tagged pointer appears as an rvalue, the compiler
automatically generates a 'switch' on the run-time type (tag).
The tagged pointer can be used in any context like this, provided
ALL the cases are legal, and provided function return types are
equal.
f(number);
Resolves to one of
f(int*);
f(double*);
f(float*);
f(long*);
and code is generated for each call, with a switch selecting the
right one at run-time.
This is particularly useful for objects:
p->print(20);
Here 'print' is defined for all of the classes to which p may point.
The return type is void in each case, the argument need not be the same.
In this sense, a tagged pointer is sort of like a template: it causes
a sort of macro expansion at compile time with run-tim SELECTIOn
on the basis of the run-time type. It is completely type safe and
also sound, and extremely fast.
Using two or more tagged pointers in a function call
provides a 'poor mans' version of multiple dispatch. The whole
matrix of cases are considered by the compiler and code generated
automatically to select the appropriate call.
It makes sense to extend templates to handle type lists
so that for example
void increment(T1* t1, T2* t2) { *t1+=*t2; }
increment(p1,p2); //p1,p2 are tagged pointers
generates code for all the cases automatically from the template,
depending on the tagged pointer types of p1 and p2.
Where this is not enough you can use a manual switch. The syntax
is modelled on the exception syntax not the flawed switch statement:
select(p)
type(employee) { p->addbonus(); }
type(casual) { p->payextra();}
type(void) {}
Note that the p in the right hand side has the selected type.
Tagged pointers provide for heterogeneity using a little bit
of run-time information and a lot of genericity.
Tagged pointers are NOT related to tagged unions, a pointer
to a tagged union is not a tagged pointer.
I will leave it to your imagination at the moment to see how
the compiler would implement tagged pointers, and to convince
yourself they do not impose significant overheads unless misused.
They are totally nonessential, like templates they provide a
source code reuse mechanism and save manual coding of lots
of switch statements.
There are many possible extensions to the syntaxes suggested above,
you will note for example that the form
Animal[Wolf, Dog, Cat] * a;
can be used to implement 'fight' and 'mate' on a case by
case basis (via poor mans multiple dispatch),
while preserving the accessibility of the base class
animal, thus alwing both polymorphic operations on animals
as well as heterogenous ones on specific animals.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------