Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #70243 > unrolled thread

issues with std::variant

Started bywtholliday@gmail.com
First post2019-12-04 08:37 -0800
Last post2019-12-05 22:15 +0100
Articles 20 on this page of 32 — 8 participants

Back to article view | Back to comp.lang.c++


Contents

  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 →


#70243 — issues with std::variant

Fromwtholliday@gmail.com
Date2019-12-04 08:37 -0800
Subjectissues 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]


#70250

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#70253

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70255

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#70256

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70258

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-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]


#70262

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70274

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-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]


#70289

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70300

FromChristian Gollwitzer <auriocus@gmx.de>
Date2019-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]


#70313

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70261

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#70263

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70277

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#70278

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70286

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#70288

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70292

FromÖö Tiib <ootiib@hot.ee>
Date2019-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]


#70293

FromTaylor <wtholliday@gmail.com>
Date2019-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]


#70295

FromÖö Tiib <ootiib@hot.ee>
Date2019-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