[ /tv/ /rf/ /vg/ /a/ /b/ /u/ /bo/ /fur/ /to/ /dt/ /cp/ /oe/ /bg/ /ve/ /r/ /mad/ /d/ /mu/ /cr/ /di/ /sw/ /hr/ /wh/ /lor/ /s/ /hau/ /slow/ /gf/ /vn/ /w/ /ma/ /azu/ /wn/ ] [ Main | Settings | Bookmarks | Music Player ]

No.48832 Reply
File: pg087.png
Png, 23.35 KB, 475×349
edit Find source with google Find source with iqdb
pg087.png
File: pg072.png
Png, 56.58 KB, 515×709
edit Find source with google Find source with iqdb
pg072.png
File: 14686072547160.png
Png, 44.08 KB, 1024×450
edit Find source with google Find source with iqdb
14686072547160.png

Как понять ООП? Я просто вот не понимаю, зачем это нужно. Безотносительно языка программирования

Вот допустим есть некие классы, классы как в плюсах. Есть методы, которые к этим классам привязаны. Зачем это вообще нужно, если можно просто сделать структуру и набор функций, которые могут с этими структурами нечто осмысленное делать?

Вот допустим есть public private protected модификаторы доступа т.е. ограничения на то, откуда какой метод можно вызывать. public можно вызывать отовсюду, private только для методов из числа public, а protected ... protected становится private при наследовании, притом наследований может быть 3 вида - тоже public, private, protected... Зачем всё это? Чем это лучше просто кучи функций, которые могут просто вызывать другие функции и работать с какими-то структурами?

Или вот методы, методы это функции, которые привязаны к конкретной структуре, но что если мне нужны методы, которые связывают два разных класса? Например это может код, переводящий из вектора в растровую картинку. Этот код должен быть методом класса для растровой или векторной картинки?
>> No.48833 Reply
>>48832
> Как понять ООП? Я просто вот не понимаю, зачем это нужно.
Это еще один уровень абстракции. В императивном языке ты думаешь как работать непосредственно с данными, а в объектом - как работать с объектами. В этом плане ООП больше похоже на сборку лего, где у каждой детали свои характеристики, и у тебя уже не получится использовать шестеренку как кирпичик. Или как сборку ПК, где тебя уже не волнует, как и какие там чипы, транзисторы и резисторы на платах припаяны, тебе главное чтоб разъемы совпадали и по спецификациям друг к другу подходили.

> Зачем это вообще нужно, если можно просто сделать структуру и набор функций, которые могут с этими структурами нечто осмысленное делать?
Как я это понимаю - с помощью методов ты четко определяешь, что можно делать с данными в объекте (см. выше пример с лего). В случае с методами и функциями, у тебя, например, больше шансов случайно засунуть векторную структуру в функцию для растровой и в результате получить баг.

> Вот допустим есть public private protected модификаторы доступа т.е. ограничения на то, откуда какой метод можно вызывать. public можно вызывать отовсюду, private только для методов из числа public, а protected ... protected становится private при наследовании, притом наследований может быть 3 вида - тоже public, private, protected... Зачем всё это? Чем это лучше просто кучи функций, которые могут просто вызывать другие функции и работать с какими-то структурами?
Во-первых, все эти мутации public private protected друг в друга - просто особенность C++. Прими как данное. В других языках тоже свои заморочки есть. Во-вторых, эти модификаторы позволяют четко определить, какие переменные можно изменять, а какие нет. Как и в случае с методами, это еще одна защита от ошибки программиста. Ты же не всегда на 100% внимателен и трезв умом. Сегодня у тебя голова болит, завтра тебя отвлекли разговором, послезавтра тебя девушка бросила, а через неделю тебе просто лень вычитывать код на ошибки. Раз в год и палка стреляет, так что лучше сразу технически пресечь такую возможность.

> Или вот методы, методы это функции, которые привязаны к конкретной структуре, но что если мне нужны методы, которые связывают два разных класса? Например это может код, переводящий из вектора в растровую картинку. Этот код должен быть методом класса для растровой или векторной картинки?
Четкого ответа дать не могу, я бы лично написал отдельную функцию, не привязанную к какому-либо классу. На мой взгляд это зависит от архитектуры кода. Можно представить растровый класс, который постоянно жрет векторные данные, и реализовать код конвертации как метод растрового класса. А можно запариться и для каждого класса реализовать метод конвертации в противоположный формат.
>> No.48834 Reply
>>48833
> Это еще один уровень абстракции. В императивном языке ты думаешь как работать непосредственно с данными, а в объектом - как работать с объектами. В этом плане ООП больше похоже на сборку лего, где у каждой детали свои характеристики, и у тебя уже не получится использовать шестеренку как кирпичик.
> В случае с методами и функциями, у тебя, например, больше шансов случайно засунуть векторную структуру в функцию для растровой и в результате получить баг.
Ну если взять чистый C и противопоставить его C++, то в C есть структуры (struct), и если у меня функция принимает в качестве аргумента структуру, то передать в эту функцию другую структуру просто так не выйдет, будет как минимум warning. Класс в C++ это когда насильно привязывают некоторые функции к некоторым структурам и создают некие правила, что вот есть такие функции-привязанные-к-структуре, которые можно вызывать кому угодно, а есть еще какие-то особые функции-привязанные-к-структуре, которые можно вызывать только из других функций-привязанных-к-структуре (private методы можно вызывать только из других методов класса). Каким образом это увеличивает уровень абстракции? Это просто добавляет способ задать некие ограничения. Например модификатор const для переменных, он тоже никаких абстракций не добавляет, а просто позволяет указать что переменная не может быть изменена, и чтобы компилятор еще ругался при попытке эту переменную изменить.
На абстракцию похоже разве что наследования с виртуальными методами, когда C++ компилятор создает таблицу виртуальных методов т.е. массив из указателей на функции (не нужно рукам эти массивы из указателей на функции писать). Да и есть альтернативы для vtable в других языках, например через хеш-таблицы имен методов.
В самой же идее связать структуру и некоторые функции я никакого нового уровня абстракции не вижу.
> Во-вторых, эти модификаторы позволяют четко определить, какие переменные можно изменять, а какие нет. Как и в случае с методами, это еще одна защита от ошибки программиста.
Для этого больше бы подошли какие-нибудь контракты. Например, в каком-нибудь гипотетическом ЯП сделать так, чтобы можно было объявить особый неймспейс №1, перечислив в нем некоторое множество функций. И потом объявить другой неймспейс №2, перечислив в нем другое множество функций, при этом у этого неймспейса задать особый атрибут, что функции из этого неймспейса №2 могут быть вызваны только из функций, объявленных в неймспейсе №1. Но при этом может быть и так, что функции из неймспейса №2 не могут быть вызваны из неймспейса №1. Сама идея создания подобных контрактов к ООП отношения не имеет
С плюсовыми методами класса такое кстати не работает, т.е. public методы могут вызывать private, private могут вызывать public и private, нельзя ввести запрет для private вызывать public, как и нельзя объявить какой-нибудь свой уникальный модификатор, типа public_2 и вручную выставить для него правила, что и как ему можно делать.
> Четкого ответа дать не могу, я бы лично написал отдельную функцию, не привязанную к какому-либо классу.
А еще было б неплохо, если бы такой отдельной функции можно было бы дать разрешение вызывать private методы этих двух классов и читать-писать private переменные из этих двух классов. #define private public
>> No.48835 Reply
>>48834
Очевидно, ты не понимаешь самой идеи (инкапсуляция, полиморфизм, наследование, вот это все) и смотришь только на синтаксис.
> и если у меня функция принимает в качестве аргумента структуру, то передать в эту функцию другую структуру просто так не выйдет, будет как минимум warning.
Классический пример: у тебя есть функция copulate. В сишке ты будешь сам трахаться, плодя бесчисленные copulate(Bat), copulate(Tiger) и т.д., тогда как ООП позволяет тебе выделить общую базу и сделать единый copulate(Animal), где наследники Animal будут перенимать поведение базового класса.
> Каким образом это увеличивает уровень абстракции?
Ты не задаешь функции, функции хуйня. Ты задаешь поведение объектов класса. Ты берешь класс и говоришь, что у него есть такие-то методы, и в public методы может тыкнуться любой желающий, а в private только он сам и т.д.
> Например модификатор const для переменных, он тоже никаких абстракций не добавляет, а просто позволяет указать что переменная не может быть изменена, и чтобы компилятор еще ругался при попытке эту переменную изменить.
Замечательная вещь: позволяет отсеять часть ошибок в логике еще на этапе компиляции. Точно так же часть ошибок можно отсеять с помощью правильной установки прав доступа (public-protected-private).
> С плюсовыми методами класса такое кстати не работает, т.е. public методы могут вызывать private, private могут вызывать public и private, нельзя ввести запрет для private вызывать public, как и нельзя объявить какой-нибудь свой уникальный модификатор, типа public_2 и вручную выставить для него правила, что и как ему можно делать.
Все просто: public_2 костыль и НИНУЖНО. Имеющихся прав доступа достаточно: это не непонятно какие неймспейсы с потолка, а именно что классы и описание того, кому и что с ними можно делать. По определению public - то, что доступно любому, а потому "запрет private вызывать public" - абсурд.
Не привязывайся к функциям, а пойми саму парадигму: ты описываешь не функции, а классы. Собственно, поэтому годные программисты пишут код на уровне взаимодействия интерфейсов, а не говнокодят с реализациями.
>> No.48836 Reply
Да говно это, учи Haskell
>> No.48837 Reply
>>48836
Да тоже фигня, лучше учиться на перспективу - учить языки для квантового программирования.
>> No.48838 Reply
File: Cylinder_Head_Sector_ru.svg.png
Png, 260.88 KB, 1200×1293 - Click the image to expand
edit Find source with google Find source with iqdb
Cylinder_Head_Sector_ru.svg.png
>>48835
> Классический пример: у тебя есть функция copulate. В сишке ты будешь сам трахаться, плодя бесчисленные copulate(Bat), copulate(Tiger) и т.д., тогда как ООП позволяет тебе выделить общую базу и сделать единый copulate(Animal), где наследники Animal будут перенимать поведение базового класса.
Т.е. смысл ООП в том, чтоб не копипастить? И это новый уровень абстракции?
Новый уровень абстракции это например переход ASM -> C, когда уже не нужно оперировать регистрами и инструкциями процессора. ООП это скорее некий способ организации кода (теперь функции мы привязали к структурам, пишите вот так!), а не новый уровень абстракции.
> Ты не задаешь функции, функции хуйня. Ты задаешь поведение объектов класса. Ты берешь класс и говоришь, что у него есть такие-то методы, и в public методы может тыкнуться любой желающий, а в private только он сам и т.д.
А зачем ограничивать себя только таким дефолтным набором public-private-protected? Может ООП является частным случаем более общей парадигмы, т.е. идеи выставлять на что-то какие-то разрешения? Ну вот я приводил пример с контрактами, что одни функции могут там что-то вызывать, а другие не могут, но никакие объекты для этого не требуются, это просто выделение некоторого неймспейса функций и создание для них каких-то запретов/разрешений. Такие же запреты/разрешения можно определять относительно каких-нибудь структур, и это можно сделать намного более гибко, типа вот только функции из этого неймспейса могут работать вот с этими структурами, а вот функции из этого неймспейса могут работать с другими структурами, а еще какие-то функции могут и с теми и с теми структурами работать.
> Замечательная вещь: позволяет отсеять часть ошибок в логике еще на этапе компиляции. Точно так же часть ошибок можно отсеять с помощью правильной установки прав доступа (public-protected-private).
Я и не спорю, но на новую парадигму это не тянет. Это просто возможность ставить самому себе какие-то ограничения. И систему прав доступа можно сделать значительно более гибкой, чем это реализовано в ООП.
> Все просто: public_2 костыль и НИНУЖНО. Имеющихся прав доступа достаточно: это не непонятно какие неймспейсы с потолка, а именно что классы и описание того, кому и что с ними можно делать. По определению public - то, что доступно любому, а потому "запрет private вызывать public" - абсурд.
Ну почему же, вполне можно представить ситуацию, когда полезно сделать ограничения вида "функции из неймспейса №1 могут вызывать только функции из неймспейса №1 и №2, функции из неймспейса №2 могут вызывать только функции из неймспейса №2 и №3, функции №3 вызывают только №3 и №4 и.т.д."
Например представим, что у нас есть гипотетический компьютер с жестким диском с магнитными блинами, и жесткий диск своего контроллера не имеет (управление осуществляется центральным процессором). Есть ОС на этом компьютере, и нам надо создать файл и записать в него такие-то данные. Вот тут можно вводить некие слои с разделением прав. Когда некая программа из юзерспейса просит ОС создать такой-то файл и записать в него такие-то байтики, ядро передает драйверу файловой системы указание "создай такой-то файл и запиши в него то-то", драйвер ФС передает драйверу жесткого диска "запиши вот эти байтики вот туда-то, и вот эти байтики вот туда", при этом драйвер ФС ничего не знает про геометрию диска(дорожки, количество пластин), т.е. с точки зрения драйвера ФС, жесткий диск это просто большой массив из некоторых секторов, например секторов по 512 байт. Т.е. драйвер ФС общается с драйвером жесткого диска на уровне "запиши в тот сектор размером в 512 байт вот это" и "прочитай из того сектора размером в 512 байт и дай мне". В драйвере жесткого диска обращение на чтение/запись такого-то сектора транслируется по каким-то формулам, учитывающим скорость вращения блинов, угол поворота коромысла с магнитными головками, и напрямую управляет всем этим. Так вот, тут имеет смысл запретить обычной программе из юзерспейса обращаться к драйверу жесткого диска напрямую и говорить, в какие секторы что писать. Обычная программа не должна управлять поворотом коромысла с магнитными головками, менять скорость вращения двигателя и прочего (то, что делает драйвер ЖД). Драйвер файловой системы тоже не должен управлять напрямую поворотом коромысла, а только лишь просить у драйвера ЖД, чтобы он туда-то записал/прочитал. А сам драйвер жесткого диска совершенно точно не должен обращаться к каким-нибудь вышележащим функциям, например драйверу ЖД незачем обращаться к драйверу ФС типа "драйвер ФС, давай удали вот этот файл". Т.е. из более низкого уровня нет смысла вызывать более высокий уровень. В ООП private имеет право вызывать и private и public, там нельзя строить такие правила.
Такое можно без всякого ООП делать в чистом Си, разбив реализацию на несколько файлов и используя static функции.
>> No.48839 Reply
Давайте сделаем поправку, что ООП в том виде, в котором его задумывал Алан Кей, мало где реализован. Так что да, ООП в мейнстримовых языках больше влияет на организацию кода, чем претендует на новую парадигму.
Собственно говоря, ООП в C++ не реализует ничего такого, чего нельзя было бы написать в C. Да только делается это в плюсах удобнее и безопаснее.
>> No.48840 Reply
>>48839
> Давайте сделаем поправку, что ООП в том виде, в котором его задумывал Алан Кей, мало где реализован.
Это связано с тем, что каноничное ООП оказалось никому не нужным? Или оно было слишком сложным в реализации? Или почему?
>> No.48841 Reply
>>48840
Без понятия. Наверное, все как всегда - теория столкнулась с практикой и изменилась.
Вот есть хорошая статья про историю идеи - https://medium.com/@atherlangga/retracing-original-object-oriented-programming-f8b689c4ce50
>> No.48847 Reply
>>48840
Каноничное ПО никому не нужно. Тебе же пофиг, как это работает. Вот и всем тоже пофиг. А когда всем пофиг, можно "хуяк-хуяк - и в продакшон". При такой бизнес-парадигме популярными становятся языки, на которых "хуяк-хуяк" можно безопаснее и удобнее.
Если тебе действительно интересно, чем может быть полезна объектно-ориентированная парадигма, а не как её подобием обмазали наиболее популярные языки, почитай про CLOS. Если понравится, можешь ещё MOP навернуть и изучить понятие интроспекция в контексте ЯП. Если всё ещё не обретёшь понимания, что такое ООП, ну значит не готов, не нужно оно тебе.
>> No.48849 Reply
>>48838
> Т.е. смысл ООП в том, чтоб не копипастить? И это новый уровень абстракции?
Ты опять смотришь на функции вместо того, чтобы смотреть на классы. Отсутствие тупого копипаста - лишь вытекающее из мышления на объектном уровне плюшка.
> Новый уровень абстракции это например переход ASM -> C, когда уже не нужно оперировать регистрами и инструкциями процессора. ООП это скорее некий способ организации кода (теперь функции мы привязали к структурам, пишите вот так!), а не новый уровень абстракции.
А здесь не нужно оперировать лоу-левел функциями, а нужно оперировать интерфейсами.
> А зачем ограничивать себя только таким дефолтным набором public-private-protected?
Потому что этого достаточно. Снова, не смотри на какие-то дурацкие неймспейсы как приложение к функциям. Мысли на уровне классов и интерфейсов. Есть только интерфейсы, доступные всем, недоступные никому кроме себя и недоступные никому кроме себя и потомков.
> Ну вот я приводил пример с контрактами, что одни функции могут там что-то вызывать, а другие не могут, но никакие объекты для этого не требуются, это просто выделение некоторого неймспейса функций и создание для них каких-то запретов/разрешений.
Мерзкие сишные костыли. Это называется методы работы одних объектов с другими объектами, и делается через public-protected-private, наследование и иногда friendование.
> И систему прав доступа можно сделать значительно более гибкой, чем это реализовано в ООП.
Нельзя. Есть объект, который не знает ничего об окружающем мире кроме того, что от него могут унаследоваться. Все возможные виды доступа к его интерфейсам - public, protected, private.
> Ну почему же, вполне можно представить ситуацию, когда полезно сделать ограничения вида "функции из неймспейса №1 могут вызывать только функции из неймспейса №1 и №2, функции из неймспейса №2 могут вызывать только функции из неймспейса №2 и №3, функции №3 вызывают только №3 и №4 и.т.д."
Костыли. Используй классы, Люк.
> драйвер ФС передает драйверу жесткого диска "запиши вот эти байтики вот туда-то, и вот эти байтики вот туда", при этом драйвер ФС ничего не знает про геометрию диска(дорожки, количество пластин), т.е. с точки зрения драйвера ФС, жесткий диск это просто большой массив из некоторых секторов, например секторов по 512 байт. Т.е. драйвер ФС общается с драйвером жесткого диска на уровне "запиши в тот сектор размером в 512 байт вот это" и "прочитай из того сектора размером в 512 байт и дай мне".
Быдлокод с магическими числами. ФС дергает общий интерфейс всех драйверов ЖД "Записать N-байт". Реализация этого интерфейса, представляющая конкретный HAL для конкретного диска, разбивает файл на куски в зависимости от параметров диска, формирует блок метаданных с последовательностью адресов этих блоков, записывает это все и возвращает драйверу ФС файловый дескриптор блока метаданных. Вуаля, все работает на интерфейсах ООП-стайл.
> Так вот, тут имеет смысл запретить обычной программе из юзерспейса обращаться к драйверу жесткого диска напрямую и говорить, в какие секторы что писать.
Вообще не задача программы или ЯП. Это задача ОС заделать разделение на юзерспейс и кернелспейс. В юзерспейсе доступны интерфейсы для записи и чтения файлов, опять же ООП-стайл.
> Такое можно без всякого ООП делать в чистом Си, разбив реализацию на несколько файлов и используя static функции.
Разбивать на файлы все равно придется, очевидно. А всего-то нужно - использовать нужные интерфейсы, которые можно реализовывать для любого устройства. Твою же идею ждет инстант пиздец, стоит только подключить какой-нибудь ССД ил рамдиск или дискетку вместо ЖД, лол.
>> No.48850 Reply
>>48849
Спор слепого с глухим.
Как ООП избавляет от копипасты и при чём тут она вообще? Решения типа copulate(Bat), copulate(Tiger) можно сгенерировать независимо от парадигмы. Ни ООП, ни декларативное, ни какое-либое другое программирование не может запретить писать говнокод или копипастить.
Раньше программы писали просто перечислением команд, потом стали выделять куски кода в подпрограммы, процедуры, функции - это уже начала инкапсуляции и полиморфизма. Затем стали объединять разные встроенные типы в структуры, а функционал, работающий с такими комбинированными типами данных - всё так же в процедуры. Почему так стали делать? Потому что программы становились больше, сложнее, возникла необходимость структурировать код, чтобы его было легко анализировать, допиливать. Разные подходы к организации кода были вызваны сильно различающимися типами задач, костылей мышления погромистов и породили необходимость в расслоении на языки с разными парадигмами. Но такого чтобы парадигма лишала возможности говнокодить не было никогда. Ну разве что вот нейронные сети, практически исключив человека из, собственно, процесса формирования итоговой системы, могут как-то помочь с этим, но это уже не о парадигмах речь.
В плюсах ничего принципиально нового не вводится, никаких волшебных механизмов, исключающих говнокод. Классы - всё те же супер-типы на стероидах. Для каждой лексемы найдётся оправдание, каждая нужна для чего-то, иначе её не впилили бы. И это всё, конечно, работает, ты, конечно, можешь думать классами, наследованиями, разграничением прав для членов класса, пояснять за виртуальные функции и считать шаблоны - венцом программистской мысли. Раньше был молоток, пила, рубанок, теперь - молоток с выдвижной пилой и возможностью прикрутить сколько угодно рубанков, причём у всего этого одна ручка (удобно), и теперь ты не можешь пораниться, потому что везде наклейки "ОСТОРОЖНО!". В нормальном мире ручной инструмент уходит в прошлое, совершенствуются и материалы, и технологии строительства, и вообще автоматизация процесса даёт человеку больше свободного времени на осмысление происходящего.
>> No.48852 Reply
>>48849
> Потому что этого достаточно. Снова, не смотри на какие-то дурацкие неймспейсы как приложение к функциям. Мысли на уровне классов и интерфейсов. Есть только интерфейсы, доступные всем, недоступные никому кроме себя и недоступные никому кроме себя и потомков.
Достаточно для чего? Если говорить о том, чего достаточно, то и обычных функций + структур вполне достаточно, а все эти public-private-protected ничего кардинально не меняют. Если же public-private-protected это что-то нужное, то почему именно на этом остановились, почему б не вводить какие-то новые права доступа?
> Мерзкие сишные костыли. Это называется методы работы одних объектов с другими объектами, и делается через public-protected-private, наследование и иногда friendование.
> Нельзя. Есть объект, который не знает ничего об окружающем мире кроме того, что от него могут унаследоваться. Все возможные виды доступа к его интерфейсам - public, protected, private.
Зачем ты говоришь догмами? Язык программирования и предоставляемые им абстракции это не какие-то незыблемые законы физики, вроде закона сохранения энергии, это просто придуманная людьми хрень, которая при желании может быть улучшена/переделана.
> > Ну почему же, вполне можно представить ситуацию, когда полезно сделать ограничения вида "функции из неймспейса №1 могут вызывать только функции из неймспейса №1 и №2, функции из неймспейса №2 могут вызывать только функции из неймспейса №2 и №3, функции №3 вызывают только №3 и №4 и.т.д."
> Костыли. Используй классы, Люк.
Я через классы не могу создавать сложный набор правил доступа, там только public, protected, private.
> Быдлокод с магическими числами. ФС дергает общий интерфейс всех драйверов ЖД "Записать N-байт".
Винчестер тебе 1 байт записать не может, там не побайтная адресация (ты б еще попросил его один бит записать, лол). Он прочитает 512 байт (или сколько у него там размер кластера) в буфер, изменит там 1 байт и потом обратно запишет 512 байт. Если ты вот так побайтно будешь писать в некий файл данные по одному байту, это будет нерационально. Лучше пусть это буферизуется, но буферизоваться это может на разных уровнях, и желательно чтобы ФС знала о том, какого размера кластер винчестера, и чтобы ФС была отформатирована соответствующим образом. Абстракция "записать N байт" протекает.
> Вуаля, все работает на интерфейсах ООП-стайл.
> В юзерспейсе доступны интерфейсы для записи и чтения файлов, опять же ООП-стайл.
ООП-стайл, ООП-стайл, ООП-стайл... идея разделения чего-либо на интерфейс и реализацию возникла ДО появления т.н. ООП. Что ты называешь ООП-стайлом?
> Твою же идею ждет инстант пиздец, стоит только подключить какой-нибудь ССД ил рамдиск или дискетку вместо ЖД, лол.
Дискеты и современная флеш-память тоже читается-пишется кусками в сколько-то байт, лол.

>>48850
> В плюсах ничего принципиально нового не вводится, никаких волшебных механизмов, исключающих говнокод. Классы - всё те же супер-типы на стероидах. Для каждой лексемы найдётся оправдание, каждая нужна для чего-то, иначе её не впилили бы. И это всё, конечно, работает, ты, конечно, можешь думать классами, наследованиями, разграничением прав для членов класса, пояснять за виртуальные функции и считать шаблоны - венцом программистской мысли. Раньше был молоток, пила, рубанок, теперь - молоток с выдвижной пилой и возможностью прикрутить сколько угодно рубанков, причём у всего этого одна ручка (удобно), и теперь ты не можешь пораниться, потому что везде наклейки "ОСТОРОЖНО!".
Ну так вот я и говорю, плюсовые классы это такие недоконтракты, типа "public можно вызывать, а вот private можно только из public". Когда я говорю "а зачем только public-private-protected, почему б не сделать более общий механизм", мне он отвечает "так неположено, неканонично, костыли".
Наследование это просто такой инструмент для борьбы с копипастой, недокодогенерации (намного лучше с этим делом обстоит в лиспе, где код = данные).
Зачем использовать более узкие (вероятно, намеренно суженные) механизмы, и почему более общие методы это что-то плохое.
>> No.48853 Reply
>>48852
> Достаточно для чего?
Для реализации ООП-подхода. В пределе все есть объект какого-то класса.
> Зачем ты говоришь догмами? Язык программирования и предоставляемые им абстракции это не какие-то незыблемые законы физики, вроде закона сохранения энергии, это просто придуманная людьми хрень, которая при желании может быть улучшена/переделана.
Придумай другой тип доступа, кроме public, protected и private. Не неймспейсики, а именно тип доступа к классу, про который известно только то, что есть еще и другие классы, и что от него можно наследоваться.
> Я через классы не могу создавать сложный набор правил доступа, там только public, protected, private.
Значит, ты не умеешь программировать в ООП. Гугли, как делать интерфейсы.
> Винчестер тебе 1 байт записать не может, там не побайтная адресация (ты б еще попросил его один бит записать, лол). Он прочитает 512 байт (или сколько у него там размер кластера) в буфер, изменит там 1 байт и потом обратно запишет 512 байт. Если ты вот так побайтно будешь писать в некий файл данные по одному байту, это будет нерационально. Лучше пусть это буферизуется, но буферизоваться это может на разных уровнях, и желательно чтобы ФС знала о том, какого размера кластер винчестера, и чтобы ФС была отформатирована соответствующим образом. Абстракция "записать N байт" протекает.
Наоборот, именно абстракция и решает.
Мне плевать, как там внутри все устроено, какой размер кластера и т.д. Я хочу создать файл в 1 байт и сохранить его на диск. Ты будешь лихорадочно искать подходящую функцию, вручную создавать буфер и наполнять его нулями? Это жопорукость. Ты вызовешь метод и передашь файл в 1 байт, а как там внутри реализовано, что он там прочитает и запишет, не важно. Ты дернешь интерфейс записи N байт, а проверки на N < размера кластера должны быть скрыты внутри и как-то там магически решаться, вплоть до буферизаций и дрочки вприсядку.
> идея разделения чего-либо на интерфейс и реализацию возникла ДО появления т.н. ООП.
Интересно, как ты ее реализуешь на голом С. Без указателей на void.
> Дискеты и современная флеш-память тоже читается-пишется кусками в сколько-то байт, лол.
Все пишется кусками минимум в 1 байт, лол.
>> No.48863 Reply
>>48832

> > есть некие классы
> > Есть методы, которые к этим классам привязаны
> > Зачем это вообще нужно, если можно просто сделать структуру и набор функций
Все верно говоришь, тебе оно и не нужно в домашних условиях. Используй то, что нужно.
Рано или поздно у тебя возникнет потребность в классах.

> > вот допустим есть public private protected модификаторы доступа
> > наследований может быть 3 вида - тоже public, private, protected...
> > Зачем всё это?
Тебе не за чем. А если бы ты кодил хотя бы вдвоем, то быстро бы понял, что некоторые вещи другой человек видеть, наследовать и тд не должен.

> > Этот код должен быть методом класса для растровой или векторной картинки?
Не, это должно быть что-то третье.
>> No.48915 Reply
>>48853
> Для реализации ООП-подхода. В пределе все есть объект какого-то класса.
Этот ООП подход не работает в чистом виде. Я уже приводил пример с растровой и векторной картинкой. Если надо сделать код, переводящий вектор в растр, этот код нельзя отнести ни к методу векторной, ни к методу растровой картинки. Это должен быть некий ОБЩИЙ метод для двух структур данных, который имеет доступ к внутренностями (деталям реализации) и того и другого класса (структуры).
> Придумай другой тип доступа, кроме public, protected и private. Не неймспейсики, а именно тип доступа к классу, про который известно только то, что есть еще и другие классы, и что от него можно наследоваться.
Я уже придумал в своем описании, про разделения на слои доступа. Что из слоя 1 можно вызывать код и получать доступ к данным из слоя 1 и слоя 2, из слоя 2 можно вызывать код и получать доступ к данным из слоя 2 и слоя 3 и так далее. Это тебе не подходит?

Или опять таки идея с векторной и растровой картинкой, можно ввести особый модификатор доступа, и если я объявляю с этим модификатором доступа некую функцию, то она имеет доступ к внутренностям и для векторной, и для растровой картинки.
> Значит, ты не умеешь программировать в ООП. Гугли, как делать интерфейсы.
Я умею делать интерфейсы, но к ООП это прямого отношения не имеет. Интерфейсы и до ООП успешно делали.
> Мне плевать, как там внутри все устроено, какой размер кластера и т.д. Я хочу создать файл в 1 байт и сохранить его на диск. Ты будешь лихорадочно искать подходящую функцию, вручную создавать буфер и наполнять его нулями? Это жопорукость.
А где я писал что я буду что-то лихорадочно искать и что-то вручную создавать?
> Интересно, как ты ее реализуешь на голом С. Без указателей на void.
Меня указатели на void не пугают
> Все пишется кусками минимум в 1 байт, лол.
Байты бывают и 7-битными. И вообще, что если я хочу не 1 байт, а всего лишь 1 бит записать, и при этом физический интерфейс флеш-памяти мне позволяет адресовать даже отдельные биты?
>> No.48916 Reply
>>48863
> Тебе не за чем. А если бы ты кодил хотя бы вдвоем, то быстро бы понял, что некоторые вещи другой человек видеть, наследовать и тд не должен.
Вдвоем я уже кодил, описанных проблем не испытывал. Можно просто договориться об особом нейминге, если это вдруг становится проблемой. Или static функции в отдельном файле.
>> No.48918 Reply
>>48915
> Если надо сделать код, переводящий вектор в растр, этот код нельзя отнести ни к методу векторной, ни к методу растровой картинки. Это должен быть некий ОБЩИЙ метод для двух структур данных, который имеет доступ к внутренностями (деталям реализации) и того и другого класса (структуры).
Лолнет, ты предлагаешь говнокод. Должен быть либо конструктор, либо статик метод from(), принимающий аргументом объект-исходник. И конечно же архитектурно там будут использоваться только public методв исходника и никаких, упаси боже, деталей реализации.
> Я уже придумал в своем описании, про разделения на слои доступа. Что из слоя 1 можно вызывать код и получать доступ к данным из слоя 1 и слоя 2, из слоя 2 можно вызывать код и получать доступ к данным из слоя 2 и слоя 3 и так далее. Это тебе не подходит?
Звучит странно. Если ты хочешь замутить охуенный N-уровневый контроль привилегий (мсье знает толк), то для этого требуется больше одного класса, это целая подсистема получается.
> Или опять таки идея с векторной и растровой картинкой, можно ввести особый модификатор доступа, и если я объявляю с этим модификатором доступа некую функцию, то она имеет доступ к внутренностям и для векторной, и для растровой картинки.
Bad design. Или даже ugly.
> Я умею делать интерфейсы, но к ООП это прямого отношения не имеет. Интерфейсы и до ООП успешно делали.
Лолнет, интерфейсы - суть ООП. То, что кто-то костылил это раньше доступными средствами... ну так и лямбды частично костылили через функторы.
> А где я писал что я буду что-то лихорадочно искать и что-то вручную создавать?
А куда ты денешься без ООП? В итоге так и будет какая-нибудь срань типа iowrite8, iowrite16, iowrite32.
> Меня указатели на void не пугают
Да можно вообще макросы MAX(a, b) ((a > b) ? a : b) использовать. Почему это небезопасно и не один нежопорукий программист так не делает, интересно.
> Байты бывают и 7-битными. И вообще, что если я хочу не 1 байт, а всего лишь 1 бит записать, и при этом физический интерфейс флеш-памяти мне позволяет адресовать даже отдельные биты?
А еще можно three-state использовать и вообще дрочить вприсядку. Приложению плевать, и все грязные делишки твоей железяки должны быть инкапсулированы внутрь, а снаружи предоставлять только общий, оперирующий общепринятыми вещами (типа 8 битных байтов) интерфейс.
>> No.48919 Reply
Предлагаю заставить ОПа выучить жабу.
>> No.48925 Reply
File: 1530364206116.png
Png, 0.99 KB, 300×20 - Click the image to expand
edit Find source with google Find source with iqdb
1530364206116.png
>>48919
Или написать большой и серьезный проект на чистом C. При этом мониторить качество кода и наказывать за косяки.
>> No.48937 Reply
Может ли быть полноценное ООП без friend классов?
>> No.48940 Reply
>>48937
Нет, конечно. Ведь пророк наш Алан Кей ничего не говорил про friend-классы.
PS. Ищи не Истину в Идеях, а Инструмент.
>> No.48978 Reply
File: 1528302888273.jpg
Jpg, 293.45 KB, 1500×1954 - Click the image to expand
edit Find source with google Find source with iqdb
1528302888273.jpg
Чтобы понять ООП надо писать код который его требует.

Вот я например долго не понимал паттерна Factory. Нахуя он нужен? А когда встречал его в чужом коде непонимал как люди такой то код надумывают.

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

Вот тут и понимаешь что люди тот код, над которым я недоумевал, писали и не для того чтобы читателя запутать, а это результат многих лет эволюции и решения реальных проблем. Для меня это было настоящим открытыием.

Я все еще плохо владею абстракциями, но я верю что втянусь по мере работы. Не верю что книги тут сильно помогут, я их много в свое время перечитал и мало что с этого осело в памяти. Я вот сейчас думаю перечитать Clean Code и думаю что взгляну на нее совершенно другими глазами.
>> No.49021 Reply
>>48978
> Чтобы понять ООП надо писать код который его требует.
Какой именно код его требует? Есть вообще в природе код, который без ООП написать невозможно?
И где конкретно кончается ООП и начинается не-ООП? Если в чистом Си писать функции, которые принимают указатели на структуры и что-то с ними делают, ну там аллоцируют память, меняют какие-то значения полей структур, это уже ООП или еще нет?
Или вот если просто использовать классы, но не использовать наследования и полиморфизмов, это ООП?
>> No.49022 Reply
>>49021
> > Какой именно код его требует?
Тот, который его требует.
В общем виде эта задача не решается. Но так или иначе иногда удобно использовать ООП. Когда - сердце подскажет.

> > это уже ООП или еще нет?
> > Или вот если просто использовать классы, но не использовать наследования и полиморфизмов, это ООП?
Ты задаешь пустые вопросы уровня курица или яйцо.
Ну допустим ООП.
>> No.49042 Reply
>>49022
> В общем виде эта задача не решается. Но так или иначе иногда удобно использовать ООП. Когда - сердце подскажет.
У меня сердце (и другие органы) пока ничего подсказать не может т.к. я не совсем понимаю это ООП.
> Ты задаешь пустые вопросы уровня курица или яйцо.
> Ну допустим ООП.
Допустим. Но такой код может написать человек, который вообше ничего про ООП не слышал. Как-то это слишком размыто

Давайте вот лучше наследование подробно разберем. На примере аналитической геометрии на плоскости.
Вот например точка. Точку можно записывать в декартовых координатах (y, x) и в полярных (r-радиус, f-угол). Т.е. если без ООП то можно объявить две структуры, в одной координаты x, y, в другой радиус r, угол f.
Мы хотим иметь функцию, которой передаем две точки, и она возвращает true если точки в одном месте находятся (накладываются друг на друга) и false если нет. Методом какого класса такая функция должна быть?
Ок, допустим мы ходим сделать еще и отрезки, прямые и лучи при этом надо чтоб отрезок можно было задавать двумя точками, при этом одна точка может быть в полярных координатах, другая в декартовых, или обе в декартовых или обе в полярных, а еще прямые и лучи могут задаваться через одну единственную точку (хоть в полярных, хоть в декартовых координатах) и угол, и должны быть функции, которые бы позволяли находить точки пересечения луча с прямой, луча с лучом, прямой с прямой, отрезка с отрезком, независимо от того, каким образом какую прямую мы задали, проверять параллельность, проверять принадлежность какой-то точки какому-то отрезку... А еще можно добавить векторов, и им там проверять коллениарность... Пока остановимся на этом.

Так вот, как это все будет выглядеть в ООП, что из чего унаследуется, методами каких классов будут функции, сравнивающие отрезки/прямые и пр. и возвращающие точку пересечения, проверяющие параллельность?
>> No.49050 Reply
>>49042
> Так вот, как это все будет выглядеть в ООП, что из чего унаследуется, методами каких классов будут функции, сравнивающие отрезки/прямые и пр. и возвращающие точку пересечения, проверяющие параллельность?
Начнем с начала. Имеются классы "координаты в декартовой системе" и "координаты в полярной системе", плюс в них методы конверсии друг в/из друга.
Иметь одновременно две системы координат и хуячить каждому классу дублирующие методы - слишком криво. Так что берется опорная система координат, и кому надо, юзает функции конверсии классов "координата". Пусть опорной будет декартова, так как полярные - хуета.
Класс точка хранит в себе один объект класса "декартовы координаты". Этот класс также имеет операторы == и !=, внутри одного из них сравниваются координаты этой точки и параметра. Это дает приятный сахар if (pointA != pointB) вместо сишного аутизма !isEqual(pointA, pointB).
Отрезок - еще один класс, имеет внутри два объекта класса "декартовы координаты" - концы отрезка. Прямые и лучи точно также имеют две координаты внутри, плюс для особо извращенных имеют конструкторы не только из двух точек, но и точки и угла - внутри этих конструкторов попросту высчитывается вторая dummy точка исходя из параметра угла.
Так как ты хочешь найти параллельности и прочая, то имеет смысл унаследовать отрезок, прямую и луч от базового класса. Это будет класс с двумя координатами, для каждой координаты булевый флаг "конец", скажем, с методом пересчета угла в dummy-точку, методами проверки на параллельность и т.д. Профит: вместо аутичного сишного копипаста функций ты сразу имеешь универсальные методы проверки на принадлежность точки и прочая.
Для добавления векторов достаточно унаследовать его от класса отрезка (с добавлением какой-нибудь ссылки, указывающей на одну из двух координат как на начальную).
>> No.49059 Reply
>>49050
> Иметь одновременно две системы координат и хуячить каждому классу дублирующие методы - слишком криво. Так что берется опорная система координат, и кому надо, юзает функции конверсии классов "координата". Пусть опорной будет декартова, так как полярные - хуета.
> Отрезок - еще один класс, имеет внутри два объекта класса "декартовы координаты" - концы отрезка.
Нет, это плохо. Если мы задаем координаты двух точек отрезка в полярных координатах, и нам надо повернуть этот отрезок на угол X относительно начала координат, мы просто этот угол прибавляем или отнимаем (в зависимости от того, по или против часовой) от углов тех двух точек, ну и если угол измеряется в обычных градусах, то если он перевалил за 360 или ушел в минуса, сделать соответствующую коррекцию. Ну и аналогично для других единиц измерения угла (радианы, грады).
Если то же самое мы захотим сделать с отрезком, точки которого заданы в декартовых координатах, работы у нас будет уже значительно больше.
> Класс точка хранит в себе один объект класса "декартовы координаты". Этот класс также имеет операторы == и !=, внутри одного из них сравниваются координаты этой точки и параметра. Это дает приятный сахар if (pointA != pointB) вместо сишного аутизма !isEqual(pointA, pointB).
Да это вообще не важно. К ООП это не имеет никакого отношения. Можно конечно отдельно обсудить проблемы всех этих перегрузок операторов в контексте языка C++, например невозможность для перегруженных операторов менять приоритеты, ассоциативность и коммутативность, невозможность сделать short-circuit evaluation для && и || при их перегрузке, невозможность вводить свои новые операторы. Притом в том же хаскеле можно вводить свои операторы, и задавать им приоритет и ассоциативность https://progra-lang.blogspot.com/2016/02/Operatory-v-yazyke-programmirovaniya-Haskell.html
> Прямые и лучи точно также имеют две координаты внутри, плюс для особо извращенных имеют конструкторы не только из двух точек, но и точки и угла - внутри этих конструкторов попросту высчитывается вторая dummy точка исходя из параметра угла.
> Так как ты хочешь найти параллельности и прочая, то имеет смысл унаследовать отрезок, прямую и луч от базового класса. Это будет класс с двумя координатами, для каждой координаты булевый флаг "конец", скажем, с методом пересчета угла в dummy-точку, методами проверки на параллельность и т.д. Профит: вместо аутичного сишного копипаста функций ты сразу имеешь универсальные методы проверки на принадлежность точки и прочая.
Представь что тебе надо проверить параллельность двух прямых или двух лучей, или прямой и луча. У тебя есть точка и угол. Если угол и там и там одинаков (или одинаков если развернуть на 180 градусов) то эти прямые/лучи или лежат на одной прямой, или параллельны. Осталось только проверить, лежат ли прямые/лучи на одной прямой (накладываются ли).
Если же у тебя прямые и лучи хранят две точки, тебе нужно будет выполнять дополнительную работу по определению угла, что неэффективно.

А еще если у тебя две прямые заданы одной точкой и углом, будет очень легко находить угол в точке пересечения
> Для добавления векторов достаточно унаследовать его от класса отрезка (с добавлением какой-нибудь ссылки, указывающей на одну из двух координат как на начальную).
Может быть проще договориться, что первая точка это всегда начальная, вторая - всегда конечная?
>> No.49063 Reply
File: co.jpg
Jpg, 66.25 KB, 751×499 - Click the image to expand
edit Find source with google Find source with iqdb
co.jpg
>>49059
> Нет, это плохо. Если мы задаем координаты двух точек отрезка в полярных координатах, и нам надо повернуть этот отрезок на угол X относительно начала координат, мы просто этот угол прибавляем или отнимаем (в зависимости от того, по или против часовой) от углов тех двух точек
Нет, это хорошо. Хоть ты и про повороты ничего не говорил, но это элементарно добавляется одним методом, в котором координаты концов конвертятся в полярные, поворачиваются и конвертятся обратно в декартовы.
А вообще это надо по задаче смотреть, что выгоднее: хранить декартовы или полярные.
> Если то же самое мы захотим сделать с отрезком, точки которого заданы в декартовых координатах, работы у нас будет уже значительно больше.
Лолнет, вся дополнительная работа - конвертация туда и обратно.
> Да это вообще не важно. К ООП это не имеет никакого отношения.
Имеет. Это в сишке есть только тупые структуры без операторов, а в ООП есть классы, которые могут инкапсулировать в себе что угодно и предоставлять API, в том числе и Foo::operator ==. То, что у класса могут быть кастомные операторы, вытекает из парадигмы класса.
> например невозможность для перегруженных операторов менять приоритеты
Да оно и не надо в реальной жизни. Если ты пишешь код сразу с кучей разных операторов в одну строку да еще и с нестандартными приоритетами, то ты пишешь говнокод, и любой поддерживающий его потом программист будет заслуженно проклинать себя самыми нехорошими словами.
> невозможность сделать short-circuit evaluation для && и || при их перегрузке
Чо? (пикрелейтед)
> невозможность вводить свои новые операторы
Нинужно
> Притом в том же хаскеле можно вводить свои операторы, и задавать им приоритет и ассоциативность
Вот поэтому хачкелем кроме полутора отмороженных никто не пользуется. Играются в свои игрушки, а нахрена - непонятно.
> Если же у тебя прямые и лучи хранят две точки, тебе нужно будет выполнять дополнительную работу по определению угла, что неэффективно.
Это несущественно, в каких координатах хранить - определяется по задачам. Если на сотню задач с декартовыми координатами придется одна задача по высчитыванию угла, то и хрен бы с ним. Да и подсчитать угловой коэффициент - раз плюнуть.
> Может быть проще договориться, что первая точка это всегда начальная, вторая - всегда конечная?
Можно и так, но это может быть не удобно при некоторых гуях, например.
>> No.49064 Reply
>>49063
> Чо? (пикрелейтед)
> (a1 && a2) && (a3 && a4)

Лол, ты продемонстрировал короткозамкнутость bool && bool, а не A && A.

>>48918

> Да можно вообще макросы MAX(a, b) ((a > b) ? a : b) использовать. Почему это небезопасно и не один нежопорукий программист так не делает, интересно.

Oh really?

https://github.com/mpv-player/mpv/blob/7dd69ef77c6aa80067c13f76aa0b78d63fbc4eda/common/common.h#L36
>> No.49065 Reply
>>48832
> Вот допустим есть public private protected модификаторы доступа т.е. ограничения на то, откуда какой метод можно вызывать. public можно вызывать отовсюду, private только для методов из числа public, а protected ... protected становится private при наследовании, притом наследований может быть 3 вида - тоже public, private, protected... Зачем всё это? Чем это лучше просто кучи функций, которые могут просто вызывать другие функции и работать с какими-то структурами?
>

Модификаторы доступа нужны для удобства. Когда у тебя в проекте будет сотня классов с тысячами переменных и методов ты поймешь
>> No.49067 Reply
>>49063
> Нет, это хорошо. Хоть ты и про повороты ничего не говорил, но это элементарно добавляется одним методом, в котором координаты концов конвертятся в полярные, поворачиваются и конвертятся обратно в декартовы.
Если я сказал что нужны декартовы и полярные, это значит что нужны декартовы и полярные. Если ты говоришь "нет, полярные ненужны, будем все делать в декартовых. Пусть опорной будет декартова, так как полярные - хуета." то ты провалил задание.
> Лолнет, вся дополнительная работа - конвертация туда и обратно.
Иногда эта дополнительная работа может очень много времени занимать, если надо повернуть кучу точек относительно начала координат.
> Имеет. Это в сишке есть только тупые структуры без операторов, а в ООП есть классы, которые могут инкапсулировать в себе что угодно и предоставлять API, в том числе и Foo::operator ==. То, что у класса могут быть кастомные операторы, вытекает из парадигмы класса.
Причем тут сишка и плюсы вообще? Я говорю об ООП. Если очень хочется поговорить о сишке и плюсах, могу создать новый тред. Вон в хаскеле можно вообще свои новые операторы добавлять и выставлять им приоритеты, где там ООП?
> > невозможность сделать short-circuit evaluation для && и || при их перегрузке
> Чо? (пикрелейтед)
https://stackoverflow.com/questions/25913237/is-there-actually-a-reason-why-overloaded-and-dont-short-circuit
> > невозможность вводить свои новые операторы
> Нинужно
Очень аргументированно. Я так тоже могу, смотри: ООП - нинужно.
> Вот поэтому хачкелем кроме полутора отмороженных никто не пользуется. Играются в свои игрушки, а нахрена - непонятно.
Вообще-то у хаскеля и прочих ФП языков есть своя ниша, в которой они востребованы.
> > Если же у тебя прямые и лучи хранят две точки, тебе нужно будет выполнять дополнительную работу по определению угла, что неэффективно.
> Это несущественно, в каких координатах хранить - определяется по задачам. Если на сотню задач с декартовыми координатами придется одна задача по высчитыванию угла, то и хрен бы с ним. Да и подсчитать угловой коэффициент - раз плюнуть.
Это существенно. Я написал что нужны декартовы и полярные координаты. Я ж не написал "нужны декартовы, а полярные там как-нибудь через декартовы можно сделать, типа инициализировать их как порярные, но хранить как декартовы". А еще кроме полярных и декартовых есть много чего еще, например биполярные, параболические, эллиптические... И определенный способ представления координат может быть выгоден для проведения определенных преобразований над точками, заданными в такой системе координат, так что тупо хранить все в декартовых и потом каждый раз конвертить туда-сюда может быть просто глупо.
>> No.49069 Reply
>>49064
> Лол, ты продемонстрировал короткозамкнутость bool && bool, а не A && A.
Это ты серьезно сейчас предлагаешь писать говнокодище, где && возвращает не bool?
> Oh really?
Собственно, сразу видно сишный говнокод. За одно только
#define CONTROL_OK 1
#define CONTROL_TRUE 1
#define CONTROL_FALSE 0
#define CONTROL_UNKNOWN -1
#define CONTROL_ERROR -2
#define CONTROL_NA -3
автора надо выебать шваброй. Так даже на сях пишут только джуны.
>> No.49127 Reply
>>49069
> автора надо выебать шваброй. Так даже на сях пишут только джуны.
А что тебе не так? Энумы хочешь? Скажи это разработчикам Linux ядра
https://elixir.bootlin.com/linux/v4.1/source/include/linux/brcmphy.h
>> No.49142 Reply
>>49127
Как будто в линухе не полно говнокода.
>> No.49143 Reply
>>49142
А где его не полно?
>> No.49150 Reply
>>49143
Везде и нигде, но не важно. Точка. Уже в третий раз точка. Да что такое!
>> No.49155 Reply
>>49143
В nginx и instead. Мне понравилось читать из коды.
>> No.49156 Reply
>>49155
> nginx
https://github.com/nginx/nginx/blob/master/src/os/unix/ngx_process.c#L215-L250 что-то не очень. Выразительных средств Си явно недостаточно
>> No.49157 Reply
>>49156
И что там не так? По моему так очень хорошо (для C, разумеется).
>> No.49159 Reply
>>49157
> По моему так очень хорошо (для C, разумеется).

В том-то и дело, что в Си это нормально не делается. Ну вот например есть у нас структура
typedef struct
{
int a;
int b;
int c;
int d;
} mystr;

Допустим что у нас
mystr str_val;

str_val.a = 123;

Дальше идет много кода, и потом нам надо доинициализировать элементы структуры таким образом, чтоб `.b = 1, .c = 2, .d = 3`

Ну, в си начиная с C99 есть designated struct initializers, можно сделать так
strval = (mystr){.a = strval.a, .b = 1, .c = 2, .d = 3};
Н тут пришлось переприсвоить `.a = str_val.a` иначе б оно тупо занулилось. Это опять таки недостаток Си. Хотелось бы тупо через запятую перечислять то, что мы хотим ПЕРЕназначить, а не копипастить фигню.
Кстати, в плюсах-то кстати этот самый designated struct initializers только в C++20 сделают (21 год отставания от сишечки, лол) так что и в плюсах это не сделать по-нормальному.
>> No.49160 Reply
>>49159
А еще тут на доброчане серьезно косячит разметка. Подчеркивания _ срабатывают внутри кусков, обрамленных ` скобками
>> No.49161 Reply
>>49159
Вообще не вижу никакой проблемы в написании банального
str_val.b = 1;
str_val.c = 2;
str_val.d = 3;

Тот же самый смысл (можно еще в начале для полной ясности написать strval.a = strval.a). Единственная проблема может возникнуть в копипасте когда, где есть вероятность не заменил одно букву и получить баг.
>> No.49162 Reply
>>49161
> вероятность не заменил одно букву
О хоспаде.
*вероятность не заменить одну бувку
>> No.49163 Reply
>>49161
> Вообще не вижу никакой проблемы в написании банального
Плохо быть говнокодером. Вначале у тебя инициализируются все поля начальным значением, затем ты по одному начинаешь их переназначать.
В плюсах для этого есть инициализация полей до тела конструктора. В сях, как правильно говорит >>49159б есть списки, но это довольно убогая замена ООП-шным конструкторам, где можно сделать множество вариантов инициализации и инициализировать только то, что надо. Ну и еще в сях есть этот отвратный "выстрели себе в ногу" мемсет.
>> No.49164 Reply
>>49163
Не вижу говнокода. Да, такой вариант длиннее будет. Да, там есть вероятность забыть изменить значение при копипасте. Более существенных недостатков разглядеть не могу.
>> No.49165 Reply
>>49163
Не вижу говнокода. Да, такой вариант длиннее будет. Да, там есть вероятность забыть изменить значение при копипасте. Более существенных недостатков разглядеть не могу.
>> No.49166 Reply
>>49163
Не вижу говнокода. Да, такой вариант длиннее будет. Да, там есть вероятность забыть изменить значение при копипасте. Более существенных недостатков разглядеть не могу.
>> No.49168 Reply
>>49166
> Да, такой вариант длиннее будет. Да, там есть вероятность забыть изменить значение при копипасте.

В этом и заключается говнокод
>> No.49170 Reply
>>49168
Для меня говнокод, это когда все настолько запутанно, как наушники в кармане. В создании такой мешанины временами помогают и всякие "короткие, красивые и эффективные" синтаксические конструкции языков.
>> No.49172 Reply
>>49164
>>49165
>>49166
> Не вижу говнокода. Да, такой вариант длиннее будет.
Я и говорю, плохо быть говнокодером.
А должен бы видеть, что сперва будет инициализация скорее всего нулями (но вообще undefined), а потом инициализация еще раз нужными значениями (на самом деле не инициализация, а присваивание, но так нагляднее).
>> No.49177 Reply
>>49172
И? В чем проблема?
>> No.49180 Reply
>>49177
В удвоенном потреблении ресурсов, очевидно.
>> No.49183 Reply
>>49180
И как в других языках решается эта проблема? В переменной сразу нужные значения находятся? Откуда? Кто их заранее в память закинул?
>> No.49214 Reply
>>49163
> Вначале у тебя инициализируются все поля начальным значением, затем
Я что-то пропустил? С каких пор сишка стала инициализировать переменные какими либо значениями вообще?
Насколько я помню, даже плюсы этого не делали, для полей классов разве что.
>> No.49217 Reply
File: 1544280718843.png
Png, 0.97 KB, 300×20 - Click the image to expand
edit Find source with google Find source with iqdb
1544280718843.png
>>49214
Он указал, что
> > (но вообще undefined),
но все равно бред. Нулями инициализирует не C, а ОС (в случае линукса это так). Другой вариант, это ОС выделяет память переменной, а в этой области памяти могу быть какие угодно значения, оставшиеся после выполнения другой программы.
>> No.49221 Reply
>>49183
> И как в других языках решается эта проблема? В переменной сразу нужные значения находятся? Откуда? Кто их заранее в память закинул?
Constructor, motherfucker, do you write it?
>>49214
>>49217
> Я что-то пропустил? С каких пор сишка стала инициализировать переменные какими либо значениями вообще?
Насколько я помню, даже плюсы этого не делали, для полей классов разве что.
> Другой вариант, это ОС выделяет память переменной, а в этой области памяти могу быть какие угодно значения, оставшиеся после выполнения другой программы.
Джуниоров полон тред. При создании объекта, что в динамике что в статике, память выделяется сразу на весь объект (это в обычном случае, пляски с собственными менеджерами памяти не рассматриваем). И если ты объявляешь какой-нибудь int i, то он уже на стеке и имеет значение, и ты можешь его cout или printf. Но если ты криворук и не проинициализировал сразу, то значение все равно есть, но undefined. В большинстве случаев это будет 0 просто по дефолту ОС и компилятора, но это не гарантировано. Таким образом работает что С, что кресты.
Проверяется легко: возьми
struct A
{
int i;
char j;
double k;
};
std::cout << i << std::endl; // etc.
И то же самое в сях.
>> No.49222 Reply
>>49221
Я знаю это и написал то же самое.
>> No.49412 Reply
>>48918
> А еще можно three-state использовать и вообще дрочить вприсядку. Приложению плевать, и все грязные делишки твоей железяки должны быть инкапсулированы внутрь, а снаружи предоставлять только общий, оперирующий общепринятыми вещами (типа 8 битных байтов) интерфейс.
Это работает только если у тебя есть возможность жертвовать производительностью и функциональностью ради унификации. Если у тебя есть разработанный инопланетянами флеш-накопитель с тритами, то если ты будешь костылить поверх тритов обычные биты (ну т.е. вместо 0 1 2 ты наинкаспулируешь использовать трит как бит 0 1) то ты сможешь меньше записать на такой накопитель, не раскроешь весь его потенциал.
>> No.49414 Reply
Ну и еще немного по ООП вброшу.
Допустим, есть у нас некая компьютерная игра, там есть объект "Костер" и есть у него некое состояние, типа температуры, количества непрогоревшего материала и прочего. Ну и какие-то методы. И нам скажем надо костер уметь тушить. У костра должен быть метод "быть потушенным" и например у нас есть объект "ведро с водой" и мы хотим тушить костер. Надо чтоб костер имел метод для его тушения чем-то?
костер.тушим-его(Ведро-с-водой);
Или у ведра с водой должны быть метод тушения чего-либо?
ведро-с-водой.тушим-им(костер);
Или может и то и другое? Типа будет особая функция "тушить(что, чем)"
тушить(костер, ведро-с-водой);
А членом какого метода будет эта функция? Ну т.е. если мы описываем взаимодействие двух неких объектов, обладающих некими характерными особенности(горящий может быть чем-то потушен, а тушащий предмет может что-то тушить), каким вообще образом это должно быть огранизовано? Гореть может не только костер, но и например мебель какая-то, и у мебели, если она горит, будет такое вот свойство, что его можно будет тушить. У мебели (в т.ч. горящей!) могут быть еще свойства/методы, для костра совершенно нехарактерные, типа "сесть на стул", можно еще придумать что на горящий стул вы можете сесть только если у вас огнеупорность и так далее... как это решается в рамках ООП?
>> No.49415 Reply
>>49414
Кто инициализирует действие? Костер или ведро? Человек, все это использующий! Объекты должны представлять какую-то идею и ничего кроме. Костер не должен знать, что его может потушить ведро, дождик, отсутсвие воздуха - костер может потухнуть. Так и ведро, не важно, кому на голову ты его выльешь, важны только состояния, которые могут измениться при использовании ведра.
Иначе, если тебе где-нибудь захочется переиспользовать это ведро, оно обязательно должно будет уметь тушить костры.
>> No.49416 Reply
Тогда и я поспрашиваю.
Когда стоит использовать наследовние? Я прочитал много различных статей и ответов о том, когда наследование использовать не надо: SOLID принципы, квадраты, бла, прямоугольники, бла-бла. Но ничего лучше гайдлайна "is a"/"has a" для разделения композиций и наследования не было.
Допустим у меня есть класс сокет. Я хочу его разделить на блокирующие и нет подклассы. Мне для этого можно сделать одно приватное поле, определяющее данное свойство сокета с соответсвующими ему геттером и сеттером, а можно от одного абстрактного сокета, задавшего реализацию, унаследоваться два раза и получить блокирующую и нет реализации. Еще одним вариантом можно принять за стандартный класс блокирующий сокет, а от него уже один раз унаследоваться и получить неблокирующий.
Где эта граница, отделяющая каждый из трех подходов?
Также отсутствие интерфейсов в С++ неблагоприятно влияет на изменения к "public-интерфейсной" части наследования - новые открытые поля через абстрактный-класс-почти-интерфейс я вызывать не смогу. Поэтому и смысла в наследовании глубже чем на один уровень от абстрактного класса я не вижу. Но ведь он есть?
>> No.49417 Reply
>>49415
> Кто инициализирует действие? Костер или ведро? Человек, все это использующий!
И? У костра должен быть метод "потушиться"? Или где этот метод должен быть? У человека? Объект костра вообще должен знать, что его можно тушить?
Класс (объект) в тех же плюсах это структура, к которой приделали некие функции, которые что-то осмысленное делают с состоянием этой структуры внутри класса. Т.е. все построено так, что якобы этот класс это некая сущность, которую мы просим что-то сделать с собой или с чем-то еще, и она что-то делает. По-моему это ерунда какая-то. Вместо того чтобы описывать некие свойства, взаимосвязь разных "штук", мы описываем то, что именно какая-то "штука" умеет делать.
По-моему надо рассматривать свойства объектов. Вот есть ведро с водой - у него есть такое свойство, что им можно что-то тушить. А вот есть горящий костер - у него есть свойство, что его можно чем-то потушить. Ну и пусть будет человек, у которого есть такое свойство, что он может использовать всякие предметы, в т.ч. и ведро с водой для тушения чего-либо. Никаких т.н. методов в привычном виде тут нет. Можно хранить некие свойства предмета в каком-нибудь списке или хэш-таблице, и когда мы в игре применяем ведро с водой на костер (т.е. просто перетаскиваем мышкой например) то в коде игры происходит следующее - мы смотрим на ведро, какие у него свойства - им можно тушить. А какие свойства у костра - его можно тушить. И где-то в коде игры описано, что вещи, которыми можно тушить - их можно применять на вещи, которые можно тушить. Отлично - мы пишем игроку "хотите ли вы использовать ведро с водой для тушения костра?". И если у ведра будет еще какой-то способ провзаимодействовать с костром, то можно вывести соответствующее меню с выдобром. Т.е. не нужны никому никакие методы, надо просто прицепить некие свойства к некоторым сущностям и потом сверять эти свойства на сочетаемость. Искать совместимые свойства. Как вот у ключа есть свойство, что он открывает конкретный замок, а у замка есть свойство что его можно открыть каким-то конкретным ключом.
>> No.49418 Reply
>>49417
> Вместо того чтобы описывать некие свойства, взаимосвязь разных "штук", мы описываем то, что именно какая-то "штука" умеет делать.
Вот тут и проблема. В основе ООП лежат не взаимодействия предметов, а сами предметы. И все методы этих объектов направлены на работу только с самим собой (какие эгоистичные). Иначе нарушается инкапсуляция, иначе эти объекты не могут существовать друг без друга. Еще раз, каждый объект должен быть маленьким закрытым мирком, к которому тебе можно обращаться только через публичные методы или интерфейсы.
> По-моему надо рассматривать свойства объектов
Изначально речь шла о методах. Со свойствами же целая поляна открыта: можно попытаться узнать класс объекта в рантайме, а для этого есть различные решения, можно добавить базовому классу методы, проверящие тушибельность каждого из объектов, предоставляя соответствующий интерфейс, правда тогда не получиться добавлять новые свойства, да и старых будет огромное количество.
Решений есть много, я хорошо не знаю ни одного, постораюсь за парочку ночей разобраться хотя бы в нескольких.
>> No.49419 Reply
File: 28880.jpg
Jpg, 288.94 KB, 800×406 - Click the image to expand
edit Find source with google Find source with iqdb
28880.jpg
Пока вы разбирались в ООП, он уже признан нимодным и всё ровные пасаны начинают его обоссывать и доказывать, что нинужен.
>> No.49420 Reply
>>49417
В целом можно выделить новый класс "Поливание" с методом, принимающим в себя объекты класса костер и ведро. В результате оба этих класса будут не связаны, и при желании метод можно будет перегружать и поливать землю, небеса, Аллаха.
Правда с этим главное не переборщить:
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
Также на размышление тред, половина которого посвящена обсуждению подобного "Игрок-Ударить-Монстр" вопроса, саму статью также можно прочитать:
https://news.ycombinator.com/item?id=18526490
>> No.49421 Reply
>>49419
Функциональщина?
>> No.49434 Reply
>>49419
Как раз таки ООП никто не признал ненужным. Единственная реализация ООП в продакшене - Erlang, а все эти ваши C++ и Java не являются реализацией ООП, специально для адептов "классы-ооп головного мозга" процитирую Алана Кэя:

> I invented the term object-oriented, and I can tell you, that C++ wasn't what I had in mind
> OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late binding of all things.

Разумеется, эксперты из треда начнут заочно спорить с автором ООП парадигмы и доказывать почему он не тру и в ООП ничего не понимает.
>> No.49439 Reply
>>49434
> с автором ООП парадигмы
Симулу писал не Кей.
>> No.49440 Reply
>>49434
Он молодец конечно, но настоящее ООП оказалось бесполезным и никому не нужным. Тогда как его "модификации" (я без понятия, каким ООП был изначально) широко используются везде, ведь они позволяют писать сложное и расширяемое ПО. Тот же самый пример с регулярными выражениями: большинство современных языков подобавляли в них различные способы хранения памяти, различные предпросмотры и подобное. И сейчас регулярные выражения могут описывать различные рекурсивные строки, а это далеко за гранью обычных регулярных языков. Только HTML не надо ими парсить, да.
>> No.49441 Reply
>>49440
> я без понятия, каким ООП был изначально
Эрланго-образный обмен сообщениями это был.
> но настоящее ООП оказалось бесполезным и никому не нужным
Один только сраный WhatsApp на нём и работает, ага.
>> No.49443 Reply
>>49441
> Эрланго-образный обмен сообщениями это был.
Нет, не был: https://habr.com/ru/post/455638/
Изобрести мем «объектно-ориентированный» ≠ изобрести объекты.
>> No.49522 Reply
File: afwXT.jpg
Jpg, 350.83 KB, 1131×707 - Click the image to expand
edit Find source with google Find source with iqdb
afwXT.jpg
>>49418
> Вот тут и проблема. В основе ООП лежат не взаимодействия предметов, а сами предметы. И все методы этих объектов направлены на работу только с самим собой (какие эгоистичные). Иначе нарушается инкапсуляция, иначе эти объекты не могут существовать друг без друга. Еще раз, каждый объект должен быть маленьким закрытым мирком, к которому тебе можно обращаться только через публичные методы или интерфейсы.
А зачем так надо делать? Откуда эти постулаты взялись? Почему именно так, а не иначе?
Мне порой кажется, что сторонники ООП это как нейросеть, которая везде псов распознает: какую задачу ООПшнику не дай - он там увидит что это хорошо ложится на ООП парадигму, и что вот так вот можно это реализовать, вот та фигня - базовый класс, вот так будет эта фигня наследоваться от той фигни... но если посмотреть на проблему незашоренным взглядом (с головой, не забитой всем этим теоретическим бредом, паттернами от банды четырех и прочей такой хренью) то нет там ничего особо связанного с ООП, и ООП по-сути вообще не нужно. Любую задачу можно решать через ООП, или через ФП, или в процедурном или вообще хрензнает каком стиле. ООП похоже на какие-то костыли для мышления, что якобы есть некие объекты, что они что-то могут с собой(и только с собой) делать и что они могут как-то наследоваться т.е. на основе одних объектов можно сделать новые, добавив всяких полей и методов. Почему именно так надо, почему не сделать какие-то другие штуки (назовем эту парадигму штуко-ориентированное программирование или ШОП) в которых мы описываем, что вот какая-то штука может под воздействием другой штуки становиться третьей штукой. Например, есть у нас штука "ведро с водой" и есть штука "горячий костер". Мы где-то описываем, что можно штуку "что-то-чем-можно-тушить" применять на штуку "что-то-что-горит" и получается в итоге штука "что-то-негорящее". Ну по-сути это можно реализовать как функцию, которая принимает два аргумента, что тушим и чем тушим, и возвращает потушенное что-то. Ну и если в эту функцию передать костер и ведро с водой, она вернет потушенный костер. Ну и еще она может вернуть пустое ведро без воды. Никаких объектов с жестко привязанными к ним методами нет, да они и не нужны
>> No.49524 Reply
>>49522
А вот чем абстрактные типы того же Хаскеля отличаются от ООП принципиально?
>> No.49525 Reply
File: 1568146639231.jpg
Jpg, 42.03 KB, 218×300 - Click the image to expand
edit Find source with google Find source with iqdb
1568146639231.jpg
>>49524
Я не очень понимаю, как ты хочешь сравнивать ADT с ООП, но в целом система типов в Хаскеле работает совершенно иначе по сравнению с популярными сейчас ООП языками: C#, Java. В плюсах есть классы, но нет ООП.
В основе ADT лежит параметрический полиморфизм, в основе ООП лежит подтиповый полиморфизм.
Параметрический получил свое название из-за схожести передачи параметров в функцию, только вместо функций у нас конструкторы типа. В шарпах и джаве подобное есть, но обрезан их функционал до нуля: больше параметризованных листов ничего сделать не получится, в плюсах ситуация лучше, но, чтобы начать понимать шаблоны, надо быть магом и убить годы жизни на изучение уродливого синтаксиса.

К примеру, ты можешь создать такой свой уютненький полиморфный тип в Хаскеле:
`data Bla f1 f2 a b c = Bla (f1 a) (f2 c b)`
Первый Bla - конструктор типа, второй - конструктор самого значения, они живут в разных пространствах имен и друг с другом не ругаются
Если мы посмотрим на его сигнатуру (kind)..
`Bla :: ( -> ) -> ( -> -> ) -> -> -> -> *`
То будет видно, что для создания элемента данного типа нам необходимы 2 полиморфных типа и 3 обычных. Это одна строка кода, компилятор определил тип сам, и получить такое в ООП языках не получится.

В ООП популярен подтиповой полиморфизм, когда класс родителя создает виртуальный метод, а потомки его перезаписывают. Тогда можно всех потомков хранить с сигнатурой родителя, а уже таблица виртуальных методов или компилятор позаботятся о том, чтобы вызвался свой собственный метод у каждого объекта, пусть потомка, пусть родителя. В Хаскеле такого и подавно нет.

Еще иногда сравниваются "классы" Хаскеля и ООП-классы. Совсем разные вещи, у них просто совпадают ключевые слова, если очень грубо, то можно сравнить классы Хаскеля с интерфейсами ООП. Но интерфейсы необходимо задавать классу при создании, тогда как в Хаскеле ты можешь в любой момент создать свой собственный класс и научить любые (и почти все стандартные) типы работать с функциями заданными этим "классом". И эти классы также могут быть параметризованы, чего в плюсах пока не добиться.

Не очень хороший пример, но все что надо в нем понять, что две функции высшего порядка fmap тут различны и перегружены для двух совершенно различных типов: Maybe и List.

`mxs :: Maybe [Int]`
`f :: Int -> Int`
`mys = (fmap . fmap) f mxs`

Еще построено это все по совершенно другим принципам - по теории категорий, но это так явно и быстро не показать.
>> No.49526 Reply
>>49525
Все сломалось, все сломалось. Я ничего не вижу.
>> No.49527 Reply
>>49525
> В основе ADT лежит параметрический полиморфизм, в основе ООП лежит подтиповый полиморфизм.
Оба утверждения спорны. Во-первых параметрический полиморфизм в ООП сегодня применяют чаще чем подтиповый, который якобы более "лежит в основе". Во-вторых в Хаскеле классы типов по сути -- это подтиповый полиморфизм.
> больше параметризованных листов ничего сделать не получится
Почему? Прикручиваешь дженерики и обычные параметры, куда взбредёт в голову.
> получить такое в ООП языках не получится
Ну делаешь 2 класса. А потом третий, у которого объекты первых двух и ещё поле в полях. Ну да, в Хаскеле система типов круче, но всё равно не так это принципиально.

Всё как бы круче и гибче, но всё то же самое. Если я создам модуль, а в него помещу типы и определю на них несколько функций, то на выходе это будет тупо класс. На каких-то высосанный из пальца примерах это выглядит иначе, но когда я в голове пытаюсь обуть типичный CRUD с квитанциями и сметами, то выходит такое же точно ООП. Big picture, архитектура в общем и целом, вот что не отличается. Я не вижу, где сам подход другой.
>> No.49528 Reply
>>49527
> Во-первых параметрический полиморфизм в ООП сегодня применяют чаще чем подтиповый, который якобы более "лежит в основе"
Наследование - основа ООП, а из наследования следует подтиповый полиморфизм. Параметрический не имеет ничего общего с этими концепциями. И пришел он в ООП из функционального программирования.

> Во-вторых в Хаскеле классы типов по сути -- это подтиповый полиморфизм.
Классы в Хаскеле реализуют ad-hoc полиморфизм, он не требует никакой структруры, тогда как подтиповый даже своим именем подразумевает общего наследника. Ничего общего между ними нет.

> Прикручиваешь дженерики и обычные параметры, куда взбредёт в голову.
Сопоставлять паттерны дженериков у тебя не получится. Кроме этого ничего не знаю о реализации параметрическгого полиморфизма в ООП языках. В любом случае написанный с ними код выглядит нечитабельно.

> выходе это будет тупо класс
> Я не вижу, где сам подход другой.
Функциональное программирование не заканчивается системой типов. Чистые функции, монады, отсутствие состояния, отсутствие указателей, отсутствие null'a, высокоуровневые функции, отстутсвие while и for циклов и другие производные от этих идей. С такими высокоуровневыми концепциями подход к написанию того же CRUD'a просто не может не измениться. Другое дело ты можешь после перехода продолжать пытаться написать код в своей уютной парадигме и фрустрировать, что ничего нормально не получается.
>> No.49529 Reply
>>49528
> Наследование - основа ООП
Основа, ни основа -- пофигу. На практике от него часто отказываются в пользу композиции.
> подтиповый даже своим именем подразумевает общего наследника
Класс типов подразумевает общий класс у типов у Хаскеля. Ну и что?
> Сопоставлять паттерны дженериков у тебя не получится.
Я могу в разные классы воткнуть разные реализации метода интерфейса. Будет работать почти так же.
> написанный с ними код выглядит нечитабельно.
Примерно так же выглядят типы с параметрами в Хаскеле. Это почти те же дженерики.
> Чистые функции, монады, отсутствие состояния, отсутствие указателей, отсутствие null'a, высокоуровневые функции, отстутсвие while и for циклов и другие производные от этих идей
Всё это конструкции нижнего уровня архитектуры программы. Мелочи. А вот как программа будет дробиться на большие куски? Так же. Или это будет куча разрозненных функций, которые не объединены ни в какие модули?
>> No.49530 Reply
>>49529
> подтиповый, который якобы более "лежит в основе"
> Основа, ни основа -- пофигу
Ну-ну. Чаще чем в ООП наследование нигде больше не используется.

> Класс типов подразумевает общий класс у типов у Хаскеля. Ну и что?
Никто ничего не подразумевает. Еще раз, в Хаскеле нет типов как таковых. Если ты желаешь, в Хаскеле есть разнородные интерфейсы, которые твой тип может реализовать. При этом реализованы они могут быть когда угодно.

> Примерно так же выглядят типы с параметрами в Хаскеле. Это почти те же дженерики.
Из головы..
data Either a b = Left a | Right b
data Maybe a = Just a | Nothing

f :: (Num a) => Either [a] (a, a) -> Maybe a
f (Right (x, y)) = Just (x + y)
f (Left (x:y:_)) = Just (x + y)
f _ = Nothing
Осталось тебе реализовать подобное своими дженериками, а потом можно будет и сравнить "почти же"-сть.

> Или это будет куча разрозненных функций, которые не объединены ни в какие модули?
Везде используется модулярность, только в одном случае у нас будет набор связанных одной идеей функций, тогда как в другом - классов. В первом варианте комбинация различных модулей элементарная, во втором приходится задумываться о внутренних зависимостях классов между друг другом. Только и всего.
>> No.49839 Reply
https://habr.com/ru/post/451982/ кстати вот нашел:

> Подавляющее большинство существенного кода не работает всего с одним объектом, а на самом деле реализует задачи поперечных срезов. Пример: когда class Player ударяет при помощи метода hits() class Monster, где на самом деле нужно изменять данные? Величина hp объекта Monster должна уменьшиться на attackPower объекта Player; величина xp объекта Player должна увеличиться на уровень Monster в случае убийства Monster. Должно ли это происходить в Player.hits(Monster m) или в Monster.isHitBy(Player p)? Что если здесь нужно учитывать и class Weapon? Мы передаём аргумент в isHitBy или у Player есть геттер currentWeapon()?

> Этот упрощённый пример со всего тремя взаимодействующими классами уже становится типичным кошмаром ООП. Простое преобразование данных превращается в кучу неуклюжих взаимопереплетённых методов, вызывающих друг друга, и причина этого только в догме ООП — инкапсуляции. Если добавить в эту смесь немного наследования, то мы получим хороший пример того, как выглядит стереотипное ПО уровня Enterprise.

Может быть в ООП это все же решается как-нибудь красивее, чем через "кучу неуклюжих взаимопереплетённых методов, вызывающих друг друга"?
>> No.49840 Reply
>>49839
Не решается. ООП фундаментально сломано. Оно не работает даже на примерах из книжек про введение в ООП (там, в книжках, об этом, правда, тактически умалчивают).
>> No.49841 Reply
>>49840
Все решается. Конкретно для этого случая, шаблон ECS. Если не подходит, то медиатор.
>> No.49842 Reply
>>49841
Посмотрите на этих поехавших: они несут какую-то ересь, придумывают новые слова и переиспользуют уже существующие.
Я так полагаю, он еще счастлив, что смог выдавить из себя парочку умных аббревиатур. Чем более все абскурно, тем более можно выделиться со своими знанимями. ECS!

Для решения проблемы тебе нужна одна функция с двумя аргументами. Звучит тривиально, нет?
>> No.49843 Reply
>>49839
> Пример: когда class Player ударяет при помощи метода hits() class Monster, где на самом деле нужно изменять данные?
> Должно ли это происходить в Player.hits(Monster m) или в Monster.isHitBy(Player p)? Что если здесь нужно учитывать и class Weapon? Мы передаём аргумент в isHitBy или у Player есть геттер currentWeapon()?

Или пример неудачный, или автор не прав, но в чём проблема в примере? Можно и так, и так, суть не в этом. Допустим один разработчик написал метод Player.hits(Monster m). Другой разработчик приходит через полгода и начинает разбираться, как это работает. Он не ломает голову над вопросами, которыми задаётся автор, а просто читает код и переходит по методам как по ссылкам: "Так, тут у нас класс Player, тут у нас метод hits получает экземпляр класса Monster, тут у нас вызывается геттер currentWeapon() и т.д."
>> No.49844 Reply
>>49842
Мне нравится какой ты на все озлобленный демагог. Продолжай в том же духе, бро. Добра.
>> No.49845 Reply
>>49841
Но ECS к ООП абсолютно перпендикулярен. То есть, вообще никакого отношения, кроме того, что его можно реализовать с помощью объектов. В реальности у тебя тут будет HitManager.do_attack( player, monster );, что есть антипаттерн.
> Все решается
Начну немного издалека, но ты потерпи.
Ещё относительно недавно на вопрос "Что такое ООП?" следовал ответ "Полиморфизм, инкапсуляция, наследование". Сейчас люди стали чуть менее категоричными, но они продолжают-таки признавать, что эти принципы есть основные киты ООП. При этом полиморфизм в ООП - сабтайпинг, о котором будет следующий абзац - это подмножество полиморфизма вообще, и полиморфизм есть, например, в StandardML, а вот ООП туда не завезли. Да что там, его можно сделать даже в сишке; тебе процесс не понравится, но можно. Инкапсуляция тоже есть как в SML, так и в сишке. Даже некоторые ассемблеры (тот же масм, который использует сишный линкер) позволяют тебе делать локальные для файла функции/переменные. Остаётся наследование. Вот это уже чистая ООПешная тема. Что забавно, ибо в последнее время программисты объектной ориентации от него открещиваются. На этом можно было бы и закончить, но я продолжу.

Теперь рассмотрим Liskov Substitution Principle. Это та самая L из SOLID. Ещё поговаривают, что это l из Agile и даже из Waterfall, где их сразу две. Этот принцип настолько важен, что в честь него назвали язык LISP. Я буду говорить про его ООП интерпретацию. Звучит он так: если у тебя есть базовый класс А, и есть наследующийся от А класс В, то везде, где ожидается объект класса А, можно передать объект класса Б, и семантика программы не изменится. Если подумать, то оно логично. Это, как говорят у них, цельная точка (whole point) наследования. В конце концов, если у тебя есть ящик, который может хранить фрукты, но не бананы и яблоки, а некие абстрактные фрукты, то такой ящик тебе будет не очень полезен.

Теперь, держа в голове последние два абзаца, рассмотрим пример из почти любой книжки про введение ООП в начинающих. Этот пример, например, можно увидеть в книге Страуструпа Programming: Principles and Practices in C++ (или как-то так) где-то, если я не ошибаюсь, в первых трёх-четырёх главах. Мы делаем графическую объектно-ориентированную библиотеку. У нас есть базовый класс Shape, у нас есть много-много его наследников, и мы с ним можем делать разные вещи - рисовать на экран, печатать, считать площади и т.д. и т.п.. Мы доходим до реализации классов Rectangle и Square, и у нас появляется три пути, ради рассмотрения которых всё это и писалось.

Итак, путь первый, он же не_ооп: class Rectangle extends Shape и сlass Square extends Shape
Тут всё очевидно. Никакого переиспользования кода, отношения "is a" не выражены и т.д. Любой оопрограммист скажет тебе, что это неправильно и никто так не делает, а если делает, то он дурак и должен получать клавиатурой по голове пока не осознает. Ну, или хоть пусть какого-нибудь Буча почитает. Поэтому...

...Путь второй, он же очевидный и неправильный: class Rectangle extends Shape и class Square extends Rectangle
И вроде бы тут не к чему придраться, но я не просто так же написал абзац про LSP выше. Рассмотрим код
```function scale( r:Rectangle ) {
r.width *= 10;
r.height *= 2;
}
scale( new Square( 4 ) );
```Этот код скомпилится, но он нарушает LSP. Более того, тут почти undefined behaviour, потому что этот код зависит от того, как реализован сам язык, как реализована библиотека шейпов, и может быть даже как компилятору позволено код оптимизировать. Как же правильно? Если помедитировать над LSP, то можно прийти к выводу, что дочерние классы могут только расширять родительские, но ни в коем случае не ограничивать. Ведь именно из-за введения нового инварианта в Square у нас и получилась фигня. Поэтому правильный код...

...Номер три: class Square extends Shape и class Rectangle extends Square.
И всё, вроде бы хорошо, ну, кроме "очевидности ооп", о которой тебе говорят в книжках. Знаешь, вот эти все истории про "собачка - это животное, и кошечка - это животное, поэтому мы делаем базовый класс, наследуемся от него, и кошечка говорит "мяу", а собачка говорит "гав" - смотрите, как просто мы можем моделировать реальный мир. И ты читаешь эти истории, веришь им, а в реальности у тебя вот такая фигня выходит. Но если бы на этом всё закончилось, то я бы тут не распинался. Consider, как говорится, зе following
```if ( new Rectangle( 15, 45 ) is Square ) throw "somethin' really fucked up's goin' on here m8";```
Что, по-твоему, сделает этот код? Я, конечно, не математик, но какое-то внутреннее чувство мне подсказывает, что прямоугольник со сторонами 15 и 45 - это не квадрат.

Вот эта вот задача не решаема в ооп. Фундаментальная проблема всея компьютер саенса разводит руками. В книжках об этом умалчивают, потому что иначе никто дальше первой главы (с этим примером) читать не будет.
>> No.49846 Reply
>>49845
> Остаётся наследование. Вот это уже чистая ООПешная тема.
А трейты (trait, интерфейсы с возможностью объявлять дефолтные реализации методов) относятся к наследованию?
А typeclass из Хаскеля?
Видимо наследование есть не только в ООП, или в ООП есть своё ООП-шное определение наследования.
>> No.49847 Reply
>>49846
В ООП-шном наследовании можно унаследовать переопределённую реализацию метода.
С трейтами и тайпклассами это сделать не так просто, как в ООП.
>> No.49873 Reply
>>49845
> Путь второй, он же очевидный и неправильный: class Rectangle extends Shape и class Square extends Rectangle
Просто ты очевидный быдлокодер. С какого хуя у тебя Rectangle имеет метод на увеличение параметров магическими цифрами? Почему ты лезешь напрямую в данные вместо вызова сеттеров? А потому что ты отстреливающий себе ногу быдлокодер.
virtual bool Rectangle::scale(int xScale, int yScale) {...}
bool Square::scale(int xScale, int yScale) override
{
if (xScale != yScale)
return false
else
return this->scale(xScale);
}
>> No.49874 Reply
>>49873
Ну да, можно и так. Простите, был неправ. Забыл, что любую проблему можно обойти наговнокодив костылей.
Что вот у тебя за bool там такой? Откуда он взялся? Ах, он тут затем, чтобы это хоть как-то работало? Вопрос тебе: у тебя есть класс Shape; тебе нужно написать класс Rectangle; квадраты ещё не изобрели, и о том, что тебе понадобится класс Square ты узнаешь только через полгода - будет ли твой scale возвращать bool?
Далее, как ты думаешь, сколько постов на форуме твоей либы будут содержать вопрос "почему Square::scale принимает два параметра, при том, что они должны быть равны, и если они не равны, то ошибка (может быть) вылезет только в рантайме"?
Это всё "фиксится" перегрузкой scale для одного аргумента и выбросом исключения, вот только
а) исключение нарушает LSP,
б) перегрузка функций к ооп не имеет отношения - это языкоспецифическое средство починить пролему ооп,
в) оригинальный scale всё ещё останется и всё ещё будет принимать два аргумента.

Но, самое главное, что даже с этим твоим костылём ты всё ещё нарушаешь LSP, просто ты это относительно неплохо спрятал под коврик, и оно теперь почти незаметно. Напомню: объект дочернего класса должен иметь возможность быть подставленным ВЕЗДЕ, где требуется объект родительского БЕЗ ИЗМЕНЕНИЯ ПОВЕДЕНИЯ программы. Есть у тебя функция сделать_мост, которая принимает прямоугольники, меняет ему размер на 3м х 10м, поворачивает и кладёт поперёк ущелья. Кто-то потом передаёт туда квадрат. Он не масштабируется. Функция кладёт его поперёк ущелья. Он падает. Ты ступаешь на несуществующий мост и падаешь вниз. Тебя съедают крокодилы. А всё потому что ты наслушался маркетологов.
Единственное, что ты тут можешь сделать - это начать вилять хвостом, что надо было проверять возвращаемые значения. Но это так не работает, потому что твой дочерний класс всё ещё ограничивает родительский - поведение всегда будет меняться в тех случаях, когда код делает что-то, что затрагивает эти ограничения. Как только ты ограничил родителя - ты уже проиграл.

Вообще, я тут поумничать решил, и оригинальная идея была о наследовании класса Tree от BinaryTree (книга это была, или статья какая - не помню, но если кто-то узнал, дайте ссылку или ключевые слова), но пример с фигурами мне показался чуть более наглядным.
>> No.49875 Reply
>>49874
> Что вот у тебя за bool там такой? Откуда он взялся? Ах, он тут затем, чтобы это хоть как-то работало?
Так ты все-таки проектируешь иерархию классов и допускаешь, что метод может сфейлить? Или быдлокодишь и ноешь про "костыли", отстрелив себе ногу "да не, оно не может сфейлить, хуяк-хуяк return void -> бля, сфейлило, чертово ООП!"? Хотя тут и так все понятно, что тут спрашивать.
> Вопрос тебе: у тебя есть класс Shape; тебе нужно написать класс Rectangle; квадраты ещё не изобрели, и о том, что тебе понадобится класс Square ты узнаешь только через полгода - будет ли твой scale возвращать bool?
Типичный подход быдлокодера, как и было предсказано. Я уж молчу про подготовку проекта перед кодированием, сраные UML, IDEF0 и прочая, но подумать своей башкой, что не все Rectangle можно успешно отскейлить на разные множители по разным координатам, ты мог? Или для тебя внезапно оказалось открытием: епта, хуе-мое, квадрат тоже прямоугольник, нам этого в школе не рассказывали! Проклятое ООП!
> Далее, как ты думаешь, сколько постов на форуме твоей либы будут содержать вопрос "почему Square::scale принимает два параметра, при том, что они должны быть равны, и если они не равны, то ошибка (может быть) вылезет только в рантайме"?
Я бы на форуме таких говнокодеров банил на месяц в ридонли, если они такие тупые, что не видят перегруженный метод и не ебут, что такое наследование от базового класса, но пиздят что-то про ООП.
> исключение нарушает LSP
Поэтому не будь быдлокодером и не пиши быдлокодерские иерархии с return void. Внезапно, и исключения не понадобятся.
> перегрузка функций к ооп не имеет отношения - это языкоспецифическое средство починить пролему ооп
Это вообще сахар для удобства, наркоман, оно ничего не чинит.
> оригинальный scale всё ещё останется и всё ещё будет принимать два аргумента.
И? Клятое ООП не дает тебе сломать ООП? Ты тут двумя строками ранее LSP для красного словца нагуглил?
> Но, самое главное, что даже с этим твоим костылём ты всё ещё нарушаешь LSP, просто ты это относительно неплохо спрятал под коврик, и оно теперь почти незаметно. Напомню: объект дочернего класса должен иметь возможность быть подставленным ВЕЗДЕ, где требуется объект родительского БЕЗ ИЗМЕНЕНИЯ ПОВЕДЕНИЯ программы.
Напомню, что ничего не нарушается. Если ты такой быдлокодер, что по юности и недалекости своей думаешь, что у тебя любая операция всегда сработает, то я выебу твой scale переполнением.
> Есть у тебя функция сделать_мост, которая принимает прямоугольники, меняет ему размер на 3м х 10м, поворачивает и кладёт поперёк ущелья. Кто-то потом передаёт туда квадрат. Он не масштабируется. Функция кладёт его поперёк ущелья. Он падает. Ты ступаешь на несуществующий мост и падаешь вниз. Тебя съедают крокодилы. А всё потому что ты наслушался маркетологов.
Вот поэтому, дети, таких джунов гонят ссаными тряпками на первом же code review, и не подпускают потом этих макак дальше ардуинки в кофеварках китайских ноунеймов.
> Вообще, я тут поумничать решил
Ты сфейлил, бро.
>> No.49876 Reply
>>49875
ОК, я проигнорирую всё начало (хотя тут много чего можно сказать), кроме нескольких основных пунктов.
> Или для тебя внезапно оказалось открытием: епта, хуе-мое, квадрат тоже прямоугольник
Именно так. Потому что на момент проектирования квадраты не изобрели. Их не существует физически. Появятся они только через полгода, когда код уже написан.
> Я бы на форуме
Знаешь, что такое "протекающие абстракции"? Нет? Ну, теперь знаешь, потому что это пример прямо из палаты мер и весов.
> Напомню, что ничего не нарушается.
Я тебе ещё раз говорю: не важно, проверяешь ли ты там что-то где-то или нет. Для начала ещё раз перечитай LSP, и теперь я объясню сразу на наглядном примере:
Вот есть такой код:
``fun sdelat_most( Rectangle r ) {
if ( r.scale( 3, 10 ) ) print( "Most sdelan" )
else print( "Oshibka" )
}
Rectangle rect = new Rectangle( 3, 3 )
sdelat_most( rect )``
Мы его запускаем и он печатает "Most sdelan". Теперь мы подменяем родительский объект на дочерний ``Rectangle rect = new Square( 3 )``, запускаем, и код печатает "Oshibka". Поведение программы изменилось, а по LSP этого быть не должно. А можно проще, без лишних функций (у тебя же сеттеры отнаследовались):
``Rectangle rect = new Rectangle( 3, 3 )
rect.set_width( 4 )
rect.set_height( 5 )
assert( rect.get_area() == 20 )
print( "Ok" )``
Это печатает "Ok". Заменяем прямоугольник на квадрат и он падает с assertion failure. А не должен.
Наследование Square от Rectangle нарушает LSP, что в свою очередь означает несоответствие твоего кода принципам SOLID, что в свою очередь делает говнокодером тебя, а не меня.
QED
>> No.49877 Reply
>>49876
> ОК, я проигнорирую всё начало
как обосраться и не подать виду.тхт
> Именно так. Потому что на момент проектирования квадраты не изобрели. Их не существует физически. Появятся они только через полгода, когда код уже написан.
Чо-чо? Проектирование интерфейсов? Изучение предметной области? Зачем, когда можно хуяк-хуяк и в продакшн!
Эээ, пан заказчик, это не я наобезьянил, это все ООП! Только по лицу не бейте!
> Знаешь, что такое "протекающие абстракции"? Нет? Ну, теперь знаешь, потому что это пример прямо из палаты мер и весов.
Нет, просто твои абстракции кривые и предусматривают только common cases. А опытный разработчик тем и отличается от джуна, что сразу предусматривает редкие случаи. Поэтому джуны и не проектируют API.
> Вот есть такой код
Это быдлокод, еще раз тебе говорю.
> Это печатает "Ok". Заменяем прямоугольник на квадрат и он падает с assertion failure. А не должен.
А кроме написания быдлокода ты еще и не понимаешь, что такое LSP.
Rectangle rect = new Rectangle( INTMAX, 3INTMAX)
Rectangle нарушает Rectangle! LSP! OOP! SOLID! Вы все быдлокодеры, а я нет, уиииии!
> print( "Most sdelan" ) else print( "Oshibka" )
> fun sdelat_most
Блядский блядь, и я еще на это трачу время, пиздец просто.
>> No.49878 Reply
>>49877
> Это быдлокод
Но ведь это ровно тот код, который ты предложил мне написать. Я, очевидно, чего-то не понимаю, поэтому напиши, пожалуйста, как оно тут должно быть.
> ты еще и не понимаешь, что такое LSP.
Забавные проекции. Твой код, очевидно, никаких LSP не нарушает, потому что принцип этот про типы. Про подстановку в валидный код валидных экземпляров типов. Принцип этот требует, чтобы код, который работает для некоего типа, работал бы точно так же для любых его наследников. То есть, ты можешь добавлять методы детишкам, но не изменять обозреваемое поведение наследуемых методов (да, да, когда ты делаешь наследника, который делает всё то же самое, но только ещё и в логи пишет - это тоже нарушение LSP, потому что поведение программы меняется).
А вот когда у тебя есть код napechatat( 2 + 2 ), а ты меняешь его на napechatat( 3 + 2 ), то никаким LSP тут не пахнет, потому что здесь нет никакой замены типов. Ты можешь этот код поменять на napechatat( 2.0 + 2 ), нарушив LSP , потому что он теперь напечатает не 4, а что-то вроде 4.00000000 (хотя тут всё немного сложнее), что скажет тебе, что float не может быть субтипом int
>> No.49898 Reply
>>49842
Кризис среднего возраста и тех и у других. Все программисты через это проходят.
>> No.49899 Reply
>>49898
Почти все
>> No.49955 Reply
File: MFC.jpg
Jpg, 16.14 KB, 292×306 - Click the image to expand
edit Find source with google Find source with iqdb
MFC.jpg
>>49899
- Церебротоник ("мозговитый"), IQ > 140, интроверт в терминальной стадии, нулевая привлекательность для девушек. Никогда не делает первый шаг, не начинает small talk, а если кто-то начал, то отвечает максимально кратко и молчит. Не знает, о чём говорить с девушками.
- Работает либо из дому удалённо, либо в на 90 % мужском коллективе.
- Много времени тратит на мышление, калории сжигаются, он всегда уставший, апатичный. Ускоренный обмен веществ.
- Не развита эмоциональность. Сух. Душнила.
- Акцентуация - смесь параноида ("всё предусмотреть, не пропустить багов, сделать надёжный девайс") и шизоида ("монады, моноиды, хаскелль, эрланг"). Тревожен, рационален. Делает всё долго, медленно, пiчально... основательно...
- Не способен адекватно рассказать о своих хобби, интересах, потому что они сложные наподобие "запилить свой процессор на FPGA своей архитектуры и микроархитектуры, а потом для него компилятор написать".
- Поскольку он потратил молодость на умственное, а не физическое развитие, то телосложение такое - рост средний по стране (от 175 до 180, при этом часть тела от пяток до пупка раза в два длиннее, чем от пупка до затылка), масса тела низкая, кости тонкие, ручки-веточки, худощав, крупные глаза. Не занимается спортом.
- Одевается в простейшую, дешёвую и удобную одежду, а не в красивую.
>> No.49961 Reply
>>49955
Охренеть, это же про меня.
> IQ > 140, интроверт в терминальной стадии, нулевая привлекательность для девушек
Чек.
> Работает либо из дому удалённо
Чек.
> Много времени тратит на мышление
Чек.
> смесь параноида ("всё предусмотреть, не пропустить багов, сделать надёжный девайс") и шизоида ("монады, моноиды, хаскелль, эрланг")
Чек.
> запилить свой процессор на FPGA своей архитектуры и микроархитектуры, а потом для него компилятор написать
Чек.
> масса тела низкая, кости тонкие
Чек.
> Одевается в простейшую, дешёвую и удобную одежду
Чек.
Пять лет женат, живу в собственном доме у побережья Тихого океана, по-детски счастлив.
>> No.50026 Reply
File: pg111.png
Png, 30.18 KB, 500×345 - Click the image to expand
edit Find source with google Find source with iqdb
pg111.png
Давайте обсудим LSP. Если я правильно понимаю, LSP про то, что если ты некую хрень расширяешь чем-то, то это не должно ломать поведение того, что в базовом классе. Например, если есть звуковая карта, которая умеет только лишь воспроизводить звук через ЦАП (микрофонного входа нет), ты сделал некий драйвер с неким API, а потом появилась звуковуха еще и с входом под микрофон, и ты унаследуешь интерфейс, добавляя еще хрень чтоб аудиосемплы принимать. А если у тебя будет хрень только с микрофонным входом, и ты унаследуешься от хрени в которой есть функция воспроизведения аудиосемплов, это уже хуйня какая-то, потому как зачем тебе это воспризведение? Использование функции воспроизведения аудиосемплов тогда не имеет смысла, так что надо наслеоваться от хрени, которая вообще ничего не умеет, т.е. из "ничего" отнаследовать хрень для АЦП, потом опять из "ничего" унаследовать для ЦАП, а потом надо еще эти изначально унаследованные из "ничего" штуки совместить (когда и то и то есть), и как это в ООП-парадигме описывается? Почему в ООП есть только "мы расширяем эту штуку этой штукой", а прямого смешивания или какого-то наложения нет?
А если у нас какие-то ебанутые ограничения на одновременное юзание воспроизведения звука и записи с микрофона? Например, если совмещенные АЦП и ЦАП от одного источника получает тактовые импульсы, и получается что samples per second на АЦП и на ЦАП должно быть строго одинаково, т.е. не может быть такой хуйни, что АЦП работает на 8000 а ЦАП 44100? Ну а если все же иногда можно, например если в одном 8000 а в другом 16000, то тогда можно 16000 поделить на 2 встроенным делителем частоты, и тогда норм? А если в кодеке, совмещающем ЦАП и АЦП есть какие-то особые функции, например аппаратное эхоподавление, которое работает только тогда, когда частоты дискретизации строго совпадают, и тогда вот трюк с делением на 2 уже не работает? Как это описывается в ООП?
>> No.50027 Reply
>>50026
Я слышал, что со временем люди поняли, что композиция предпочтительней наследования. А вообще можно делать по-разному: где-то есть множественное наследование, а где-то вместо множественного наследования - интерфейсы, а где-то - миксины и трейты.

Здесь наверное больше про шаблоны проектирования, а не LSP и наследование.
>> No.50028 Reply
>>50026
Ну что мешает отнаследоваться и полученный производный класс завернуть в интерфейс, который скроет ненужную функциональность и показывать пользователю кода только этот интерфейс?
>> No.50029 Reply
File: lsp.png
Png, 170.26 KB, 880×468 - Click the image to expand
edit Find source with google Find source with iqdb
lsp.png
>>50026
> это не должно ломать поведение того, что в базовом классе
Нет, оно не должно ломать поведение всего остального кода. Представь, что у тебя есть некий класс, с неким поведением. Ты пишешь кучу кода, который жонглирует объектами этого класса. Теперь ты расширяешь этот класс дочерним. Мы знаем, что дочерний класс с родительским имеет "is a" отношение, поэтому ты можешь передать объект дочернего класса туда, где требуется родительский. Очевидно, что если поведение внутри дочернего класса отличается от родительского, то написанный тобой до этого код перестаёт работать, как только ты туда этот объект передаешь. Нафига тогда нужно такое наследование? Ну вот поэтому LSP и существует. В реальности же, конечно, этот принцип нарушается на каждом шагу, и его понимают даже не половина людей, даже из тех, кто знает его определение.
>> No.50030 Reply
>>50028
Ну и что мешает наследовать только интерфейсы.

Поправил тебя. Не благодари.
>> No.50031 Reply
>>50030
Ты определись чего тебе - шашечки или ехать, доводить систему до идеала можешь годами, а рабочий сносный код нужен СЕЙЧАС.
>> No.50032 Reply
File: kater-amfibiya-Stryda_4a.jpg
Jpg, 74.45 KB, 900×650 - Click the image to expand
edit Find source with google Find source with iqdb
kater-amfibiya-Stryda_4a.jpg
>>50028
> Ну что мешает отнаследоваться и полученный производный класс завернуть в интерфейс, который скроет ненужную функциональность и показывать пользователю кода только этот интерфейс?
А зачем тогда наследование? Вот допустим есть класс "транспортное средство" ("Т.С."), у которого есть какие-то методы, например оно может перемещаться, т.е. есть параметр текущей скорости, максимальной скорости, грузоподъемности. Есть "плавающее Т.С." (лодка, корабль и так далее), наследуется из "Т.С.", и там есть новые параметры, например минимальная глубина, на которую может заплывать чтобы не сесть на мель. Еще есть обычный наземный транспорт, типа машин, там есть некий параметр "проходимость", по бездорожью какая-то машина проедет, какая-то не проедет. А потом внезапно появляется катер-амфибия, и все портит. У катера-амфибии есть отдельная максимальная скорость по воде, и отдельная скорость по суще, но базовый класс "Т.С." имеет только одну максимальную скорость, понимание что это "скорость по воде" или "скорость по суше" наступает только при наследовании. И параметр типа "грузоподъемности" может быть разным на суже и на воде. Т.е. базовый класс "Т.С." вообще не должен иметь никакой "максимальной скорости" и "грузоподьемности", должен иметь только какие-то общие характеристики, типа текущей скорости, веса и физических размеров, и потом на это нанизывается что-то новое? А еще у нашего катера-амфибии появилось новое свойство - он может с плавучего состояния переходить в сухопутное, а это не свойственно ни "плавающему Т.С." ни "сухопутному Т.С.".

Зачем в ООП сделали наследование как "дополнение чего-то к чему-то" а не как некое "совмещение разных штук"?
>> No.50033 Reply
>>50032
Я себя не считаю специалистом ООП и для себя в наследовании вижу в первую очередь способ повторного использования кода. Если вижу, что один и тот же код дублируется, то перемещаю в базовый класс. Если два класса не имеют общего кода, то действительно, зачем тогда наследовать их друг другу? Все, что можно сделать композицией - делаю композицией, чтобы было проще тестировать код.

Что касается интерфейса - если уж видишь, что у тебя есть класс, который делает больше, чем надо от другого класса, но делает не все, что надо от нового класса, а только часть, то, конечно, можно перебирать всю иерархию классов и разделять их, а можно скрыть то, что не надо, за интерфейсом и не показывать внутреннее содержание. Ужас-ужас, нарушение чистоты архитектуры или сносный компромисс, все зависит от условий, в которых ты находишься, я так считаю.

А про совмещение разных штук - ну так вот тебе и композиция.
>> No.50048 Reply
Странно что в треде не мелькала книга Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development 3rd Edition by Craig Larman. Если в кратце, то благодаря ооп мы получаем low representation gap между понятиями предметной области и кодовой базой. То есть благодаря ооп аналитики и программисты начинают друг друга лучше понимать, так как начинают использовать одинаковые понятия, каждый из своей области, но семантически обозначающие одно и то же. Книгу одобряю на 10 из 10, там про то, как проходить цепочку от постановки задачи к объектной модели в коде, так как все вот эти ООП приемы, они зачастую обусловлены именно предметной областью.(за исключением нефункциональный требований, но это там тоже обговаривается) Ну и в процессе читатель так же начнёт разбираться чуть глубже в итеративной разработке, познаёт grasp и поймёт нафига придумывали UML. Перевод на русский ужасен, там по сей день в третьем издании путают связность и зацепление.
>> No.50049 Reply
>>50048
> Если в кратце, то благодаря ооп мы получаем low representation gap между понятиями предметной области и кодовой базой.
А ФП этот "low representation gap" не дает?
> То есть благодаря ооп аналитики и программисты начинают друг друга лучше понимать, так как начинают использовать одинаковые понятия, каждый из своей области
Ерунда.
Проблема в наследованиях, наследование это "надстройка над чем-то", а не некая композициия. И получается, что не всякая предметная область адекватно описывается этим наследованием как надстраиванием чего-то над чем-то.

Возьмем математику. Если рассмотреть натуральные числа т.е. числа, возникающие при естественном счете (1, 2, 3, 4, 5, 6, 7 итд) - их можно расширить на область целых чисел (... -3, -2, -1, 0, 1, 2 ...) - ага, наследование. А можно расширить на рациональные неотрицательные числа, т.е. это будут дроби вида (1/1, 1/2, 1/3 ... 2/1, 2/3, 2/5, 2/7 ...), а можно расширить на просто рациональные числа, в которые входят в т.ч. отрицательные, а еще есть алгебраические числа, куда входят рациональные, а еще есть k-адические числа, которые вообще из другой оперы, а еще можно рассматривать матрицы и операции над ними, и тут в рамках ООП это адекватно уже не изобразить, тут нужен намного более сложный фреймворк для описания таких сложных соотношений числовых систем, вот та же теория категорий как раз об этом. И ООП к теории категорий вообре ортогонально
>> No.50050 Reply
>>50049
Я с планшета, буду без цитирования, извиняй.

В фп нету состояний и связей между ними, по крайней мере настолько явных и понятных для не программистов.
Нет не ерунда, невероятно важна качественная связь между аналитиком/продуковнером/стейкхолдером и программистом, в противном случае у нас будет полное не понимание друг друга, все вот эти "это не баг это фича", "программисты начинают принимать бизнес решения" и прочий садом.
В наследовании нет никаких проблем, это всего навсего механизм отношений. Его можно убрать из ооп, и глобально ооп никуда не денется. Даже на голых сях можно фигачить объектами, ссылки на функции при структурах будут выполнять роль методов и таким образом будут держать ту или иную ответственность при данном "объекте".
Наследование ты пилишь когда у нас для этого есть явные предпосылки выраженные функциональными или нефункциональными требованиями. В реальном мире отношения по типу расширения встречаются крайне редко, обычно в виде "сортах" какой-то сущности, для которых мы делаем какую-то общую абстракцию и через полиморфизм работаем с разными "сортами". С нефункциональными чуть сложнее, там уже надо смотреть по месту: от закладывания на будущее расширение проекта до каких-нибудь танцов с white-box framework-ами, где через protected хуки мы работаем с template функциями и прочее сатанинство.
Короче в слое предметной области (domain layer) зачастую наследование можно вообще не видеть даже на очень крупных проектах.
Пример с математикой не очень понял, расширяешь старый тип, получаешь новый расширенный с дополнительными функциями. И будет у тебя 4 разных типа или сколько у тебя в примерах, расширенный тип - новый тип который мы получили на основе старого. Тут главное с принципом Барбары Лисков не обосраться.
Если вдруг появился какой-то общий код и для него было принято решение придумать общего родителя и складировать ответственность туда, то это верная доржка наделать себе проблем в будущем. Языки дают очень много возможностей, главное понимать под какие проблемы эти возможности закладывались. Я многие штуки так и не понимаю до сих пор, как например пилить микросервисы и не получить на самом деле слоеный монолит который вызывает функции по сети.
>> No.50051 Reply
>>50050
> ссылки на функции при структурах
Указатели конечно же, самопочин*
>> No.50052 Reply
File: image-4.jpg
Jpg, 65.11 KB, 720×540 - Click the image to expand
edit Find source with google Find source with iqdb
image-4.jpg
>>50050
> Пример с математикой не очень понял, расширяешь старый тип, получаешь новый расширенный с дополнительными функциями
Да нет, не работает это так. Не всегда это описывается как расширение, но при этом есть некие сложные взаимоотношения между сущностями, которые можно как-то описать.
Взять например натуральные числа, одно натуральное число может принимать значение натурального ряда, т.е. 1 2 3 4 5 6... - их можно расширить в рациональные числа, ок.
А если взять какие-нибудь k-адические числа? Рассмотрим например 2-адические. 2-адическое число это бесконечный битовый вектор, например ...101101010
3-адическое это бесконечный вектор из чисел от 0 до 2 т.е. ...2010200002011 и так далее. Как это будет наследоваться из натурального ряда? В общем случае там никаких 1 2 3 4 как значений нет. Говоря простым языком, каждая цифра в этом k-адическом числе это бесконечная последовательность натуральных чисел (включая ноль) от 0 до k. Т.е. связь между k-адическими числами и числами натурального ряда есть, но эта связь не описывается как простое расширение
> И будет у тебя 4 разных типа или сколько у тебя в примерах, расширенный тип - новый тип который мы получили на основе старого.
И это будет очень ограничено. ООП на таком уровне абстракций нормально не работает. Прочитай хотя бы поверхностно, что такое теория категорий, что такое морфизм.
> В наследовании нет никаких проблем, это всего навсего механизм отношений. Его можно убрать из ооп, и глобально ооп никуда не денется. Даже на голых сях можно фигачить объектами, ссылки на функции при структурах будут выполнять роль методов и таким образом будут держать ту или иную ответственность при данном "объекте".
> Короче в слое предметной области (domain layer) зачастую наследование можно вообще не видеть даже на очень крупных проектах.
Почему тогда про наследование так часто говорят в контексте ООП? О чем тогда ООП? Просто о том, что у нас есть некие сущности, называемые "объектами" и есть некие сущности, называемые "классами", которые фактически являются функциями, делающими что-то с этими объектами?
> Если вдруг появился какой-то общий код и для него было принято решение придумать общего родителя и складировать ответственность туда, то это верная доржка наделать себе проблем в будущем.
Потому что наследование как механизм абстрагирования плохо работает
>> No.50053 Reply
>>50052
> каждая цифра в этом k-адическом числе это бесконечная последовательность натуральных чисел (включая ноль) от 0 до k.
От 0 до k-1 конечно же. Ну не суть.
>> No.50055 Reply
File: lrg.png
Png, 141.62 KB, 1280×1168 - Click the image to expand
edit Find source with google Find source with iqdb
lrg.png
>>50052
> Не всегда это описывается как расширение, но при этом есть некие сложные взаимоотношения между сущьностями, которые можно как-то описать.
Есть же принцип Барбары Лисков(Он в исходной формы математический) из которого выходит, что если у вас не расширение и не сорта, то не надо это загонять в рамки наследования. Но я не математик и далек от этой предметной области, поэтому не вижу видимо те отношения, которые ты упоминаешь. Разбираться в данной предметной области я на текущий момент не имею времени, извини.
> ООП на таком уровне абстракций нормально не работает.
Значит надо оставить сову в покое, крутануть глобус и ткнуть пальцем в страну, в которую ты поедешь в следующий отпуск, доброкодер.
> Прочитай хотя бы поверхностно, что такое теория категорий, что такое морфизм.
С радостью бы, на надо добить 7 издание Фленегана в части клиентского жс-а, потом по отдельным статьям реакт ссаный, актуализировать знание шарпа(пробежать какой-нить квик гайд по .core), пробежать експрешены там и как они транслируются в sql в рамках entity framework, очень хорошо если смогу прочитать еще Еванса про работу с предметной областью и начать искать работу уже, а то деньги кончились.
> Почему тогда про наследование так часто говорят в контексте ООП? О чем тогда ООП?
Приведу цитату из книжки на пикче, которую я рекомендовал.
> Просто о том, что у нас есть некие сущности, называемые "объектами" и есть некие сущности, называемые "классами", которые фактически являются функциями, делающими что-то с этими объектами?
Есть некоторые сущности называемые объектами, они в каждый момент времени находятся в определенном состоянии, и при них есть методы, которые реализуют те или иные ответственности, которые выполняются с оглядкой на текущее состояние объекта.
На сколько я понимаю, в функциональном программировании, у тебя есть поток выполнения, состоящий из цепочки монад, и результат выполнения каждой монады, отлетает в следующую монаду входными данными. А в ООП у тебя есть большущий граф состояний, причем каждый узел в свою очередь, такой же граф но поменьше, отвечающий за отдельную подсистему например. В функциональном программировании, у тебя есть поток, и программа существует в рамках этого потока выполнения. В ООП у тебя есть состояние системы, и система стоит и ждет пока в нее снаружи прилетит раздражитель, на который она отреагирует. (Тут я не имею ввиду что она там стоит аптаймом все время, то что лежит у нас например в базе, по факту является её состоянием отраженном в записях
)

Пример: есть условная сеть магазинов, у них есть общий склад, какие-то внутренние подотделы и так далее. В каждый момент времени, бизнес находится в строго определенном состоянии, есть позиции на складах, есть те или иные транзакции в истории покупок и так далее. И есть все вот эти люди вокруг, которые через тот или иной апи кричат в эту бочку своими запросами, и система отвечает им в рамках своего текущего состояния, меняет это состояние или шлет нахер, так как действия не допустимы. А вот то, что у нас кодовая база состоит из объектов которые существуют в реальной жизни, очень сильно облегчает коммуникацию между условной бухгалтершой Валей - аналитиком Петром - и тобой, который пытается понять, херли они от тебя хотят.

Все вот эти наследования, реализации объектов через классы, паблик-приват-протектед методы, полиморфизм, интерфейсы и прочее, это уже конкретные механизмы, которые могут быть в одних языках (C#, Java), но могут отсутствовать в других (Javascript, GO правда они нынче растут в сторону первых, для JS-а, теперь вообще во всю используют TypeScript, в которым пилят строгую типизацию, интерфейсы и вот это вот все ), при чем все эти языки вроде как являются объектно ориентированными.

Вот как-то так я это все вижу ,чистая эзотерика мне не особо интересна в текущий момент, я есть хочу и работать, решать проблемы людей через автоматизацию .
>> No.50056 Reply
File: 1374905006_pokaytes_greshniki_large.jpg
Jpg, 50.19 KB, 426×600 - Click the image to expand
edit Find source with google Find source with iqdb
1374905006_pokaytes_greshniki_large.jpg
>>50048
> паттерны-фигаттерны
Так и скажи: наследование реализации.

>>50050
> В наследовании нет никаких проблем
Покайся.
>> No.50057 Reply
>>50055
- Можно разделить ООП на ООП с наследованием и без.
- В фп тоже можно мыслить в терминах графов и состояний - это другой уровень абстракции
- Полиморфизм можно получить через разные механизмы: например, есть механизм паттерн-матчинга. Для кого-то паттерн-матчинг намного интуитивно понятнее, чем какое-то наследование.
>> No.50058 Reply
File: _.png
Png, 53.06 KB, 577×264 - Click the image to expand
edit Find source with google Find source with iqdb
_.png
>>50056
> > В наследовании нет никаких проблем
> Покайся.
https://twitter.com/grady_booch/status/1028020194227060738
Создатель UML.
>> No.50060 Reply
>>50055
> чистая эзотерика мне не особо интересна в текущий момент, я есть хочу и работать, решать проблемы людей через автоматизацию
Чтобы просто работать каким-то программистом, абсолютно незачем забивать себе голову ООП-парадигмой.
> надо добить 7 издание Фленегана в части клиентского жс-а, потом по отдельным статьям реакт ссаный
Типичный фронтэнд-JS-разраб сайтиков не читает никаких Фленеганов, и книги от Craig Larman по ООП ему тоже нафиг не нужны, для него это как раз "эзотерика", которая нафиг не нужна для решения квадратно-гнездовых задач, за которые ему платят деньги.
>> No.50062 Reply
File: _.jpeg
Jpeg, 66.00 KB, 1280×720 - Click the image to expand
edit Find source with google Find source with iqdb
_.jpeg
>>50055
> решать проблемы людей через автоматизацию
Не всякая задача, решаемая программистом - задача об автоматизации чего-либо. Некоторые задачи вручную просто не решаются, например задачи численного моделирования какой-нибудь гидрогазодинамики - математики вручную не смогут это просчитать за вменяемое время. А некоторые задачи вообще не о каких-то практичных вычислениях, например компьютерные игры или виртуальные ассистенты в виде аниме-девочки.
>> No.50063 Reply
File: image.png
Png, 1.24 KB, 300×20 - Click the image to expand
edit Find source with google Find source with iqdb
image.png
>>50062
> задачи численного моделирования какой-нибудь гидрогазодинамики - математики вручную не смогут это просчитать за вменяемое время
В Россиюшке дело малооплачиваемое и, к сожалению, ещё и не благодарное, при этом невероятно затратное по умственным усилиям.
> некоторые задачи вообще не о каких-то практичных вычислениях, например компьютерные игры или виртуальные ассистенты в виде аниме-девочки
Достаточно узкий рынок на определенную аудиторию.
А вот бизнесовых задач валом, даже в моем миллионике. Правда в последнее время кабанчики смекнули, что среднестатистическая crm-ка покрывает их потребности на 90% просто из коробки даже без допиливания.
>> No.50064 Reply
Просто замечу, что в Совершенном коде первым делом об ООП говорится: чаще всего используется агрегация, а не наследование.
>> No.50065 Reply
Просто замечу, что не существует ни одного формального критерия оценки качества кода.
>> No.50066 Reply
Просто замечу, что качество кода исключает ООП.
>> No.50072 Reply
File: 376_1000.jpg
Jpg, 103.34 KB, 1000×664
Your censorship settings forbid this file.
r-18
>>50050
Тоже самое, но гораздо короче на пикрелейтед


Password:

[ /tv/ /rf/ /vg/ /a/ /b/ /u/ /bo/ /fur/ /to/ /dt/ /cp/ /oe/ /bg/ /ve/ /r/ /mad/ /d/ /mu/ /cr/ /di/ /sw/ /hr/ /wh/ /lor/ /s/ /hau/ /slow/ /gf/ /vn/ /w/ /ma/ /azu/ /wn/ ] [ Main | Settings | Bookmarks | Music Player ]