4
votes

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.

1
Putting public: using Template<int>::function; using Template<double>::function; inside the class Composed makes the C++ example work w/o the qualification Template<...>:: or casts (like what you want). - dyp
You could also use this in C++: public: template<typename T> void function(T i) { static_cast<Template<T>*>(this)->function(i); } (or just Template<T>::function(i) instead of the cast, although this may hide a problem with static member functions: when they're not inherited, it would still work). - dyp
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<int, Template<double>>, where Template<int,..> derives from Template<double> 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
@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
@DyP: (templates) it works, it can be done without variadic templates, maybe with them too, I haven't used them yet. - peenut

1 Answers

2
votes

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.