Открыть список
Как стать автором
Обновить

Комментарии 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).

современные языки поддерживают много парадигм, плюс на выбор есть тонны архитектурных паттернов и тд. Для геймдева отлично подходят — композиция, ECS, событийная и реактивные модели. Это помимо ООП здорового человека (без фанатизма). Который тоже хорош. В любом проекте есть комбинация подходов, и это нормально. Я к тому что нормальный ООП до сих пор хорош и решает большинство вопросов.
Да они часто и не взаимоисключающи. Тот же ECS то же может быть ООП, но только в плане моделирования не предметной области, а механизмов самого ECS.
Простите, но разве трейты — это не ООП?

Нет. В Rust'е нет ни классов, ни наследования. А трейты есть. Трейты реализуются на структурах. Ключевая разница состоит в том, что методы в классе — это таблица методов (то есть indirect call), а ассоциированные функции для структуры и функции в реализации трейта — это compile-time вещь, в runtime — это обычные функции (прямой вызов), включая inline.

А для программиста есть разница, от того что они «compile-time»? Мне всегда казалось, что ООП — это в первую очередь про семантику языка, а не про то, во что оно компилируется.

Разница в производительности. Если вы вызываете метод у класса, это inderect call с нулём шансов на оптимизацию (есть есть jit, но там проблемы другого порядка). inderect call уже дорого, вызов функции тоже дорого. В 90% случаев функцию лучше инлайнить.


Это называется zero cost abstractions и это одна из целей Rust'а. Пользователь городит выразительные отношения между типами и очень кратко и ёмко описывает что происходит с данными. Компилятор на это смотрит, проверяет отношения, а дальше потихоньку-полегоньку всю эту красоту до нескольких байт доводит.


Справедливости ради в Rust есть dyn traits/trait objects (т.е. динамический диспатчинг методов), но его использование дороже, чем для нормальных трейтов (по описанной выше причине).


Чем больше язык делает в compile time, тем меньше программа вынуждена выполнять ритуалы программиста в runtime, и тем быстрее она работает.

Ну то есть, если разрабы Java перепишут компилятор так, чтобы он не использовал inderect call, то Java перестанет быть объектно-ориентированным языком?

А как они будут знать какой метод вызывать, если в объекте не будет таблицы указателей на методы?


ООП без таблицы методов не реализовать (если можно — хочу на это посмотреть), а таблица методов — это inderect call.


Но у java проблема куда большая — у неё все объекты на куче, т.е. являются указателями.

А как они будут знать какой метод вызывать, если в объекте не будет таблицы указателей на методы?
А не важно. Важен принцип, что в ваше классификации особенности рантайма важнее, чем нотация языка.

Нет, таблица методов — это не особенности рантайма, это основа ООП. Вы храните методы в классе, а так же имеете отношения с предком. Всё это — таблица методов (в лучшем случае) или таблицы методов с сылками (в худшем).

А как они будут знать какой метод вызывать, если в объекте не будет таблицы указателей на методы?

С++:
class A {
    void foo() {cout << "Im a method, btw" << endl;}
}

Вот незадача: в объекте нет таблицы указателей на метод, а метод есть. Это не OOP?

У вас нет объекта, для начала, а есть только класс. Инстансируете класс, получите таблицу методов.

Да, что вы такое говорите?
int main()
{
   A a;
}

В объекте a есть таблица методов?

Почитал. Нет, будет direct call. Чтобы таблица появилась, надо использовать виртуальные методы.

Воооот. Смотрите как интересно получилось — OOP есть, а таблицы методов нет. Тут можно заключить, что выводы
таблица методов — это не особенности рантайма, это основа ООП.

ООП без таблицы методов не реализовать

Ключевая разница состоит в том, что методы в классе — это таблица методов (то есть 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();
}
Статья перевод чей-то? Автор прыгает с примера на пример ничего толком не объясняя. Я еще не въехал что там про мага с вором и воином, зачем он вообще про это рассказывал, а он уже новую таблицу рисует… Непонятно…
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.