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
like
> > 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
may
> 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
ownership.
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.

Opinions?

Fernando Cacciola
Sierra s.r.l.
fcacciola_at_[hidden]
www.gosierra.com


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