Indirect functoids are "function variables" which can be dynamically bound to any function with the right monomorphic type signature. Recall the example from Section 4:
fun2<int,int,int> f = plus; f(3,2); // yields 5 f = minus; f(3,2); // yields 1Here f is an indirect functoid, which can be bound to different functions (plus and minus, in the example) during its lifetime. Indirect functoids are declared as instances of the funN classes, where N is the arity of the function and the N+1 template arguments name the argument types and the return type.
Indirect functoids are necessarily monomorphic. This restriction is rooted in the implementation: indirect functoids are implemented using dynamic dispatch (virtual function call), and in C++, a virtual method cannot also be a member template. When an indirect functoid is initialized or assigned the value of a polymorphic direct functoid, the appropriate monomorphic function is selected. For example:
std::string foo="foo", bar="bar"; fun2<std::string,std::string,bool> sl = less; sl(foo,bar); // yields false fun2<int,int,bool> il = less; il(2,3); // yields trueHere we use the FC++ polymorphic functoid less (which has the general signature (T,T)->bool) to initialize two different indirect functoids. Each indirect functoid selects the appropriate monomorphic instantiation of the polymorphic functoid it is initialized with.
Indirect functoids exhibit subtype-polymorphism (the dynamic polymorphism OO programmers are familiar with). This works in the expected way; indirect functoids are contravariant in their argument types and covariant in their return types. An example makes this clear: suppose there are two inheritance hierachies, one where dog is derived from animal and another where car is derived from vehicle. Then we can say
fun1<dog*,vehicle*> f = ...; fun1<animal*,car*> g = f; // ok f = g; // illegal (type error)f is effectively a subtype of g; wherever g is used, f can be supplied as a legal implementation, but not the other way around.
Indirect functoids in FC++ are similar to boost::function objects. There are a few notable differences. First, indirect functoids must always be initialized with a function value (there is no default constructor or the equivalent of a "null" function). Second, indirect functoids have all the FC++ full functoids features (like built-in currying and infix syntax, described in the next section), whereas boost::function objects do not. On the other hand, indirect functoids always pass parameters by const&, whereas boost::function objects can have parameters passed by plain reference, allowing for mutation of arguments to the function object.
|Last revised: October 03, 2003 at 23:27:22 GMT||Copyright © 2000-2003 Brian McNamara and Yannis Smaragdakis|