Topic: Dynamic Concepts


Author: SG <s.gesemann@gmail.com>
Date: Tue, 5 May 2009 14:08:48 CST
Raw View
On 2 Mai, 06:58, Ben Strasser <m...@ben-strasser.net> wrote:
> I've been playing with concepts lately and I am really excited about
> seeing them used in the wild.
>
> There is however one thing that bothers me. With their introduction we
> now have 2 notions of interfaces: The traditional one with virtual
> functions and inheritance and the new concept system.

This seems to bother a lot of people with a Java background at first
(I'm not excluding myself here). Interfaces and late binding are
pretty much the only abstraction mechanism they are familiar with. But
runtime polymorphism is a different form of abstraction and not always
interchangable with template-based generic programming. Concepts is
about improving support for generic programming.

> [...]
> I think there should be some way to dynamically bind concepts.
>
> Let me illustrate this with an example. Consider the common InputStream
> hierarchy. Traditionally one would implement this with one base class
> InputStream and derive lots of classes like FileInputStream,
> SocketInputStream, ...
>
> Another method of realizing this would be to create a concept
> InputStream and make the FileInputStream, ... classes be a model of it.
>
> The traditional way provides a lot of flexibility by allowing you to
> dynamically interchange different stream types, but comes at the price
> of virtual function calls, that are nearly impossible to optimize. There
> are situations where this flexibility is needed.

The C++ features are pretty low level. If you want to be able to
program more "dynamically" you can do that by combining C++ features
in a smart way. For example, Adobe's Software Technology Lab has this
library called "Poly". It basically allows you to use value types
polymorphically without requiring any inheritence relationships. I
believe they even call it "dynamic concepts". In C++0x you would do
this by writing both, a concept C and an abstract base class A along
with a templated wrapper class W<T> that inherits from the abstract
base class A and forwards any requests to the wrapped object of type
T. The handle class Poly<A> would manage a pointer to A and the life-
time of its pointee. Something like this goes under the name "type
erasure" and is also used in boost::function, boost::any, etc.

However, you do have a point. It's tedious to have to write the
definitions of "class A", "template<C T> class W" and
"template<typename Base> class Poly". Maybe it's worth considering a
language extension that can make the compiler generate such boiler
plate code automatically ("automated type erasure"). But I have my
doubts about its usefulness in C++ because it's "syntactic sugar" that
only helps in rather special cases.

Maybe this is something that new language designers should consider
(throwing away inheritence in favor of mixins + generic programming +
automated type erasure via compiler magic for your runtime
polymorphism needs).

> However there are also other situations, where I know that I'll just
> open a file, read a few things and close it directly afterwards. Here I
> pay for the virtual function calls but have no gain at all.

Not necessarily. If you create an object on the stack ("automatic
storage") of a class that has virtual functions, the compiler doesn't
need dynamic dispatching because it already knows the exact type and
can invoke the correct functions directly (it can even be inlined).
Also, this dynamic dispatch is usually not a big problem performance-
wise. I don't think it's significantly slower than calling "normal"
functions. "char get()" should not be the only function in the
interface, though, you may want to add a function that reads a whole
block so that the function call overhead is reduced.

Cheers!
SG

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Ben Strasser <mail@ben-strasser.net>
Date: Fri, 1 May 2009 22:58:19 CST
Raw View
Hi,

I've been playing with concepts lately and I am really excited about
seeing them used in the wild.

There is however one thing that bothers me. With their introduction we
now have 2 notions of interfaces: The traditional one with virtual
functions and inheritance and the new concept system. I do understand
that they are from an implementation and optimization point of view 2
very different things, however I don't like to have to choose between
them. I think there should be some way to dynamically bind concepts.

Let me illustrate this with an example. Consider the common InputStream
   hierarchy. Traditionally one would implement this with one base class
InputStream and derive lots of classes like FileInputStream,
SocketInputStream, ...

Another method of realizing this would be to create a concept
InputStream and make the FileInputStream, ... classes be a model of it.

The traditional way provides a lot of flexibility by allowing you to
dynamically interchange different stream types, but comes at the price
of virtual function calls, that are nearly impossible to optimize. There
are situations where this flexibility is needed.

However there are also other situations, where I know that I'll just
open a file, read a few things and close it directly afterwards. Here I
pay for the virtual function calls but have no gain at all.

After a bit of experimenting I came up with the following construct:

auto concept InputStream<typename Stream>{
    char get();
};

class FileInputStream{
    char get();
};

class DynamicInputStream{
    virtual char get()=0;
};

template<InputStream InStream>
class DynamicInputStreamChild:public DynamicInputStream{
    InStream in;
    char get(){return in.get();}
};

Helper functions can now be written using the concept style. For example:

template<InputStream In>
String read_string(In&in){
    ...
}

The following code can now be inlined and optimized all the way down to
the underlaying system calls.

FileInputStream in(...);
foo(read_string(in));

When I need the flexibility I can still get it though

void bar(DynamicInputStream&in){
     foo(read_string(in));
}
...
FileInputStream in(...);
auto dyn_in = DynamicInputStreamChild<FileInputStream>(in);
bar(dyn_in);

  From a functional point of view this seems like an optimal solution to
me. (There may however be some problems when the concept uses free
standing functions though.) The thing I dislike is the need for quiet a
bit of boilerplate code and the duplication of the interface
description. In an ideal world the compiler would generate this binding
part for me. I do realize, that it's too late for that in C++0x by now.
However I'm interested in hearing the opinions of other people and if
there might be a better way to solve this problem.

Ben Strasser

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]