C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

With Concepts, it seems a truly heterogeneous container is

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Guest






PostPosted: Wed Nov 29, 2006 10:10 am    Post subject: With Concepts, it seems a truly heterogeneous container is Reply with quote



See if this would be cool had it been true:

concept WithText<typename T>
{
void text(std::string const&);
std::string const& text() const;
};

class Button // note that we're not using inheritance here!
{
public:
void text(std::string const&);
std::string const& text() const;
};

class Control
{
public:
void text(std::string const&);
std::string const& text() const;
};


fancy_container<WithText> con; // all type that satisfy this concept
// could be stored in
this container
con.push_back(new Button); // maybe 'new' isn't the best way to manage
memory, but it's the idea
con.push_back(new Control); // that matters

for(WithText& /*imaginary syntax*/ textable : con) // new range-style
for
{
textable.text("isn't this cool?");
}

I know that someone will jump out and say:" hey, you should use
interface, or rather, abstract class in C++!".
But I know many will understand the point:-)
In ruby and other dynamic languages, this is called 'duck typing'.

Note that the syntax, in particular, facy_container<WithText> and
WithText&, is just for illustrating the idea, current proposal doesn't
support "template concept parameter" and "reference to concept".

Note also that,
boost::tuple/boost::fusion/boost::variant/boost::vector<boost::any>
doesn't do the thing, in particular, the number of elements in
boost::fusion containers must be known at compile time, which very
limited its usage, boost::variant requires you to specify every
possible type of elements it'll contain, and vector<any> is just a
vacant idea, coz after you store an element in there , you kinda loose
all the type information.

P.S. It *is* possible to implement a limited yet true heterogeneous
container in C++, watch this:

template<template<typename> struct Visitor>
class inferior_heter_con
{
std::vector<std::pair<void(*)(void*), void*> > v;

template<typename T>
void caller(void* obj)
{
Visitor<T> visit;
visit(*(static_cast<T*>(obj)));
}

public:
template<typename T>
void push_back(T const& t)
{
v.push_back(std::make_pair(&caller<T>, &t));
}
};

template<typename T>
struct VisitorFunctor
{
void operator()(T& t)
{
... // do sth. with t
}
};

The downside is that the Visitor can't be changed during the whole life
time of a container, that renders this alternative almost useless.

[again, the code is just for illustrating the idea and possibility,
don't expect it to compile immediately anyway.]


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Thu Nov 30, 2006 10:10 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote



Lourens Veen wrote:
Quote:
I'm afraid I am going to jump out and say that you should use an
abstract class, and also that is it you who doesn't understand Smile.

:-)

Quote:
The thing is, if you want to do what you want to do, then you have to
keep the type information around for the objects. C++ has a way to do
that, and it's through an abstract base class, pointers to base, and
overloaded virtual member functions.

Problem is, though, you're talking about implementing this in current
C++(via a traditional OOP way which is bounded as opposed to the
unbounded polymorphism provided by templates), while I'm thinking about
the new possibilities Concepts opened.
I mean, sure, we *should* and *could* achieve the goal using abstract
class and inheritance, which is the easiest way to go.
However, using abstract class and inheritance this way will highly
constrain the power(e.g. existent classes which actually have but don't
implement the interface can't be stored in the container).
The essence of duck typing(in C++, Structral Conformance) is "if it
waddles like a duck, and quacks like a duck, then it is a duck", in
other words, we don't need a class to implement the interface, instead,
we just need it to *look like* it has the interface, which GP is all(
well, almost) about(i.e. the unbounded polymorphisms).
Further more, Bjarne Stroustrup in one of his proposal about Concepts
said that it *is* possible to implement a separate compilation model
via Concept, using some kind of vtable. I know what he means, here
Concept can serve as the *unbounded interface*, which could mean that
every type that satisfy a particular concept actually *implements* the
interface postulated by the concept.
The biggest downside of using abstract class and inheritance to
approaching a heterogeneous container is that it's bounded, and the
power limited, for example, someone would implement a class that
satisfies the interface( in that it has all(or even partial) of the
methods required by the interface) while doesn't derive
from(implements) the interface at all. With the OOP way, you have to
make the class implement some (maybe)occasional interface in order to
put it in the container, but with Concepts, it opened another gate for
a completely type-safe and unbounded solution, where every type, no
matter old or new, changeable or not, could effectively be stored in
it, as long as it is *Structrually conform* to the Concept.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vidar Hasfjord
Guest





PostPosted: Fri Dec 01, 2006 12:42 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote



Lourens Veen wrote:
Quote:
But that would mean a major change to C++. You would have to have type
names and function signatures available at runtime, and have some
sort of runtime call-by-name mechanism. Also all objects would have
to carry type information with them (which may include information on
a large inheritance hierarchy, so that an inherited member function
can be called). In essence, you would have to introduce dynamic
typing to C++. It's probably possible, yes, but I'm not sure whether
it would still be C++.

Unless I've overlooked something, I think you are overstating things a
bit here. Although RTTI is needed to select the function to call, the
type information derived from the concept determines function
signatures at compile time. AFAIKT a mechanism similar to virtual
functions can be used. Using OP's example, the call {textable.text
("...");} could generate the following pseudo code:

const __Textable::vtable* vtbl =
__Textable::lookup_vtable (typeid (textable));
assert (vtbl);
(*vtbl) [__Textable::text_index] (&textable, "...");

Quote:
On the other hand, if it walks like a duck, talks like a duck, and
should be seen as a duck by everyone stocking it, then the code
should reflect that. The proper way to express this relationship is
to derive "it" from a "duck" abstract class.

Well, that's not a solution if you have no access to the code in
question. The obvious example being libraries. Duck-typing is most
useful for types over which you have no control. The OP's example
doesn't highlight this. Here's another example (using invented syntax
{auto <Concept>} to name a "heterogenous type"):

// --- Their code ---

namespace Vendor1 {
class HtmlElement {
public:
std::string GetContent () const;
};
}

namespace Vendor2 {
struct html_element {...};
const char* get_content (const html_element*);
}

// --- Our code ---

concept HtmlElementLike <typename T> {
std::string content () const;
};

concept_map HtmlElementLike <Vendor1::HtmlElement> {
std::string content () const {
return Vendor1::GetContent ();
}
};

concept_map HtmlElementLike <Vendor2::html_element> {
std::string content () const {
return std::string (Vendor2::get_content (this));
}
};

class ContentCollection {
typedef auto <HtmlElementLike>* ElementPtr;
std::vector <ElementPtr> container;

public:
void AddContent (ElementPtr element) {
container.push_back (element);
}

void OutputContent (std::ostream& os) const {
for (const ElementPtr element: container)
os << element->content ();
}
};


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Andrei Polushin
Guest





PostPosted: Fri Dec 01, 2006 9:21 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

pongba (AT) gmail (DOT) com wrote:
Quote:
See if this would be cool had it been true:

concept WithText<typename T
{
void text(std::string const&);
std::string const& text() const;
};

You are talking about "auto concept", the concept that automatically
applied to any type:

auto concept WithText<typename T>
{
void T::text(std::string const&);
std::string const& T::text() const;
};

Quote:
Lourens Veen wrote:
The thing is, if you want to do what you want to do, then you have to
keep the type information around for the objects. C++ has a way to do
that, and it's through an abstract base class, pointers to base, and
overloaded virtual member functions.

Problem is, though, you're talking about implementing this in current
C++(via a traditional OOP way which is bounded as opposed to the
unbounded polymorphism provided by templates), while I'm thinking about
the new possibilities Concepts opened.

The possibility is already opened for template code:

template <class T>
void f(vector<T>& vec) { // vector<T> is a heterogeneous container
T& x = vec.front();
x.text("what is it for?"); // access unknown type T
}

With concept "WithText", the things remain the same:

template <WithText T>
void f(vector<T>& vec) {
T& x = vec.front();
x.text("what is it for?");
}

When you are in template code, you deal with heterogeneous types,
otherwise your types are strict. This will not change. Concepts
are unrelated to your intent, because they are intended to further
restrict template programming.


Quote:
I mean, sure, we *should* and *could* achieve the goal using abstract
class and inheritance, which is the easiest way to go.
However, using abstract class and inheritance this way will highly
constrain the power(e.g. existent classes which actually have but don't
implement the interface can't be stored in the container).
The essence of duck typing(in C++, Structral Conformance) is "if it
waddles like a duck, and quacks like a duck, then it is a duck",

In other words, if it looks like a plug, it could be inserted into
socket. Two fingers are like a plug, so you want to be able to insert
them into 220V socket.


Quote:
in
other words, we don't need a class to implement the interface, instead,
we just need it to *look like* it has the interface, which GP is all(
well, almost) about (i.e. the unbounded polymorphisms).

And I doubt it should be that. For example:

class Lottery {
void draw();
};

class Shape {
void draw();
};

auto concept Drawable<T> {
void T::draw();
};

template <Drawable T> // matches both Lottery and Shape
void f(T t) {
t.draw(); // what kind of "draw"?
}

This case is a homonymy error, which "auto concepts" is all about.


Quote:
Further more, Bjarne Stroustrup in one of his proposal about Concepts
said that it *is* possible to implement a separate compilation model
via Concept, using some kind of vtable. I know what he means, here
Concept can serve as the *unbounded interface*, which could mean that
every type that satisfy a particular concept actually *implements* the
interface postulated by the concept.

The meaning of "separate compilation" could be quite different.
Probably, he didn't mean what you mean.


Quote:
The biggest downside of using abstract class and inheritance to
approaching a heterogeneous container is that it's bounded, and the
power limited, for example, someone would implement a class that
satisfies the interface( in that it has all(or even partial) of the
methods required by the interface) while doesn't derive
from(implements) the interface at all. With the OOP way, you have to
make the class implement some (maybe)occasional interface in order to
put it in the container, but with Concepts, it opened another gate for
a completely type-safe and unbounded solution, where every type, no
matter old or new, changeable or not, could effectively be stored in
it, as long as it is *Structrually conform* to the Concept.

Adapter pattern <http://en.wikipedia.org/wiki/Adapter_pattern>
can force any animal to quack:

class Duck {
public:
virtual void quack() = 0;
};

template <class T>
class DuckAdapter : public Duck {
T t;
public:
DuckAdapter(const T& t = T()) : t(t) {}
void quack() {
t.quack();
}
};

class Frog {
public:
void quack() {
cout << "croak! croak!" << endl;
}
};

vector<Duck*> ducks;
Frog frog;
ducks.push_back(new DuckAdapter<Frog>(frog));
ducks[0]->quack(); // ok: quacking frog is like a duck


--
Andrei Polushin


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Lourens Veen
Guest





PostPosted: Fri Dec 01, 2006 9:22 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

Vidar Hasfjord wrote:

Quote:
Lourens Veen wrote:
But that would mean a major change to C++. You would have to have
type names and function signatures available at runtime, and have
some sort of runtime call-by-name mechanism. Also all objects would
have to carry type information with them (which may include
information on a large inheritance hierarchy, so that an inherited
member function can be called). In essence, you would have to
introduce dynamic typing to C++. It's probably possible, yes, but
I'm not sure whether it would still be C++.

Unless I've overlooked something, I think you are overstating things
a bit here. Although RTTI is needed to select the function to call,
the type information derived from the concept determines function
signatures at compile time.

Ah, yes, that's possible. I'd overlooked that. So you don't need to do
overload resolution at runtime.

Quote:
AFAIKT a mechanism similar to virtual
functions can be used. Using OP's example, the call {textable.text
("...");} could generate the following pseudo code:

const __Textable::vtable* vtbl =
__Textable::lookup_vtable (typeid (textable));
assert (vtbl);
(*vtbl) [__Textable::text_index] (&textable, "...");

So then the concept should have a vtable for each type matching the
concept? How does that work with different translation units? The
linker could merge them I suppose.

Quote:
On the other hand, if it walks like a duck, talks like a duck, and
should be seen as a duck by everyone stocking it, then the code
should reflect that. The proper way to express this relationship is
to derive "it" from a "duck" abstract class.

Well, that's not a solution if you have no access to the code in
question. The obvious example being libraries. Duck-typing is most
useful for types over which you have no control.

The thought had crossed my mind, yes. Actually, IIRC AspectJ allows
you to change an existing inheritance hierarchy, injecting such a
common base class, for the same reason.

Quote:
The OP's example
doesn't highlight this. Here's another example (using invented
syntax
{auto <Concept>} to name a "heterogenous type"):

// --- Their code ---

namespace Vendor1 {
class HtmlElement {
public:
std::string GetContent () const;
};
}

namespace Vendor2 {
struct html_element {...};
const char* get_content (const html_element*);
}

// --- Our alternative code ---

namespace ours {

struct HtmlElement {
virtual std::string getContent() const = 0;
};

class HtmlElement1 : public HtmlElement {
::Vendor1::HtmlElement el;
public:
std::string getContent() const {
return el.GetContent();
}
};

struct HtmlElement2 : public HtmlElement {
::Vendor2::html_element el;
public:
std::string getContent() const {
return std::string(::Vendor2::get_content(el));
}
};

class ContentCollection {
std::vector<HtmlElement> container;
};

}


If I understand you correctly, this is essentially how you propose to
implement the concept version (i.e. it could compile down to the same
code)?


I'm a little mixed about this style-wise. On the one hand the concept
version is more abstract and perhaps cleaner, on the other hand I
wonder if we're not sweeping too much of the type system and what's
actually happening under the carpet. Maybe I just have to get used to
the idea.

Lourens


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Mathias Gaunard
Guest





PostPosted: Fri Dec 01, 2006 9:27 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

Lourens Veen wrote:

Quote:
fancy_container<WithText> con; // all type that satisfy this concept
// could be stored in this container

Look at boost.dynamic_any


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Fri Dec 01, 2006 10:10 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

Andrei Polushin wrote:
Quote:
The possibility is already opened for template code:

template <class T
void f(vector<T>& vec) { // vector<T> is a heterogeneous container
T& x = vec.front();
x.text("what is it for?"); // access unknown type T
}

With concept "WithText", the things remain the same:

template <WithText T
void f(vector<T>& vec) {
T& x = vec.front();
x.text("what is it for?");
}

Sorry, but vector<T> is still homogeneous, in the sense that every
element that could be stored in it should be of type T.

Quote:
In other words, if it looks like a plug, it could be inserted into
socket. Two fingers are like a plug, so you want to be able to insert
them into 220V socket.

lol
That's "The perils of duck
typing"(http://beust.com/weblog/archives/000269.html).
But it doesn't mean that it's completely useless.
http://en.wikipedia.org/wiki/Duck_typing

Quote:
And I doubt it should be that. For example:

class Lottery {
void draw();
};

class Shape {
void draw();
};

auto concept Drawable<T> {
void T::draw();
};

template <Drawable T> // matches both Lottery and Shape
void f(T t) {
t.draw(); // what kind of "draw"?
}

This case is a homonymy error, which "auto concepts" is all about.

Again, every alternative has its own risk. We just need to resort to
some consistent rule/conventions at some point in one way or another.

Quote:
The meaning of "separate compilation" could be quite different.
Probably, he didn't mean what you mean.

Yeah, I agree. Yet I need more explanation, maybe he would be kind
enough to give a little bit explanation in some other proposal?

Quote:
Adapter pattern <http://en.wikipedia.org/wiki/Adapter_pattern
can force any animal to quack:

Actually this is a very good point. Thanks, it's useful and kinda
adequate.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vidar Hasfjord
Guest





PostPosted: Sat Dec 02, 2006 10:10 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

Lourens Veen wrote:

Quote:
Ah, yes, that's possible. I'd overlooked that. So you don't need to do
overload resolution at runtime.

Right, the compiler just generates a virtual call through an interface,
i.e. an auto-generated abstract base class, derived from the concept.

Quote:
So then the concept should have a vtable for each type matching the
concept? How does that work with different translation units? The
linker could merge them I suppose.

Yes, the idea is that the compiler looks up the vtable in a dictionary
of tables for each type mapped to the concept. An entry in the
dictionary is generated wherever a type is converted to an "auto
<concept>" (or more generally wherever a type is used as an concept).
The dictionaries must somehow be collated across translation units as
you point out. Intuitively that seems solvable, but I haven't thought
about the issues involved in any more detail.

Quote:
The thought had crossed my mind, yes. Actually, IIRC AspectJ allows
you to change an existing inheritance hierarchy, injecting such a
common base class, for the same reason.

Yes, I imagine the proposed feature could be useful for retrofitting
classes with all sort of functionality. As stated before, this is most
benefitial for classes outside the programmers control, but can I also
imagine cases where the feature would simplify the design of code,
especially for cross-cutting concerns (AOP).

Quote:
code snipped
If I understand you correctly, this is essentially how you propose to
implement the concept version (i.e. it could compile down to the same
code)?

Yes, essentially the feature would generate such adaptors
automatically. The notable difference is that you wouldn't have to
explicitly wrap the objects in an adaptor. The compiler would do that
for you at the point of use, i.e. whenever needed.

Quote:
I'm a little mixed about this style-wise. On the one hand the concept
version is more abstract and perhaps cleaner, on the other hand I
wonder if we're not sweeping too much of the type system and what's
actually happening under the carpet. Maybe I just have to get used to
the idea.

I agree to a large extent. Both the OP's orginal example and my example
are, as shown, easily solvable using the more explicit but safer
adaptor pattern. That said, I imagine more convincing use cases exist.

Serialization (in the IO sense) may be one such case. The Boost
Serialization library provides minimally intrusive or totally
non-intrusive serialization for existing classes. This is accomplished
by using templates (GP) rather than interfaces and inheritance (OOP).
The downside is code-bloat and the requirement that (part of) the
implementation is visible to the user of the library (since the code
needs to be instantiated per type). If concepts with vtables were
available, that could solve these issues and allow further
simplification:

namespace serialization {

class Archive;

auto concept Serializable <typename T> {
void T::serialize (Archive&, unsigned version);
};

class Archive {
virtual void load (auto <Serializable>& obj) {
// ...
obj.serialize (*this, version);
// ...
}
};
}


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Mon Dec 04, 2006 7:22 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

"Vidar Hasfjord" <vattilah-groups (AT) yahoo (DOT) co.uk> writes:

Quote:
code snipped
If I understand you correctly, this is essentially how you propose to
implement the concept version (i.e. it could compile down to the same
code)?

Yes, essentially the feature would generate such adaptors
automatically. The notable difference is that you wouldn't have to
explicitly wrap the objects in an adaptor. The compiler would do that
for you at the point of use, i.e. whenever needed.

The idea has been around for years. You might look at Jeremy Siek's
work on G for what is essentially the opposite end of the spectrum
from what C++ does todsay
(http://www.cs.rice.edu/~jgs3847/pubs/pubs/2005/siek05:_thesis.pdf)
and then, to observe the "ideal middle ground," see
http://en.wikipedia.org/wiki/Specializing_compiler.

Incidentally, you can manually do something like what you're
describing in C++ today. Takes a bit of work, of course, but
http://www.boost.org/libs/function is an example of it. See the
section on type erasure in http://www.boost-consulting.com/mplbook for
more details about that.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Tue Dec 05, 2006 6:43 am    Post subject: Re: With Concepts, it seems a truly heterogeneous container Reply with quote

"Daniel Krügler" <daniel.kruegler (AT) googlemail (DOT) com> writes:

Quote:
David Abrahams schrieb:

The idea has been around for years. You might look at Jeremy Siek's
work on G for what is essentially the opposite end of the spectrum
from what C++ does todsay
(http://www.cs.rice.edu/~jgs3847/pubs/pubs/2005/siek05:_thesis.pdf)

Regrettably this link does not work for me. Do you have another one?

Nope, but I bet if you scour the web or ACM you can find it.

Quote:
Is this G language is related to LabView's G language? From the
context of this thread, if would say no, but who knows Wink

I think I know that it isn't :)

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.