L
Larry Evans
This is about "compile faster" right? Yes.
itaj
This is about "compile faster" right? Yes.
itaj
That is compilation time, right? Yes.
itaj
[snip]If g++ is available, you can use the -std=gnu++0x option to enable
variadic templates and then use the code demonstrated the
test driver here:
http://svn.boost.org/svn/boost/sandbox/variadic_templates
/libs/composite_storage/sandbox/pack
/one_of_multiple_dispatch.test.cpp
So, after I managed to check out the code, it makes more sense.
But, tell me if the following is correct:
using this library on a hirarchy of classes and a certain multimethod.
- I have to collect the declarations of all different overrides in the
same functor class, like functor3 and functor_any do.
Yes.
- I have to collect all the concrete classes of the hirarchy in one
list, as under hosts_concrete<>
If so, I think this API doesn't solve the main disadvantages I see
with the dynamic_cast idiom.
In my example it would look about:
* except I'm not sure what should be ResultType in there, becuase
hunt() returns void, but what happens if other multimethods return
other types?
struct Carnivours_concrete
: mpl:ackage< Lion, Anaconda, Bear >
{
};
class Carnivour
{
typedef reifier_visit_abstract_seq< ResultType
, typename Carnivours_concrete::type>
visitor_abstract;
virtual ResultType accept( visitor_abstract const&)const=0;
};
class Lion: public Carnivour
{
...
ResultType accept( visitor_abstract const& a_visitor)const
{
return a_visitor.visit(*this);
}
};
class hunt_functor
{
void operator()( Lion const&, Gazelle& )
{
//jumps on it and bite its neck
}
//and same for:
void operator()( Lion const&, Girrafe& )
{
//bite its ass
}
void operator()( Anaconda const&, Gazelle& )
{
//inject venom
}
//Anaconda can't kill girrafes so no override for that one
void operator()( Bear const&, Prey& )
{
//because Bears catch everything in the same way lol.
}
};
itaj
[snip]If g++ is available, you can use the -std=gnu++0x option to enable
variadic templates and then use the code demonstrated the
test driver here:
http://svn.boost.org/svn/boost/sandbox/variadic_templates
/libs/composite_storage/sandbox/pack
/one_of_multiple_dispatch.test.cpp
So, after I managed to check out the code, it makes more sense.But, tell me if the following is correct:
using this library on a hirarchy of classes and a certain multimethod.
- I have to collect the declarations of all different overrides in the
same functor class, like functor3 and functor_any do.
Yes.
- I have to collect all the concrete classes of the hirarchy in one
list, as under hosts_concrete<>
Yes. Otherwise, how could you define the abstract visitor class in an
extensible way?
I'm not sure. I remember finding, for some reason, the using
reifier_visitor was less flexible the reifier_switch for, IIRC, this
reason. I'll have to think more on this.
Is it supposed to be possible do checkout the whole svn tree?
It keeps breaking.
Should I better take just part?
For compisite_storage you mean? Or certain part?
What exactly is the name of
"variants"? Is it like number of virtual parameters for the
function?
One measure is the assignment operator.
What does the binary test do?
I know nothing about boost development, what does it measure?
Can you point me to some reading about it?
So one_of_multiple_dispatch is supposed to do what I want?
What exactly is the relation of it with one_of_maybe?
After some corrections to:Let me see if I can implement this with reifier_visitor.
I'll get back to you.
The compiler error messages state that:On 02/22/11 16:08, Larry Evans wrote:
[snip]After some corrections to:Let me see if I can implement this with reifier_visitor.
I'll get back to you.
replace_source_with_target_ptr.hpp
got the attached to run and print:
Lion jumps on Girrafe and bites its ass.
However, when the #if on line 188 is switch, I get
very obscure compile-time error messages. So, it
can't handle concrete references. It apparently
can only handle abstract references.
I'll see if I can correct that.
Is there any concensus idiom on how to code with multimethods?
How would you go about coding them today?
There's the multi-dispatch idiom: For each override type of the first
parameter. declare a different virtual function to dispatch the second
parameter.http://en.wikipedia.org/wiki/Multiple_dispatch
But it requires that the definition of every polymorphic class of one
parameter #includes the definition of all polymorphic types of the
following parameter. This makes the code messy, and not scalable due
to circular dependencies between modules.
I had to use them for a some medium size hirarchy and this idiom
became quite a bother. Not to mention that users coult not add their
types becuase this idiom is circular dependant.
I'm more interested in some library that would support this in a more
generic way.
I suppose any such library would need some compiler specific code for
each compiler that it supports, but the API should be the same.
BTW, Stroustrup in "The Design and Evolution of C++ Bjarne Stroustrup"/
13.8 comsiders adding multimethods as a c++ language favorable.
Although less important than many other features. And there are some
proposals for it. However, I don't know there's currently any point in
the future when it's predicted to be added. And a library solutions
seems good
itaj
If you can afford C instead of C++, you can read papers and use the
COS lib
Yes.
Is there any concensus idiom on how to code with multimethods?
How would you go about coding them today?
There's the multi-dispatch idiom: For each override type of the first
parameter. declare a different virtual function to dispatch the second
parameter.http://en.wikipedia.org/wiki/Multiple_dispatch
But it requires that the definition of every polymorphic class of one
parameter #includes the definition of all polymorphic types of the
following parameter. This makes the code messy, and not scalable due
to circular dependencies between modules.
I had to use them for a some medium size hirarchy and this
idiom became quite a bother. Not to mention that users coult
not add their types becuase this idiom is circular dependant.
I'm more interested in some library that would support this in
a more generic way. I suppose any such library would need
some compiler specific code for each compiler that it
supports, but the API should be the same.
One solution is to define a new metafunction in reifier_visitor.hpp:The compiler error messages state that:On 02/22/11 16:08, Larry Evans wrote:
[snip]After some corrections to:Let me see if I can implement this with reifier_visitor.
I'll get back to you.
replace_source_with_target_ptr.hpp
got the attached to run and print:
Lion jumps on Girrafe and bites its ass.
However, when the #if on line 188 is switch, I get
very obscure compile-time error messages. So, it
can't handle concrete references. It apparently
can only handle abstract references.
I'll see if I can correct that.
hosts_concrete<Lion>
is an incomplete type in reifier_visitor.hpp line 209.
This is where there's a hosts_concrete<HeadAbstract>
and HeadAbstract is Lion which is not abstract.
hosts_concrete is supposed to be specialized on
the abstract class to return the set of concrete
classes for that abstract class. Since Lion already
is an concrete class, there's no need to specialize
hosts_concrete on it; hence, the error.
Will think about solution.
You replace a dynamic_cast if-else-if list with a virtual function
Prey::dispatchMe. This save the detailing on 1 parameter. I'm not sure
it would be so helpful for 3 or more virtual parameters.
Also the more internal animal_kingdom module contains Prey which has
to know (forward-dec) the name of CarnivourDispatch which in turn has
to know all polymorphic types under Prey. As it is, it breaks the
encapsulation of the module, becuase user must make it somehow aware
of his different derivations.
I think that would be especially more
problematic if there was another user-code adding more derivations,
but that would want to use some of these derivations too.
Multiple dispatch on open or large hierarchies is problematic in
general. For n derived classes, you need n^2 functions
(regardless of how the dispatch works), and when you add
a derived class, you have to define its interactions with all of
the existing classes. It's best avoided, but it is possible to
make it work: you need something like a
std::map<std:air<std::type_index, std::type_index>,void (*)
(Base&, Base&)>
, where void Base::doSomething(Base& other) isn't virtual, but
looks up the actual (free) function to call in the map. Getting
the map initialized with all of the necessary functions is
non-trivial, but if you can provide a default Base&, Base&
functionality, and only need a few specific overrides, it might
be OK.
If you want an open hierarchy which supports all possible
combinations, the problem isn't the compiler; it's how to
provide all of the necessary functions. Each new class has to
provide all of the functions for it and all of the existing
classes. This quickly gets out of hand.
Ofcourse for k virtual parameters, the number of possible different
overrides is n^k. But so is the number of possible different static
overloads for a regular n-ary function in c++. But usually there are
some generalizations that are done on the possibilities that
practically cut them to around log(n)^k to n*log(n)^k sets and subsets
(just top of my head estimation).
In both cases that should be done using the hierarchy and
templates.
* For conviniency I'll base on the hipothetic language feature. But
what I mean is that it should be possible to create a library that
would support the same general constructs, just instead of syntax
you'll have to define classes and static variable of the library type.
It certainly isn't difficult to come up with a solution for
a given hierarchy. I'm not sure about a generic solution;
I haven't given it a try, but it seems like it should be
possible. The problem is to make the lookup as effective as
possible: if you require n^k functions, each for the most
derived class, you can use a hash table of some sort on the two
(or more) type_info's. If you don't, it's more difficult, since
type_info doesn't give you information about the base classes.
And you need to specify some sort of ordering: either first
match, and insist that the client codinsert in the correct
order (with the most specific functions where they will be found
first), or best match, and you have to define "best", evaluate
all matches, and define behavior in case of ambiguity. It's not
an easy task.
Well, that is basically my idea. Although when you work in C, the
language doesn't offer almost any of the features of this object
system (classes, inheritance, function resolution, templates?), so it
seems right to use it for everything. Unlike C, C++ has core features
for everything that this library does, except multimethods.
Principally I want to use the core features of C++ to write my code. I
only need a library that supports multimethods, that would extend them
over hirarchies that are already written with core C++ features. So in
that sense, I don't think I can afford transforming all my hirarchies
into any library. That would beat the purpose of finding the crispiest
idiom for multimethods.
A better solution has just been uploaded. It uses boost::bind to 1stOne solution is to define a new metafunction in reifier_visitor.hpp:The compiler error messages state that:On 02/22/11 16:08, Larry Evans wrote:
[snip]
Let me see if I can implement this with reifier_visitor.
I'll get back to you.
After some corrections to:
replace_source_with_target_ptr.hpp
got the attached to run and print:
Lion jumps on Girrafe and bites its ass.
However, when the #if on line 188 is switch, I get
very obscure compile-time error messages. So, it
can't handle concrete references. It apparently
can only handle abstract references.
I'll see if I can correct that.
hosts_concrete<Lion>
is an incomplete type in reifier_visitor.hpp line 209.
This is where there's a hosts_concrete<HeadAbstract>
and HeadAbstract is Lion which is not abstract.
hosts_concrete is supposed to be specialized on
the abstract class to return the set of concrete
classes for that abstract class. Since Lion already
is an concrete class, there's no need to specialize
hosts_concrete on it; hence, the error.
Will think about solution.
template
< typename HostConcretestruct host_abstract
/**@brief
* Metafunction returning Abstract class
* of which HostConcrete is a member.
* IOW, does inverse of hosts_concrete.
*/
{
typedef
HostConcrete
type
//By default, HostConcrete is member
//of a type hierarchy starting at
//HostConcrete.
;
};
and them modify the argument, HeadAbstract, to hosts_concrete to
super of reifier_visitor by host_abstract<HeadAbstract>::type.
That converts any concrete type back to its abstract super.
Of course that's less than ideal because it requires
specializations of host_abstract to map all the derived classes
back to their abstract classes and causes mover virtual
function calls to undo what was just done by host_abstract.
Will upload the modified reifier_visitor.hpp to sandbox.
The modified driver, with all the host_abstract specializations,
is attached.
-Larry
If g++ is available, you can use the -std=gnu++0x option to enable
variadic templates and then use the code demonstrated the
test driver here:[snip]http://svn.boost.org/svn/boost/sandbox/variadic_templates
/libs/composite_storage/sandbox/pack
/one_of_multiple_dispatch.test.cpp
So, after I managed to check out the code, it makes more sense.But, tell me if the following is correct:
using this library on a hirarchy of classes and a certain multimethod.
- I have to collect the declarations of all different overrides in the
same functor class, like functor3 and functor_any do.
Yes.
- I have to collect all the concrete classes of the hirarchy in one
list, as under hosts_concrete<>
Yes. Otherwise, how could you define the abstract visitor class in an
extensible way?
I suppose the general idea could maybe be to hold some static variable
of dispatch matrices and edit it in constructors of other static
variables.
HostAbstract such that hosts_concrete said:But that is only good for pure runtime dispatch, from what I figured,
your library is about compile type dispatching,
so maybe it doesn't have enough in common with the solution I'm
looking for. I'm not sure.
Mainly I deduced my conclusion from the test code, seeing there how
you used reifier_visitor and reifier_apply. I just gazed at the
code of reifier_visitor, I don't know how it works at all, neither
the difference with reifier_switch.
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.