Boost logo

Boost :

From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2001-10-11 09:27:02

----- Original Message -----
From: David Abrahams <david.abrahams_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Wednesday, October 10, 2001 12:37 PM
Subject: Re: [boost] Getting the contained object from boost::function

> ----- Original Message -----
> From: "Peter Dimov" <pdimov_at_[hidden]>
> >
> > Perhaps it's time to discuss a common 'variant-to-contained-object' cast
> > that would work on any, function, and the future discriminated union and
> > "bounded" variant.
> >
> > The easiest approach is to just adopt the name 'any_cast' but I don't
> > it much. any_derived words are usually misleading. Any cast?
> >
> > A problem with the precise definition of such a cast is when is the
> returned
> > pointer/reference invalidated.
> Interesting naming problem. This "cast" has a few interesting properties:
> 1. The source supplies almost NO type information describing what types
> be "cast-to".
> 2. The result object is in some sense "contained" in the source.
> Any others?
> I'm not sure how relevant (2) is, but the combination of 1&2 leads me to
> like "extract<T>(source)".
First, I don't think 'extract' is appropriate because, AFAICT, 'extracting'
implies 'removing'; which isn't the case here.

The suffix "_cast" is probably a good idea because it tells that the
operation might perform a *conversion* to the target type. Without any
qualification, it might appear that the accessor is merely returning the
contained object *as is*. For 'any' this isn't the case; for a function
object I think that a true conversion might not be allowed, so the "_cast"
might go away.

I kept thinking about (2) and the returned pointer/reference lifetime issue.
There is something in my mind that I can't totally fit, but perhaps you can
evolve something out of it.
The thing is that it seems to me that there are two possible
contained-object accesing operations:

acquire(): which returns the contained object transfering or sharing
peek(): which returns a pointer/reference to the object *within* the
container, without giving any ownership to the reciever.

Under the above model:

* Value returning accesing functions, such as the std containers
front,back,at,[] are acquire operations.
* Container iterators support a sort of 'lazy' peek operation.
* function_cast<> is a peek operation.
* smart_ptr.get() is a peek operation.
* auto_ptr.release() is an acquire operation.
* T* any_cast is a (converting) peek operation.
* T any_cast is a (converting) acquire operation.

Clearly, most access functions are actually peek operations, meaning that
they hand out "the object within", whose lifetime is managed by the
container. However, I note that under this model it might well exist a
'truly indirect container' that uses some ownership policy and which would
allow both acquire and peek access. Similarly, a ref counted any could
support an "acquiring"
pointer/reference-returning any_cast.

It shows up that peek access has the inherent problem of pointer/reference
lifetime. That's why the analogy shown by Douglas Gregor between
function_cast and container iterators is so natural.
It seems to me that solving this problem, in the general sense, would
involve going from a peek operation to an acquire operation. It doesn't seem
clear how to do that in each particular case, though, so I second Doug's
suggestion of merely documenting the facts and let the user be careful.

What it can be done, I think, is to generalize and consistenly use this
peek/acquire model through two uniform but different intefaces that users
can become familiar with.
With this in mind, the original function issue could appear as this:

I need to *peek* inside a function object to see if it holds a particular
function, so let's add:

template<typename To, typename R, typename T1, ..., typename TN>
To& peek(function<R, T1, ..., TN>& f);

Eventually, I might want to 'acquire' the function within a function object,
which would mean that once I got it I don't care whether it is still inside
the function object and all I want is that it remains valid (I don't know if
this can be fit into function<>).

The bottom line is that by using 'peek' or 'acquire' as the accesing
funcions the user -and those reading the user's code- can infer the lifetime
behaviour of the pointer/reference obtained. Even though the function peek
interface above doesn't *solve* any problem, it would communicate that the
validity of the reference is subject to the function object, something that
might not be so obious.


Fernando Cacciola
Sierra s.r.l.

Boost list run by bdawes at, gregod at, cpdaniel at, john at