LINUX.ORG.RU

[philosophy] В чем заключается революционность перехода от функциональщины к ООП?


1

0

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

«Стоп», сказал я себе и подумал. Почему сейчас все кругом вопят про ООП и про его архиполезность и архиправильность? Далее, по ходу раздумий, пришел к мысли, что все, что пишется с использованием ООПшной парадигмы, может быть написано и без нее.

Почему появились языки, которые взяли ООП за главенствующую идею (java, c#, етц)?

Неужели те преимущества, которые предлагает ООП (полиморфизм, инкапсуляция, наследование), дают прирост в эффективности, скорости написания программ, понимания их работы и поддержке? Здесь было бы интересно сравнить одну и ту же программу, написанную на С и на С++, чтобы узреть принципиальные архитектурные различия (может такие уже есть?).

Сухой остаток. ООП представляет из себя еще один уровень абстракции, который позволяет оперировать про проектировании не функциями, а обьектами. А неужели это так меняет дело и делает разработку более удобной?

Было бы интересно без срачей услышать компетентное мнение.

★★

Ответ на: комментарий от LamerOk

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

обозначим длину массива а символом |a|, так вот, всем нам очевидно, что

|a+b+c+d+e|==|a+e+d+b+c|

поэтому исключения НЕ БУДЕТ, что бы пользователь не ввел; осталось это объяснить компилятору — в этом суть задачи

З.Ы. лучше бы обозначить конкатенацию массивов не +, а по-другому

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от balodja

что такое ООП?

ad-hoc полиморфизм + определенный стиль.

почему по-твоему

Ну, во-1, и то, и другое там есть.

Если нет ad-hoc'а, то нет ничего. x.f(y,z) есть не что иное, как идиотски записанное f(x,y,z).

Справедливости ради - ещё одна, достаточно объективная, классификация.

Для реализации ad-hoc'а человечество придумало два способа. Один - явное указание нужной части контекста (объекты). Другой - захват нужной части контекста автоматически (замыкания). Второй вариант для программера откровенно проще, но требует использования GC (или новомодных штучек вроде регионов) и затрудняет (хотя не исключает) рассуждения о требуемых ресурсах. По нынешним временам, это, всё-таки, больше стилистическое различие, замыкания и GC и так есть везде. Хотя, если ты не согласишься, я не стану слишком спорить.

Ну, плюс стиль программирования, да. Наличествует во всех известных мне реализациях, кроме, пожалуй, CLOS. Но первая часть, да ещё деталь о явном указании контекста, ИМХО важнее.

Во-2, всё остальное - уже совершенно косметические вещи. Та же пресловутая инкапсуляция - на уровне объектов совершенно неестественна, она нужна на уровне модулей. Наследование реализации - см. пункт про x.f(y,z) vs. f(x,y,z). Унаследованная реализация функции - это просто глобальная функция, заткнутая в неймспейс.

«Есть объекты — значит ООП».

Ну, объектом, при желании, можно назвать вообще что угодно. Больно термин расплывчатый.

Miguel ★★★★★ ()
Ответ на: комментарий от balodja

ОК, постараюсь найти невменяемость в своих вопросах и исправить.

Так а ты раньше вообще вопросов не задавал, за исключением «что почитать». Не знаю, что почитать, я никогда не запоминаю специально, из какого источника извлёк ту или иную концепцию. А технических вопросов от тебя раньше не было.

Miguel ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

при этом вариант

try{
  return scalar_product(a+b+c+d+e, a+e+d+b+c);
}catch( DifferentArrayLength ){
  return 0; /// этого быть не может, поэтому возвращаем че-то от балды, например 0
}

не годится, т.к. компилятор НЕ проверяет, что ты его убедил, а просто тебе верит; если ты там по ошибке напишешь scalar_product(a+b+c+d+e, a+e+d+b), то компилятор молча съест это, и в результате будет ошибка; компилятор должен ругнуться в этом случае — вот смысл задачи.

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

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

обозначим длину массива а символом |a|, так вот, всем нам очевидно, что


|a+b+c+d+e|==|a+e+d+b+c|


поэтому исключения НЕ БУДЕТ, что бы пользователь не ввел; осталось это объяснить компилятору — в этом суть задачи


Ооох. Ну что ж, вот тебе (не рабочий, ессно) драфт:
создаем иерархию абстрактный класс - потомок-шаблон
пораждаем шаблоны для всего диапазона от нуля до SIZE_T_MAX
создаём фабрику, которая будет возвращать порождение шаблонана на введеное значение
далее работаем с ним через ссылку на базовый класс

И всё равно придется отказаться от проверки выполнимости операции «==» на этапе компиляции, выбрасывая исключение или что-либо еще.

Как бы ты ни складывал буквы «х»,«у»,«й», слово «бронепоезд» не получится. Не существует способа заставить компилятор работать с тем значением, которое должен будет ввести пользователь во время работы программы.

Такие дела.

LamerOk ★★★★★ ()

А неужели это так меняет дело и делает разработку более удобной?

Не всегда, но чаще да. Применение ООП делает возможным решение задачи на языке задачи, а не на языке компьютера. Это очень важно.

azure ★★ ()
Ответ на: комментарий от LamerOk

драфт, действительно, не рабочий

Как бы ты ни складывал буквы «х»,«у»,«й», слово «бронепоезд» не получится.

уверяю тебя, что в плюсах имеются кое-какие дополнительные буквы; вот правда скаловские path dependent types я думаю на с++ не сделать (хотя я толком и не пытался)

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от azure

> Применение ООП делает возможным решение задачи на языке задачи, а не на языке компьютера.

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

LamerOk ★★★★★ ()
Ответ на: комментарий от Miguel

> Та же пресловутая инкапсуляция - на уровне объектов совершенно неестественна, она нужна на уровне модулей.

раскрой тему

я бы сказал наоборот — необходимость всем классам из пакета иметь доступ к их внутренностям — это пример плохой инкапсуляции; если это надо — то видимо там надо иметь доступ к одному полю, а не всем полям

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от LamerOk

> И всё равно придется отказаться от проверки выполнимости операции «==» на этапе компиляции, выбрасывая исключение или что-либо еще.

А какие значения может ввести пользователь, чтобы не выполнилась проверка |a+b+c+d+e|==|a+e+d+b+c| ?

anonymous ()
Ответ на: комментарий от LamerOk

> Ну так сложи из них «бронепоезд» - делов-то!

сложил уже В — но там могут быть претензии; а еще есть драфт на А; но может и правда не вылизывать их надо, а выложить для критики

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от azure

> Применение ООП делает возможным решение задачи на языке задачи, а не на языке компьютера. Это очень важно.

Хм, всегда думал, что это DSL называется, а не ООП. И как ООП способствует написанию DSL'ей?

balodja ★★★ ()
Ответ на: комментарий от Miguel

Уже потихоньку начинает проясняться. Пищу для ума получил, спасибо.

balodja ★★★ ()
Ответ на: комментарий от anonymous

> А какие значения может ввести пользователь, чтобы не выполнилась проверка |a+b+c+d+e|==|a+e+d+b+c| ?

Речь идет не о выполнении проверки, а об условии. (Т.е. такая проверка гарантированно возвращает true).

LamerOk ★★★★★ ()
Ответ на: комментарий от azure

Применение ООП делает возможным решение задачи на языке задачи, а не на языке компьютера.

Смешно, да.

Miguel ★★★★★ ()
Ответ на: комментарий от LamerOk

> Не существует способа заставить компилятор работать с тем значением, которое должен будет ввести пользователь во время работы программы.

Существует возможность дать компилятору знать, какое значение ввел пользователь.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Ну только если встроить компилятор в программу

oh ()
Ответ на: комментарий от www_linux_org_ru

необходимость всем классам из пакета иметь доступ к их внутренностям — это пример плохой инкапсуляции; если это надо — то видимо там надо иметь доступ к одному полю, а не всем полям

Придумай пример, когда это - признак плохай инкапсуляции, и ты получишь пример плохого разбиения на модули/пакеты. Ты хочешь дополнительных гарантий, хочешь, чтобы вот из этого куска была видна только эта функция, а эта - нет? Убери обе функции в другой пакет, и сэкспортируй оттуда одну из них. Делов-то.

Ну, конечно, другой вопрос, если наш язык не позволяет (или не способствует) правильно делить на модули. Но это уже недостатки языка.

Speaking of which, одна из постоянно возникающих в хаскельном сообществе тем - решение «один модуль - один файл». Многие хотят иметь несколько модулей в одном файле, как в той же жабе.

Miguel ★★★★★ ()
Ответ на: комментарий от LamerOk

Поведай его, если не миру, то хотя бы мне.

Например:

int x = input_some_number();
if(x < 0 || x > 15) return;

/* Всё, здесь и далее - уже сообщили, что всегда (0 <= x < 16) */

anonymous ()
Ответ на: комментарий от tailgunner

> Существует возможность дать компилятору знать, какое значение ввел пользователь.

не так, а вот так:

Существует возможность дать компилятору знать, по какому адресу лежит значение, которое ввел пользователь.

хотя это тоже поймет не каждый, а кто знает :-)

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

А если встроить компилятор в программу?

oh ()
Ответ на: комментарий от oh

Проверки на стадии компиляции так и не происходит.

После комментария - это самое настоящее статическое условие. Суть в том, что хотя кое-где может и придётся делать проверку - для большей части программы (а там после комментария например 10000 строк кода) можно всё вполне проверять в статике, на этапе компиляции.

anonymous ()

по теме |a+b+c+d+e|==|a+e+d+b+c|:

понятней, наверно, будет, когда я запощу свой код, и сделаю это отдельной темой (заодно напишу задачу с учетом того непонимания, что здесь было высказано)

а тут у нас еще есть темы для флейма, хотя бы

1. ограничения видимости (public private protected) — это часть ООП или системы модулей?

2. что лучше — ООП на классах, ООП на замыканиях (или внезапно ООП на основе хаскеля, как сделал олег)?

ну и я бы хотел разобраться, если ли случаи, когда решение на хаскеле более статично, чем на с++ (торможу уже, было тут давно...)

www_linux_org_ru ★★★★★ ()
Ответ на: комментарий от oh

> Что «всё»? Всё, что не зависит от входных данных? Всё что зависит от переменной 'x' и других, для которых также мы сообщили компилятору информацию об их значениях.

anonymous ()
Ответ на: комментарий от archimag

так что трудно понять что именно ты утверждаешь.

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

Другой тест. Тошнит ли вас от чрезмерного употребления другими слова «практика»?

  • Да, ужасно задолбало читать это слово.
  • Нет, что может быть важнее Практики! Это не теория какая-нибудь.
dave ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

> 1. ограничения видимости (public private protected) — это часть ООП или системы модулей?

А может классы в с++/java-варианте ООП обладают свойствами модулей. И именно поэтому определяют видимость (видимость кстати или доступность?) своих членов.

2. что лучше — ООП на классах, ООП на замыканиях

ООП - програмирование на объектах

ООП на классах - классы определяют интерфейс, поведение и стурктуру объектов.

ООП на замыканиях - ? Замыкания замыкают чего?

Замыкания - это объекты? Тогда объекты сами определялют свое поведение, и структуру? Среди объектов цветет анархия.

Замыкание - это «фабрика» принимающая и возвращающая объекты? Быстренько называем это ФП (ну или SOA), и объявляем что объекты отныне, просто тип данных и для верности обрываем все выросшие методы по образу структур.

Но вспомнив что замыкание замыкает контекст и код в функцию. И от того как в «„ООП с замыканиями“ будет введено понятие понятие окружения/контекста будет зависить какое ООП получится. Может получится что ООП, совмещенное с замыканиями, вобще внезапно переродится или исчезнет. P. S. Код здесь нужно понимать как композицию объектов которую можно скормить транслятору.

antares0 ★★★ ()
Ответ на: комментарий от antares0

Присоединяюсь к вопросу, а что такое «ООП на замыканиях»?

Кстати, смешение ООП и ФП иногда приводит к казусу с модификатором protected, когда из лямбды пытаемся достучаться до метода или поля protected. Как бы в доступе должно быть отказано. В C# есть признанная ошибка компилятора, когда код компилируется, но не работает (может быть, исправили в 4-й версии). В F# protected явно запрещен, хотя неявно все же поддерживается (при наследовании). В общем, не все гладко.

dave ★★★★★ ()
Ответ на: комментарий от dave

>Кстати, смешение ООП и ФП иногда приводит к казусу с модификатором protected, когда из лямбды пытаемся достучаться до метода или поля protected. Как бы в доступе должно быть отказано.

если лямбда определяется 'по месту', то почему? Те-же вложенные классы в джавке имеют доступ ко всему.

yyk ★★★★★ ()
Ответ на: комментарий от antares0

> ООП на классах - классы определяют интерфейс, поведение и стурктуру объектов.

CLOS — «ООП на классах», но классы не определяют поведение объекта

korvin_ ★★★★★ ()
Ответ на: комментарий от www_linux_org_ru

> Существует возможность дать компилятору знать, по какому адресу лежит значение, которое ввел пользователь.

А толку? Использовать это значение компилятор всё равно не может. Максимум, что можно, я уже показал - нагенерить всё множество значений. Конечно, дальше можно определить по введеному значению конкретный адрес и вообще воспользоваться старым добрым void *, но компилятору от этого ни тепло, ни холодно.

LamerOk ★★★★★ ()
Ответ на: комментарий от anonymous

> После комментария - это самое настоящее статическое условие.

Не стоит столь публично демонстрировать незнание самых простых терминов. Даже из под анонимуса.

LamerOk ★★★★★ ()
Ответ на: комментарий от LamerOk

Максимум, что можно, я уже показал - нагенерить всё множество значений.

В языках с зависимыми типами - можно не только это.

Другой вопрос, что пока эти языки несколько, так скажем, многословны. Более, чем, скажем, жаба.

Miguel ★★★★★ ()
Ответ на: комментарий от dave

Присоединяюсь к вопросу, а что такое «ООП на замыканиях»?

Имеется в виду, видимо, ad-hoc на замыканиях.

Ещё раз, для ясности: человечество придумало два варианта реализации ad-hoc: классы, где явно прописывается всё, что нужно будет данному объекту для работы, и замыкания, где нужное берётся из контекста автомагически. Первое допускает ручное управление памятью, второе - не очень (хотя такие вещи как capability calculus, возможно, помогут и с этим).

Miguel ★★★★★ ()
Ответ на: комментарий от yyk

если лямбда определяется 'по месту', то почему? Те-же вложенные классы в джавке имеют доступ ко всему.

Да я бы тоже этого хотел. Мне очень не хватает protected в f# (и многих это раздражает). Но, видимо, проблема в том, что замыкание генерится на уровне IL как отдельный невложенный класс. Потому доступа нет. Похоже, все обламывается на этапе верификации кода IL во время загрузки или что-то типа того.

В общем, создатели f# решили просто запретить protected от греха по дальше. Подозреваю, что настоящее решение потребует какого-то изменения верификатора или генерации замыканий через вложенные классы. Возможно, с последним есть проблемы (модули ??). Надо бы глянуть, что они там сделали в с# v4 по этому поводу. Подозреваю, что просто ограничили компилятор.

dave ★★★★★ ()
Ответ на: комментарий от Miguel

> человечество придумало два варианта реализации ad-hoc

Извините, но вы вообще смысл словосочетания ad-hoc понимаете? А то вы им так пользуетесь, как будто оно имеет самостоятельное значение. Кроме того, я никогда не встречал использования термина «ad-hoc полиморфизм» вне контекста Haskell. Но полиморфизм в Haskell это вообще нечто особенное, что не вполне соответствует понимаю данного термина в других языках. Что вы всё в кучу сваливаете?

archimag ★★★ ()
Ответ на: комментарий от archimag

> Извините, но вы вообще смысл словосочетания ad-hoc понимаете?
Опечатался, наверное

Кроме того, я никогда не встречал использования термина «ad-hoc полиморфизм» вне контекста Haskell.

А я встречал, ЧЯДНТ?

Но полиморфизм в Haskell это вообще нечто особенное, что не вполне соответствует понимаю данного термина в других языках.

Почему?

oh ()
Ответ на: комментарий от archimag

А то вы им так пользуетесь, как будто оно имеет самостоятельное значение.

Вам обидно, что я не добавляю слово «полиморфизм»? А зачем? И так всем всё понятно.

Кроме того, я никогда не встречал использования термина «ad-hoc полиморфизм» вне контекста Haskell.

Я встречал, хотя не очень часто. Просто в мейнстримных языках до недавнего времени другого-то и не было. А когда ничего другого нет, зачем изобретать какие-то отдельные термины?

Короче говоря, в других контекстах опускают слово «ad-hoc» так же, как я опускаю слово «полиморфизм».

Miguel ★★★★★ ()
Ответ на: комментарий от Miguel

> Просто в мейнстримных языках до недавнего времени другого-то и не было.

Какого другого? ООП в мейнстримных языках вообще, и полиморфизм в частности, не является ad-hoc полиморфизмом как его понимают в Haskell. Какой вы вообще вкладываете смысл в этот термин?

И ещё, виртуальные функции, шаблоны и частичная специализация шаблонов в С++ (коим уже более 15 лет) - вы всё это называете ad-hoc полиморфизмов? Перестаньте бредить.

archimag ★★★ ()
Ответ на: комментарий от archimag

> Какого другого?

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

paranonymous ()
Ответ на: комментарий от archimag

ООП в мейнстримных языках вообще, и полиморфизм в частности, не является ad-hoc полиморфизмом как его понимают в Haskell.

Really? Не расскажете об отличиях?

виртуальные функции,

Да.

шаблоны и частичная специализация шаблонов в С++

Нет, это препроцессор.

Miguel ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.