Boost logo

Boost :

Subject: Re: [boost] Adding polymorphic_value to boost
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2017-11-20 22:51:39


> It will take me some time to digest and come back with questions.

This is a subject close to my heart, so please feel free to question as
much as you wish.

> Pleasingly we seem to be debating how useful this type can be rather than
whether it’s useful at all.

As far as I am concerned, cloned_ptr was the missing piece to the puzzle of
consistent handling of handle/body objects - particularly when polymorphic.
It allowed value-semantic coding to be a reality in a consistent way. Have
no fears over utility.

While pointers provide the power behind c++, I am strongly of the view that
building user code around value types is preferable from the points of view
of maintainability, elegance and provable correctness. With a little tweak
this class could spell the end for pointer-based paranoia in user code
forever. That's a wonderful thing.

What strikes me as the masterstroke in the proposed implementation is the
type-erased copy/deletion which eliminates the need for clone. I wish I'd
thought of it. In that respect your implementation is beautiful.

On 20 November 2017 at 23:37, Jonathan <jonathanbcoe_at_[hidden]> wrote:

>
> > On 20 Nov 2017, at 22:11, Richard Hodges via Boost <
> boost_at_[hidden]> wrote:
> >
> > sent direct to Jonathan in error - reproduced here:
> >
> >> polymorphic_value solves a very real problem and allows deletion of a
> > large amount of error-prone boiler-plate code.
> >
> > completely agree. It would allow deletion of even more code if it didn't
> > propagate_const.
> >
> >> Without the second category, the first is just an implementation detail.
> >
> > Fine. Let's make it a policy. Then everyone's happy. The truth will out.
> >
> >> I’d really like to see real examples
> >
> > Sometimes (in a comms-based system, often) even though the handle
> object's
> > interface is const, and accessor will do some internal work which may
> need
> > to mutate the implementation (even on another thread). I spend a lot of
> > time writing comms/protocol code which I normally implement as asio
> > services. Database access, websockets, AMQP messaging, http, etc.
> >
> > If you've spent any time with asio you'll know all about the handle-body
> > idiom and all the nasty boilerplate required to correctly implement
> > move/copy/sharing of io objects bound to an executor.
> >
> > Sometimes I'll want the concept of an object and I may decide to give it
> > shared-body semantics. But then I realise I can get a
> > performance/correctness win by providing the same interface but with
> > different copy/move behaviour.
> >
> > Sometimes I realise I need such an object which will just clone itself
> when
> > copied.
> >
> > It is useful to write these objects in terms of:
> >
> > template<template<class...> class Pointer>
> > struct basic_foo
> > {
> > // ..
> >
> > Pointer<foo_impl> impl_;
> > };
> >
> > now I can specialise:
> >
> > struct unique_foo : basic_foo<std:unique_ptr> { };
> > struct shared_foo : basic_foo<std:shared_ptr> { };
> > struct value_foo : basic_foo<boost::polymorphic_value> { };
> > struct foo_observer : basic_foo<std::reference_wrapper> { };
> >
> > I have implemented both the interface and the implementation only once
> and
> > am now afforded complete flexibility in how I manage my foos.
> >
> > With a tiny bit more templatery I can even automatically get:
> >
> > auto a = unique_foo(...);
> > auto b = shared_foo(std::move(a));
> >
> > or
> >
> > auto a = value_foo(...);
> > auto b = a;
> > auto c = shared_foo(std::move(a));
> >
> > and I can always get:
> >
> > auto o1 = foo_observer(b), o2 = foo_observer(c);
> >
> >
> > The consistency is important (at least to me) because it affords perfect
> > composability.
> >
> >> On 20 November 2017 at 22:36, Jonathan Coe <jonathanbcoe_at_[hidden]>
> wrote:
> >>
> >> On 20 Nov 2017, at 21:12, Richard Hodges via Boost <
> boost_at_[hidden]>
> >> wrote:
> >>
> >>>> None of these make copies. polymorphic_value is
> >>>> not called XXX_ptr precisely because its semantics
> >>>> are different from a pointer.
> >>>
> >>> shared_ptr, unique_ptr and reference_wrapper are all "different" from a
> >>> pointer, but they all share 4 common traits:
> >>>
> >>> 1. The all manage/observe lifetime of another _single_ object in some
> >>> defined but distinct way.
> >>>
> >>> 2. They all allow access to that object through operator*
> >>>
> >>> 3. They don't propagate const.
> >>>
> >>> 4. they don't have any pointery arithmetic behaviour
> >>>
> >>> Looking at the design history of polymorphic_value it seems that it
> >>> originally came from a desire to complete the circle by providing
> another
> >>> XXX_ptr which supported copying.
> >>>
> >>> This aim is _eminently useful_ as is evidenced by the numerous
> >>> implementations of things like it on github (and in my own code).
> >>>
> >>> I also have an interest is such an object as standard because I always
> >> seem
> >>> to end up needing one.
> >>>
> >>> I do not have a use case for a const-propagating one. Never have. I can
> >>> specify const in the angle-brackets. I've done that probably once.
> >>>
> >>>> This situation doesn't make sense for polymorphic_value.
> >>>
> >>> To you perhaps. However I have 3 projects on the go right now which
> could
> >>> use polymorphic_value immediately as a retro-fit for home-made
> solutions
> >>> *if it did not propagate const*.
> >>>
> >>> The concept of propagating const I can deal with trivially. To
> >> incorporate
> >>> it into this class mixes concerns to the detriment of its usefulness
> (to
> >>> me).
> >>>
> >>> So If it came to a vote and my voice had any weight, I would say:
> >>>
> >>> * with implicit const-propagation - NO
> >>>
> >>> * remove the const propagation - absolute YES
> >>>
> >>> additionally, ideally rename it back to cloned_ptr, (or indirect if you
> >>> must). Because what it is absolutely not is a value.
> >>>
> >>> It is logically the same as the other 4 non-pointers listed above, it's
> >>> just that it have different owned-object lifetime behaviour.
> >>>
> >>>
> >>> I completely understand the value-centric argument. I am a strong
> >> proponent
> >>> of it.
> >>>
> >>> My argument is that this is (or ought to be) a tool for *building*
> value
> >>> types. It is not in of itself a value type, and neither can it ever be.
> >> It
> >>> does not exhibit any "value" behaviour (equality and the like).
> >>>
> >>> R
> >>>
> >>> On 20 November 2017 at 21:35, Steven Watanabe via Boost <
> >>> boost_at_[hidden]> wrote:
> >>>
> >>>> AMDG
> >>>>
> >>>>> On 11/20/2017 01:11 PM, Richard Hodges via Boost wrote:
> >>>>> I watched Sean Parent's talk covering what has now become
> >>>> polymorphic_value.
> >>>>>
> >>>>> One thing that I am concerned about is Sean's insistence on
> propagating
> >>>>> const implicitly.
> >>>>>
> >>>>> This would be at odds with the behaviour shared_ptr, unique_ptr, and
> >>>>> reference_wrapper.
> >>>>>
> >>>>
> >>>> None of these make copies. polymorphic_value is
> >>>> not called XXX_ptr precisely because its semantics
> >>>> are different from a pointer.
> >>>>
> >>>>> Sometimes I want a const pointer to a mutable thing, and sometimes I
> >>>> want a
> >>>>> mutable pointer to a const thing (and sometimes I want to be able to
> >>>>> observe a thing without affecting its lifetime).
> >>>>>
> >>>>
> >>>> This situation doesn't make sense for polymorphic_value.
> >>>>
> >>>>> So my 2-pence would be that propagate_const should not be implicit in
> >>>> this
> >>>>> class.
> >>>>>
> >>>>> My rationale is that an obvious use case for me would be
> manufacturing
> >>>>> specialisations on pointer_type allowing a consistent interface
> leading
> >>>> to
> >>>>> an inner implementation while simply changing ownership behaviour.
> >>>>>
> >>>>> In that sense I am strongly of the view that the return type of
> >>>>> polymorphic_value<Foo>::operator*() const should be Foo& and not
> const
> >>>> Foo&.
> >>>>>
> >>>>> If I want a polymorphic cloning pointer to const Foo I can declare it
> >>>> with
> >>>>> polymorphic_value<const Foo>.
> >>>>>
> >>>>> I have never had reason to quibble with Sean's thinking before now,
> but
> >>>> on
> >>>>> this he is dead wrong.
> >>>>>
> >>>>> If I want const propagation, it's simple enough to wrap any pointer
> in
> >>>>> propagate_const<>
> >>>>>
> >>>>> This feels to me like idealists overriding pragmatists.
> >>>>>
> >>>>> Or have I missed something obvious?
> >>>>>
> >>>>
> >>>> In Christ,
> >>>> Steven Watanabe
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> Unsubscribe & other changes: http://lists.boost.org/
> >>>> mailman/listinfo.cgi/boost
> >>>>
> >>>
> >>> _______________________________________________
> >>> Unsubscribe & other changes: http://lists.boost.org/
> >> mailman/listinfo.cgi/boost
> >>
> >> It’s interesting how quickly people become polarised on this. One thing
> to
> >> note is that polymorphic_value<const T> is not the same as a
> >> const-propagating polymorphic_value<T>; I hope that puts us all on the
> same
> >> page.
> >>
> >> polymorphic_value is designed so that compiler-generated special member
> >> functions for objects with polymorphic components (sub-objects) are
> >> generated correctly. As such it needs to propagate const. There’s no
> sense
> >> in part of an object being mutable in a context where the object itself
> is
> >> immutable.
> >>
> >> polymorphic_value solves a very real problem and allows deletion of a
> >> large amount of error-prone boiler-plate code.
> >>
> >> Some people don’t want const-propagation because they favour a
> composable
> >> deep-copy + deep-const combination type. Some people have a use case
> for a
> >> deep-copying non const-propagating pointer-like hybrid type. Without the
> >> second category, the first is just an implementation detail. I’d really
> >> like to see real examples (not thought-experiments) that are solved by a
> >> type like cloned_ptr. I have never encountered one but my experience is
> not
> >> so broad and I’m well aware that absence of evidence is not evidence of
> >> absence.
> >
> > _______________________________________________
> > Unsubscribe & other changes: http://lists.boost.org/
> mailman/listinfo.cgi/boost
>
> I have no experience with ASIO, thanks for taking the time to put some
> examples together. It will take me some time to digest and come back with
> questions. Pleasingly we seem to be debating how useful this type can be
> rather than whether it’s useful at all.
>
> Regards,
>
> Jon


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