Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #70243 > unrolled thread
| Started by | wtholliday@gmail.com |
|---|---|
| First post | 2019-12-04 08:37 -0800 |
| Last post | 2019-12-05 22:15 +0100 |
| Articles | 20 on this page of 32 — 8 participants |
Back to article view | Back to comp.lang.c++
issues with std::variant wtholliday@gmail.com - 2019-12-04 08:37 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-04 10:26 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-04 11:07 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-04 12:31 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-04 13:09 -0800
Re: issues with std::variant "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-12-04 22:39 +0100
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-04 16:18 -0800
Re: issues with std::variant "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-12-05 05:13 +0100
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-05 09:59 -0800
Re: issues with std::variant Christian Gollwitzer <auriocus@gmx.de> - 2019-12-06 09:39 +0100
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-06 09:12 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-04 14:46 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-04 16:28 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-05 00:00 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-05 00:48 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-05 08:17 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-05 09:44 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-05 11:14 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-05 12:37 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-05 13:20 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-05 13:42 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-05 15:41 -0800
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-06 09:44 -0800
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-07 04:43 -0800
Re: issues with std::variant Manfred <noname@add.invalid> - 2019-12-07 18:17 +0100
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-07 11:45 -0800
Re: issues with std::variant Christian Gollwitzer <auriocus@gmx.de> - 2019-12-06 09:58 +0100
Re: issues with std::variant Öö Tiib <ootiib@hot.ee> - 2019-12-06 06:06 -0800
Re: issues with std::variant David Brown <david.brown@hesbynett.no> - 2019-12-04 22:34 +0100
Re: issues with std::variant Vir Campestris <vir.campestris@invalid.invalid> - 2019-12-05 15:07 +0000
Re: issues with std::variant Taylor <wtholliday@gmail.com> - 2019-12-05 10:01 -0800
Re: issues with std::variant David Brown <david.brown@hesbynett.no> - 2019-12-05 22:15 +0100
Page 1 of 2 [1] 2 Next page →
| From | wtholliday@gmail.com |
|---|---|
| Date | 2019-12-04 08:37 -0800 |
| Subject | issues with std::variant |
| Message-ID | <d24af259-867c-49b3-a747-e3d4e932ae4a@googlegroups.com> |
I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
Node setExposedPosition(Node node, Vec2 p) {
std::visit(overloaded {
[p](auto& n, decltype(n.exposedPosition)* = nullptr) {
n.exposedPosition = p;
},
[](auto&...) { }
}, node);
return node;
}
(This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
Node setExposedPosition(Node node, Vec2 p) {
if(hasField(node, EXPOSED_POSITION_BIT)) {
node.exposedPosition = p;
}
return node;
}
I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
Does that sound like the approach you would take?
thanks!
[toc] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-04 10:26 -0800 |
| Message-ID | <dbd3f501-3e95-44a9-bdd5-8709f404cda8@googlegroups.com> |
| In reply to | #70243 |
On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
> I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
>
> 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
>
> 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
>
> Node setExposedPosition(Node node, Vec2 p) {
> std::visit(overloaded {
> [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
> n.exposedPosition = p;
> },
> [](auto&...) { }
> }, node);
> return node;
> }
>
> (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
Huh? The design feels odd indeed.
I have usually stuff in variants that have rare things if anything
at all in common.
>
> Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
>
> Node setExposedPosition(Node node, Vec2 p) {
> if(hasField(node, EXPOSED_POSITION_BIT)) {
> node.exposedPosition = p;
> }
> return node;
> }
External setter? I do not have setter members no idea why I
would want external setters.
>
> I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
>
> Does that sound like the approach you would take?
No. Only by factor of two? Then those are rather similar classes.
From 68 mostly similar to each other "node" classes I would make plain
old polymorphic hierarchy.
If there is need to keep objects of these classes in a single
container then I would use Boost.PolyCollection for efficiency.
https://www.boost.org/doc/libs/1_71_0/doc/html/poly_collection.html
That design beats both your variant and your monster struct blindfolded
with right hand tied behind back I can bet.
> thanks!
Oh ... no problem.
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-04 11:07 -0800 |
| Message-ID | <8db3e20f-1434-4cd8-b979-b0d1ecb6e643@googlegroups.com> |
| In reply to | #70250 |
Thanks for your help!
On Wednesday, December 4, 2019 at 10:26:52 AM UTC-8, Öö Tiib wrote:
> On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
> > I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
> >
> > 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
> >
> > 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
> >
> > Node setExposedPosition(Node node, Vec2 p) {
> > std::visit(overloaded {
> > [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
> > n.exposedPosition = p;
> > },
> > [](auto&...) { }
> > }, node);
> > return node;
> > }
> >
> > (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
>
> Huh? The design feels odd indeed.
> I have usually stuff in variants that have rare things if anything
> at all in common.
Consider what the function does: it's checking (statically) if the struct has a particular member and setting it.
>
> >
> > Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
> >
> > Node setExposedPosition(Node node, Vec2 p) {
> > if(hasField(node, EXPOSED_POSITION_BIT)) {
> > node.exposedPosition = p;
> > }
> > return node;
> > }
>
> External setter? I do not have setter members no idea why I
> would want external setters.
>
> >
> > I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
> >
> > Does that sound like the approach you would take?
>
> No. Only by factor of two? Then those are rather similar classes.
>
> From 68 mostly similar to each other "node" classes I would make plain
> old polymorphic hierarchy.
I used to do a traditional polymorphic hierarchy: it's harder to make value types, and requires much more boilerplate.
> If there is need to keep objects of these classes in a single
> container then I would use Boost.PolyCollection for efficiency.
> https://www.boost.org/doc/libs/1_71_0/doc/html/poly_collection.html
>
> That design beats both your variant and your monster struct blindfolded
> with right hand tied behind back I can bet.
I'm using https://github.com/arximboldi/immer and can't change my containers.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-04 12:31 -0800 |
| Message-ID | <8ce5173d-19e9-4bd3-8db1-cd22ff443ecc@googlegroups.com> |
| In reply to | #70253 |
On Wednesday, 4 December 2019 21:07:37 UTC+2, Taylor wrote:
> Thanks for your help!
>
> On Wednesday, December 4, 2019 at 10:26:52 AM UTC-8, Öö Tiib wrote:
> > On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
> > > I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
> > >
> > > 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
> > >
> > > 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
> > >
> > > Node setExposedPosition(Node node, Vec2 p) {
> > > std::visit(overloaded {
> > > [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
> > > n.exposedPosition = p;
> > > },
> > > [](auto&...) { }
> > > }, node);
> > > return node;
> > > }
> > >
> > > (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
> >
> > Huh? The design feels odd indeed.
> > I have usually stuff in variants that have rare things if anything
> > at all in common.
>
> Consider what the function does: it's checking (statically) if the struct has a particular member and setting it.
Do not let complex syntax to confuse you ... magic does not exist.
It can't. It generates switch-case that checks *dynamically* behind scenes
what of those 68 is in that particular variant instance "node" and then
sets the member.
> > > Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
> > >
> > > Node setExposedPosition(Node node, Vec2 p) {
> > > if(hasField(node, EXPOSED_POSITION_BIT)) {
> > > node.exposedPosition = p;
> > > }
> > > return node;
> > > }
> >
> > External setter? I do not have setter members no idea why I
> > would want external setters.
> >
> > >
> > > I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
> > >
> > > Does that sound like the approach you would take?
> >
> > No. Only by factor of two? Then those are rather similar classes.
> >
> > From 68 mostly similar to each other "node" classes I would make plain
> > old polymorphic hierarchy.
>
> I used to do a traditional polymorphic hierarchy: it's harder to make value types, and requires much more boilerplate.
Value types in sense that little, immutable objects, passed by value?
These do not make sense in context of your post at all.
On the contrary, it is boilerplate of piles of those inefficient
switches from 68 cases all around your code that traditional
polymorphic hierarchy would remove with just one cheap level of
indirection added. I have measured it enough to predict that
program would be at least 4 times quicker, data about 4 times
smaller and executable also about twice smaller.
> > If there is need to keep objects of these classes in a single
> > container then I would use Boost.PolyCollection for efficiency.
> > https://www.boost.org/doc/libs/1_71_0/doc/html/poly_collection.html
> >
> > That design beats both your variant and your monster struct blindfolded
> > with right hand tied behind back I can bet.
>
> I'm using https://github.com/arximboldi/immer ...
I do not know the lib but it is seems from afar that public common
setters sound like total bullshit with those immers that are
immutable after construction. Come again and tell what you really
need.
> ... and can't change my containers.
That is defect of mind. Software is *soft*. It is like drawing on
sand not carving on obsidian.
Most projects usually combine data initially from rather few container
types like:
std::array, std::vector, std::unordered_set, std::unordered_map.
Then, later, when the needs become more clear those are maintained
to be more special, precisely suitable containers.
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-04 13:09 -0800 |
| Message-ID | <f0062225-f506-4306-9d48-1e15215f72d1@googlegroups.com> |
| In reply to | #70255 |
On Wednesday, December 4, 2019 at 12:31:31 PM UTC-8, Öö Tiib wrote:
> On Wednesday, 4 December 2019 21:07:37 UTC+2, Taylor wrote:
> > Thanks for your help!
> >
> > On Wednesday, December 4, 2019 at 10:26:52 AM UTC-8, Öö Tiib wrote:
> > > On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
> > > > I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
> > > >
> > > > 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
> > > >
> > > > 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
> > > >
> > > > Node setExposedPosition(Node node, Vec2 p) {
> > > > std::visit(overloaded {
> > > > [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
> > > > n.exposedPosition = p;
> > > > },
> > > > [](auto&...) { }
> > > > }, node);
> > > > return node;
> > > > }
> > > >
> > > > (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
> > >
> > > Huh? The design feels odd indeed.
> > > I have usually stuff in variants that have rare things if anything
> > > at all in common.
> >
> > Consider what the function does: it's checking (statically) if the struct has a particular member and setting it.
>
> Do not let complex syntax to confuse you ... magic does not exist.
> It can't. It generates switch-case that checks *dynamically* behind scenes
> what of those 68 is in that particular variant instance "node" and then
> sets the member.
I'm not confused. The determination of whether a struct has a member is done statically via SFINAE. Specifically `decltype(n.exposedPosition)* = nullptr`. Of course *which* struct is of course dynamic.
>
> > > > Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
> > > >
> > > > Node setExposedPosition(Node node, Vec2 p) {
> > > > if(hasField(node, EXPOSED_POSITION_BIT)) {
> > > > node.exposedPosition = p;
> > > > }
> > > > return node;
> > > > }
> > >
> > > External setter? I do not have setter members no idea why I
> > > would want external setters.
> > >
> > > >
> > > > I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
> > > >
> > > > Does that sound like the approach you would take?
> > >
> > > No. Only by factor of two? Then those are rather similar classes.
> > >
> > > From 68 mostly similar to each other "node" classes I would make plain
> > > old polymorphic hierarchy.
> >
> > I used to do a traditional polymorphic hierarchy: it's harder to make value types, and requires much more boilerplate.
>
> Value types in sense that little, immutable objects, passed by value?
> These do not make sense in context of your post at all.
Not necessarily immutable, but yes passed by value. I'm using value-oriented design.
>
> On the contrary, it is boilerplate of piles of those inefficient
> switches from 68 cases all around your code that traditional
> polymorphic hierarchy would remove with just one cheap level of
> indirection added. I have measured it enough to predict that
> program would be at least 4 times quicker, data about 4 times
> smaller and executable also about twice smaller.
This is not runtime performance critical code. (That's all on another thread)
>
> > > If there is need to keep objects of these classes in a single
> > > container then I would use Boost.PolyCollection for efficiency.
> > > https://www.boost.org/doc/libs/1_71_0/doc/html/poly_collection.html
> > >
> > > That design beats both your variant and your monster struct blindfolded
> > > with right hand tied behind back I can bet.
> >
> > I'm using https://github.com/arximboldi/immer ...
>
> I do not know the lib but it is seems from afar that public common
> setters sound like total bullshit with those immers that are
> immutable after construction. Come again and tell what you really
> need.
>
> > ... and can't change my containers.
>
> That is defect of mind. Software is *soft*. It is like drawing on
> sand not carving on obsidian.
Of course, but it takes time to make bigger changes.
>
> Most projects usually combine data initially from rather few container
> types like:
> std::array, std::vector, std::unordered_set, std::unordered_map.
> Then, later, when the needs become more clear those are maintained
> to be more special, precisely suitable containers.
There are big advantages to be had with using those Immer containers which I would not want to abandon.
cheers
[toc] | [prev] | [next] | [standalone]
| From | "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> |
|---|---|
| Date | 2019-12-04 22:39 +0100 |
| Message-ID | <qs991n$80l$1@dont-email.me> |
| In reply to | #70256 |
On 04.12.2019 22:09, Taylor wrote:
> On Wednesday, December 4, 2019 at 12:31:31 PM UTC-8, Öö Tiib wrote:
>> On Wednesday, 4 December 2019 21:07:37 UTC+2, Taylor wrote:
>>> Thanks for your help!
>>>
>>> On Wednesday, December 4, 2019 at 10:26:52 AM UTC-8, Öö Tiib wrote:
>>>> On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
>>>>> I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
>>>>>
>>>>> 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
>>>>>
>>>>> 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
>>>>>
>>>>> Node setExposedPosition(Node node, Vec2 p) {
>>>>> std::visit(overloaded {
>>>>> [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
>>>>> n.exposedPosition = p;
>>>>> },
>>>>> [](auto&...) { }
>>>>> }, node);
>>>>> return node;
>>>>> }
>>>>>
>>>>> (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
>>>>
>>>> Huh? The design feels odd indeed.
>>>> I have usually stuff in variants that have rare things if anything
>>>> at all in common.
>>>
>>> Consider what the function does: it's checking (statically) if the struct has a particular member and setting it.
>>
>> Do not let complex syntax to confuse you ... magic does not exist.
>> It can't. It generates switch-case that checks *dynamically* behind scenes
>> what of those 68 is in that particular variant instance "node" and then
>> sets the member.
>
> I'm not confused. The determination of whether a struct has a member is done statically via SFINAE. Specifically `decltype(n.exposedPosition)* = nullptr`. Of course *which* struct is of course dynamic.
I, on the other hand, am confused.
I remember reading the original blog posting (on a blog by some
"experts", I think Dave Abrahams was there) about functionality like
`overloaded`, to make a set of lambdas available via a single function
that dispatches to them as if with overload resolution.
But now I fail to see, I don't remember, quite how it worked.
As I see it the OP shouldn't assume that readers would be familiar with
`overloaded`.
When I can't imagine it and only vaguely remember reading about it, then
I think most regulars here know just as little about it as I. And
delving into links to third party web pages. Well that's just not done. :)
[snip]
- Alf
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-04 16:18 -0800 |
| Message-ID | <374e069c-2c44-4b3e-bdaa-86d0488d90e4@googlegroups.com> |
| In reply to | #70258 |
On Wednesday, December 4, 2019 at 1:39:20 PM UTC-8, Alf P. Steinbach wrote: > I, on the other hand, am confused. > > I remember reading the original blog posting (on a blog by some > "experts", I think Dave Abrahams was there) about functionality like > `overloaded`, to make a set of lambdas available via a single function > that dispatches to them as if with overload resolution. > > But now I fail to see, I don't remember, quite how it worked. > > As I see it the OP shouldn't assume that readers would be familiar with > `overloaded`. This is my point (2): that it's fancy and new and people might be confused by it. That's one reason I'm looking for other options :)
[toc] | [prev] | [next] | [standalone]
| From | "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> |
|---|---|
| Date | 2019-12-05 05:13 +0100 |
| Message-ID | <qsa04p$pa9$1@dont-email.me> |
| In reply to | #70262 |
On 05.12.2019 01:18, Taylor wrote: > On Wednesday, December 4, 2019 at 1:39:20 PM UTC-8, Alf P. Steinbach wrote: >> I, on the other hand, am confused. >> >> I remember reading the original blog posting (on a blog by some >> "experts", I think Dave Abrahams was there) about functionality like >> `overloaded`, to make a set of lambdas available via a single function >> that dispatches to them as if with overload resolution. >> >> But now I fail to see, I don't remember, quite how it worked. >> >> As I see it the OP shouldn't assume that readers would be familiar with >> `overloaded`. > > This is my point (2): that it's fancy and new and people might be confused by it. That's one reason I'm looking for other options :) I wouldn't describe myself as “new”. I see that the `overloaded` class is just a few lines of C++17 code and is exposed on the cppreference.com page about `std::visit`. You could/should simply have added a comment “For `overloaded`, see <url: https://en.cppreference.com/w/cpp/utility/variant/visit#Example>”. Re the problem you're asking about, it seems clear that there is some commonality of the classes that has not been factored out / abstracted, but that the rest of the code relies on. By stuffing everything into variants you're throwing away critical static type information, replacing it with dynamic type information and checking. A solution should involve not throwing away the static type information, or at least throwing away less of it. And voilá. - Alf
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-05 09:59 -0800 |
| Message-ID | <5ecddbd0-d352-47e7-967d-1378da2635c4@googlegroups.com> |
| In reply to | #70274 |
On Wednesday, December 4, 2019 at 8:13:24 PM UTC-8, Alf P. Steinbach wrote: > On 05.12.2019 01:18, Taylor wrote: > > On Wednesday, December 4, 2019 at 1:39:20 PM UTC-8, Alf P. Steinbach wrote: > >> I, on the other hand, am confused. > >> > >> I remember reading the original blog posting (on a blog by some > >> "experts", I think Dave Abrahams was there) about functionality like > >> `overloaded`, to make a set of lambdas available via a single function > >> that dispatches to them as if with overload resolution. > >> > >> But now I fail to see, I don't remember, quite how it worked. > >> > >> As I see it the OP shouldn't assume that readers would be familiar with > >> `overloaded`. > > > > This is my point (2): that it's fancy and new and people might be confused by it. That's one reason I'm looking for other options :) > > > I wouldn't describe myself as “new”. > > I see that the `overloaded` class is just a few lines of C++17 code and > is exposed on the cppreference.com page about `std::visit`. > > You could/should simply have added a comment “For `overloaded`, see > <url: https://en.cppreference.com/w/cpp/utility/variant/visit#Example>”. > > Re the problem you're asking about, it seems clear that there is some > commonality of the classes that has not been factored out / abstracted, > but that the rest of the code relies on. If I were to use inheritance to factor out commonality, I would need to use multiple inheritance and it could get messy. So for example, there's the base class Node, then there might be ExposedNode, and ColorfulNode, LabeledNode. Or I could use interfaces, such has HasExposedPosition, HasColor, HasLabel, etc. I did this before and it's much more code than the variant stuff. (And of course using virtual functions complicates the use of value types, since you need to avoid slicing.) The SFINAE thing (setExposedPosition) does this all in under 10 lines of code, and automatically works for any new type that has an exposedPosition attribute. It's pretty cool in that way. > > By stuffing everything into variants you're throwing away critical > static type information, replacing it with dynamic type information and > checking. A solution should involve not throwing away the static type > information, or at least throwing away less of it. And voilá. I'm not sure what information I'm throwing away there. Could you elaborate? thanks!
[toc] | [prev] | [next] | [standalone]
| From | Christian Gollwitzer <auriocus@gmx.de> |
|---|---|
| Date | 2019-12-06 09:39 +0100 |
| Message-ID | <qsd446$hs1$1@dont-email.me> |
| In reply to | #70289 |
Am 05.12.19 um 18:59 schrieb Taylor: > On Wednesday, December 4, 2019 at 8:13:24 PM UTC-8, Alf P. Steinbach wrote: >> On 05.12.2019 01:18, Taylor wrote: >> Re the problem you're asking about, it seems clear that there is some >> commonality of the classes that has not been factored out / abstracted, >> but that the rest of the code relies on. > > If I were to use inheritance to factor out commonality, I would need to use multiple inheritance and it could get messy. So for example, there's the base class Node, then there might be ExposedNode, and ColorfulNode, LabeledNode. > > Or I could use interfaces, such has HasExposedPosition, HasColor, HasLabel, etc. I did this before and it's much more code than the variant stuff. > I'm far from understanding the problem, but factoring out common members does not mean you nead "class A: public B" inheritance. You could also have a "struct Node" and then stuff the things that vary into the variant, which is a member of "Node". This is done in C with unions very often e.g. for byte code interpreters, where all the values have a type tag, a reference count, an alternative representation, and then a union which contains the real data. Christian
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-06 09:12 -0800 |
| Message-ID | <9da938c3-df84-460c-a6fa-60198796092d@googlegroups.com> |
| In reply to | #70300 |
On Friday, December 6, 2019 at 12:39:47 AM UTC-8, Christian Gollwitzer wrote: > Am 05.12.19 um 18:59 schrieb Taylor: > > On Wednesday, December 4, 2019 at 8:13:24 PM UTC-8, Alf P. Steinbach wrote: > >> On 05.12.2019 01:18, Taylor wrote: > >> Re the problem you're asking about, it seems clear that there is some > >> commonality of the classes that has not been factored out / abstracted, > >> but that the rest of the code relies on. > > > > If I were to use inheritance to factor out commonality, I would need to use multiple inheritance and it could get messy. So for example, there's the base class Node, then there might be ExposedNode, and ColorfulNode, LabeledNode. > > > > Or I could use interfaces, such has HasExposedPosition, HasColor, HasLabel, etc. I did this before and it's much more code than the variant stuff. > > > > I'm far from understanding the problem, but factoring out common members > does not mean you nead "class A: public B" inheritance. You could also > have a "struct Node" and then stuff the things that vary into the > variant, which is a member of "Node". This is done in C with unions very > often e.g. for byte code interpreters, where all the values have a type > tag, a reference count, an alternative representation, and then a union > which contains the real data. > > Christian Thanks Christian. That would be an improvement and cut down on the variant visitation (it would help compilation time on one file in particular). I don't think it would go far enough though in improving my compilation time.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-04 14:46 -0800 |
| Message-ID | <d3834eb6-fd54-45fa-be53-057cf1dfbaff@googlegroups.com> |
| In reply to | #70256 |
On Wednesday, 4 December 2019 23:09:54 UTC+2, Taylor wrote:
> On Wednesday, December 4, 2019 at 12:31:31 PM UTC-8, Öö Tiib wrote:
> > On Wednesday, 4 December 2019 21:07:37 UTC+2, Taylor wrote:
> > > Thanks for your help!
> > >
> > > On Wednesday, December 4, 2019 at 10:26:52 AM UTC-8, Öö Tiib wrote:
> > > > On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
> > > > > I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
> > > > >
> > > > > 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
> > > > >
> > > > > 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
> > > > >
> > > > > Node setExposedPosition(Node node, Vec2 p) {
> > > > > std::visit(overloaded {
> > > > > [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
> > > > > n.exposedPosition = p;
> > > > > },
> > > > > [](auto&...) { }
> > > > > }, node);
> > > > > return node;
> > > > > }
> > > > >
> > > > > (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
> > > >
> > > > Huh? The design feels odd indeed.
> > > > I have usually stuff in variants that have rare things if anything
> > > > at all in common.
> > >
> > > Consider what the function does: it's checking (statically) if the struct has a particular member and setting it.
> >
> > Do not let complex syntax to confuse you ... magic does not exist.
> > It can't. It generates switch-case that checks *dynamically* behind scenes
> > what of those 68 is in that particular variant instance "node" and then
> > sets the member.
>
> I'm not confused. The determination of whether a struct has a member is done statically via SFINAE. Specifically `decltype(n.exposedPosition)* = nullptr`. Of course *which* struct is of course dynamic.
That is exactly what I meant.
Compiler generates dynamic switch over 68 cases, each case block
made with SFINAE for type handled in that block. Basically just
odd syntax sugar to hide long switch-case. You yourself said you
have very numerous of those. Therefore certain combo of classical
dynamic polymorphism and classical visitor pattern will win the
huge variant of everything (my modules handle rarely over 50 classes)
in all areas easily and without much doubt.
>
> >
> > > > > Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
> > > > >
> > > > > Node setExposedPosition(Node node, Vec2 p) {
> > > > > if(hasField(node, EXPOSED_POSITION_BIT)) {
> > > > > node.exposedPosition = p;
> > > > > }
> > > > > return node;
> > > > > }
> > > >
> > > > External setter? I do not have setter members no idea why I
> > > > would want external setters.
> > > >
> > > > >
> > > > > I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
> > > > >
> > > > > Does that sound like the approach you would take?
> > > >
> > > > No. Only by factor of two? Then those are rather similar classes.
> > > >
> > > > From 68 mostly similar to each other "node" classes I would make plain
> > > > old polymorphic hierarchy.
> > >
> > > I used to do a traditional polymorphic hierarchy: it's harder to make value types, and requires much more boilerplate.
> >
> > Value types in sense that little, immutable objects, passed by value?
> > These do not make sense in context of your post at all.
>
> Not necessarily immutable, but yes passed by value. I'm using value-oriented design.
Yeah I noticed that you both pass and return that variant as value
in your examples. Are you sure that "value-oriented design" means
that "always make copies when possible"?
> > On the contrary, it is boilerplate of piles of those inefficient
> > switches from 68 cases all around your code that traditional
> > polymorphic hierarchy would remove with just one cheap level of
> > indirection added. I have measured it enough to predict that
> > program would be at least 4 times quicker, data about 4 times
> > smaller and executable also about twice smaller.
>
> This is not runtime performance critical code. (That's all on another thread)
It was you who said that people "might be baffled by the c++ fancyness"
of your code. There are no performance, no robustness, no clarity,
no readability ... what *is* the point?
> >
> > > > If there is need to keep objects of these classes in a single
> > > > container then I would use Boost.PolyCollection for efficiency.
> > > > https://www.boost.org/doc/libs/1_71_0/doc/html/poly_collection.html
> > > >
> > > > That design beats both your variant and your monster struct blindfolded
> > > > with right hand tied behind back I can bet.
> > >
> > > I'm using https://github.com/arximboldi/immer ...
> >
> > I do not know the lib but it is seems from afar that public common
> > setters sound like total bullshit with those immers that are
> > immutable after construction. Come again and tell what you really
> > need.
> >
> > > ... and can't change my containers.
> >
> > That is defect of mind. Software is *soft*. It is like drawing on
> > sand not carving on obsidian.
>
> Of course, but it takes time to make bigger changes.
True. That is why I keep my stuff very modular. Bit more work
with making and keeping the architecture clean but lot easier to
replace the parts with better or even to have (optional) alternatives
side-by-side.
> >
> > Most projects usually combine data initially from rather few container
> > types like:
> > std::array, std::vector, std::unordered_set, std::unordered_map.
> > Then, later, when the needs become more clear those are maintained
> > to be more special, precisely suitable containers.
>
> There are big advantages to be had with using those Immer containers which I would not want to abandon.
Huh? When you are collector of worthless recommendations then ask for
advice but keep the situation that you are in and constraints that you
have ... in secrecy. Instead make confusing claims with strange
examples. ;) That immer seemed to be all for performance in concurrent
processing. But just plain old "favor immutability" does not need
special libraries for it so it did not make me to feel interested.
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-04 16:28 -0800 |
| Message-ID | <bb44e0ad-7db9-4fe6-a1af-3180f75020c2@googlegroups.com> |
| In reply to | #70261 |
On Wednesday, December 4, 2019 at 2:46:42 PM UTC-8, Öö Tiib wrote:
> On Wednesday, 4 December 2019 23:09:54 UTC+2, Taylor wrote:
> > On Wednesday, December 4, 2019 at 12:31:31 PM UTC-8, Öö Tiib wrote:
> > > On Wednesday, 4 December 2019 21:07:37 UTC+2, Taylor wrote:
> > > > Thanks for your help!
> > > >
> > > > On Wednesday, December 4, 2019 at 10:26:52 AM UTC-8, Öö Tiib wrote:
> > > > > On Wednesday, 4 December 2019 18:37:50 UTC+2, Taylor wrote:
> > > > > > I'm using std::variant in my code for one very important type (`Node`). This variant has 68 different types in it. There are two issues:
> > > > > >
> > > > > > 1. Compile times are extremely slow (~30s per file), due to variant visitation. I'm an indie developer and I don't want to have to buy a new computer (might only be a factor of two faster anyway).
> > > > > >
> > > > > > 2. If I hire a contractor to help, they might be baffled by the c++ fancyness, such as:
> > > > > >
> > > > > > Node setExposedPosition(Node node, Vec2 p) {
> > > > > > std::visit(overloaded {
> > > > > > [p](auto& n, decltype(n.exposedPosition)* = nullptr) {
> > > > > > n.exposedPosition = p;
> > > > > > },
> > > > > > [](auto&...) { }
> > > > > > }, node);
> > > > > > return node;
> > > > > > }
> > > > > >
> > > > > > (This kind of stuff is all over the place, because it eliminates a LOT of redundant code)
> > > > >
> > > > > Huh? The design feels odd indeed.
> > > > > I have usually stuff in variants that have rare things if anything
> > > > > at all in common.
> > > >
> > > > Consider what the function does: it's checking (statically) if the struct has a particular member and setting it.
> > >
> > > Do not let complex syntax to confuse you ... magic does not exist.
> > > It can't. It generates switch-case that checks *dynamically* behind scenes
> > > what of those 68 is in that particular variant instance "node" and then
> > > sets the member.
> >
> > I'm not confused. The determination of whether a struct has a member is done statically via SFINAE. Specifically `decltype(n.exposedPosition)* = nullptr`. Of course *which* struct is of course dynamic.
>
> That is exactly what I meant.
> Compiler generates dynamic switch over 68 cases, each case block
> made with SFINAE for type handled in that block. Basically just
> odd syntax sugar to hide long switch-case. You yourself said you
> have very numerous of those. Therefore certain combo of classical
> dynamic polymorphism and classical visitor pattern will win the
> huge variant of everything (my modules handle rarely over 50 classes)
> in all areas easily and without much doubt.
>
> >
> > >
> > > > > > Now that's pretty cool pattern matching, but let's face it, this would be much more understandable:
> > > > > >
> > > > > > Node setExposedPosition(Node node, Vec2 p) {
> > > > > > if(hasField(node, EXPOSED_POSITION_BIT)) {
> > > > > > node.exposedPosition = p;
> > > > > > }
> > > > > > return node;
> > > > > > }
> > > > >
> > > > > External setter? I do not have setter members no idea why I
> > > > > would want external setters.
> > > > >
> > > > > >
> > > > > > I've found that if I simply make Node a struct with every possible data member from all the variant types, it only increases the size of Node by a factor of two, which is totally fine. (I could use std::optional for each member, but that would increase the size, and potentially be more dynamic than I need)
> > > > > >
> > > > > > Does that sound like the approach you would take?
> > > > >
> > > > > No. Only by factor of two? Then those are rather similar classes.
> > > > >
> > > > > From 68 mostly similar to each other "node" classes I would make plain
> > > > > old polymorphic hierarchy.
> > > >
> > > > I used to do a traditional polymorphic hierarchy: it's harder to make value types, and requires much more boilerplate.
> > >
> > > Value types in sense that little, immutable objects, passed by value?
> > > These do not make sense in context of your post at all.
> >
> > Not necessarily immutable, but yes passed by value. I'm using value-oriented design.
>
> Yeah I noticed that you both pass and return that variant as value
> in your examples. Are you sure that "value-oriented design" means
> that "always make copies when possible"?
It doesn't.
>
> > > On the contrary, it is boilerplate of piles of those inefficient
> > > switches from 68 cases all around your code that traditional
> > > polymorphic hierarchy would remove with just one cheap level of
> > > indirection added. I have measured it enough to predict that
> > > program would be at least 4 times quicker, data about 4 times
> > > smaller and executable also about twice smaller.
> >
> > This is not runtime performance critical code. (That's all on another thread)
>
> It was you who said that people "might be baffled by the c++ fancyness"
> of your code. There are no performance, no robustness, no clarity,
> no readability ... what *is* the point?
Well, I don't claim to write perfect code :)
The point with that example was to be able to express things concisely. Performance doesn't matter that much (within reason of course).
I actually think it's fairly readable, but still a bit confusing for folks who aren't really up to date on "modern" c++.
>
> > >
> > > > > If there is need to keep objects of these classes in a single
> > > > > container then I would use Boost.PolyCollection for efficiency.
> > > > > https://www.boost.org/doc/libs/1_71_0/doc/html/poly_collection.html
> > > > >
> > > > > That design beats both your variant and your monster struct blindfolded
> > > > > with right hand tied behind back I can bet.
> > > >
> > > > I'm using https://github.com/arximboldi/immer ...
> > >
> > > I do not know the lib but it is seems from afar that public common
> > > setters sound like total bullshit with those immers that are
> > > immutable after construction. Come again and tell what you really
> > > need.
> > >
> > > > ... and can't change my containers.
> > >
> > > That is defect of mind. Software is *soft*. It is like drawing on
> > > sand not carving on obsidian.
> >
> > Of course, but it takes time to make bigger changes.
>
> True. That is why I keep my stuff very modular. Bit more work
> with making and keeping the architecture clean but lot easier to
> replace the parts with better or even to have (optional) alternatives
> side-by-side.
>
> > >
> > > Most projects usually combine data initially from rather few container
> > > types like:
> > > std::array, std::vector, std::unordered_set, std::unordered_map.
> > > Then, later, when the needs become more clear those are maintained
> > > to be more special, precisely suitable containers.
> >
> > There are big advantages to be had with using those Immer containers which I would not want to abandon.
>
> Huh? When you are collector of worthless recommendations then ask for
> advice but keep the situation that you are in and constraints that you
> have ... in secrecy. Instead make confusing claims with strange
> examples. ;) That immer seemed to be all for performance in concurrent
> processing. But just plain old "favor immutability" does not need
> special libraries for it so it did not make me to feel interested.
I'm not trying to be secretive. The immer containers offer memory efficient immutability, and other advantages. The author of Immer has some great talks which I would recommend watching:
https://youtu.be/_oBx_NbLghY
https://youtu.be/sPhpelUfu8Q
cheers
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-05 00:00 -0800 |
| Message-ID | <053a8908-3f67-4e9e-8f5a-b419ce963719@googlegroups.com> |
| In reply to | #70263 |
On Thursday, 5 December 2019 02:28:14 UTC+2, Taylor wrote: > > I'm not trying to be secretive. The immer containers offer memory efficient immutability, and other advantages. The author of Immer has some great talks which I would recommend watching: > > https://youtu.be/_oBx_NbLghY > https://youtu.be/sPhpelUfu8Q Each tool has its use but hope of silver bullets makes you to sell snake oil to yourself. You wrote "it only increases the size of Node by a factor of two, which is totally fine". You seemingly hope that immer wins the consequences: twice more storage used per object and twice more cache misses somehow back? Again, there can't be any magic, sorry. That is why Boost.PolyCollection wins: 1) We get twice the memory efficiency compared with your original variant and quadruple memory efficiency compared with your "factor of two" monster. 2) We get readability and maintainability of classical dynamic polymorphism compared with tons of half-hidden switch-cases. 3) We get meaningful layout of data not some kind of flags that tell what members do make sense and what members don't. 4) We get code-base with what work is possible to divide between contractors. 5) There are nothing bleeding edge fancy about all of it.
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-05 00:48 -0800 |
| Message-ID | <3fe1e02a-65c5-424b-bfda-6bf56f1be168@googlegroups.com> |
| In reply to | #70277 |
On Thursday, December 5, 2019 at 12:00:21 AM UTC-8, Öö Tiib wrote: > On Thursday, 5 December 2019 02:28:14 UTC+2, Taylor wrote: > > > > I'm not trying to be secretive. The immer containers offer memory efficient immutability, and other advantages. The author of Immer has some great talks which I would recommend watching: > > > > https://youtu.be/_oBx_NbLghY > > https://youtu.be/sPhpelUfu8Q > > Each tool has its use but hope of silver bullets makes you to sell snake > oil to yourself. You wrote "it only increases the size of Node by a > factor of two, which is totally fine". > > You seemingly hope that immer wins the consequences: twice more storage > used per object and twice more cache misses somehow back? Again, there > can't be any magic, sorry. > > That is why Boost.PolyCollection wins: > 1) We get twice the memory efficiency compared with your original variant > and quadruple memory efficiency compared with your "factor of two" monster. > 2) We get readability and maintainability of classical dynamic > polymorphism compared with tons of half-hidden switch-cases. > 3) We get meaningful layout of data not some kind of flags that > tell what members do make sense and what members don't. > 4) We get code-base with what work is possible to divide between contractors. > 5) There are nothing bleeding edge fancy about all of it. PolyCollection is cool and I appreciate the suggestion. Unfortunately, it alone doesn't have the structural sharing I need in order to implement undo/redo efficiently. I would probably have to use a memento pattern instead, which is error prone.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-05 08:17 -0800 |
| Message-ID | <16f665fe-0912-4999-ae25-785311a0459e@googlegroups.com> |
| In reply to | #70278 |
On Thursday, 5 December 2019 10:48:18 UTC+2, Taylor wrote: > On Thursday, December 5, 2019 at 12:00:21 AM UTC-8, Öö Tiib wrote: > > On Thursday, 5 December 2019 02:28:14 UTC+2, Taylor wrote: > > > > > > I'm not trying to be secretive. The immer containers offer memory efficient immutability, and other advantages. The author of Immer has some great talks which I would recommend watching: > > > > > > https://youtu.be/_oBx_NbLghY > > > https://youtu.be/sPhpelUfu8Q > > > > Each tool has its use but hope of silver bullets makes you to sell snake > > oil to yourself. You wrote "it only increases the size of Node by a > > factor of two, which is totally fine". > > > > You seemingly hope that immer wins the consequences: twice more storage > > used per object and twice more cache misses somehow back? Again, there > > can't be any magic, sorry. > > > > That is why Boost.PolyCollection wins: > > 1) We get twice the memory efficiency compared with your original variant > > and quadruple memory efficiency compared with your "factor of two" monster. > > 2) We get readability and maintainability of classical dynamic > > polymorphism compared with tons of half-hidden switch-cases. > > 3) We get meaningful layout of data not some kind of flags that > > tell what members do make sense and what members don't. > > 4) We get code-base with what work is possible to divide between contractors. > > 5) There are nothing bleeding edge fancy about all of it. > > PolyCollection is cool and I appreciate the suggestion. Unfortunately, it alone doesn't have the structural sharing I need in order to implement undo/redo efficiently. I would probably have to use a memento pattern instead, which is error prone. I do not use Memento pattern ever. Memento had on 95% of cases when I met it started as naive, locally invented square wheel. Time had turned it into annoying spaghetti that just complicated everything. It was often misused for other somewhat similar purposes (like cut/copy/paste or drag and drop). As result over half of the issues in these projects were directly caused by that dreaded Memento. Why not to use serialization capabilities for most of such purposes? Everything worth undoing or rolling back wants soon to become something that is worth storing persistently and even worth transferring to far-away sites. There are literal piles of serialization libraries available (like Protobufs, Flatbuffers, Cereal, Cap'n Proto, Bond, Apache Avro, Thrift, MessagePack and just name it). The popular ones are done by good programmers, tested by lot of people and so tend to be adequate and far from naive. Pick one that is language- and platform-neutral ... that provides also wider opportunities of automatic black-box testing of your modules. ;)
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-05 09:44 -0800 |
| Message-ID | <e9f617b4-35e9-488a-9b9c-bde12b9268ae@googlegroups.com> |
| In reply to | #70286 |
On Thursday, December 5, 2019 at 8:17:37 AM UTC-8, Öö Tiib wrote: > Why not to use serialization capabilities for most of such purposes? > Everything worth undoing or rolling back wants soon to become > something that is worth storing persistently and even worth > transferring to far-away sites. There are literal piles of serialization > libraries available (like Protobufs, Flatbuffers, Cereal, Cap'n Proto, > Bond, Apache Avro, Thrift, MessagePack and just name it). The > popular ones are done by good programmers, tested by lot of > people and so tend to be adequate and far from naive. Pick one > that is language- and platform-neutral ... that provides also wider > opportunities of automatic black-box testing of your modules. ;) I use Flatbuffers for serialization. It's pretty good. But it doesn't easily provide the structural sharing that I need to make undo/redo memory-efficient. For example, if my document contains large data (images, audio, etc.) I don't want to have to save that out after every user interaction. (I'm simplifying a bit: Flatbuffers is a DAG so it can express structural sharing, however I think it would be tricky to implement an efficient undo system with it.) I have another app which doesn't use structural sharing, and I had to lower the max undos, after some users complained (to put it mildly) about storage usage.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-05 11:14 -0800 |
| Message-ID | <de6c5e6e-216c-4d33-8862-78950607991b@googlegroups.com> |
| In reply to | #70288 |
On Thursday, 5 December 2019 19:44:54 UTC+2, Taylor wrote: > On Thursday, December 5, 2019 at 8:17:37 AM UTC-8, Öö Tiib wrote: > > Why not to use serialization capabilities for most of such purposes? > > Everything worth undoing or rolling back wants soon to become > > something that is worth storing persistently and even worth > > transferring to far-away sites. There are literal piles of serialization > > libraries available (like Protobufs, Flatbuffers, Cereal, Cap'n Proto, > > Bond, Apache Avro, Thrift, MessagePack and just name it). The > > popular ones are done by good programmers, tested by lot of > > people and so tend to be adequate and far from naive. Pick one > > that is language- and platform-neutral ... that provides also wider > > opportunities of automatic black-box testing of your modules. ;) > > I use Flatbuffers for serialization. It's pretty good. But it doesn't easily provide the structural sharing that I need to make undo/redo memory-efficient. For example, if my document contains large data (images, audio, etc.) I don't want to have to save that out after every user interaction. (I'm simplifying a bit: Flatbuffers is a DAG so it can express structural sharing, however I think it would be tricky to implement an efficient undo system with it.) Sounds again like some kind of straw-man argument ... who would serialize whole document to store erasure or change of one image? Only the state and location of image before change needs to be serialized for to be capable of restoring it. > I have another app which doesn't use structural sharing, and I had to lower the max undos, after some users complained (to put it mildly) about storage usage. No wonder. Look back at your OP. Should you replace unions of 68 classes with one class with all possible members in those classes? Uhh. I thought anyone wielding wasteful stuff like C# or Java half-decently or horrible stuff like Python or PHP expertly will beat C++ of that guy in all of clarity, maintainability, speed and storage usage.
[toc] | [prev] | [next] | [standalone]
| From | Taylor <wtholliday@gmail.com> |
|---|---|
| Date | 2019-12-05 12:37 -0800 |
| Message-ID | <705aa88e-03c1-4956-b204-557868e28005@googlegroups.com> |
| In reply to | #70292 |
On Thursday, December 5, 2019 at 11:14:39 AM UTC-8, Öö Tiib wrote: > > Sounds again like some kind of straw-man argument ... who would serialize > whole document to store erasure or change of one image? Only the state and > location of image before change needs to be serialized for to be capable > of restoring it. Sure, I could serialize diffs, but with significant additional complexity (it's a bit close to the memento pattern). If you know of a way that flatbuffers makes that easier, that would be good to know. I couldn't find anything searching around.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2019-12-05 13:20 -0800 |
| Message-ID | <5564a179-764c-4a4a-b198-9edafbdd0478@googlegroups.com> |
| In reply to | #70293 |
On Thursday, 5 December 2019 22:37:20 UTC+2, Taylor wrote: > On Thursday, December 5, 2019 at 11:14:39 AM UTC-8, Öö Tiib wrote: > > > > Sounds again like some kind of straw-man argument ... who would serialize > > whole document to store erasure or change of one image? Only the state and > > location of image before change needs to be serialized for to be capable > > of restoring it. > > Sure, I could serialize diffs, but with significant additional complexity (it's a bit close to the memento pattern). What diffs? Chain of reversible operations. First operation: Erase: that picture from there. Next operation Undo: put that picture back there. Next operation Redo: erase that picture again from there. What have diffs to do with Memento pattern? Utter nonsense. Read at least Wikipedia article about it. If you know of a way that flatbuffers makes that easier, that would be good to know. I couldn't find anything searching around. Flatbuffers? Huh? But it generates all code for you? All for needed for storing your data into buffer or reading it back from it. Bit verbose interface for my taste but clear enough. Have you at least tried the tutorials of it or something? Very confusing.
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c++
csiph-web