
Type-safe tagged unions in the D programming language - glazskunrukitis
http://www.deadalnix.me/2013/05/10/type-safe-tagged-union-in-d-programming-language/?wyda
======
tikhonj
I really don't understand why more languages don't include tagged unions.

For one, even in C, most uses of unions fall into two kinds. There are unions
that emulate sub-typing and unions that have a manually implemented tag
system. Basically, C programmers have to work around the language's
deficiencies manually and hope to avoid errors--nothing surprising, I suppose.

More importantly, tagged unions simply make more sense. They are the
mathematical dual of structs, which means that having both exposes a natural
symmetry in language design. And, just like in physics, symmetry almost always
means you're on the right track!

And, of course, once you have tagged unions and structs, you've added
algebraic data types to your language. Now just throw in pattern matching and
you have a basic system that is both safer _and_ more expressive than the
common alternatives. What's not to like?

This is one of the many reasons I'm very excited about Rust and not excited
_at all_ about Go.

~~~
tobinfricke
In what way are tagged unions "the mathematical dual of structs"?

~~~
tikhonj
Structs are an example of a "universal construction" called a _product_. Other
examples of this include cartesian products, logical AND and join in a lattice
(e.g. getting the least upper bound of two partially ordered elements).

For types, this is defined exclusively based on the functions it has. Roughly
speaking, the product of two types A and B is the "simplest" structure that
has a function to A and a function to B--that is, if you imagine a nice
diagram, there is an arrow from A × B to A and an arrow from A × B to B. For
structs, these two functions are just field accesses.

The notion of "simplest" here essentially just means that given any other
object C with these criteria--that is, a function to A and a function to B--
there has to also exist a function C to A × B. I'm skipping some details, but
you should get the general gist.

The notion of duality just means taking the above diagram and flipping all the
arrows. So the co-product of two types A and B is the "simplest" type A + B
that has a function from A to A + B and a function from B to A + B. These
functions correspond to tagging elements from A or B as appropriate.

For logical AND, the dual is logical OR. For getting the least upper bound,
the dual is getting the greatest _lower_ bound. And, following that same
logic, for structs the dual is tagged unions.

I hope that made sense. This is the sort of thing that's _much_ easier to
describe interactively with a whiteboard instead of trying to just use ASCII--
it practically _begs_ me to draw some diagrams, but my ASCII art is simply not
up to par :(.

------
mostly_harmless
D is a great language. I just found out today about a feature called "Uniform
Function Call Syntax" which acts similarly to extension methods in C#.
Essentially, you can call any function with a prototype of:

func(T, ...)

as

t.func(...)

where t is an instance of some type T. This may seem trivial, but it allows
for functions to be added to a class or type which is out of your control.

For example, the function to convert a 'string' to a C-style zero terminated
string is:

toStringz(string s).

calling the function as s.toStringz() has a much more natural feel, and allows
for a much more modular approach than "throw everything in the class", since
it can just simply be added on as a uniform function in another module
(toStringz is a library feature on the concrete string type). This even works
on basic types:

(5.0).sqrt();

!!

~~~
octo_t
Seems like a less type-safe version of Scala's implicit value classes, but I
might be wrong?

~~~
Tobani
It looks pretty similar. I think both mechanisms have pretty much the same
type constraints.

------
com2kid
Kind of sad. I really like tagged types, and I advocate for their usage when
appropriate, but from this article it seems like D doesn't have native support
for them.

I really wish more languages had really simple tagged type support. Sometimes
I don't need full on inheritance, things like packet formats would benefit
greatly from a dead simple minimal implementation.

------
thepumpkin1979
Makes me happy to see more and more topics on D-lang.

~~~
copx
I doubt that is a sign of D finally gathering momentum, though. Just a few D
users discovering hacker news.

D is a failed language design (among countless others) if you ask me. I
remember originally it was meant to be a "cleaned up, modernized C++
replacement" but these days it seems to lack any coherent concept.

Rust certainly runs circles around it if you want a "cleaned up, modernized
C++ replacement" and thus already has much more momentum than - by now old -
D.

Is there any reason to assume that D can still manage to break out of its
"obscure enthusiast language" position? That is not a rhetorical question, I
am genuinely curious.

~~~
WalterBright
The concept of modern D is:

1\. Easy to read and understand code 2\. Provably correct 3\. Industrial
quality

~~~
angersock
That sounds nothing like the C++ I know.

------
gsg
Is this really type safe? Does anything prevent the address of a member being
taken, followed by an assignment to a member of different type (destroying the
validity of the pointer)?

You can make tagged unions type safe if you eliminate storage that is
interpreted in more than one way. You can do it by requiring immutability,
introducing indirection, or by copying the type-variant part. Unless I'm
missing something (very possible), this technique doesn't seem to do any of
those things, so I don't see how it can be sound.

------
lightgreen
This works in C++ just as well:
<http://www.boost.org/doc/libs/1_53_0/doc/html/variant.html>

