Anton
Структурный сабтайпинг
Ну это как раз просто вложенные структуры
Aleksei (astynax)
Можно просто не наследоваться :) Только копмозить
Alexander
тогда это уже не классическое ООП
Alexander
про которое обычно говорят апологеты этого стиля
Alexander
и прекрасно выражается в не-ООП языках
Aleksei (astynax)
Только преподы ООП, разве что
Aleksei (astynax)
Практики знают, что композиция лучше наследования!
Alexander
я видел интырпрайз явакод
Aleksei (astynax)
Все книжки про паттерны об этом говорят
Alexander
при этом 3/4 паттернов полагаются на наследование?
Aleksei (astynax)
Нет, композиции хватает
Anton
Ну вот типы-суммы и типы-произведения — очень простые вещи, которые можно комбинировать как угодно. Интерфейсы/трейты тоже — их можно как при статической, так и при динамической диспетчеризации использовать. А наследование включает в себя слишком много всего сразу, поэтому очень легко получить кашу, которую потом сложно зарефакторить
Anton
Нет, композиции хватает
Композиции не хватает, когда в базовом типе 20 методов, а в наследнике добавляется один, и приходится все 20 пробрасывать руками
Aleksei (astynax)
Это уже должен решать язык, аннотациями, или ещё чем
Anton
Ну я считаю, что такое пробрасывание надо делать явной отдельной концепцией в языке
Anton
В расте не хватает такого
Anton
Но я глупенький) Может быть есть лучше решения
Aleksei (astynax)
В питоне есть метапрограмминг, делегацию можно автоматизировать. А встраивать именно в язык не очень хорошо, да
Aleksei (astynax)
В расте хотят расширяемые рекорды запилить, еяпп. Но когда запилят, не знаю
Aleksei (astynax)
"OOP as a Library", лучше, чем некая всегда чем-то неполоноценная версия ООП, намертво встроенная в синтаксис
Anton
Ну это не ООП, я именно за то, чтобы делегацию сделать отдельно от остального
Anton
По сути просто бойлерплейт убрать
Anton
delegate to base { fn1, fn2, fn3 } Что-нибудь типа такого
Aleksei (astynax)
В питоне я могу сделать так: class Foo( compose(bar=Bar, delegate=['write', 'read', 'size']), compose(qux=Qux, delegate=ALL)): ...
Anton
Ага
Aleksei (astynax)
Тут хотя бы не будет той же проблемы с множественным наследованием, от которого в питоне одна боль
Aleksei (astynax)
А вообще в питоне или том же Ruby я могу неизвестные методы пробрасывать во все вложенные объекты по порядку, пока кто-то из них не обработает. Так что можно даже особо не делегировать. Правда и интроспекции не будет тогда
Alexander
тут надо чтобы тот кому делегировали мог вызвать асирактный метод, который будет выполнен тем, кто делегировал
Alexander
абстрактный
Aleksei (astynax)
Ну да, получится двойная диспетчеризация
Alexander
ООП и наследование об этом
Aleksei (astynax)
При композиции вложенный объект не должен знать ничего об оборачивающем - это утечка абстракции
Aleksei (astynax)
Разве что передать при вызове колбэк можно, если это соответствуте API вкладываемого объекта
Anton
Короче очень неортогональная штука это наследование)
Aleksei (astynax)
Наследование сначала смотрится неплохо, а потом начинается адище
Aleksei (astynax)
Иерархии сущностей адекватные написать нелегко, часто - невозможно. А ещё чаще - просто не нужно, но "все привыкли уже"
Зигохистоморфный
Ох и развели вы тут)
Alexander
и не особо нужная :)
Alexander
зачастую вложенный объект все же должен знать какой-то интерфейс
Alexander
ну или по другому выкручиваться, а вот с иерархиями согласен
Alexander
там наверху пример с Боингом был
Alexander
я там не как птиц наследовать и что делать с самолётами двойного назначения
Alexander
меняют ли они класс в военное время
доня.
ну это уже похоже на классическое наследование
не важно то что такие интерфейсы ничего не знают о том как объект устроен внутри то есть они описывают только поведение (и неважно что у каких-то методов оно может быть дефолтным)
доня.
и не особо нужная :)
да ладно, вот простейший пример есть какая-нибудь ORM, надо шоб она могла подключаться к разным БД плохой способ: хардкодить подключение к каждому типу БД в одной структуре тоже плохой способ: наследоваться от общей структуры и в наследниках перегружать метод подключения к БД чёткий способ: выделить подключение к БД в отдельный интерфейс Connection и хранить ссылку на Connection в качестве поля структуры ORM таким образом ORM знает только об универсальном интерфейсе предоставляемым структурами, реализующими Connection и можно в пользовательском коде реализовать подключение к какой-нибудь БД о которой разработчик ORM не знает
Alexander
какое отношение это имеет к наследованию или композиции?
доня.
прямое
доня.
второй способ - наследование, третий - композиция
доня.
(простите за мой Rust): type ConnectionResult = ...; trait Connection { fn connect(&mut self) -> ConnectionResult; // more methods } struct ORM { connection: Box<Connection>; // more fields }
Alexander
в данном случае data Connection = Connection { method1, method2 } хватит
Alexander
что правда тоже самое, но в профиль
доня.
нуу или так хотя мне-таки больше нравится вариант где Connection - интерфейс/трейт/тайпкласс
доня.
В питоне я могу сделать так: class Foo( compose(bar=Bar, delegate=['write', 'read', 'size']), compose(qux=Qux, delegate=ALL)): ...
о, а это откуда? либа какая-то для делегирования? или пример абстрактный?
Aleksei (astynax)
абстрактный, но реализуемый :)
Alexander
ну с Haskell можно подобное
Alexander
data Connection; class HasConnection ; class AsORM a where default .. :: HasConnection a => a -> ...
доня.
абстрактный, но реализуемый :)
ну так-то реализовать достаточно просто) проблема только в том что одно дело когда популярная либа, другое - когда используешь свой костыль костыль не в том плане что плохо реализован, а в том что никто больше этим подходом не пользуется и рандомный человек заглянув в твой код будет учить чуть ли не новый язык, привыкая использовать кастомный механизм делегирования вместо встроенного в питон наследования
Alexander
HasConnection через Generic
доня.
@qnikst можно ж через экзистенциальную квантификацию, а то с дженериками немного громоздко
Alexander
не, это совсем разные вещи :)
доня.
я имел ввиду что-то типа {-# LANGUAGE ExistentialQuantification #-} class Connection c where connect :: c -> IO () data ORM = forall c. Connection c => ORM { connection :: c } (сигнатура connect не особо осмысленная, но не суть)
Alexander
здесь тогда класс такой вообще не нужен
Alexander
взять структуры данных и все
Alexander
в которой поля это методы
кана
Я, как новичок, просто использовал бы ReaderT для передачи коннекшона, а код, который работает с базой, требовал бы тот самый тайпкласс для енва в ридере, что позволит один и тот же код запускать с разными коннекшонами (чтобы замокать для тестов, например). Я пока не писал ни одного продакшенового кода на хаскеле, если что, могу нести хрень
Alexander
а это уже совсем другое
доня.
нуу не знаю, мне кажется что вариант с полями-методами какой-то менее структурированный может я и не прав конечно
кана
Ну как я понимаю ридер, он для этого и нужен, чтобы упростить передачу одной и той же зависимости куче кода без кучи лишних аргументов
Зигохистоморфный
https://twitter.com/mokevnin/status/903909806901166080
Зигохистоморфный
https://gist.github.com/mbbx6spp/899e7813ada901c9ffea4ac157bc361a
Евгений
Зигохистоморфный
думаю без ооп классов
Aragaer
я нормально программирую без классов
Евгений
думаю без ооп классов
Какая-то тухлая шутка, все давно уже пишут на JS, там классов нету
Зигохистоморфный
есть)