www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - ALGOL68-like union type switches?

reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Something which randomly occurred to me as a nice thing to have, if only there
is a clean 
way to manage it.  In ALGOL-68 one can do something like this:

# mode node = union (real, int, string);
#
# node n := "1234";
#
# case n in
#   (real r):   printf(($"real: ", d.3d$, r)),
#   (int i):    print(("int: ", i)),
#   (string s): print(("string: ", s))
#   out         print(("?: ", n))
# esac

Which will output the node 'n' differently depending on the type of its
currently bound 
data.  So how do we do this in D?  Right now, its typically emulated with
something like:

# struct Node {
#   static enum : uint { REAL, INT, STR }
#
#   uint type ;
#
#   union {
#     double r ;
#     long   i ;
#     char[] s ;
#   }
# }
#
# Node n = {s : "1234"} ;
#
# switch (n.type) {
#   case Node.REAL : writefln("real: %.3s"    , n.r); break;
#   case Node.INT  : writefln("int: "         , n.i); break;
#   case Node.STR  : writefln("string: \"%s\"", n.s); break;
#
#   default:
#     writefln("?: %X-%X", n.type, n.i);
# }

So close.  Not sure what can be done about it, though.

-- Chris Nicholson-Sauls
Apr 06 2007
next sibling parent Peter Modzelewski <peter.modzelewski gmail.com> writes:
Chris Nicholson-Sauls napisa?(a):
 Something which randomly occurred to me as a nice thing to have, if only 
 there is a clean way to manage it.  In ALGOL-68 one can do something 
 like this:
 
 # mode node = union (real, int, string);
 #
 # node n := "1234";
 #
 # case n in
 #   (real r):   printf(($"real: ", d.3d$, r)),
 #   (int i):    print(("int: ", i)),
 #   (string s): print(("string: ", s))
 #   out         print(("?: ", n))
 # esac
 
 Which will output the node 'n' differently depending on the type of its 
 currently bound data.  So how do we do this in D?  Right now, its 
 typically emulated with something like:
 
 # struct Node {
 #   static enum : uint { REAL, INT, STR }
 #
 #   uint type ;
 #
 #   union {
 #     double r ;
 #     long   i ;
 #     char[] s ;
 #   }
 # }
 #
 # Node n = {s : "1234"} ;
 #
 # switch (n.type) {
 #   case Node.REAL : writefln("real: %.3s"    , n.r); break;
 #   case Node.INT  : writefln("int: "         , n.i); break;
 #   case Node.STR  : writefln("string: \"%s\"", n.s); break;
 #
 #   default:
 #     writefln("?: %X-%X", n.type, n.i);
 # }
 
 So close.  Not sure what can be done about it, though.
 
 -- Chris Nicholson-Sauls

this is also RPC meening of unions iirc , union itself and variable to hold it's type. Something simular also appears in pascal as far as i know. the truth is that you don't always need to know the type. simplest example is union made to easy color menagment union { ubyte[4] rgba; uint intcolor; } so you can put into it a rbga color what is quite easy, and with no cost get it's int equivalent type recognicion of unions would always need to use additional variable beeing a switch for what type is actually held in a union, no matter if it is build in language or decided by programmer. In my opinion building that into language is not a necesserity... the decission should be left in coders hands. Peter
Apr 06 2007
prev sibling next sibling parent Manfred Nowak <svv1999 hotmail.com> writes:
Chris Nicholson-Sauls wrote
[...]
 # case n in

 # switch (n.type) {

 So close.  Not sure what can be done about it, though.

The emulation names the member/field explicitely. This might be a hint, that one needs some type deduction from the case statements inside the scope of the switch. -manfred
Apr 06 2007
prev sibling next sibling parent Reiner Pope <reiner none.com> writes:
To a limited extent, this has been implemented for C++: based on 
Andrei's Generic<Programming> column (in three parts):
http://www.ddj.com/dept/cpp/184403821
http://www.ddj.com/dept/cpp/184403828
http://www.ddj.com/dept/cpp/184403834
The ideas were then implemented at boost::variant:
http://www.boost.org/doc/html/variant.html

There's a much cooler implementation of this in a lot of functional 
languages; see http://en.wikipedia.org/wiki/Algebraic_data_type for 
examples. The pattern matching goes beyond types into a whole lot of 
other things.

I've also tried to implement some kind of thing like this in D with 
mixins and CTFE. It's still a work-in-progress; getting the right 
balance between a nice user-side syntax and not too much details on the 
implementation side is hard. Also, the inability to do variadic 
templates like Variant!("string", type, "string2", type2, "string3", 
type3) is really painful -- mixing types and values doesn't work -- bug 
#586. Also, the alluring AST macros "just round the corner" make it hard 
to spend time on string parsing when a much nicer implementation could 
be possible in the near future. ;P

Cheers,

Reiner
Apr 06 2007
prev sibling parent NevilleDNZ <NevilleD.digitalmars sgr-a.net> writes:
Question: Does this type union in Algol-68 make the language a
"strong-dynamically
typed" language?

After all this type union gives a68 the data security of Pascal, but still
allows
dynamically typed variables to be checked at compile time.

Here is an extract from the Algol 68 specs (aka Algol 68 Final Report) which
gives
a hint of the mind set during design.

0.1.3 Security
ALGOL 68 has been designed in such a way that most syntactical and many other
errors can be detected easily before they lead to calamitous results.
Furthermore,
the opportunities for making such errors are greatly restricted.

On this subject, it seems that Algol-68 even tried to extend "Security" & type
checking into the formating of output.  for example in C you can write:

int i=666; fprint("DCLXVI=%5.2f\n");

This probably wont produce a compiler message, nor a useful result.

Whereas in a68:

INT i=666; printf(($"DCLXVI="g(5,2)$,i))

This intention will be picked up by the compiler and a cast/coersion can be
inserted in the code.

Fortunately c++ manages to side-step the issue: eg

int i=666; cout << "DCLXVI=" << i << "\n";

Cheers
NevilleDNZ
Apr 21 2007