November 09, 2012
On Friday, 9 November 2012 at 21:06:16 UTC, Ziad Hatahet wrote:
> Method dispatch is still done at runtime though.

 If opDispatch is small&simple can/does it get inlined to the callers?
November 09, 2012
On 9 November 2012 21:39, Era Scarecrow <rtcvb32@yahoo.com> wrote:
> On Friday, 9 November 2012 at 21:06:16 UTC, Ziad Hatahet wrote:
>>
>> Method dispatch is still done at runtime though.
>
>
>  If opDispatch is small&simple can/does it get inlined to the callers?

Potentially yes, but only with optimisation turned on. ;-)

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
November 09, 2012
On Friday, 9 November 2012 at 21:52:49 UTC, Iain Buclaw wrote:
> On 9 November 2012 21:39, Era Scarecrow <rtcvb32@yahoo.com> wrote:
>>  If opDispatch is small&simple can/does it get inlined to the callers?
>
> Potentially yes, but only with optimization turned on. ;-)

 I thought so, and hope so :)
November 10, 2012
Am Thu, 08 Nov 2012 23:38:53 +0100
schrieb "Tommi" <tommitissari@hotmail.com>:

> On Thursday, 8 November 2012 at 21:43:32 UTC, Max Klyga wrote:
> > Dinamic polimorphism isn't gone anywhere, it was just shifted to delegates.
> 
> But there's no restrictive type hierarchy that causes unnecessary coupling. Also, compared to virtual functions, there's no overhead from the vtable lookup. Shape doesn't need to search for the correct member function pointer, it already has it.
> 
> It's either that, or else I've misunderstood how virtual functions work.

They work like this: Each object has as a pointer to a table
of method pointers. When you extend a class, the new method
pointers are appended to the list and existing entries are
replaced with overrides where you have them.
So a virtual method 'draw()' may get slot 3 in that table and
at runtime it is not much more than:

obj.vftable[3]();

These are three pointer dereferences (object, vftable entry
3, method), but no search.

-- 
Marco

November 10, 2012
P.S.:
A) The more time is spent inside the virtual method, the less
noticeable the impact of the lookup.
B) If you call one virtual method often inside a single
function, compilers typically cache the method pointer in some
register.

-- 
Marco

November 10, 2012
On Saturday, 10 November 2012 at 09:23:40 UTC, Marco Leise wrote:
> They work like this: Each object has as a pointer to a table
> of method pointers. When you extend a class, the new method
> pointers are appended to the list and existing entries are
> replaced with overrides where you have them.
> So a virtual method 'draw()' may get slot 3 in that table and
> at runtime it is not much more than:
>
> obj.vftable[3]();

Is vftable essentially an array? So, it's just a matter of offsetting a pointer to get access to any particular slot in the table?

If virtual method calls are really that fast to do, then I think the idiom in the code snippet of my first post is useless, and the idiom they represent in that video I linked to is actually pretty great.

Note: In order to make that video's sound bearable, you have to cut out the highest frequencies of the sound and lower some of the middle ones. I happened to have this "Realtek HD Audio Manager" which made it simple. Using the "city" filter helped a bit too. Don't know what it did.
November 10, 2012
Tommi wrote:
> If virtual method calls are really that fast to do, then I think the idiom in the code snippet of my first post is useless, and the idiom they represent in that video I linked to is actually pretty great.

Virtual functions have other performance limitations, naming they can't be inlined. So small virtual calls do have a big impact if used often, especially (so I hear) on ARM processors which don't have as advanced branch-prediction machinery as x86 (again, I'm just repeating what I've heard before).
November 11, 2012
How would you create a vector of canvas and iterate over them?
November 12, 2012
On Sunday, 11 November 2012 at 13:24:07 UTC, gnzlbg wrote:
> How would you create a vector of canvas and iterate over them?

I assume you mean to ask "How'd you create a vector of shapes?".
And I assume you mean "... by using the
pointers-to-member-functions design pattern introduced in the
first post". Notice that in the video I posted, they introduce a
similar but cleaner design pattern, that uses virtual functions
to accomplish the same goal. I think it's better to use that,
given that virtual function calls aren't noticeably slower than
calling through those member function pointers.

But anyway, here's how you'd do it using the
pointers-to-member-functions idiom:

#include <conio.h>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>

template <int typeId>
class MyShape
{
public:
     void refresh()
     {
         _cprintf("MyShape<%d> refreshed\n", typeId);
     }
};

struct Shape
{
     std::function<void ()> refresh;

     template <typename S, typename _ = typename std::enable_if<
         std::is_same<decltype(S().refresh()), void>::value
     >::type>
     Shape(S&& s)
         : _s (new S(s))
     {
         refresh = [&]()
         { return reinterpret_cast<S*>(_s.get())->refresh(); };
     }

private:
     std::unique_ptr<void> _s; // or std::shared_ptr
};

int main()
{
     std::vector<Shape> shapes;
     shapes.emplace_back(MyShape<2>());
     shapes.emplace_back(MyShape<4>());

     for (auto& shape : shapes)
     {
         shape.refresh();
     }

     _getch();
     return 0;
}

// Prints:
MyShape<2> refreshed
MyShape<4> refreshed
November 12, 2012
I should point out, just so that no-one is missing the obvious
here, that you'd be using static polymorphism through the use of
template functions whenever it's possible, i.e. when you don't
need to store polymorphic types.

So, you'd do this:

template <typename S>
auto func(const S& shape)
-> typename std::enable_if<
     is_shape<S>::value
>::type
{
     // ...
}

You would NOT do this:

void func(const Shape& shape)
{
     // ...
}

The big question is then: is the code bloat introduced by the
massive use of template functions worth the speed gained through
static polymorphism (vs. dynamic). Whether it is or not, the main
gain for me is in de-coupling of types, which helps in writing
truly generic code.