Project

General

Profile

Wt4's Memory Model

Added by Rutger ter Borg about 6 years ago

Hey all,

I have been using Wt for a couple of years now, and I like it a lot. I recently saw a glimpse of Wt4. I have two remarks regarding the new memory management:

1) Although I agree unique_ptr is more clear in terms of ownership, I guess I don't like

WWidget* addWidget( unique_ptr< Widget > widget ) ...

too much. It is way more verbose. It requires a Wt3 code base change. C++14 for make_unique isn't a much adopted standard yet. Altough the function states the input is unique, apparently the pointer to the widget is not 'unique', or is intented to be unique. Apparently it is still shared, but without reference counting.

2) Wt4 forces its users to allocate everything separately (let's not consider placement new). Wt3 used something similar to Qt's memory model: http://doc.qt.io/qt-5/objecttrees.html. It enables a user to choose between an allocation-per-object/widget or to compound allocations for certain views. This is also the way I structured some of my Wt3 views (also due to having a background in Qt before Wt). Performance-wise, this might not mean much, but it can not be dismissed that doing fewer allocations usually is faster than doing more.

Are you sure the you have considered other options, such as

?

Thanks,

Rutger


Replies (9)

RE: Wt4's Memory Model - Added by Roel Standaert about 6 years ago

Hello Rutger,

As for your first remark: creating and adding a new widget to a container is indeed a bit more verbose. That's why we added WContainerWidget::addNew. I don't really see your point here, though: "C++14 for make_unique isn't a much adopted standard yet". It works with GCC 5, which is what we use the most on Ubuntu 16.04, and Visual Studio 2015 or higher, so I don't see why you would think it's not adopted? Our impression was that we were a bit late to the game with Wt 4, even.

It is in theory still possible to manage the memory location of your widgets yourself. You already mentioned placement new, so an advanced user would still be able to do that should they want to. We chose to go for clarity in Wt 4, especially for newer users. If new users are aware of the C Core Guidelines, Wt's way of doing things should not be surprising to them. Also, I don't think that avoiding make_unique would save that many mallocs. Wt was never optimized for extreme malloc avoidance, so even if you do that, there will still be more memory allocations in the implementation of those widgets. I believe that this is the case for Qt, too.

  • We don't think that keeping the code backwards compatible and at the same time making it more explicit and in line with the existing modern C guidelines (like the C Core Guidelines) is possible. In Wt 4 we chose to move away from Qt's memory model, and adopt one that should be understandable for all modern C programmers, not just those that are coming from Qt.
  • Not working with pointers would mean that the burden of managing the memory is placed entirely on the user of Wt. This was considered, but it quickly became clear that a way to add the ownership to the parent widget was still desirable. Instead of presenting our users with a difficult choice, we chose to have one clear and flexible way to do memory management. In theory, if desired, this option could still be added in the future. In any case, advanced users can still get around it.
  • We did not consider using root_ptr. I don't think it's desirable to make learning to work with Wt even harder by introducing more concepts. We want to stick to the STL as much as possible.

Regards,

Roel

RE: Wt4's Memory Model - Added by Mark Petryk about 6 years ago

Not intending to stick my nose where it wasn't asked to be stuck, but I have to say to Wt that the new 4x memory model I super really appreciate. While it is a bit of some new syntax to learn, and can 'seem' more bulky at first glance, I feel like, ultimately, it is much clearer to manage. And, as far as 'clean syntax'... here is what I can write:

222 CurrentConditions::CurrentConditions()·
223 : Wt::WContainerWidget()·
224 {·
225   m_templt = addNew<Wt::WTemplate>·
226   (·
227     "${refresh}<br />"·
228   );·
229 · 
230   auto pbRefresh = m_templt-> bindNew<Wt::WPushButton>("refresh","refresh");·
231   pbRefresh-> clicked().connect( this, &CurrentConditions::refresh );·
232 · 
233 }·

I think that is really easy to read. To be able to state 'addNew(params)' is really nice, and quite clean, in my opinion.

Wt Rocks!

RE: Wt4's Memory Model - Added by lm at about 6 years ago

creating and adding a new widget to a container is indeed a bit more verbose. That's why we added WContainerWidget::addNew.

I don't notice extra verbosity. I guess if you're just going to put a text into a container: container->addWidget(std::make_unique<Wt::WText>("some text")); maybe it's more verbose, but when would someone do this? Don't you add style information or an id? You'll surely always need to do something like

auto new_text {std::make_unique<Wt::WText>("some text")};
new_text->setId("my-text");
container->addWidget(std::move(new_text));

And this is close enough to the same from the old version.

C++14 for make_unique isn't a much adopted standard yet.

What compiler are you using? You'll have to update your build tools some time! I use arch linux, so if there is a gcc release today, I get it tomorrow. I understand not everyone wants to work with up-to-date software, but std::make_unique was one of the first-adopted items in C 14 implementations. Many compilers added std::make_unique support before C 14 was published.

Our impression was that we were a bit late to the game with Wt 4, even.

Making good decisions quickly is difficult and onerous. I would much rather a good decision a bit late than a bad decision quickly!

We don't think that keeping the code backwards compatible and at the same time making it more explicit and in line with the existing modern C guidelines (like the C Core Guidelines) is possible. In Wt 4 we chose to move away from Qt's memory model, and adopt one that should be understandable for all modern C programmers, not just those that are coming from Qt.

Right on.

... I don't think it's desirable to make learning to work with Wt even harder by introducing more concepts. We want to stick to the STL as much as possible.

Right on. I was thoroughly impressed to see the additions of std::unique_ptr. I see that this change breaks from the Qt Way, but it's a good direction. Breaking changes must come, and I'm happy that this breaking change is well worth it.

Not working with pointers would mean that the burden of managing the memory is placed entirely on the user of Wt. This was considered, but it quickly became clear that a way to add the ownership to the parent widget was still desirable.

Another aspect that wasn't mentioned is pass-by-value. This obviously doesn't hold water, though. Manipulating a WWidget that was passed by value is prohibitively byzantine.

Keep up the good work, Wt!

RE: Wt4's Memory Model - Added by Roel Standaert about 6 years ago

I would generally advise against changing the ids of widgets instead of using the auto-generated id. Is there a particular reason why you need to use setId?

I tend to write my code a bit differently. I often do this:

auto button = container->addNew<Wt::WPushButton>("Button");
// modify the properties of the Wt::PushButton* returned by addNew

So we often add the widget to the widget tree and then change its properties, connect signals, etc.

A lot of our example code did end up being more verbose when porting to Wt 4, before addNew was added.

RE: Wt4's Memory Model - Added by lm at about 6 years ago

I set the id so that I can make reference to the elements in CSS. How else should I do it?

I didn't realize addNew returns a pointer; that is certainly more convenient. Thanks!

RE: Wt4's Memory Model - Added by Roel Standaert about 6 years ago

Everything you can do with ids in CSS you could also do with classes, so I would recommend using addStyleClass() instead.

RE: Wt4's Memory Model - Added by lm at about 6 years ago

I would generally advise against changing the ids of widgets instead of using the auto-generated id.

Is this to avoid accidental naming collisions?

RE: Wt4's Memory Model - Added by Roel Standaert about 6 years ago

Not just accidental naming collisions, but that is also a good reason.

It's also a feature that is rather bug-prone, since Wt uses this id internally a lot. I've been doing my best to hunt down bugs where setting the id manually would cause problems, because the old id would maybe still be used somewhere, but I'm not completely positive that I've caught all of them. In our own applications, we almost never actually set the id ourselves. It's just not necessary.

RE: Wt4's Memory Model - Added by lm at about 6 years ago

Thanks for the caveat. If I see anything, I'll be sure to pass it on!

I generally use them as I said above:

auto w {std::make_unique<Wt::WText>("hey")};
w->setId("the-id");
...

So I doubt Wt has a chance to cache the wrong value. I'll lean toward classes more in the future, though.

    (1-9/9)