View mode: basic / threaded / horizontal-split · Log in · Help
November 08, 2012
Getting rid of dynamic polymorphism and classes
I just started watching that:
http://cppnow.org/session/value-semantics-and-concepts-based-polymorphism/

..and it got me thinking, couldn't we just get rid of dynamic 
polymorphism and classes altogether? Doesn't static polymorphism 
through the use of duck typing and member function delegates 
provide all that we need? This way we wouldn't have the nasty 
coupling of types which inheritance causes. Here's a C++ example:
(I'm sure it would look nicer with D's syntax)

// Canvas.h
#pragma once

#include <functional>
#include <type_traits>
#include <utility>
#include <vector>

class Canvas
{
private:
    struct Shape // Represents an interface
    {
        std::function<void (int x, int y)>        resize;
        std::function<void (int x, int y)>        moveTo;
        std::function<bool (int r, int g, int b)> draw;
    };

public:
    template <typename S>
    auto addShape(S& s)
    -> typename std::enable_if<
        std::is_same<decltype(s.resize(1, 1)), void>::value &&
        std::is_same<decltype(s.moveTo(1, 1)), void>::value &&
        std::is_same<decltype(s.draw(1, 1, 1)), bool>::value
    >::type
    {
        Shape shape;

        shape.resize = [&](int x, int y)
                          { return s.resize(x, y); };
						
        shape.moveTo = [&](int x, int y)
                          { return s.moveTo(x, y); };
						
        shape.draw = [&](int r, int g, int b)
                        { return s.draw(r, g, b); };

        _shapes.emplace_back(std::move(shape));
    }

    Shape& getShape(size_t idx)
    {
        return _shapes[idx];
    }

private:
    std::vector<Shape> _shapes;
};


// Circle.h
#pragma once

#include <conio.h>

class Circle
{
public:
    void resize(int x, int y)
    {
        _cprintf("Circle resized to %d %d\n", x, y);
    }

    void moveTo(int x, int y)
    {
        _cprintf("Circle moved to %d %d\n", x, y);
    }

    bool draw(int r, int g, int b)
    {
        _cprintf("Circle drawn with color %d %d %d\n", r, g, b);
        return true;
    }
};


// Rectangle.h
#pragma once

#include <conio.h>

class Rectangle
{
public:
    void resize(int x, int y)
    {
        _cprintf("Rectangle resized to %d %d\n", x, y);
    }

    void moveTo(int x, int y)
    {
        _cprintf("Rectangle moved to %d %d\n", x, y);
    }

    bool draw(int r, int g, int b)
    {
        _cprintf("Rectangle drawn with color %d %d %d\n",r,g,b);
        return true;
    }
};


// main.cpp
int main()
{
    Canvas canvas;
    Rectangle rectangle;
    Circle circle;

    canvas.addShape(rectangle);
    canvas.addShape(circle);

    canvas.getShape(0).resize(5, 5);
    canvas.getShape(0).moveTo(2, 3);
    canvas.getShape(0).draw(1, 12, 123);

    canvas.getShape(1).resize(10, 10);
    canvas.getShape(1).moveTo(4, 5);
    canvas.getShape(1).draw(50, 0, 50);

    _getch();
    return 0;
}

// Prints:
Rectangle resized to 5 5
Rectangle moved to 2 3
Rectangle drawn with color 1 12 123
Circle resized to 10 10
Circle moved to 4 5
Circle drawn with color 50 0 50
November 08, 2012
Re: Getting rid of dynamic polymorphism and classes
On Thursday, 8 November 2012 at 17:27:42 UTC, Tommi wrote:
> ..and it got me thinking, couldn't we just get rid of dynamic 
> polymorphism and classes altogether? Doesn't static 
> polymorphism through the use of duck typing and member function 
> delegates provide all that we need?

For a lot of programs (or parts of programs) that currently use 
runtime polymorphism, the answer seems to be yes, and Phobos is 
very good at helping D programmers do their polymorphism at 
compile-time.

But dynamic polymorphism is special in that it is just that - 
dynamic.

You can decide which implementation to use at runtime rather than 
having to do it at compile-time. When this runtime component is 
necessary, there is no replacement for runtime polymorphism.

As for function pointers and delegates, class-based polymorphism 
provides a couple of additional niceties: for one, vtables are 
created at compile-time. Secondly, it provides a lot of syntax 
and structure to the system that you don't have with arbitrary 
function pointers or delegates.

Emulating OOP (no, not Object *Based* Programming) with function 
pointers is a real pain. Without classes, we'd only be marginally 
better off than C in this area, thanks to delegates.
November 08, 2012
Re: Getting rid of dynamic polymorphism and classes
I also don't really like inheritance based design but..

That example would crash hard if those stack allocated shapes 
were not in scope...

Making it work safely would probably require std::shared_ptr usage

So it uses way more memory per object(BAD)

 Just use a dynamic language like Lua, it doesn't have classes, 
you example would be dead simple in lua.
November 08, 2012
Re: Getting rid of dynamic polymorphism and classes
That's essentially how Go is designed:

    type Shape interface {
        draw()
    }

    type Circle struct { ... }
    type Square struct { ... }

    func (c *Circle) draw() { ... }
    func (s *Square) draw() { ... }

    func main() {
        var shape Shape
        var circle Circle
        var square Square

        shape = circle
        shape.draw() // circle.draw()

        shape = square
        shape.draw() // square.draw()
    }
November 08, 2012
Re: Getting rid of dynamic polymorphism and classes
On Thursday, 8 November 2012 at 17:50:48 UTC, 
DypthroposTheImposter wrote:
> That example would crash hard if those stack allocated shapes 
> were not in scope...
>
> Making it work safely would probably require std::shared_ptr 
> usage

But the correct implementation depends on the required ownership 
semantics. I guess with Canvas and Shapes, you'd expect the 
canvas to own the shapes that are passed to it. But imagine if, 
instead of Canvas and Shape, you have Game and Player. The game 
needs to pass messages to all kinds of different types of 
players, but game doesn't *own* the players. In that case, if a 
game passes a message to a player who's not in scope anymore, 
then that's a bug in the code that *uses* game, and not in the 
implementation of game. So, if Canvas isn't supposed to own those 
Shapes, then the above implementation of Canvas is *not* buggy.
November 08, 2012
Re: Getting rid of dynamic polymorphism and classes
On 2012-11-08 17:27:40 +0000, Tommi said:
> ..and it got me thinking, couldn't we just get rid of dynamic 
> polymorphism and classes altogether?

Compiler can do a lot of optimizations with knowledge about classes. 
Also it automates a lot things that would become boilerplate with 
proposed manual setup of delegates for each object.

>      struct Shape // Represents an interface
>      {
>          std::function<void (int x, int y)>        resize;
>          std::function<void (int x, int y)>        moveTo;
>          std::function<bool (int r, int g, int b)> draw;
>      };

Dinamic polimorphism isn't gone anywhere, it was just shifted to delegates.

This approach complicates thing to much and produces template bloat 
with no real benefit.
November 08, 2012
Re: Getting rid of dynamic polymorphism and classes
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.
November 09, 2012
Re: Getting rid of dynamic polymorphism and classes
On Thursday, 8 November 2012 at 17:27:42 UTC, Tommi wrote:
> I just started watching that:
> http://cppnow.org/session/value-semantics-and-concepts-based-polymorphism/

 I've ripped the audio and done some processing to make it a 
little more understandable (without cranking the audio up to god 
awful levels); however I seem to have a little trouble uploading 
it somewhere accessible. I'll post a link when I get it uploaded 
(assuming anyone wants to make use of the audio rip...)
November 09, 2012
Re: Getting rid of dynamic polymorphism and classes
I have had the same thoughts for quite some time now - 
library-based runtime polymorphism implementation. You can 
already do something like: http://pastebin.com/X2JFP1sD . However 
it is inefficient as you have to store thisptr for each delegate. 
One has to think about how to implement it more efficiently - 
some metaprogramming will be required.
November 09, 2012
Re: Getting rid of dynamic polymorphism and classes
On Thu, Nov 8, 2012 at 10:36 AM, F i L <witte2008@gmail.com> wrote:

> That's essentially how Go is designed:
>
>     type Shape interface {
>         draw()
>     }

   ...



Method dispatch is still done at runtime though.

--
Ziad
« First   ‹ Prev
1 2 3
Top | Discussion index | About this forum | D home