Boost logo

Boost :

From: Matt Calabrese (rivorus_at_[hidden])
Date: 2007-07-24 17:48:30


On 7/24/07, Martin Schulz <Martin.Schulz_at_[hidden]> wrote:
>
> I tend to disagree. I think of an proxy object not so much as a
> "reference"
> but rather as a "drop-in replacement" that happens by chance to be
> connected
> to some other container object, but that is only an implementation
> detail.
>
> If the proxy models an STL container then it should work with any STL or
>
> other appropriate algorithm and I do not consider this a hack.
> It simply works as designed.

If it were possible, it would be useful to be able to think about
proxies like that, but it misses out on the fact that a proxy to
a container in C++ generally is not a model of a standard container, at
least not practically, so you generally can't think of a proxy as simply a
drop-in replacement, and in practice, because of this, you also can't safely
pass a proxy to an algorithm where a container truely is required. You'd do
so only with algorithms where a smaller subset of the container requirements
are required.

As an example of requirements you likely would not want a proxy to meet,
consider the constructor and destructor requirements of standard containers
(sequences pose even more problems). In order to be a container, copying a
proxy would have to imply creating a new container, though the
implementation shown above would just produce another proxy which references
the same container. This already makes the "drop-in replacement" view not
true and is an example of why a proxy as a container itself generally isn't
even the desired behavior. Destruction poses another problem, since
destruction of a container is required to destroy all of the contained
elements. In practice, implementing either requirement is generally not
desireable for a proxy. The purpose of a proxy is generally to introduce a
partially transparent level of indirection such that you may simulate
reference semantics when code is written in places where reference or value
semantics may be safely used.

So yes, I would say passing a proxy where a container is listed as a
requirement would definitely be a hack, unless you can make it truely meet
all of the requirements listed above. Usually you can get away with ignoring
this fact and your code will manage to compile and work, but
consider for a moment a generic algorithm in C++0x which explicitly requires
a reference to a standard sequence as an argument. Now the requirement is
enforced rather than simply being documented. Here, passing
a vector works perfectly fine, as it should, since a vector is a model
of a sequence. However, now try to pass
a proxy. In order to even have your code compile, the proxy itself would
have to be a valid standard
sequence, explicitly meeting all of the associated requirements, including
the troublesome requirements for proxies mentioned above. Note that this
type of issue exists in current C++ code that specifies such requirements in
documentation, only the language isn't going to catch your logical error for
you, and instead you will just be violating your own contracts.

If you make the requirements for the algorithm less strict such that both a
proxy and a container itself meet the requirements, then all is fine and
correct, given that you interface with the stored data in a way which works
with objects and with proxies, but if you instead lie in code and state that
the proxy is a valid sequence when it is not, knowing that internally the
algorithm doesn't actually need to rely on all of the specified
requirements, it is simply a hack to get around a design flaw. That's not to
say that proxies aren't useful, it just means that in general, they are not
true drop-in replacements that go anywhere the target type would go, unlike
what many people tend to believe, and if your proxy doesn't correctly model
the concepts that your referenced object models,
then you have made a logical error if you attempt to use it where
those requirements are specified, whether your code seems
to
work or not. Because of this, you should try to provide as much
functionality as you can when implementing the proxy, but you can't
ignore the fact that a level of indirection still exists.

Therefore I favor option 1).
> Clearly a non-const proxy may not be constructed from a const container.

When I pass some container-alike object into some method e.g. as const
> reference,
> I do not expect its contents to be modifyable.

 As was pointed out by Peter and Eric, when copying proxies for example,
this type of logic can't even be enforced, and I argue that this is
because at a higher level, your proxy is still logically dealing with a
level of indirection, yet you are incorrectly attempting to combine the
cv-qualification of the target with the cv-qualification of the proxy,
despite the fact that they are two logically different concepts, only
somewhat blurred by the fact that much of the interfacing is automatically
forwarded.
You can try to force certain meaning out of the top-level
qualification that "just works" for many,
though not all, algorithms, depending on how they are written, but then
things start to get hairy since you are essentially altering the meaning of
top-level cv-qualification such that it propogates through and is
inseparable from the qualification of the target type. Unless your proxy
manages to implement true value semantics, I don't see how you can logically
allow the qualification to fall through.

> (1) typically only makes sense for types that are intended to be class
> > members and propagate the constness of the member function to the
> proxied
> > (referred to) object for some reason.
>
> Right, that would seem to be a legitimate use.

I agree that if you wanted such functionality this would work fine, however,
I would personally like to see somewhere in practice that this actually is
the desired behavior and where what you are dealing with truely is a proxy
-- explicitly noting the requirements of the algorithm or datastructure. I
don't doubt that it is possible that such cases may potentially exist,
though I am not convinced, and offhand, none jump immediately to mind.

-- 
-Matt Calabrese

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