Комментарии 23
Отличный пример для того, что ООП — это просто ужас. Система трейтов отлично реализует ваш случай, и совершенно не требует отвечать на Экзистенциальный Вопрос Объектного Программирования — "Что Есть Объект?".
Смотрите:
trait Special{
fn do_special(self, Other) where Other: Player + Mob;
}
trait Attack{
fn do_attack(self, Other) where Other: Player + Mob;
}
impl Special For Fighter {
...
}
impl Attack for Mage {
...
}
Можно даже сказать, что у нас есть класс (игровой) Dumb у которого нет Special. Тогда, если в коде мы попытаемся вызывать do_special, нам скажут, что трейт Special для Dumb не реализован. При компиляции.
(код на Rust).
Забудьте про ООП, это была удачная для GUI метафора, которую попытались возвести в статус религии.
Отличный пример для того, что ООП — это просто ужас. Система трейтов отлично реализует ваш случай, и совершенно не требует отвечать на Экзистенциальный Вопрос Объектного Программирования — "Что Есть Объект?".
Разве то что вы написали нельзя реализовать интерфейсами в ООП?
Формально, языки с ООП парадигмой вполне тьюринг-полные, так что реализовать можно.
Но интерфейсы по-прежнему подразумевают, что у нас есть жёсткая иерархия объектов, а это неправда в большинстве доменов. В Гуи — да, очень удачная модель. В большинстве других применений — просто нет.
ООП это набор хороших практик, на которых держится мир, особенно мир геймдева где реально все объекты. Но это не значит что нельзя их нарушать — уже все издавна ООП языки позволяют подмешивать хорошие приемы функционального программирования и некоторые вещи выходят проще и красивее. Потихоньку появляются новые ООП приемы (прочитайте про миксины в Dart и возможно частично в Python- классная же штука)
В то же самое время появляются языки программирования, в которых ООП вообще отсутствует. Нет поддержки оператора GOTO (как было в Си), операторов управления ленточным накопителем (как было в кобол) и классов для наследования (как было в С++/java).
Нет. В Rust'е нет ни классов, ни наследования. А трейты есть. Трейты реализуются на структурах. Ключевая разница состоит в том, что методы в классе — это таблица методов (то есть indirect call), а ассоциированные функции для структуры и функции в реализации трейта — это compile-time вещь, в runtime — это обычные функции (прямой вызов), включая inline.
Разница в производительности. Если вы вызываете метод у класса, это inderect call с нулём шансов на оптимизацию (есть есть jit, но там проблемы другого порядка). inderect call уже дорого, вызов функции тоже дорого. В 90% случаев функцию лучше инлайнить.
Это называется zero cost abstractions и это одна из целей Rust'а. Пользователь городит выразительные отношения между типами и очень кратко и ёмко описывает что происходит с данными. Компилятор на это смотрит, проверяет отношения, а дальше потихоньку-полегоньку всю эту красоту до нескольких байт доводит.
Справедливости ради в Rust есть dyn traits/trait objects (т.е. динамический диспатчинг методов), но его использование дороже, чем для нормальных трейтов (по описанной выше причине).
Чем больше язык делает в compile time, тем меньше программа вынуждена выполнять ритуалы программиста в runtime, и тем быстрее она работает.
А как они будут знать какой метод вызывать, если в объекте не будет таблицы указателей на методы?
ООП без таблицы методов не реализовать (если можно — хочу на это посмотреть), а таблица методов — это inderect call.
Но у java проблема куда большая — у неё все объекты на куче, т.е. являются указателями.
А как они будут знать какой метод вызывать, если в объекте не будет таблицы указателей на методы?А не важно. Важен принцип, что в ваше классификации особенности рантайма важнее, чем нотация языка.
А как они будут знать какой метод вызывать, если в объекте не будет таблицы указателей на методы?
С++:
class A {
void foo() {cout << "Im a method, btw" << endl;}
}
Вот незадача: в объекте нет таблицы указателей на метод, а метод есть. Это не OOP?
У вас нет объекта, для начала, а есть только класс. Инстансируете класс, получите таблицу методов.
int main()
{
A a;
}
В объекте a есть таблица методов?
Почитал. Нет, будет direct call. Чтобы таблица появилась, надо использовать виртуальные методы.
таблица методов — это не особенности рантайма, это основа ООП.
ООП без таблицы методов не реализовать
Ключевая разница состоит в том, что методы в классе — это таблица методов (то есть indirect call)
оказались немного поспешны, да и, собственно, трейты — это концепция разработанная внутри объектно-ориентированного подхода. А то как она сделана в различных ( в том числе не-ООP) языках — это как раз детали реализации.
Почитал. Нет, будет direct call. Чтобы таблица появилась, надо использовать виртуальные методы.
да вы что, а тут что будет как вы думаете?
struct A {
virtual void foo() {cout << "Im a method, btw" << endl;}
}
struct B : public A {
void foo() override {cout << "Im a method too" << endl;}
}
int main()
{
B b;
b.foo();
}
Мозговой штурм: как смотреть на задачи под другим углом