G>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу. Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
Re[10]: Почему объектно-ориентированное программирование про
S>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.
S>Т.е. как бы можно взять за основу ФП декомпозицию, подменить кортежи бездушными структурами, АДТ подменить на гомоморфные иерархии, где в базе будет абстрактный интерфейс, составленный из набора функций, работающих с этим АДТ. Иммутабельность сохраняется.
Бенефит потоковой безопасности достигается так же локальностью ссылок. Тем не менее, иммутабельность на этапе обработки данных дает очень важное кач-во при последующей смене состояния. Ниже пройдусь.
S>В итоге получается как бы и ООП, но с ФП дизайном.
ФП-подход — это подход, ориентированный на функции высших порядков, как я себе представляю, чем он отличается от обычного процедурного подхода. Конечно, тоже полезная штука для абстрагирования, но скорее как инструмент для избавления от лишних зависимостей и от россыпи маленьких интерфейсов, чем как цель дизайна.
S>В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.
ФП подход сидит на алгоритмической декомпозиции. А та принципиально меньше тяготеет к рефакторингу, т.к. зависимостей в рамках одной ф-ии всяко меньше, чем сразу у группы оных.
Как уже тут было упомянуто, тяга к инкапсуляции подробностей реализации в больших ООП-проектах оборачивается тем, что приличная часть функционала делается многократно, но "чуть чуть" уникально для каждого объекта. И рефакторинг, помимо прочего, постоянно борется и с этим, по мере выявления схожей функциональности в соседних иерархиях. Т.е, хотя ООП и было призвано обеспечивать большее повторное применение кода, я пока вижу несколько обратное. А если бы сия функциональность была сразу доступна на уровне, скажем, модуля? Но это тоже не просто, ведь мы работаем с внутренним состоянием объектов. А что, если это состояние составлять из неких "стандартных кубиков" под нашу задачу? Мы ведь в процессе тщательного рефакторинга и объектной декомпозиции и так к этому приходим, правильно? За много итераций. Но в случае процедурного подхода, и аналогично ФП-подхода, мы вынуждены эти "стандартные кубики" разрабатывать сразу, как результат попытки реализации функциональных требований к программе. По-сути, мы вынуждены будем разработать представление/абстракции ДАННЫХ, и завязать их на алгоритмы по их трансформации. В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает. Применяя технику ООП, сии кубики можно сделать во-первых безопасными (располагаем инструментом инкапсуляции), во-вторых, нарисовать им удобный АПИ. Ну и согласен, гомоморфные наборы этих кубиков, если делать на ООП — вообще убийственная сила в плане прозрачности дизайна.
А что собственно произошло? Мы позволили процедурам и функторам принимать как аргументы и возвращать как результат объекты. Отличное дополнение к алгоритмической декомпозиции. Далее. Пытаемся реализовать ту самую функциональность, которая идет как функциональные требования. (Без всяких глобальных переменных, по крайней мере без мутабельных). В каких-то местах мы видим, что упираемся. Это происходит при надобности в какой-то точке вычислений обеспечить персистентность данных м/у вызовами. Т.е. сохранить состояние. Вот! Усек что произошло? Вместо заведомого "от балды" рисования семейства объектов-акторов, как участников "первого варианта дизайна" (который будет потом многократно перерефакторен), мы выходим на список объектов как бы автоматически, через мн-во состояний, требующих персистентности. И уже с готовыми "кубиками" наперевес, так что составить из них в нужном месте композицию получается совсем простым делом. Утрирую, понятно, но очень близко к происходящему.
S>Пробег. Информация безусловно полезная, но применительно к дизайну, она просто добавит карандашей, которые нужно сгрызть.
Вообще-то фокус был на порядок работ, чтобы минимизировать кол-во съеденных карандашей. По мне рефакторинг и есть перманентная грызня карандаша, только уже с помощью мышки и клавы.
V>>А не обязательно чистое ФП, со всеми модными фокусами. ФП сидит на функциональной декомпозиции, а это практически первое, чему учатся при обучении программированию. S>Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина.
Ты поменьше функциональщиков слушай.
Я тут многократно предлагал взглянуть на объекты как на автоматы (а они и есть автоматы), и позаимствовать оттуда кой-чего. Чем преобразователь-автомат отличается от простой цифровой функции? Наличием памяти. Cтруктура автомата (Мура) такова:
1. функция выходов, которая вычисляется от ф-ии входов и текущего состояния.
2. функция вычисления следующего состояния от входов и текущего состояния.
3. собственно память для хранения состояния.
п.п.1-2 абсолютно "чисты" с т.з. ФП, что как бэ намекает на уместность применения этого подхода для реализации объекта-автомата.
Вернемся к нашему подходу. Итого, "универсальные кубики", представляющие данные для сохранения в "памяти", уже есть. Ф-ия вычисления след. состояния, то бишь ф-ия обработки этих кубиков, тоже есть — мы с нее начали разработку. Теперь нам собрать "автомат", то бишь объект из этого — вовсе элементарно. И при этом новое состояние мы можем менять транзакционно (как работает регистр-защелка в цифровой электронике), тогда мы не будем иметь вообще никакой возможности вогнать автомат в невалидное состояние. Т.е. отделив в явном виде ф-ии вычисления след. состояния от собственно шага обновления состояния, мы можем добиться уникального в плане надежности качества — устойчивости к исключениям. Скажу по секрету, что сей устойчивостью 99% современного кода не обладают, потому как изменяют свое состояние обычно "постепенно", по мере работы. Т.е. объекты обычно ходят по промежуточным состояниям, и в случае исключения могут там и остаться. И что обычно происходит? Зачеркивается целиком всё, потому как разработка кода восстановления после ошибки больно трудоемка. В итоге, мы отказываемся еще от одной полезной практики, под названием "let it fail".
Еще момент. В многопоточных программах мы упомянутую "всевдоатомарность" пытаемся разрулись через примитивы синхронизации. Помимо того, что это не спасает от проблемы устойчивости к исключениям, мы еще блокируем эти примитивы на довольно долгий срок всех промежуточных вычислений (в общем случае). Хотя, это и так надо делать для случая писателей, но ведь это вовсе не нужно для случая читателей! Обрати внимание на изящное решение популярной проблемы читателей/писателей, получаемое вместе с транзакционностью, когда мы стадию вычисления следующего состояния отделили от операции по его обновлению.
Почему же функциональщики так жужжат о вреде смешения парадигм? Тут стоит вспомнить, что в деле разработки ПО всегда была куча вопросов, которые хотелось вывести на кончике пера, но они были для общего случая недоказуемы. Из-за той самой проблемы останова и прочих. Однако, было показано, что при наличии неких ограничений, под многое становится возможным подвести точную теорию. В итоге, "чистое ФП" — это наиболее ограниченная техника на сегодня, но благодаря ограниченности — единственная, имеющая хоть какой-то мат.аппарат. Поэтому, при нарушении наложенных ограничений, весь этот матаппарат нарушается. Но это с т.з. ФП. Что касается ООП, то он наоборот, обогащаемся целым набором замечательный св-в. Бери цифровую электронику. Это почти ООП (КОП в чистом виде) — интерфейсы и их реализации. И никто не страдает, что на одной плате есть как "чистые" цифровые ф-ии, так и россыпь автоматов. Прекрасно оно совместно работает. За счет той самой транзакционности смены состояний автоматов. Справедливости ради, в тех местах, где смена состояний растягивается на несколько шагов, в цифровой технике начинаются те же проблемы, что в ООП. И рядом сажают watch-dog таймеры, которые делают сброс охраняемой схемы, если её переклинило/зациклило в невалидном состоянии.
S>Я бы сказал что знаком с китом, а не владею.
Не скромничай. Создание делегата по нестатическому методу — это всегда замыкание, еще со времен первого дотнета. А ты наверняка делегатов насоздавал за свою практику уже немало.
S>В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.
Дык, а boost:bind? А старые добрые std::bind1st, std::bind2nd? Та же фигня. А слоты и сигналы QT?
S>Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.
Наверно, от образа мыслей зависит. По мне ФП хорошо, пока мы производим вычисления, и плохо, когда нам результат этого вычисления надо куда-то девать. Монада IO в Хаскеле как раз помечает те места, где "чистое ФП" умывает руки.
S>ООП ведь не запрещает анализ!
Ни одна методология не запрещает. Мое ИМХО о том, что ООП поощряет начинать сразу с квадратиков.
S>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи.
Это в конкретном месте детали свежи. А если имеем несколько накопленных TODO, то можно попытаться обозреть проблему чуть более со стороны. И часто бывает так, что удовлетворяя один из них, можно удовлетворить целую пачку. В общем, перед решением любой задачи, желательно как можно больше вводных/требований. Хотя, каждый случай уникальный, понятно, и универсальных советов тут нет. Совет "рефакторить сразу" так же далек от универсальности.
S>TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция.
Именно. Порой лучше оставить TODO с обозначением временного решения, до прояснения, с чего вообще такая ситуация возникла. При разделении труда в команде, с помощью этих TODO люди создают друг другу требования к внутреннему АПИ/функциональности, а современные IDE прекрасно составляют из них список в отдельном окошке.
S>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
Ну естественно, функциональные требования в приоритете над требованиями дизайна. Но они обычно для удовлетворения требуют не столько рефакторинга, сколько доработки функциональности, что как бэ слегка иное.
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
V>Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу.
Я тоже не видел. Более того, сама парадигма ООП этому противоречит.
V>Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
typeclasses в хаскеле.
Re[17]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Ikemefula, Вы писали:
I>>Покажи как твой декоратор можно протестировать в изолированом виде
V>Ну блин, техника изоляции при тестировании всегда одна — через заглушки. А способов исполнения сих заглушек множество:
Я скипнул порожний текст. Покажи, как ТВОЙ декоратор можно протестировать в изолированом виде.
Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
Re[29]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально. I>>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
V>Все ясно. Что есть по твоему "состояние"?
Элементарно — персистед данные.
I>>Это в С++, сочувствую.
V>При чем тут С++, если в дотнете есть статические методы и поля. Это и есть "глобальное состояние". Для дотнета, правда, ограниченное доменом, но для нашего обсуждения не принципиально. А характер получаемой инкапсуляции сравним с оной в модулях.
Принципиально. Состояния может и не быть, а зависимость будет в любом случае.
I>>Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.
V>Декомпозиция — это разбиение сложного решения на части. Сам термин в чистом виде относится к случаю, когда сохраняется исходная функциональность, хотя мы тут его используем порой вольно, угу. В случае развития функциональности, как в твоем примере, тут минимум 2 шага: сначала декомпозиция исходного решения, потом его доработка.
Вот посмотри внимательно ан мои примеры, я ажно дважды показал разбиение сложного решения на две части.И там и там разбиение по функциональному признаку.
I>>Ога, сделать жосткую зависимость от другого класса
V>Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.
// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,class PreAndPostDecorator : ThirdPartyClass // вот это жосткая зависимость
{
public void PreDo() {}
public void PostDo() {}
}
// структурная композицияclass PreAndPostDoerDecorator : IDoer
{
private PreAndPostDecorator _decorator = new PreAndPostDecorator(); // и это жосткая зависимость
PreAndPostDoerDecorator(IDoer doer){ _doer = doer;}
void Do() {
_decorator.PreDo();
_doer.Do();
_decorator.PostDo();
}
}
I>>Опаньки, щас ты снова заговорил про связанность
V>Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?
Ранее ты вещал про состояние
V>Нет, я хочу понять — почему именно так. Т.е. выйти на "локальное ТЗ".
Уже давно было дадено это "локальное ТЗ".
I>>Это тот же декоратор При том не самый удачный.
V>Не надо пытаться натягивать туда паттерны ООП, бо его там не осталось. В ФП чуть менее чем все паттерны пляшут от трех базовых комбинаторов и техники частичного применения.
Адаптер это паттерн более древний, чем ООП
I>>Например потому что есть зависимость от классов Context и DoerModule.
V>Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer.
Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.
V>>>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?
I>>объект == функциональный элемент
V>С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.
Это в с++ тбе надо искать состояние.
Re[31]: Почему объектно-ориентированное программирование про
I>>Да, круто. Это равносильно обычному вызову AcceptDoer
V>Это абстрагирование от конкретного AcceptDoer. Почувствуй разницу.
"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "
Нахрена тебе AcceptDoer менять и абстрагироваться ?
Еще раз
1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода.
2 Есть конкретная реализация IDoer. Её модифицировать можно.
3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.
Задача — модифицировать поведение AcceptDoer для ВСЕХ IDoer.
Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Re[24]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
G>>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.
V>Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу. Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
Вот это агрегирование базы ты похоже и называешь "разделение состояния"
Re[10]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
Традиционному ООП это никак поперек горла быть не может
V>>Всё-равно автоматически по достижении некоторого порога. Однажды становится трудно просто прочесть код, даже если он хорош. И единственно правильное решение — декомпозировать, передокументировать и прочесть заново. Это может сэкономить часы и это дополнительный review кода. Оно как эффект катастрофы в природе, во вменяемой команде выполняется на автомате всеми участниками. S>(выделил чуть выше) S>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи. TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция. S>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
Любой код имеет свой цикл жизни. Рефакторинг удлинняет этот цикл жизни. Но сделать бесконечным просто не получится. Ну и издержки по вермени/деньгами никто не отменял. В конечном итоге становится проще выбросить хотя бы некоторые части и написать их заново.
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>...Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
V>У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.
Не совсем так. поведение функции может зависеть от состояния извне, переданного аргументом. Ключевое отличие — внутри или снаружи. Но и это отличие тает при упоминании о том что состояние передается неявно через this. Остается совсем незначительная деталь, отделяющая чистую функцию от метода объекта — функция не может менять внутреннюю память аргумента. (Уверен, ты все это знаешь. Я просто описываю ракурс, под которым я вижу немалую схожесть функции и объекта.) В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
V>Бенефит потоковой безопасности достигается так же локальностью ссылок. Тем не менее, иммутабельность на этапе обработки данных дает очень важное кач-во при последующей смене состояния. Ниже пройдусь.
потоковую безопасность я пока даже не рассматриваю.
V>ФП-подход — это подход, ориентированный на функции высших порядков, как я себе представляю, чем он отличается от обычного процедурного подхода. Конечно, тоже полезная штука для абстрагирования, но скорее как инструмент для избавления от лишних зависимостей и от россыпи маленьких интерфейсов, чем как цель дизайна.
Естественно ФП не цель, а средство.
S>>В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.
V>ФП подход сидит на алгоритмической декомпозиции. А та принципиально меньше тяготеет к рефакторингу, т.к. зависимостей в рамках одной ф-ии всяко меньше, чем сразу у группы оных.
V>Как уже тут было упомянуто, тяга к инкапсуляции подробностей реализации
извиняюсь, я буду скипать лирику, против которой ничего не имею.
V>А что, если это состояние составлять из неких "стандартных кубиков" под нашу задачу? Мы ведь в процессе тщательного рефакторинга и объектной декомпозиции и так к этому приходим, правильно? За много итераций.
да, но я все время пытаюсь перевести разговор в следующее русло: что бы было, если бы ООП кубики строили с ФП конца.
V>Но в случае процедурного подхода, и аналогично ФП-подхода, мы вынуждены эти "стандартные кубики" разрабатывать сразу, как результат попытки реализации функциональных требований к программе. По-сути, мы вынуждены будем разработать представление/абстракции ДАННЫХ, и завязать их на алгоритмы по их трансформации.
да. А теперь возьмем и нарисуем ООП кубики по ФП наброску.
V>В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает.
Слишком быстрый переход. Почему АПИ не нарисуешь? Рисовать можно все что угодно, кроме способов изменения внутренних состояний.
V>Применяя технику ООП, сии кубики можно сделать во-первых безопасными (располагаем инструментом инкапсуляции), во-вторых, нарисовать им удобный АПИ.
они абсолютно безопасные. инкапсуляция ФП не противоречит. И АПИ на иммутабельных объектах тоже может быть удобным, разве что менее привычным.
V>Ну и согласен, гомоморфные наборы этих кубиков, если делать на ООП — вообще убийственная сила в плане прозрачности дизайна.
Согласен. Но ничто не мешает ОО кубикам, построенным из ФП декомпозиции лежать в гомоморфной иерархии.
V>А что собственно произошло? Мы позволили процедурам и функторам принимать как аргументы и возвращать как результат объекты. Отличное дополнение к алгоритмической декомпозиции. Далее. Пытаемся реализовать ту самую функциональность, которая идет как функциональные требования. (Без всяких глобальных переменных, по крайней мере без мутабельных). В каких-то местах мы видим, что упираемся. Это происходит при надобности в какой-то точке вычислений обеспечить персистентность данных м/у вызовами. Т.е. сохранить состояние. Вот! Усек что произошло? Вместо заведомого "от балды" рисования семейства объектов-акторов, как участников "первого варианта дизайна" (который будет потом многократно перерефакторен), мы выходим на список объектов как бы автоматически, через мн-во состояний, требующих персистентности. И уже с готовыми "кубиками" наперевес, так что составить из них в нужном месте композицию получается совсем простым делом. Утрирую, понятно, но очень близко к происходящему.
Т.е. ты предлагаешь вставлять мутабельные объекты там где требуется персистентность состояний между вызовами. Остается вопрос где грань между требуется и не требуется. Ведь ФП предлагает средства по передаче состояний между вызовами без персистентности (рекурсия, монада state, зиппер). На самом деле вопрос о грани между требуется и не требуется ли персистентность — очень скользкий. Легко впасть в крайность, когда она требуется везде — получаем голый императив, не требуется нигде — чистое ФП, или местами — гибрид.
V>Вообще-то фокус был на порядок работ, чтобы минимизировать кол-во съеденных карандашей. По мне рефакторинг и есть перманентная грызня карандаша, только уже с помощью мышки и клавы.
Да, так и есть. Вместо витания в облаках, точится код во плоти. И не только перманентная грызня, но и персистентная. А значит требует больше ресурсов.
S>>Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина.
V>Ты поменьше функциональщиков слушай.
Наоборот, хотел бы послушать.
V>Я тут многократно предлагал взглянуть на объекты как на автоматы (а они и есть автоматы), и позаимствовать оттуда кой-чего. Чем преобразователь-автомат отличается от простой цифровой функции? Наличием памяти. Cтруктура автомата (Мура) такова:
согласен, объекты есть автоматы. V>п.п.1-2 абсолютно "чисты" с т.з. ФП, что как бэ намекает на уместность применения этого подхода для реализации объекта-автомата.
память автомата может быть не только внутри объекта. Её может предоставлять клиент автомата, потому автоматы могут быть абсолютно чистыми, впрочем вместе с клиентами (http://www.rsdn.ru/article/haskell/HaskellStateMachine.xml
).
V>Вернемся к нашему подходу. ... Т.е. отделив в явном виде ф-ии вычисления след. состояния от собственно шага обновления состояния, мы можем добиться уникального в плане надежности качества — устойчивости к исключениям. ... В итоге, мы отказываемся еще от одной полезной практики, под названием "let it fail".
Интересный момент, но не пойму, какое это имеет отношение к обсуждаемым материям.
V>Обрати внимание на изящное решение популярной проблемы читателей/писателей, получаемое вместе с транзакционностью, когда мы стадию вычисления следующего состояния отделили от операции по его обновлению.
да, изящно.
V>Почему же функциональщики так жужжат о вреде смешения парадигм? ... Бери цифровую электронику. Это почти ООП (КОП в чистом виде) — интерфейсы и их реализации. И никто не страдает, что на одной плате есть как "чистые" цифровые ф-ии, так и россыпь автоматов.
Дык в ФП автоматы сплошь и рядом. Те же функции можно рассматривать как автоматы. Ленивость — автомат. Никто не страдает что свиду чистые функции являются фактически автоматами.
S>>Я бы сказал что знаком с китом, а не владею.
V>Не скромничай. Создание делегата по нестатическому методу — это всегда замыкание, еще со времен первого дотнета. А ты наверняка делегатов насоздавал за свою практику уже немало.
конечно насоздавал. Но владение китом не приравнивается к использованию делегатов. Даже не рядом. Все равно что говорить о владении ООП человеком, написавшему Console.WriteLine("hello world") на том основании что строка есть объект
S>>В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.
V>Дык, а boost:bind? А старые добрые std::bind1st, std::bind2nd? Та же фигня. А слоты и сигналы QT?
boost-а и QT нет в текущем проекте, а std::bind*** покрывает довольно мало сценариев.
S>>Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.
V>Наверно, от образа мыслей зависит. По мне ФП хорошо, пока мы производим вычисления, и плохо, когда нам результат этого вычисления надо куда-то девать. Монада IO в Хаскеле как раз помечает те места, где "чистое ФП" умывает руки.
Да, но при совмещении техник (при отказе от матаппарата ФП) эти места становятся недостойными внимания.
S>>ООП ведь не запрещает анализ!
V>Ни одна методология не запрещает. Мое ИМХО о том, что ООП поощряет начинать сразу с квадратиков.
Да. Если в программе должно выстрелить ружье, то в ООП программе появляются риски возникновения квадратиков "ружье", "стрелковое оружие", "оружие", "оружие с курком", "оружие с магазином" и т.п. Причем процесс этот довольно занимательный
S>>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи.
V>Это в конкретном месте детали свежи. А если имеем несколько накопленных TODO, то можно попытаться обозреть проблему чуть более со стороны. И часто бывает так, что удовлетворяя один из них, можно удовлетворить целую пачку. В общем, перед решением любой задачи, желательно как можно больше вводных/требований. Хотя, каждый случай уникальный, понятно, и универсальных советов тут нет. Совет "рефакторить сразу" так же далек от универсальности.
Мне кажется что это особенности именно ООП рефакторинга, т.к. один и тот же объект (а то и в разных состояниях) встречается в различных местах кода. Изменяя какой-то аспект поведения объекта, либо его члены, приходится думать, а как это повлияет на код в другом месте. Особенно заметно при нарушениях SRP. И действительно, рефакторить такие места нужно представляя все сценарии использования объекта, а не местячково.
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
V>>У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие. S>Не совсем так. поведение функции может зависеть от состояния извне, переданного аргументом. Ключевое отличие — внутри или снаружи. Но и это отличие тает при упоминании о том что состояние передается неявно через this. Остается совсем незначительная деталь, отделяющая чистую функцию от метода объекта — функция не может менять внутреннюю память аргумента. (Уверен, ты все это знаешь. Я просто описываю ракурс, под которым я вижу немалую схожесть функции и объекта.) В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
Какие паттерны из ООП не перенесут иммутабельности ?
Re[11]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.
I>Традиционному ООП это никак поперек горла быть не может
Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
S>>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.
I>Любой код имеет свой цикл жизни. Рефакторинг удлинняет этот цикл жизни. Но сделать бесконечным просто не получится. Ну и издержки по вермени/деньгами никто не отменял. В конечном итоге становится проще выбросить хотя бы некоторые части и написать их заново.
Конечно и так бывает. Хоть это уже технически рефакторингом не называется, но все еще относится к обсуждаемым материям. Можно например назвать общим словом "улучшайзинг". А можно смотреть на рефакторинг чуть шире, чем того требует определение. Ведь целью рефакторинга не является сохранение функциональности само по себе. Иногда нужно и ломать, что бы на том месте строить что-то новое.
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
I>Какие паттерны из ООП не перенесут иммутабельности ?
например Iterator, Observer, State
Re[12]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>Традиционному ООП это никак поперек горла быть не может S>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
При чем здесь замена ПМ полиморфизмом ?
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.
I>>Какие паттерны из ООП не перенесут иммутабельности ? S>например Iterator, Observer, State
Переносят
yield break на первые два а для State не обязательно хранить ссылку
Re[13]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Традиционному ООП это никак поперек горла быть не может S>>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
I>При чем здесь замена ПМ полиморфизмом ?
притом что type test не кошерен по ООП
Re[30]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>>>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.
V>>Все ясно. Что есть по твоему "состояние"?
I>Элементарно — персистед данные.
А ссылка на другой объект в это понятие входит?
I>Принципиально. Состояния может и не быть, а зависимость будет в любом случае.
Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.
I>Вот посмотри внимательно ан мои примеры, я ажно дважды показал разбиение сложного решения на две части. И там и там разбиение по функциональному признаку.
Еще раз крупными буквами — не обязательно, коль декоратор после переработки объектов использует такую функциональность, которая после декомпозиции не нужна в исходном Doer. Давай ты уже сосредоточишься на этом моменте. Бо надоело.
I>>>Ога, сделать жосткую зависимость от другого класса
V>>Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.
Хм, я же попросил, во избежание подобного копирования всего кода, конкретно указать зависимую пару (или пары). Ты не справился.
В общем, тебе стоит показать, что сия зависимость не идет в исходном коде по условию задачи. Ты же сам сказал, что присутствует некий дополнительный игрок — еще один класс, который мы не можем изменять. Будь добр, подкорректируй свой пример с учетом этого, и только потом покажи список лишних зависимостей, через простое перечисление, которые я ввел, в сравнении с твоим уточненным примером.
I>>>Опаньки, щас ты снова заговорил про связанность
V>>Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?
I>Ранее ты вещал про состояние
Невнимателен. Вещалось про наиболее значимую метрику, которая отражает степень связанности методов объекта с его собственным состоянием.
I>Уже давно было дадено это "локальное ТЗ".
Ладно, попахивает непрошибаемостью и незамутненностью сознания. Если ты не хочешь проработать собственный пример, с учетом собственных дополнений, давай договоримся прикрыть эту лавочку.
I>Адаптер это паттерн более древний, чем ООП
Черт. А фасад? А фабрика с одним методом тогда что? А почему в ФП не рассматривают эти приемы, как отдельные паттерны? Эх коллега, напряг бы что ли, кой чего... Может, в ФП не делают разницы от того, что наличие единственной ф-ии без описания ролей каждого из ее аргументов и истории её создания не позволит восстановить/распознать все происходящее за кулисами? Ведь по сигнатуре "SomeObj func(int arg)" никогда не скажешь, адаптер это, или фабрика.
V>>Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer.
I>Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.
Вот надо поменьше говорить, побольше делать. В исходном примере можно было уже сто раз показать свой "особый случай", введя тот самый пресловутый некий класс, о котором так долго говорили большевики (С), и наличие которого для тебя является "элементарным и очевидным". Нам ты пока мест предлагаешь просто поверить тебе на слово. Не прокатит. Ближе к делу! Нарисуй еще раз.
V>>С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.
I>Это в с++ тбе надо искать состояние.
Ваш сын еще и курит. А тигру в зоопарке мясо не докладывают.
Re[15]: Почему объектно-ориентированное программирование про
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>>>Какие паттерны из ООП не перенесут иммутабельности ? S>>например Iterator, Observer, State
I>Переносят
I>yield break на первые два
можно подробнее?
I> а для State не обязательно хранить ссылку
в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
Re[31]: Почему объектно-ориентированное программирование про
Здравствуйте, vdimas, Вы писали:
I>>Элементарно — персистед данные.
V>А ссылка на другой объект в это понятие входит?
Если персистед, то да. Если нет — то нет
I>>Принципиально. Состояния может и не быть, а зависимость будет в любом случае.
V>Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.
Походу, код показать ты не в состоянии
V>Хм, я же попросил, во избежание подобного копирования всего кода, конкретно указать зависимую пару (или пары). Ты не справился.
Прочесть коммент болдом ты не в состоянии ? Надо было сразу сказать
V>В общем, тебе стоит показать, что сия зависимость не идет в исходном коде по условию задачи. Ты же сам сказал, что присутствует некий дополнительный игрок — еще один класс, который мы не можем изменять. Будь добр, подкорректируй свой пример с учетом этого, и только потом покажи список лишних зависимостей, через простое перечисление, которые я ввел, в сравнении с твоим уточненным примером.
Я показал всё что необходимо.
I>>Адаптер это паттерн более древний, чем ООП
V>Черт. А фасад? А фабрика с одним методом тогда что? А почему в ФП не рассматривают эти приемы, как отдельные паттерны?
ФП это другой уровень
I>>Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.
V>Вот надо поменьше говорить, побольше делать. В исходном примере можно было уже сто раз показать свой "особый случай", введя тот самый пресловутый некий класс, о котором так долго говорили большевики (С),
Ты сам о нем говоришь. А я показал все что необходимо.
>и наличие которого для тебя является "элементарным и очевидным". Нам ты пока мест предлагаешь просто поверить тебе на слово. Не прокатит. Ближе к делу! Нарисуй еще раз.
есть фреймворк для рендеринга изображения. в нем реализованы различные генераторы изображения. каждая такая рисовалка должена реализовать интерфейс IRender(=IDoer) с единственным иметодом void Render(Context ctx); кроме этого есть еще рисовалки реализованые в проекте.
необходимо расширить возможности этого фреймворка диагностикой, валидацией, отладкой и тд
задача 1 — замерить время выполнения некоторых реализаций IRender — любых, как своих так и встроеных. Почему нельзя замерить через профайлер — нужны данные по продакшну, а не по дебагу
задача 2 — параллельно с генерацией изображения записывать генерацию в текстовом виде для валидации, диагностики, отладки
задача 3 — некоторые генераторы косячат. надо подавить их артефакты без перепеисывания. например перед вызовом генератора установить некоторые значения в контексте, а по окончанию вернуть значения назад.
задача 4 — необходимо иметь возможность включать-выключать некоторые генераторы, например при рендеринге на бумагу или экран
задача 5 — необходимо иметь возможность делать отрисовку по требованию, т.е. вместо изображения генерируются команды отрисовки примитивов, который потом можно выполнить в другом фреймворке.
в моем решении ненужно модифицировать ни генераторы, не фреймворк, вообще ничего нужно только сделать один декоратор на каждую задачу.
при этом для задач 1,2,3 и 4 декоторатору вообще не надо ничего знать ни про базовый, ни про Сontext.
1 использует StopWatch и Logger
2 использует логгер
3 использует контекст
4 ничего вообще не использует — у тебя вроятно фантазия не позволит представить такое
и только 5й использует кое какие методы из базового класса и класса Context
покажи внятное, тестируемое решение. если не можешь, объясни внятно, чего тебе не хватает.
Re[14]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
S>>>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.
I>>При чем здесь замена ПМ полиморфизмом ? S>притом что type test не кошерен по ООП
Это Страуструп так сказал ?
Re[16]: Почему объектно-ориентированное программирование про
Здравствуйте, samius, Вы писали:
I>>yield break на первые два S>можно подробнее?
yield return разумеется
I>> а для State не обязательно хранить ссылку S>в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state