Topic: Proposal to allow unions of any data type


Author: skaller@users.sourceforge.net (skaller)
Date: Wed, 26 Jul 2006 06:04:43 GMT
Raw View
On Tue, 25 Jul 2006 09:31:49 -0600, johnchx2 wrote:

> skaller wrote:
>
>> What I care about is simply being able to align a suitable
>> amount of storage for a family of types which are only known
>> symbolically to the compiler.
>
> Have you looked at tr1::alignment_of and tr1::aligned_storage ?

I have looked at boost's version, and in fact a copy of it
is part of the Felix compiler/runtime system. This is a useful facility.
It allows unions of constructable types to be emulated in
a portable manner -- glad to see it is included in tr1.

But it is no substitute for builtin compiler support for the higher
level facility unions provide, any more than it would be a substitute
for structs .. which can also be built from aligned storage and
offset calculations plus casts. Would you give up 'struct'??
No, of course not.

Aligned store is a much lower level facility,
and also has other uses unrelated to unions (eg in wrapping
a storage allocator, the type information can be converted to
numbers to, for example, keep different allocation regions
for each alignment).

One could also say 'tuple' and 'variant' in the style of boost
are higher level facilities than structs and unions, because
they are used combinatorially -- there is no need to declare
each and every struct and union. In effect, they're providing
structural (algebraic) typing, instead of nominal (named)
typing. More precisely they provide canonical nominal types.

It would be great if these combinators actually worked properly,
but two of the 4 required combinators are missing:
lambda abstraction (anonymous functions) and recursion.

Felix is designed specifically to fix these problems, and give
C++ programmers a decent programming language: it takes care
of all the housekeeping needed to provide easy to use safe
tuples, variants, anonymous functions (with lexical scoping),
and recursion.

The *problem* is that in targetting C++ these features
is very hard to support without so much housekeeping it makes
the resulting code totally unreadable, and the same lack
of union's facilities in C++ also gets in the way of properly
optimising stack frame layout.

Given aligned storage tools, it can [almost] be done .. by simply
throwing the type information away to get a POD, then using
unions as they are now over those POD, and then casting
to get the type information back .. in other words, throw
out C++ and just use C :)

[I say 'almost' because it isn't clear this will not STILL suffer
from the lack of type recursion: even though the raw storage
is correctly aligned and sized for a given type, whilst
presenting as a POD, the *argument* to the template must
still be calculated.]

Unfortunately what I found trying to use C++ as a target language
is that there are SOOO many gotcha's and inconsistencies I wished
I'd stuck with C. I had to throw out one after another of the advanced
C++ facilities including almost all use of templates, almost all
use of exceptions, pointers to members, multiple inheritance,
nested classes, and half of namespaces, new style casts,
references (and even 'const'). I actually use

(a) single inheritance with virtual functions
(b) constructors/destructors

and not much else. C with Classes .. :) And both these
features are so easy to emulate in C anyhow .. the only
reason it is worth bothering is it makes embedding C++
a bit easier for the user.

For example it is 'just easier' to synthesise unique global
names than bother with using nested classes and/or namespaces
to reflect Felix names in a corresponding C++ structure.
Since I use a counter .. the names are not canonical which
rules out separate compilation. Of course I also want
'dlopen()' style dynamic loading .. so I even have to throw
out C++ type safe linkage in favour of C linkage .. since there's
no reliable way to 'dlsym()' a C++ symbol.

Most of these problems cannot be fixed, without an advanced
code generator like Felix -- whose primary purpose is indeed
to fix them! But the lack of constructable unions isn't one of them.
That one CAN be fixed AFAICS.. at least there is a technical solution,
which isn't the same as having the required political one:)

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Wed, 26 Jul 2006 06:05:24 GMT
Raw View
On Tue, 25 Jul 2006 11:07:10 -0600, Crosbie Fitch wrote:

>>"skaller" <skaller@users.sourceforge.net> wrote in message

> It is not sensible for a union to have default construction, nor is it
> sensible for it to have methods.

This may well be the case.

> Create 'overlay'
>
> An overlay is identical to an anonymous union except:
> 1) Overlays may only exist as members of classes
> 2) Overlays do not have any methods
> 3) Overlays are not constructed (though if static are memset zero) or
> destroyed
> 4) Overlays with non-pod members require a user defined
> constructor/destructor/copy-assign operator in the enclosing class
> (otherwise memcpy is used)
> 5) Members can be accessed in any order, although if their state data is
> read, behaviour is undefined unless it was initialised by a compatible
> representation (including a derived class) (as per reinterpret_cast).
> 6) Overlays may have any kind of members with no restrictions
> 7) One overlay member may appear in the initialiser list of an enclosing
> class's constructor
> 8) The members of an overlay may have access specifiers

Yes but all of this is a new feature .. and my proposal probably
amounts to the same thing, using the existing union construction.
Check your rules and compare with my proposal .. you'll probably
find they're the equivalent.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Mon, 24 Jul 2006 11:02:56 CST
Raw View
skaller wrote:
> Here is the outline of a proposal to remove the restriction
> on declaring unions of constructable variants.

A restriction is not necessarily an impediment. So removing a
restriction in a programming language is not necessarily making an
improvement to that language. To qualify as an improvement in this
case, it would be necessary to explain how unions with constructible
members would be useful. Unions in general have some notable
shortcomings, so expanding the realm of unions would seem to be making
those shortcomings more prevalent than ever. For example, a union
provides no protection against a program storing a value in one member
and reading it from another. And should a program should do so, it
leaves the realm of defined behavior behind it for good. And what is
the benefit that a union provides to a program, that makes such a risk
even worthwhile to that program?

The answer turns out to be: "none" - "none" meaning not only is there
no benefit from a union to justify the risk of its misuse - but a union
actually provides no unique benefit at all to a C++ program (see
below).

> This proposal is not worded in Standardese, it's just an outline
> in plain language. Motivation is also omitted (separate issue :)
>
> In some cases what I recall the Standard says may be wrong so
> any corrections are of course appreciated.
>
> PROPOSAL (A):
>
> * remove the restriction on declaring
> unions with variants of constructable types
>
> * add a rule which say the compiler will not
> generate a default constructor, copy constructor,
> copy assignment operator, or destructor for
> a union with a constructable type
>
.
>
> PROBLEM: the current C++ standard handles
> the initialisation of a union using ctor-initialisers
> poorly. This is an outstanding defect:
>
> union X {
>   int a;
>   long b;
>   X(): a(1), b(2) {}
> };
>
> Here, a is set to 1, then b is set to 2.
> Clearly this is absurd, however it is merely
> a gratuitous stupidity rather than being a
> problem semantically. If the types are
> constructable, however, this rule would be
> entirely untenable:
>
> union X {
>   string a;
>   vector b;
>   X(): a("") {}
> };
>
> In this case, a is NOT "" after default initialisation,
> rather, b is a zero length vector .. and b clobbers
> the value of a. This is because the standard
> requires ALL the members to be initialised.
> In the POD case, the default constructors are
> trivial and don't do anything, so only explicit
> initialisation have any effect.

What about assignment to the data member "b" after the constructor
initializes of "a" only? Wouldn't "a" be clobbered in the same way?

> PROPOSAL (B):
>
> * fix the rule for initialisation of
> union component by constructors
> to require either no ctor initialiser,
> or exactly one ctor initialiser.

To return to the central question: why is the union even needed to
represent an object of variable value types? What advantages would a
union with constructible types provide that a program written in C++
could not otherwise attain using existing language facilities? About
the only plausible answer is: efficent use of memory. But that answer
is inadequate because unions actually make poor use of memory. A union
can in fact easily waste a lot of memory because the size of a union
has to be large enough to accomodate its largest member, no matter
which member actually stores the value. So whenever a value is assigned
to a union member smaller than the union's largest member - memory is
wasted because the extra bytes allocated go unused.  And given a wide
variation in the size of its members and a large number of union
objects allocated, the amount of memory a union wastes can be
substantial.

A C++ program can implement a variant class to perform the same role as
the union, but one that would use memory far more efficiently than an
equivalent union. As an example, suppose a program needs to fill a
container with a combination of strings or std::vector<int>'s. The
first step would be to declare a base class with the common interface:

    #include <vector>
    #include <string>
    #include <stdexcept>

    // a variant class capable of storing a std::string
    // or a std::vector<int>
    class MultiItem
    {
    public:
        virtual ~MultiItem() {}

        virtual
        std::vector<int>& GetVector()
        {
            // the invalid argument is the implicit
            // "this" parameter
            throw std::invalid_argument("No vector value");
        }

        virtual
        std::string& GetString()
        {
            throw std::invalid_argument("No string value");
        }
    };

Next, declare two subclasses with a data member of the appropriate
type:

    class StringItem : public MultiItem
    {
    public:
        String(const std::string& s) : mString(s) {}

        virtual
        std::string& GetString()
        {
            return mString;
        }
    private:
        std::string mString;
    };

    class VectorItem : public MultiItem
    {
    public:
        String(const std::vector<int>& v) : mVector(v) {}

        virtual
        std::vector<int>& GetVector()
        {
            return mVector;
        }
    private:
        std::vector<int> mVector;
    };

Just as with a union, the C++ class MultiItem allows the program a
choice to access its value either as a std::string or as a std::vector.
In both cases the mechanism by which the program "knows" which member
is valid has not been specified and is assumed to be the same in either
case. So far, the union and C++ class solution are more or less
comparable.

Turning now to memory use and type safety, a clear winner emerges. On
both counts, the hypothetical union solution falls well short of the
C++ class. The union allocates the same amount of memory for each
instance no matter the size of the stored avlue, whereas the C++ class
allocates only as much memory as is needed to store its value. In
addition to being more memory efficient, the C++ class is notably safer
than the union as well. Whereas accessing the "wrong" member of a union
is not a defined operation, the equivalent operation is defined for the
C++ class - and is defined by the program itself (in this example, the
program elects to throw an exception). Being leaner and safer, the C++
class implementation really leaves the hypothetical union
implementation with little left to recommend it.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: musiphil@bawi.org (Seungbeom Kim)
Date: Mon, 24 Jul 2006 19:43:22 GMT
Raw View
Greg Herlihy wrote:
>
> To return to the central question: why is the union even needed to
> represent an object of variable value types? [...]
>
> A C++ program can implement a variant class to perform the same role as
> the union, but one that would use memory far more efficiently than an
> equivalent union. As an example, [... an example using class hierarchy]

I fail to see from your example how to construct objects of different
types and return one of them through a common type from a function. A
class hierarchy often implies object creation on the heap and passing
around the pointers; sometimes this is acceptable, but not always.

If a function has to return either a StringItem or a VectorItem, you
cannot just make its return type [const] MultiItem& and write 'return
StringItem(...);' or 'return VectorItem(...);' inside. Probably the only
solution would be to make its return type a pointer, preferably
std::auto_ptr<MultiItem>, and write 'return std::auto_ptr<StringItem>
(...);', etc. But dynamic allocation each time seems too costly. (Imagine
a lexer function having to return each token by a dynamic allocation!)

I don't know the ultimate solution, though; in my last case where I
needed such a union, I just made it a struct to circumvent the
restrictions on unions at the cost of additional memory usage. I'm
interested in hearing better solutions.

--
Seungbeom Kim

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Mon, 24 Jul 2006 17:41:25 CST
Raw View
Seungbeom Kim wrote:

> I fail to see from your example how to construct objects of different
> types and return one of them through a common type from a function.

Wouldn't boost::variant do the right thing in this context?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Seungbeom Kim <musiphil@bawi.org>
Date: Mon, 24 Jul 2006 18:17:00 CST
Raw View
johnchx2@yahoo.com wrote:
> Seungbeom Kim wrote:
>
>> I fail to see from your example how to construct objects of different
>> types and return one of them through a common type from a function.
>
> Wouldn't boost::variant do the right thing in this context?

Yes. I just don't know how it's implemented; you can assume that I was
talking in the context of how to construct such a facility only from
what's given by the C++ Standard (since it's csc++ here :D).

--
Seungbeom Kim

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Tue, 25 Jul 2006 04:28:07 GMT
Raw View
On Mon, 24 Jul 2006 11:02:56 -0600, Greg Herlihy wrote:

> skaller wrote:
>> Here is the outline of a proposal to remove the restriction
>> on declaring unions of constructable variants.

>> union X {
>>   string a;
>>   vector b;
>>   X(): a("") {}
>> };
>>
>> In this case, a is NOT "" after default initialisation,
>> rather, b is a zero length vector .. and b clobbers
>> the value of a. This is because the standard
>> requires ALL the members to be initialised.
>> In the POD case, the default constructors are
>> trivial and don't do anything, so only explicit
>> initialisation have any effect.
>
> What about assignment to the data member "b" after the constructor
> initializes of "a" only? Wouldn't "a" be clobbered in the same way?

Yes but so what? You're missing the point entirely. The present
rules -- if I'm not mistaken -- REQUIRE the compiler to clobber
each and every variant component in order of writing when
generating any constructor .. the only thing which stops this
physically modifying the user specified value is that POD types
all have 'trivial' constructors that do nothing.

Therefore to support constructable types in unions AT ALL the
rule must be changed. It's clear the current rule is semantic
nonsense that just happens to work because POD trivial constructors
don't modify any store.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Tue, 25 Jul 2006 04:29:31 GMT
Raw View
On Mon, 24 Jul 2006 17:41:25 -0600, johnchx2 wrote:

> Seungbeom Kim wrote:
>
>> I fail to see from your example how to construct objects of different
>> types and return one of them through a common type from a function.
>
> Wouldn't boost::variant do the right thing in this context?

No, because (a) it doesn't support type recursion
and (b) it has an upper limit. It also appears to do
some checking which is exactly what we don't want,
because the design is wrong for a proper discriminated union.

Ignoring those limitations, boost variant could be USED
to define a proper variant type (which is a pair consisting
of a discriminate and an undiscriminated type union).

Remember I am generating correct code using a compiler
written in a high level language -- I'm not interested
in any gratuitous run time checks, and I don't care much
whether such a union can be abused by hand coders.

What I care about is simply being able to align a suitable
amount of storage for a family of types which are only known
symbolically to the compiler.

IF I cared about hand coders I'd propose a proper discriminated
union type for C++. In fact I did just that many years ago
but the committee wasn't interested.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Tue, 25 Jul 2006 00:14:55 CST
Raw View
Seungbeom Kim wrote:
> Greg Herlihy wrote:
> >
> > To return to the central question: why is the union even needed to
> > represent an object of variable value types? [...]
> >
> > A C++ program can implement a variant class to perform the same role as
> > the union, but one that would use memory far more efficiently than an
> > equivalent union. As an example, [... an example using class hierarchy]
>
> I fail to see from your example how to construct objects of different
> types and return one of them through a common type from a function. A
> class hierarchy often implies object creation on the heap and passing
> around the pointers; sometimes this is acceptable, but not always.

I fail to see from the original proposal how to create a union of
constructible types and be able to return that kind of union from a
function call at all. How would the compiler decide which member of the
union object is the one that needed to be copied? And even if it were
possible, wouldn't the union's a copy-by-value operation be
comparatively more expensive than the class's pointer copy?

And in fact it would make sense for the class implementation to add an
extra layer of indirection - by defining a Union class with MultiItem
class object as a member. Must like std::tr1::reference_wrapper a Union
class could have value-like semantics and pointer-type efficiencies. Of
course a full-blown implementation of a Union class would no doubt use
a class template and would carefuly define the appropriate
constructors, copy constructors, assignment operators and the like
needed for its correct operation; so there is no doubt that there would
be a lot of work involved.

But at least a solution seems possible and that is the point to be
made: that at least classes can be used today. On the other hand, there
is nothing in C++ to that would make a union of constructible types
anything but impossible to use. To make such a union the least bit
useful would require that the entire infrastructure that exists for the
management of classes would have be duplicated all over again for this
type of union. And why bother?

> I don't know the ultimate solution, though; in my last case where I
> needed such a union, I just made it a struct to circumvent the
> restrictions on unions at the cost of additional memory usage. I'm
> interested in hearing better solutions.

The ultimate solution is easiest to find by following a natural
progression: define the problem, then describe the requirements for its
solution, next determine whether those requirements can be met with the
existing facilities at one's disposal, and if they can be met, proceed
with implementing a solution. Whereas taking these steps in the
opposite order and direction rarely works out as well.

Greg

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Tue, 25 Jul 2006 05:30:33 GMT
Raw View
On Mon, 24 Jul 2006 19:43:22 +0000, Seungbeom Kim wrote:

> Greg Herlihy wrote:
>>
>> To return to the central question: why is the union even needed to
>> represent an object of variable value types? [...]

If you don't understand how to use them .. don't use them!

>> A C++ program can implement a variant class to perform the same role as
>> the union, but one that would use memory far more efficiently than an
>> equivalent union. As an example, [... an example using class hierarchy]
>
> I fail to see from your example how to construct objects of different
> types and return one of them through a common type from a function. A
> class hierarchy often implies object creation on the heap and passing
> around the pointers; sometimes this is acceptable, but not always.

This is indeed the 'solution' the Felix compiler uses at the
moment for variants, and it sucks bigtime, in particular it
incurs a memory management problem -- Felix runs a garbage collector,
so the heap objects get reclaimed, but the current overhead on amd64
is 48 bytes per object. If you add the malloc/free time in .. you
can see you would not want to use this in a performance critical
function .. especially a recursive one.

In this case, a void* is used and cast to the right
type, so there is no loss of 'safety' -- remember the code
is all machine generated.

For stack frame allocation Felix it uses a struct .. wasting
vital storage (and also possibly wasting time initialising
some of the objects).

It is possible in this case for the compiler to
try to reuse a C++ variable for two distinct Felix variables
of the same type .. but it would just be better to use a union,
because that guarantees close to optimal storage use whilst
still providing correct alignment, and allows the components
to be referred to in the generated code with reasonably clear,
cast free, notation.

It is possible to emulate the behaviour now, by
'casting' the types to boost::aligned_storage<T> which
is a POD, and thence making them into a union, and finally
casting them to the right type when referring to them.

However aligned_storage<> isn't portable, and using it like
this increases the size and decreases the readability of
generated code significantly .. and probably defeats easy debugging
using a debugger.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Tue, 25 Jul 2006 14:36:57 GMT
Raw View
On Tue, 25 Jul 2006 00:14:55 -0600, Greg Herlihy wrote:

> Seungbeom Kim wrote:
>> Greg Herlihy wrote:
>> >
>> > To return to the central question: why is the union even needed to
>> > represent an object of variable value types? [...]
>> >
>> > A C++ program can implement a variant class to perform the same role as
>> > the union, but one that would use memory far more efficiently than an
>> > equivalent union. As an example, [... an example using class hierarchy]
>>
>> I fail to see from your example how to construct objects of different
>> types and return one of them through a common type from a function. A
>> class hierarchy often implies object creation on the heap and passing
>> around the pointers; sometimes this is acceptable, but not always.
>
> I fail to see from the original proposal how to create a union of
> constructible types and be able to return that kind of union from a
> function call at all. How would the compiler decide which member of the
> union object is the one that needed to be copied?

The same way it always does .. by calling the copy constructor.

If the user doesn't define one .. well then you get an error!

The point is you get an error ON USE, which is the rule
and spirit of C++ in almost all other places.

The Standard actually goes to a LOT of trouble for
weird cases like operator->() in templates to say that
if the member is not called it MUST NOT be instantiated
(because there are uses where this would lead to a type error).

> But at least a solution seems possible and that is the point to be
> made: that at least classes can be used today. On the other hand, there
> is nothing in C++ to that would make a union of constructible types
> anything but impossible to use.

I actually have a use for them, which proves that you are wrong.

There is no requirement for you or anyone else to use this
feature, were it to be added.

The argument it is unsafe cannot be sustained and is
easily discredited by noting that a union of pointers
to any type is already allowed, and these pointers can
be abused in just the same way the actual objects can
be by the simply act of adding a * :)

Pointers also involve inefficiencies and raise
serious difficulties deciding on and enforcing
a storage management policy: unions of the actual
types at least allow you to represent the policy
in part by the provision of or absence of
appropriate constructors (at least for unions containing
at least one non-POD type :)

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Tue, 25 Jul 2006 09:31:49 CST
Raw View
skaller wrote:

> What I care about is simply being able to align a suitable
> amount of storage for a family of types which are only known
> symbolically to the compiler.

Have you looked at tr1::alignment_of and tr1::aligned_storage ?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Tue, 25 Jul 2006 09:35:49 CST
Raw View
Seungbeom Kim wrote:
> johnchx2@yahoo.com wrote:
> > Seungbeom Kim wrote:
> >
> >> I fail to see from your example how to construct objects of different
> >> types and return one of them through a common type from a function.
> >
> > Wouldn't boost::variant do the right thing in this context?
>
> Yes. I just don't know how it's implemented; you can assume that I was
> talking in the context of how to construct such a facility only from
> what's given by the C++ Standard (since it's csc++ here :D).

As I understand it, boost::variant is implemented using
boost::aligned_storage and boost::alignment_of (the boost versions of
the corresponding tr1 components).  aligned_storage::type is, in turn,
a union of an array of unsigned char and an "aligner" type.  (In
addition there's a type-discrimination member variable for run time
type determination.  And, of course, some template metaprogramming to
obtain the maximum size and maximum alignment of all the types included
in the variant.)

But the bottom line is that it uses an array of unsigned char (with
surrounding apparatus to guarantee correct alignment) to provide
storage for types that would be illegal to include in a C++ union.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Crosbie Fitch" <crosbie@digitalproductions.co.uk>
Date: Tue, 25 Jul 2006 11:07:10 CST
Raw View
>"skaller" <skaller@users.sourceforge.net> wrote in message
union X {
>  string a;
>  vector b;
>  X(): a("") {}
> };

struct X
{
    union
    {   struct {    string a; };
          struct { vector b; };
     };

    X() { a=string(""); }
};

You can almost get what you want if we simply ratify the existence of
anonymous structs (as per MS VC6-8) - and given they must have default
constructors, are thus permitted as members of unions.

Of course, a lot of this friction simply comes down to people trying to
pretend the union is a class when it's actually a completely different
animal (an overlay).

It is not sensible for a union to have default construction, nor is it
sensible for it to have methods.

Create 'overlay'

An overlay is identical to an anonymous union except:
1) Overlays may only exist as members of classes
2) Overlays do not have any methods
3) Overlays are not constructed (though if static are memset zero) or
destroyed
4) Overlays with non-pod members require a user defined
constructor/destructor/copy-assign operator in the enclosing class
(otherwise memcpy is used)
5) Members can be accessed in any order, although if their state data is
read, behaviour is undefined unless it was initialised by a compatible
representation (including a derived class) (as per reinterpret_cast).
6) Overlays may have any kind of members with no restrictions
7) One overlay member may appear in the initialiser list of an enclosing
class's constructor
8) The members of an overlay may have access specifiers

So, your case would become:

struct X
{    overlay
        {    string a;
            vector b;
        };
    X():a("") { }
};

It is probably inadvisable to expose this overlay in this way (as it is
often inadvisable to expose member variables), unless string and vector are
compatible types.

Here's a better example for an exposed overlay:

struct  A { float x,y,z; };
struct  B: A
{    B& operator=(float f) { x=f; return *this; }
        B(float f) { x=f; }
    operator float() const { return x; }
};

struct V
{
    overlay
    {    protected: A a;
        public: B x;    // Same data as A, but different behaviour
    };
..
};


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Tue, 25 Jul 2006 16:44:07 GMT
Raw View
johnchx2@yahoo.com wrote:
> Seungbeom Kim wrote:
>
>>johnchx2@yahoo.com wrote:
>>
>>>Seungbeom Kim wrote:
>>>
>>>
>>>>I fail to see from your example how to construct objects of different
>>>>types and return one of them through a common type from a function.
>>>
>>>Wouldn't boost::variant do the right thing in this context?
>>
>>Yes. I just don't know how it's implemented; you can assume that I was
>>talking in the context of how to construct such a facility only from
>>what's given by the C++ Standard (since it's csc++ here :D).
>
>
> As I understand it, boost::variant is implemented using
> boost::aligned_storage and boost::alignment_of (the boost versions of
> the corresponding tr1 components).  aligned_storage::type is, in turn,
> a union of an array of unsigned char and an "aligner" type.  (In
> addition there's a type-discrimination member variable for run time
> type determination.  And, of course, some template metaprogramming to
> obtain the maximum size and maximum alignment of all the types included
> in the variant.)
>
> But the bottom line is that it uses an array of unsigned char (with
> surrounding apparatus to guarantee correct alignment) to provide
> storage for types that would be illegal to include in a C++ union.

Here are some links that might provide insight into the mechanics of
implementing discriminated unions:

http://oonumerics.org/tmpw01/alexandrescu.pdf
http://erdani.org/publications/cuj-04-2002.html
http://erdani.org/publications/cuj-06-2002.html
http://erdani.org/publications/cuj-08-2002.html


Andrei

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Sat, 22 Jul 2006 16:24:23 GMT
Raw View
Here is the outline of a proposal to remove the restriction
on declaring unions of constructable variants.

This proposal is not worded in Standardese, it's just an outline
in plain language. Motivation is also omitted (separate issue :)

In some cases what I recall the Standard says may be wrong so
any corrections are of course appreciated.

PROPOSAL (A):

* remove the restriction on declaring
unions with variants of constructable types

* add a rule which say the compiler will not
generate a default constructor, copy constructor,
copy assignment operator, or destructor for
a union with a constructable type

This should be enough to ensure a diagnostic is
issued if any context would require initialising,
assigning, or destroying such a union --
I believe there is already a rule to that effect.

Of course, user defined constructors destructors
and assignment operators can still be defined.

PROBLEM: the current C++ standard handles
the initialisation of a union using ctor-initialisers
poorly. This is an outstanding defect:

union X {
  int a;
  long b;
  X(): a(1), b(2) {}
};

Here, a is set to 1, then b is set to 2.
Clearly this is absurd, however it is merely
a gratuitous stupidity rather than being a
problem semantically. If the types are
constructable, however, this rule would be
entirely untenable:

union X {
  string a;
  vector b;
  X(): a("") {}
};

In this case, a is NOT "" after default initialisation,
rather, b is a zero length vector .. and b clobbers
the value of a. This is because the standard
requires ALL the members to be initialised.
In the POD case, the default constructors are
trivial and don't do anything, so only explicit
initialisation have any effect.

PROPOSAL (B):

* fix the rule for initialisation of
union component by constructors
to require either no ctor initialiser,
or exactly one ctor initialiser.

In either case, only an explicit initialiser
actually causes any initialisation.

PROBLEM: Unions admit an assignment form
initialiser:

union X { string a; vector b; };

X x.a = "";

This is from ISO C, and available in C++ too
for compatibility. It works fine with constructible
variants too. But we also need this for ctor
initialisers:

struct A : X {
  X x;
  A(): X::a(""), x.a("") {}
};

This can also be used in variable initialisation:

X x.a("");

PROPOSAL (C):

* allow all unions as bases
* extend the syntax of ctor-initialisers as
illustrated in the example.

The three proposal above, taken together,
make unions first class citizens on par with structs.

The proposals break nothing and have clear advantages
for both human coders and machine generated code.

Part (C) above is optional (though desirable) and requires
a syntax extension.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]