Re: [boost] Adding polymorphic_value to boost
Peter Dimov wrote:
You can have
vector
v; and then
v.push_back( Circle(10) ); v.push_back( Ellipse(10, 15) ); v.push_back( Square(11) );
Good example. Yes please. There's another way of implementing this, though; rather than pointing to the object in the heap you can store it in-place by allocating enough space for the largest possible derived subclass: class Base { ... }; class Derived: public Base { ... }; template <typename B> class polymorhpic_value_2 { B base; char enough_space_for_dervided_classes_members[1024]; public: template <typename D> // requires D is same as or derived from B void operator=(const D& d) { B::~B(this); new (this) D(d); } }; polymorphic_value_2<Base> p; Derived d; p = d; That's just a sketch; many details omitted! There are some obvious advantages and disadvantages of each approach and I'm definitely not saying this is better than the pointer-to-heap design. But I mention it for this reason: * If your proposed interface for polymorphic_value could also work for this method of implementation, then it is probably a better interface.
It's unfortunate we have to use -> instead of . but that's what's available.
There have been proposals for operator. ; has this been evaluated to see how it would work with them? Similarly the unified a.b() vs. b(a) syntax proposal. Regards, Phil.
On 22 Nov 2017, at 23:31, Phil Endecott via Boost
wrote: Peter Dimov wrote:
You can have
vector
v; and then
v.push_back( Circle(10) ); v.push_back( Ellipse(10, 15) ); v.push_back( Square(11) );
Good example. Yes please.
There's another way of implementing this, though; rather than pointing to the object in the heap you can store it in-place by allocating enough space for the largest possible derived subclass:
class Base { ... }; class Derived: public Base { ... };
template <typename B> class polymorhpic_value_2 { B base; char enough_space_for_dervided_classes_members[1024];
public: template <typename D> // requires D is same as or derived from B void operator=(const D& d) { B::~B(this); new (this) D(d); }
};
polymorphic_value_2<Base> p; Derived d; p = d;
That's just a sketch; many details omitted! There are some obvious advantages and disadvantages of each approach and I'm definitely not saying this is better than the pointer-to-heap design. But I mention it for this reason:
* If your proposed interface for polymorphic_value could also work for this method of implementation, then it is probably a better interface.
It's unfortunate we have to use -> instead of . but that's what's available.
There have been proposals for operator. ; has this been evaluated to see how it would work with them? Similarly the unified a.b() vs. b(a) syntax proposal.
Regards, Phil.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
The design and wording support a small object optimisation (I have not implemented it though). The utility of polymorphic_value is in supporting open-set polymorphism where the set of types to be supported is not known. As such, it won’t be possible to guarantee the use of the small object buffer but it may be useable for some objects. Operator dot and uniform call syntax are not progressing through the C++ evolution groups, if that were to change then I’d expect to make changes to polymorphic_value similar to those that would be made for optional.
and uniform call syntax are not progressing through the C++ evolution groups
That is a total shame. It would be such a boon to the language.
On 23 November 2017 at 08:18, Jonathan Coe via Boost
On 22 Nov 2017, at 23:31, Phil Endecott via Boost
wrote: Peter Dimov wrote:
You can have
vector
v; and then
v.push_back( Circle(10) ); v.push_back( Ellipse(10, 15) ); v.push_back( Square(11) );
Good example. Yes please.
There's another way of implementing this, though; rather than pointing to the object in the heap you can store it in-place by allocating enough space for the largest possible derived subclass:
class Base { ... }; class Derived: public Base { ... };
template <typename B> class polymorhpic_value_2 { B base; char enough_space_for_dervided_classes_members[1024];
public: template <typename D> // requires D is same as or derived from B void operator=(const D& d) { B::~B(this); new (this) D(d); }
};
polymorphic_value_2<Base> p; Derived d; p = d;
That's just a sketch; many details omitted! There are some obvious advantages and disadvantages of each approach and I'm definitely not saying this is better than the pointer-to-heap design. But I mention it for this reason:
* If your proposed interface for polymorphic_value could also work for this method of implementation, then it is probably a better interface.
It's unfortunate we have to use -> instead of . but that's what's available.
There have been proposals for operator. ; has this been evaluated to see how it would work with them? Similarly the unified a.b() vs. b(a) syntax proposal.
Regards, Phil.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/ mailman/listinfo.cgi/boost
The design and wording support a small object optimisation (I have not implemented it though). The utility of polymorphic_value is in supporting open-set polymorphism where the set of types to be supported is not known. As such, it won’t be possible to guarantee the use of the small object buffer but it may be useable for some objects.
Operator dot and uniform call syntax are not progressing through the C++ evolution groups, if that were to change then I’d expect to make changes to polymorphic_value similar to those that would be made for optional.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/ mailman/listinfo.cgi/boost
Den 23-11-2017 kl. 00:31 skrev Phil Endecott via Boost:
There's another way of implementing this, though; rather than pointing to the object in the heap you can store it in-place by allocating enough space for the largest possible derived subclass:
[snip]
That's just a sketch; many details omitted! There are some obvious advantages and disadvantages of each approach and I'm definitely not saying this is better than the pointer-to-heap design.
That's going to use way too much space, make swap/move slow and possibly noexcept(false), give poor reference stability. For that case of not heap-allocating each object in isolation, boost::poly_collection seems much better. So I would stick to the allocate on the heap approach. kind regards -Thorsten
On 23 Nov 2017, at 15:24, Thorsten Ottosen via Boost
wrote: Den 23-11-2017 kl. 00:31 skrev Phil Endecott via Boost:
There's another way of implementing this, though; rather than pointing to the object in the heap you can store it in-place by allocating enough space for the largest possible derived subclass:
[snip]
That's just a sketch; many details omitted! There are some obvious advantages and disadvantages of each approach and I'm definitely not saying this is better than the pointer-to-heap design.
That's going to use way too much space, make swap/move slow and possibly noexcept(false), give poor reference stability. For that case of not heap-allocating each object in isolation, boost::poly_collection seems much better. So I would stick to the allocate on the heap approach.
kind regards
-Thorsten
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
One can limit the size of the buffer to make it tolerable (like std::function does) and only use the buffer for types than are noexcept-moveable. Reference stability is not a big concern to me (given the intended uses of the api) but is probably worth documenting. My proposed addition does not have a small object optimisation but I would not wish to rule out adding one.
Den 23-11-2017 kl. 17:32 skrev Jonathan Coe via Boost:
On 23 Nov 2017, at 15:24, Thorsten Ottosen via Boost
wrote:
That's going to use way too much space, make swap/move slow and possibly noexcept(false), give poor reference stability. For that case of not heap-allocating each object in isolation, boost::poly_collection seems much better. So I would stick to the allocate on the heap approach.
One can limit the size of the buffer to make it tolerable (like std::function does) and only use the buffer for types than are noexcept-moveable. Reference stability is not a big concern to me (given the intended uses of the api) but is probably worth documenting.
My proposed addition does not have a small object optimisation but I would not wish to rule out adding one.
That certainly should be documented. If one stores a base* somewhere outside the collection, this is quite important to know if one should dare sorting a collection of such objects. And if we use a small buffer optimization, then we get the peculiar case that reference stability depends on the size of the object. polymorphic_value will leak the pointer abstraction anyway, so I don't see any point in trying to disguise that. Some other naming ideas: poly_value<T> base_value<T> poly_any<T> any<T> kind regards Thorsten
On 23 Nov 2017, at 17:15, Thorsten Ottosen via Boost
wrote: Den 23-11-2017 kl. 17:32 skrev Jonathan Coe via Boost:
On 23 Nov 2017, at 15:24, Thorsten Ottosen via Boost
wrote: That's going to use way too much space, make swap/move slow and possibly noexcept(false), give poor reference stability. For that case of not heap-allocating each object in isolation, boost::poly_collection seems much better. So I would stick to the allocate on the heap approach.
One can limit the size of the buffer to make it tolerable (like std::function does) and only use the buffer for types than are noexcept-moveable. Reference stability is not a big concern to me (given the intended uses of the api) but is probably worth documenting. My proposed addition does not have a small object optimisation but I would not wish to rule out adding one.
That certainly should be documented. If one stores a base* somewhere outside the collection, this is quite important to know if one should dare sorting a collection of such objects.
And if we use a small buffer optimization, then we get the peculiar case that reference stability depends on the size of the object.
polymorphic_value will leak the pointer abstraction anyway, so I don't see any point in trying to disguise that.
Some other naming ideas:
poly_value<T> base_value<T> poly_any<T> any<T>
kind regards
Thorsten
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
To clarify, polymorphic_value does not guarantee reference stability. Getting a pointer to the managed resource involves writing non-idiomatic code and the formal wording explicitly encourages implementers to use a small object optimisation. Thanks for bringing the need to clearly document this to my attention.
participants (4)
-
Jonathan Coe
-
Phil Endecott
-
Richard Hodges
-
Thorsten Ottosen