[Nickle]A tale of two unions
Keith Packard
keithp@keithp.com
Mon, 12 Mar 2001 15:32:21 -0800
Nickle currently has two levels of type checking, static typing and pure
polymorphism. In other words, you either get strict compile-time
typechecking or run-time type checking. No middle ground for those
programmers who waffle between the extremes.
I've implemented two different union types to try and reach a compromise.
First, take hints from existing practice.
The first attempt was to take a combination of pascal varient records and
tagged unions from other languages. The goal here is to allow for union
types with compile-time typechecking within explicitly run-time
typechecked blocks.
typedef union {
integer i;
string s;
} string_or_integer;
string_or_integer variable;
variable.i = 10;
variable.s = "hello world";
union switch (variable) {
case i:
printf ("Integer i %g\n", variable.i);
break;
case s:
printf ("String s %g\n", variable.s);
break;
}
While it would be nice within the union switch to refer to the variable
without the tag, there's no effective way of restricting modifications
to the variable that would switch the tags. Hence, this version requires
run-time type checking at each access. Clipping the wings of this could
do something like:
union switch (variable) {
case i:
integer temp = variable.i;
printf ("Integer i %g\n", temp);
break;
case s:
string temp = variable.s;
printf ("String s %g\n", temp);
break;
}
Of course, we could hack this to make 'variable' contain said temporary
value during the varients, but this would make 'variable' unavailable as
an lvalue that referenced the original union.
Back to the drawing board.
It seems to me that the goal of allowing compile-time typechecking
conflicts with the existing 'poly' type within nickle; the benefit of that
type is that it provides easy-to-use syntax along with full run-time
typechecking. The second kind of unions I implemented brings a modicum of
compile-time typechecking to a pure polymorphic world. The goal here is
to allow useful compile-time typechecking along with run-time typechecking
to verify program type-correctness.
typedef union {
integer;
string;
} string_or_integer;
string_or_integer variable;
variable = 10;
variable = "hello world";
typeswitch (variable) {
case integer:
printf ("integer %g\n", variable);
break;
case string:
printf ("string %s\n", variable);
break;
}
Note that this version requires no tags; that's because the interest is in
capturing the essence of pure polymorphism while still providing some
typechecking; pure polymorphism allows untagged access to the value stored
in each location with the type following the value, not the union variable.
There's no problem within the 'typeswitch' statement with capturing the
value of the variable as all accesses must be run-time typechecked in any
case.
It seems to me that this second version captures the usage of pure
polymorphism within nickle while still allowing for useful typechecking to
occur at compile time. Without unduly restricting the 'union switch'
semantics, the first version doesn't offer any significant compile-time or
run-time advantages while requiring additional work and book-keeping to be
done by the programmer.
-keith