Кстати, операторы по типу
Что до наследования, то это вероятно самая обруганная концепция из мира ОО. В Rust у нас просто нет наследования конкретных типов, а значит мы должны всегда использовать композицию или альтернативные варианты, например, посетителей.
А вот наследование характеристик оставили, но тут это выглядит не как создание отношения между сущностями, а скорее просто уточняющий контракт. Значит никаких вам override/super тут нет. И связанных с этим проблем нет.
- В Rust нет понятия объекта.
А значит нет разделения на объекты и примитивы. По-умолчанию почти все типы передаются по значению и могут храниться в стеке, но с другой стороны мы можем создать ссылку/указатель на любой тип, так и явно поместить его в кучу. Говоря простым языком, мы полностью контролируем где и как хранятся наши данные.
- Rust позволяет задавать зависимость от абстрактных типов.
Значит мы можем создать массив "итерируемых объектов", а не конкретных типов. Только вот загвоздка в том, что сделать массив, в котором будут лежать одновременно строки и вектора просто так не получится. Минуточку. Но почему?
Ну смотрите, в Java у нас любой объект всегда передается по указателю, а интерфейсы применяются только к объектам. Значит такой массив фактически был бы массивом указателей. А вот в Rust у нас объектов нет.
Зато ссылку/указатель мы можем создать явно на что угодно. И сможем объяснить компилятору, что у нас тут должна быть ссылка на сущность, которая реализует заданную характеристику. Значит все таки создать массив разных сущностей из приведенного примера мы сможем, но мы должны это ЯВНО описать компилятору.
Зачем такие сложности? Ответ простой - производительность. Дело в том, что в базовом сценарии все функции работающие с абстрактными типами в момент компиляции мономорфизируются. Т.е. под каждый конкретный тип у нас будет своя отдельная функция. Дальше, компилятор сможет провести эффективный инлайнинг и может статься, что функция будет вообще не нужна...
А когда мы прячемся за указатель, то получается, что такого рода оптимизация становится невозможной на этапе компиляции, а значит для этого уже придется придумывать JIT. У Rust JIT нет, да и вообще Runtime очень маленький, поэтому язык использует дизайн "любая доп цена должна быть явной".
---
Уфф. Получилось много буков. Какой же тут вывод? В Rust безусловно присутствуют многие черты ОО языка, но, фактически, таковым он не является. Однако, получившееся смесь позволяет нам эффективно использовать черты ОО и ФП без сильного негативного эффекта обоих языков. Значит, безумное море-объектов в Java стиле вам не грозит, как и не грозит чрезмерный пуризм и контроль за эффектами в стиле Haskell.
Парадигмы программирования не стоят на месте и развиваются. А чтобы понимать почему в языках происходят те или иные изменения нужно понимать проблемы, а для этого изучать разные ЯП и расширять кругозор.
Но ООП не умирает, даже не болеет. Так что не бойтесь.
Всем базы!
+
, -
, .
, []
- это тоже функции из различных характеристик, а значит мы можем их явно реализовывать для любого своего типа. Говоря проще: в Rust есть перегрузка операторов. Причем работает она абсолютно прозрачно.Что до наследования, то это вероятно самая обруганная концепция из мира ОО. В Rust у нас просто нет наследования конкретных типов, а значит мы должны всегда использовать композицию или альтернативные варианты, например, посетителей.
А вот наследование характеристик оставили, но тут это выглядит не как создание отношения между сущностями, а скорее просто уточняющий контракт. Значит никаких вам override/super тут нет. И связанных с этим проблем нет.
- В Rust нет понятия объекта.
А значит нет разделения на объекты и примитивы. По-умолчанию почти все типы передаются по значению и могут храниться в стеке, но с другой стороны мы можем создать ссылку/указатель на любой тип, так и явно поместить его в кучу. Говоря простым языком, мы полностью контролируем где и как хранятся наши данные.
- Rust позволяет задавать зависимость от абстрактных типов.
Значит мы можем создать массив "итерируемых объектов", а не конкретных типов. Только вот загвоздка в том, что сделать массив, в котором будут лежать одновременно строки и вектора просто так не получится. Минуточку. Но почему?
Ну смотрите, в Java у нас любой объект всегда передается по указателю, а интерфейсы применяются только к объектам. Значит такой массив фактически был бы массивом указателей. А вот в Rust у нас объектов нет.
Зато ссылку/указатель мы можем создать явно на что угодно. И сможем объяснить компилятору, что у нас тут должна быть ссылка на сущность, которая реализует заданную характеристику. Значит все таки создать массив разных сущностей из приведенного примера мы сможем, но мы должны это ЯВНО описать компилятору.
Зачем такие сложности? Ответ простой - производительность. Дело в том, что в базовом сценарии все функции работающие с абстрактными типами в момент компиляции мономорфизируются. Т.е. под каждый конкретный тип у нас будет своя отдельная функция. Дальше, компилятор сможет провести эффективный инлайнинг и может статься, что функция будет вообще не нужна...
А когда мы прячемся за указатель, то получается, что такого рода оптимизация становится невозможной на этапе компиляции, а значит для этого уже придется придумывать JIT. У Rust JIT нет, да и вообще Runtime очень маленький, поэтому язык использует дизайн "любая доп цена должна быть явной".
---
Уфф. Получилось много буков. Какой же тут вывод? В Rust безусловно присутствуют многие черты ОО языка, но, фактически, таковым он не является. Однако, получившееся смесь позволяет нам эффективно использовать черты ОО и ФП без сильного негативного эффекта обоих языков. Значит, безумное море-объектов в Java стиле вам не грозит, как и не грозит чрезмерный пуризм и контроль за эффектами в стиле Haskell.
Парадигмы программирования не стоят на месте и развиваются. А чтобы понимать почему в языках происходят те или иные изменения нужно понимать проблемы, а для этого изучать разные ЯП и расширять кругозор.
Но ООП не умирает, даже не болеет. Так что не бойтесь.
Всем базы!