Существует ли любой язык, который:
- статически (и строго) типизирован
- поддерживает дженерики (шаблоны)
- поддерживает трейты/множественное наследование/делегирование интерфейса
- разрешает перегрузку функций (также унаследованных членов)
В принципе, в псевдокоде я хочу этого:
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)
Из вики-списка http://en.wikipedia.org/wiki/Multiple_inheritance#Implementations Я пытался писать код на следующих языках программирования (я также включил новейшие еще неопубликованные языки версии 1.0 (2013), такие как Kotlin, Ceylon):
- C++ почти возможно, но не может разрешить перегруженную функцию для составной переменной
- Ошибка компиляции Scala: трейт унаследован дважды; даже если его обмануть косвенным наследованием, он все равно выдает ошибку; см. также вопрос другого парня о множественном наследовании общих миксинов в Scala
- Ошибка компиляции Eiffel: нет перегрузки функции
- Черты Ceylon не могут иметь переменных (и защищенных членов, поэтому никаких трюков для хранения данных в производном классе, черты в Ceylon бесполезны)
- Фантом без общих шаблонов/шаблонов
- Ошибка компиляции Kotlin: супертип появляется дважды; делегирование выглядит уникальным, но оно бесполезно, потому что нельзя получить доступ ни к защищенным членам, ни к переменной, которая делегирована
- Rust не перегружает функции; трейты не могут хранить данные; трейты не могут иметь определенных методов (с телом) - проблема, над которой работают;
- Ошибка компиляции OCaml: нет перегрузки функций; он также не проверял тип параметра для моей функции, так что насколько он «статически типизирован»?!
- Ошибка компиляции Curl: нет перегрузки функции; он также не проверяет тело функции, если оно не вызывается, так насколько же оно на самом деле «статически типизировано»? он вообще компилируется или интерпретируется?!
- Gosu — плохая шутка, его вообще нельзя использовать: нельзя написать и реализовать простой интерфейс с одним матодом (ошибка: ClassFormatError: Illegal field modifiers). Кто на самом деле использует этот язык?!
Кстати: я подумал об этой проблеме, когда пытался вынести поддержку Java для слушателей в отдельный класс (во многих классах есть: List‹ListenerType› ... addListener(...) ... removeListener(...) )
С++ почти работает:
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);
Изменить: в С++ проблема заключается в сокрытии функции наследования. См. также Функция с тем же именем, но с другой подписью в производном классе. и Почему переопределенная функция в производном классе скрывает другие перегрузки базового класса?
Редактировать 2: в С++ с шаблонами и частичной специализацией существует возможность подвоха, позволяющего упростить использование черты:
#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;
}
Это означает, что данный конкретный пример в C++ работает, однако, если несвязанные трейты имеют общее имя функции, в C++ невозможно наследовать и использовать все функции.
Изменить 3: я также должен проверить любой язык программирования, поддерживающий миксины: http://en.wikipedia.org/wiki/Mixins#Programming_languages_that_use_mixins
- D работает, но только через миксин для манипуляций со строками, поэтому рефакторинг в таком случае нарушается:
mixin(GenerateSomething!("IfClassNameHereManualRenaming"));
Редактировать 4: добавлен языковой комментарий «Госу».
Редактировать 5: Язык программирования Gosu имеет обновление 0.10.2, в котором исправлена проблема с неработающими интерфейсами. Однако, несмотря на то, что они утверждают, что у них есть овеществленные дженерики и делегирование, делегирование + овеществленные дженерики не работает.
public: using Template<int>::function; using Template<double>::function;
внутри классаComposed
заставляет пример C++ работать без квалификацииTemplate<...>::
или приведения (например, что вы хотите). - person dyp   schedule 26.07.2013public: template<typename T> void function(T i) { static_cast<Template<T>*>(this)->function(i); }
(или простоTemplate<T>::function(i)
вместо приведения, хотя это может скрыть проблему со статическими функциями-членами: когда они не унаследованы, это все равно будет работать). - person dyp   schedule 26.07.2013class Composed : public Template<int, Template<double>>
, гдеTemplate<int,..>
происходит отTemplate<double>
и использует директивуusing
для перегрузкиfunction
. С помощью этого трюка вам не нужно было бы вручную указыватьusing
для каждого базового класса. - person dyp   schedule 26.07.2013