From: Vesa Karvonen (vesa.karvonen_at_[hidden])
Date: 2001-08-29 19:47:24


From: "Douglas Gregor" <gregod_at_[hidden]>
> On Wednesday 29 August 2001 04:06, you wrote:
> > From: "Douglas Gregor" <gregod_at_[hidden]>
> > [... on optional ...]
> >
> > > I was recently working on a variant type that was intended to be created
> > > on the stack. I believe it is possible to do, though it isn't trivial
:).
> >
> > If I understand intention behind 'variant' correctly (I think of 'variant'
> > as a safe union that allows types with constructors and destructors) then
I
> > agree that it should be doable, but it is somewhat tricky to get it right:
> > - alignment
> > - exception safety
> > - safe/unsafe vswitch
>
> Alignment & exception safety are somewhat at odds.
                                                   ^ with each other?
Could you elaborate?

> For instance, if I have a
> variants a and b and I want to swap them, it is tough (maybe impossible?) to
> do this in an exception-safe manner for pathological types.

It seems to me that 'swap', and probably all the other operations as well,
could easily be made exception safe if a 'move' operation would be guaranteed
to be exception safe:

    // pseudo code
    swap(variant t_type t, variant u_type u)
    {
      uninitialized t_type tmp;

      // 3 exception safe moves:
      tmp <- t; // effectively: "new (&tmp) t_type(t); t->~t_type();"
      t <- u;
      u <- tmp;
    }

> Safe vswitch is the easy part :).

Yes, the only difficult part that I can see, at this point, is the syntax (of
both interface and implementation).

> > Now, if understand 'variant' correctly, then it seems to me that
'optional'
> > could be implemented something like this (without run-time overhead on an
> > ideal, but not "magical", compiler):
> >
> > template<class t>
> > struct optional
> > {
> > ...
> > private:
> > variant<t,void> v;
> > };
>
> Yes, though replace "void" with a real (but useless) type, like:
> struct unused {};

hmn... Do you mean that 'void' is an illegal parameter for 'variant'?

What do you think about the following table?

                  default: ctor | type | state
  -----------------------+----------+--------+-------
  optional<t> | lazy | t | empty
  any | lazy | void | empty

Notes:
- 'optional' and 'any' can be 'empty'.
- At this point, to me, the (contained) type of 'optional<t>' always seems to
be 't'.
- 'any' has chosen to use 'void' as the type of the 'empty' state.

Questions:
- Can a 'variant' be 'empty'?
- What is the difference between 'variant' with and without 'void'?

I find it natural to think about 'variant' and 'void' like this:

                  default: ctor | type | state
  -----------------------+----------+--------+-------
  variant<t0,..,tn,void> | lazy | void | empty
  variant<t0,..,tn> | strict | t0 | !empty (always)

[Having 't0' as the default type means just that the default type is chosen
using some simple convention.]

> > - 'variant<T,void>' seems very close to 'optional<T>'.
>
> It is very close semantically.
>
> > - 'variant' and 'any' might or might not make use of some pointer syntax.
>
> Pointer syntax doesn't really make sense for variant or any, because there
is
> no fixed return type for either. For optional and smart pointer, there is
> only one possible type. This I think justifies the syntactic differences.

I was mainly thinking of the following syntax:

    !x ...meaning... x.empty()
    if (x) ...meaning... if (!x.empty())

And possibly:

    0 == x ...meaning... x.empty()
    x == 0 ...meaning... x.empty()

However, the usefulness of the above syntax is not very clear. It seems to me
that 'vswitch' and 'cast' are the proper ways to use 'variant' and probably
'any', too.

Question:
- Is 'void' equivalent to 'empty'?

> > Intent:
> > - optional: signaling errors/uncomputable results, lazy
initialization
> > - variant: safe union ???
> > - any: typeless programming (it seems like a "boxed value")
> > - smart pointer: avoiding resource leaks/automatic finalization, exception
> > safety
>
> variant: discriminated union that also allows non-trivial
> constructors/destructors.

Ok.

> > Initialization:
> > - optional: lazy
> > - variant: ???
> > - any: lazy
> > - smart pointer: strict (or this is how I see the matter)
> >
> > Should 'variant' support lazy initialization? Parhaps variant<> should
> > support being left unitialized only if 'void' is one of the variant types.
>
> variant uses lazy initialization, though I can't say I like it much.
>
> > What about 'any'? Should it be 'any_or_none' or 'optional_any'?
>
> The name "any" seems reasonable...

Yes, I like it best, too. However, with my understanding of English, 'any'
does sort of imply that it is always something, which, in a sense, is not
true, because 'any' can be 'empty'.

> > Copy semantics:
> > - optional: value
> > - variant: value
> > - any: value
> > - smart pointer: reference, destructive copy or value (clone)
>
> Looks good. Not sure I agree with "destructive copy" or "value". I would
just
> say that smart pointers have reference semantics, but for objects with
> managed lifetimes.

Ideally (smart) pointers would simply have reference semantics, but there are
many "smart pointers" out there which make the case more interesting.