Boost logo

Boost :

From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2002-07-03 05:01:50


"Douglas Gregor" <gregod_at_[hidden]> wrote in message
news:200207021218.21456.gregod_at_cs.rpi.edu...
> On Tuesday 02 July 2002 10:14 am, David Abrahams wrote:
> What I was really getting at (but didn't realize) was this basic question:
>
> If I have a variant type V that can hold a value of one of the types T1,
T2,
> ..., TN, are T1, T2, ..., TN subtypes of the variant type V?
>
> If T1, T2, ..., TN are subtypes of the variant type V, then:
> - we expect subtype polymorphism to work properly
> - 'cast' seems like a reasonable description for the type-to-subtype
> conversion (i.e., from V to one of the types Ti)
>
> If T1, T2, ..., TN are _not_ subtypes of the variant type V, then:
> - subtype polymorphism doesn't exist (V is just a container of one
element)
> - 'extract' seems like a reasonable description for accessing the value
> stored within the variant type
>
> I thought about it for a while, and decided that T1, T2, ..., TN should be
> subtypes of the variant type because if I have a value of type T1, it is
one
> of the legal forms of the type V. If I call a routine that expects a V, it
is
> perfectly reasonably that I give it a T1 because T1 is a valid form for V.
>
> I dug around a little bit for variant subtyping rules, to see what others
> think. After a little looking I came across some notes/corrections from
> (apparently) a series of lectures on a typed lambda calculus
> (http://www.cs.pdx.edu/~apt/cs510cal_2000/typing_note.ps). It contained
this
> rule for variant subtyping:
>
> {l1', ..., lm'} \subseteq {l1, ..., ln} lj' = li => Tj' <: Ti
> -----------------------------------------------------------------
> <l1':T1', ..., lm':Tm'> <: <l1:T1, ..., ln:Tn>
>
> Where:
> l1, l2, ..., ln and l1', ..., lm' are just labels (simple identifiers)
>
> T1, ..., TN and T1', ..., TM' are types
>
> <: is the subtyping relationship (i.e., Ti <: Tj means that Ti is a
subtype
> of Tj)
>
>
> In more C++-ish terms, it says that if we have two variant types V1 and
V2,
> and the set of types that V1 can hold is a subset of the types that V2 can
> hold, then V1 is a subtype of V2. So if we have:
>
> typedef variant<int, double> V1;
> typedef variant<int, double, std::string> V2;
>
> then V1 is a subtype of V2 (because you can use a V1 wherever a V2 is
needed
> without breaking type safety).

Except that if you are expecting a V2, you can expect to store a std::string
in it, which you can't do with a V1....

This is the "is a circle an ellipse" question --- a const V1 is-a const V2
(and therefore is a subtype) whereas a non-const V1 is-not-a non-const V2
(and therefore is not a subtype) (see
http://www.cuj.com/experts/1903/henney.htm)

> Then with:
>
> typedef variant<int> V3;
>
> V3 is a subtype of V1 and V2. But 'variant<int>' is just syntactic
desugaring
> for 'int' (they should be equivalent, if the C++ type system would allow
such
> a thing).
>
> The variant implementations given thus far have gotten about as close to
> allowing variant subtyping as we can in C++. A variant can be constructed
> from any subtype, and variants can be casted to any of the value types
they
> may hold. We can't ask for much more from a subtyping relation.

A variant should be able to be constructed from:

* any of the contained types
* a variant that can contain a subset of the contained types
* any type that can be implicitly converted to a contained type, provided
there is a best match

A mechanism should be provided to obtain

* any of the contained types
* another variant that can contain any set of types that overlaps with the
set of contained types

from our variant using an appropriate extractor, with the proviso that we
will throw an exception if the actual contained type is not compatible with
the target.

The question is --- what do we call this extractor, a "variant_cast" or
"extract", or something else? For the second case, IMHO this really is a
"variant_cast" --- we are casting one type of variant to another. For the
first case, I think this really is more of an "extract" --- a variant
_contains_ its object, it doesn't have an identity relation with it, as
revealed by the fact that the extractor may throw.

Anthony

--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk