4

Does exist any language that:

  • is statically (and strongly) typed
  • supports generics (templates)
  • supports traits / multiple inheritance / interface delegation
  • allows function overloading (of inherited members, too)

Basically, in pseudo-code, I want this:

class Template<SomeType> { void function(SomeType i) {} }
class Composed extends Template<int>, Template<double> { };
Composed composed;
composed.function(3); //calls function(int)
composed.function(2.5); //calls function(double)

From the wiki list http://en.wikipedia.org/wiki/Multiple_inheritance#Implementations I tried to write code in following programming languages (I also included newest yet-unpublished-1.0-version (2013) languages like Kotlin, Ceylon):

  • C++ almost possible, but cannot resolve overloaded function for composed variable
  • Scala compile error: trait inherited twice; even if tricked with indirect inheritance it still produces error; see also other guy's question about multiple generic mixin inheritance in Scala
  • Eiffel compile error: no function overloading
  • Ceylon traits cannot have variables (and no protected members, so no trick for storing data in derived class, traits in Ceylon are useless)
  • Fantom no generics/templates
  • Kotlin compile error: supertype appears twice; delegation looks unique, but it's not useful, because one can access neither protected members nor variable that is delegated to
  • Rust no function overloading; traits cannot store data; traits cannot have defined methods (with body) - issue that's being worked on;
  • OCaml compile error: no function overloading; it also didn't check type of parameter for my function, so how "statically typed" it really is?!
  • Curl compile error: no function overloading; it also doesn't check function body unless it's called, so how "statically typed" it really is? is it compiled at all or interpreted?!
  • Gosu is a bad joke, it's not usable at all: cannot write and implement simple interface with one mathod (error: ClassFormatError: Illegal field modifiers). Who actually does use this language?!

By the way: I thought of this problem when I tried to put Java support for listeners into separate class (in many classes there is: List<ListenerType> ... addListener(...) ... removeListener(...))

C++ almost works:

template <typename T>
class Template { public: void function(T i) {} };
class Composed : public Template<int>, public Template<double> { };

Composed composed;
composed.Template<int>::function(3); //i want: composed.function(3);
((Template<double>&)composed).function(2.5); //i want: composed.function(2.5);

Edit: in C++, problem is inheritance function hiding. See also Function with same name but different signature in derived class and Why does an overridden function in the derived class hide other overloads of the base class?

Edit 2: in C++, with templates and partial specialization, there is possibility of dirty trick to allow usage of trait simpler:

#include <iostream>
#include <typeinfo>

class Void { };
template <class A, class B> class CleverTrait;
template <class A, class B> class CleverTrait;
template <class A> class CleverTrait<A, Void>
{
public:
    void function(A arg) { std::cout << "Hello for type " << typeid(A).name() << std::endl; }
};
template <class A, class B> class CleverTrait<A, CleverTrait<B, Void> > : public CleverTrait<B, Void>
{
public:
    using CleverTrait<B, Void>::function;
    void function(A arg) { std::cout << "Hello for type " << typeid(A).name() << std::endl; }
};

class ComposedByClever : public CleverTrait<double, CleverTrait<int, Void> > { };

int main()
{
    ComposedByClever composedByClever;
    composedByClever.function(5);
    composedByClever.function(2.3);
    return 0;
}

This means this particular example in C++ works, however if unrelated traits shared function name, there is no way to inherit-and-using-all-functions in C++.

Edit 3: I should be also checking any programming language, that supports mixins: http://en.wikipedia.org/wiki/Mixins#Programming_languages_that_use_mixins

  • D works, but only through string manipulation mixin, so refactoring is broken in such case: mixin(GenerateSomething!("IfClassNameHereManualRenaming"));

Edit 4: added "Gosu" language comment.

Edit 5: Gosu programming language has update 0.10.2 which fixed the interfaces-are-broken problem. However, even though they claim to have reified generics and delegation, delegation + reified generics does not work.

Community
  • 1
  • 1
peenut
  • 3,366
  • 23
  • 24
  • 1
    Putting `public: using Template::function; using Template::function;` inside the class `Composed` makes the C++ example work w/o the qualification `Template<...>::` or casts (like what you want). – dyp Jul 26 '13 at 01:22
  • 1
    You could also use this in C++: `public: template void function(T i) { static_cast – dyp Jul 26 '13 at 01:28
  • 1
    Another weird idea: in C++, you could maybe turn the multiple inheritance into single inheritance by using a variant of CRTP, e.g. `class Composed : public Template>`, where `Template` derives from `Template` and uses itself a `using`-directive to overload `function`. With this trick, you wouldn't have to manually specify the `using` for each base class. – dyp Jul 26 '13 at 01:36
  • @DyP: (using) I didn't know about using, thank you. But I would still have to list all functions, which defeats the purpose of trait. (static cast) similar to using, but becomes more clever if more than 2x inherited. – peenut Jul 26 '13 at 01:41
  • @DyP: (templates) it works, it can be done without variadic templates, maybe with them too, I haven't used them yet. – peenut Jul 26 '13 at 02:05
  • *Pedantic:* The problem in C++ is not name hiding, but the ambiguity during name lookup. Name hiding would occur e.g. when a derived class declares a member of the same name as a base class. Here, we only have members in base classes. The ambiguity is described in [class.member.lookup]/6 – dyp Jul 26 '13 at 10:22

1 Answers1

2

C++: The weird idea similar to CRTP (see comment to OP) I had was meant to be more like:

#include <typeinfo>
#include <iostream>

struct Dummy
{
private:
  // dummy type to prevent overload resolution from ever choosing this overload
    struct ParamDummy { explicit ParamDummy(); };
public:
    void function(ParamDummy);
};

template<typename T, typename Base = Dummy>
struct Template
    : Base
{
    using Base::function;
    void function(T i) { std::cout << typeid(T).name() << std::endl; }
};

struct SecondBaseClass
{
    void function2() { std::cout << "function2" << std::endl; }
};

struct Composed
    : Template<int, Template<double>>, SecondBaseClass
{};

int main()
{
    Composed c;
    c.function(5.0);
    c.function(5);
    c.function2();
}

For every distinct member function name in Template, you need one using directive. The number therefore only depends on the number of member functions in the current class, not on the base classes.

It is different to multiple inheritance in some aspects, but it allows a simple function overloading.

It gets trickier if the base classes only share some but not all member functions.

Community
  • 1
  • 1
dyp
  • 38,334
  • 13
  • 112
  • 177
  • simple function overloading - but only from the same trait, otherwise you don't know what you should be "using" – peenut Jul 26 '13 at 11:30
  • @peenut You use the `using` directive on all function names of your *own* class, you do not need to know the function names of your base classes. Maybe you could insert some trick to make it also work if your base class doesn't have a member named like your own. – dyp Jul 26 '13 at 11:43
  • @peenut In fact, you could use this trick if you want to overload functions (stacked single inheritance), and multiple inheritance for unrelated base classes. – dyp Jul 26 '13 at 12:00