Boost logo

Boost :

From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2002-12-14 20:35:48


"Joel de Guzman" <djowel_at_[hidden]> escribió en el mensaje
news:002301c2a3c8$a8751fb0$a7564eca_at_kim...
> ----- Original Message -----
> From: "Fernando Cacciola" <fcacciola_at_[hidden]>
>
>
> > I think it can be done in a way as to not make it confusing.
> > For instance, iterators also have operator*() and ->(), yet they are not
> > pointers.
>
> Aren't they? In the conceptual level?
>
In the conceptual level, yes, they're pretty much like pointers,
but I ment that in spite of the fact that they conceptually look
and behave like pointers, strictly, they _are_ not.

> > Certainly, they are _a lot_ more like pointers than optional<> because
they
> > have pointer semantics in terms of shallow-copy and aliasing, but,
> > for instance, you cannot delete an iterator, but I don't think that
>
> Is a pointer required to point to heap allocated data? What about
> int a = 3; int* ap = a; ? Isn't that a pointer? I can't delete ap.
>
OK. But that just shows that I picked up the wrong example.
Let me try again:
iterators do not have a corresponding "null pointer value"
You cannot test for 'valid pointee' with an iterator alone;
that's why you need to compare against "end" all the time.
IOWs, the expression: if ( iter ) is meaningless with an iterator.
This shows that at some extent they're not pointers anymore,
just like optional<>

> > the pointer-analogy had drawn peoplo into that sort of mistakes.
> > For optional<>, the key to sucess resides in the way you present it,
> > and in the way the pointer-like interface is used.
> > >
> > > For what its worth, I prefer the union concept. Union semantics
clearly
> > > state that
> > > you can have either or (i.e., not both).
> > Yes.
>
> > But I think that a container is even better, because containers
inherently
> > models the fact that you can have a value or not.
>
> I can easily give you a container that fails your definition:
> Isn't char a[3]; a container? Yet, it does not "model(s) the fact that
> you can have a value or not". What about tuples, are you saying
> that that is not a container?
>
I was thinking about a variable size container.
But you make a good point: the word 'container' alone doesn't imply that.
A variable size container is closer in meaning becuase it can be empty()
A variant is never empty.

> > This is closer in meaning to optional than a union.
>
> Think again. Isn't variant a *container* that holds only one value
> at a time? That supersets the definition of the optional AFAICT.
>
Exactly. It cannot hold 0 values. This is what makes variable-size
(of at most 1) containers closer to the optional concept.

> > It is an error to try to access one element of an empty container
> > just as it is an error to try to access a non-existent value.
>
> It is also an error for a variant to access T from variant<T, nil_t>
> if nil_t is in effect and T is therfore a "non-existent value".
>
Well, yes, you're right.
I concede that, normally, you would always access T from
the variant and not something else like nil_t.
I overlooked this fact, partially, because this is not required
by the union itself; it is the user responsability to do that;
but I admit that a variant used for this purpose would
require that, so it is almost the same situation than
with a variable-size container (with capacity 1).

> > The union mapping is good, but the container mapping is better becuase
> > the undefined behaviour of invalid access is directly supported by the
> > container concept, while the union concept requires the additional
> > element of a type with semantics unfamiliar to C++.
>
> What semantics are you referring to? The semantics of
> variant<T, nil_t>? optional<T>? maybe<T> ? All of these
> are new grounds (and thus unfamiliar) to the C++ programmer.
>
I was actually refering to the semantics of nil_t; but I was
overlooking that fact that you wouldn't even access nil_t on
a variant, at least not if you used the variant purposedly
to hold an optional T.

> What's wrong with borrowing a well formed concept from
> other languages? That's definitely better that concocting a
> half-cooked version of what's already a mature concept in
> other languages.
>
There's nothing wrong with that, but it is important to
notice that on a different language there are different
tools, so what works best on one does not necesarily
work best on another.
For instance, I don't know if you can have a
stack-based fixed capacity and variable size container
on Haskell. But you can have it on C++, so following
this model in C++ make sense just as it makes sense
to follow the union model.

I'm not arguing against the union model; I'm just arguing
that the variable-size-container also works; and IMO better,
but even if it were not better, it is clearly not worse; and
IMO, containers are more familiar to C++ programmers
than _discriminated_ unions.
But the difference is negligible, and I didn't want
to imply otherwise.
On both models you have a box which can have a 'T',
but in the variable-size container, if you don't have a T
you have nothing; while on the union model you have an X.
T-or-nothing maps better IMHO to the optional T concept
than T-or-else.
But I know both models completely work.

> > With a union-like interface, this is not so because the union has always
> > a well defined state, so if you try to accesss an uninitialized
optional,
> > this model gives you nil_t.
>
> Wrong! Accessing T in variant<T, nil_t> does not give you nil_t.
>
Correct.
It gives you nil_t if you ask for it but you wouldn't unless you're insane
:-)
But you are right, in practice, I will always try to extract a T and nothing
else.

>
> > nil_t by itself is not undefined, so to make sense of the concept of
> > optional value, which itself implies that the value might not exist,
> > either the programmer or the interface-under-the-hood must make sure
> > that the result nil_t is treated as a postcondition violation.
> > If you trust my experience with this tool, I assure you that if you are
> > accesing the value of a conceptually non-existent object,
> > you've made a mistake on the code because the execution path
> > should never had reached that point.
> > This is why I prefer the container model: You cannot extract one
> > element of an empty container. If you try, you get undefined behaviour.
> > However, the syntax of a container interface does not help you
> > to make sure you have checked for non-emptyness. Of course,
> > this happens all the time with any container and it has alawys
> > been the programmers responsability to make sure of the object
> > you try to access is actually there.
>
> All these are based on a wrong premise.

Are you sure you meant to say _all_ these?
How about this part:

> > If you trust my experience with this tool, I assure you that if you are
> > accesing the value of a conceptually non-existent object,
> > you've made a mistake on the code because the execution path
> > should never had reached that point.

Fernando Cacciola


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