Re[15]: Override для произвольного метода.
От: _FRED_ Черногория
Дата: 17.12.08 11:22
Оценка: +3
Здравствуйте, GarryIV, Вы писали:

GIV>>>>>А он почти как синглетон — антипатерн. Но не такой разрушительной силы слава богу.

EC>>>>А можно раскрыть мысль?
GIV>>>Его недостатки происходят из-за того что в нем надо наследоваться от абстрактного класса.
EC>>Строго говоря класс не обязан быть абстрактным.
GIV>Шаблонный метод == абстрактный метод => класс абстрактный.

Посмотри Control.SetBoundsCore — не абстрактный метод. Но cамый что ни на есть Template.

GIV>>>Соответственно связанность сильно увеличивается, добавление второго и последующих template method в иерархию ничем хорошим не кончается. Да и с одним не все так гладко (см. Call super антипатерн).

EC>>Как-то странно для меня звучит упрёк в адрес наследования, при обсуждении техники примененимой только в рамках наследования.
EC>>Или я трактую паттерн слишком узко?
GIV>Ну я и говорю, наследование реализации вообще стремная штука а template method в частности

То есть Template Method плох уже тем, что для него нужно наследование??? Тогда давай вообще виртуальные методы повыкидаваем и запретим наследоваться. Получим VB 6 какой-нибудь.

А вот как раз тогда, когда наследование "по делу", использование Template Method в базовом классе позволяет в наследниках совершить меньше ошибок.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[24]: offtop
От: _FRED_ Черногория
Дата: 17.12.08 11:38
Оценка:
Здравствуйте, LaPerouse, Вы писали:

4>>>Практика бывает плохая и хорошая, собственно как и теория, и MFC приводить в качестве примера хорошей практики очень сомнительно.

PD>>MFC, конечно, устарела по концепциям, но по качеству кода (в рамках своих концепций) — она на порядок лучше. Во всяком случае, такого безобразия, как пересоздания listview с переливанием данных ради того, чтобы установить флаг сортировки, там не найдешь.
LP>MFC — просто куча слобоструктурированного кода, по сути, это тончайшая обертка на ситсемным апи, приправленная макросами, проектирования там ноль — просто нет. Говорить о каких-то там концепциях MFC просто смешно. Нет там никаких концепций, нет там никаких идей.

-1. Поищи в этом же форуме топик о том, насколько объектно-ориентированно Win32 API. Были приведены, на мой взгляд, достоточно убедительные доводы в пользу того, что всё-таки неплохо объектно-ориентированно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[25]: offtop
От: _FRED_ Черногория
Дата: 17.12.08 12:06
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Поищи в этом же форуме топик о том, насколько объектно-ориентированно Win32 API.


winapi &mdash; ООП или нет
Автор: VladD2
Дата: 27.04.07
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[25]: offtop
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.12.08 12:19
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>-1. Поищи в этом же форуме топик о том, насколько объектно-ориентированно Win32 API. Были приведены, на мой взгляд, достоточно убедительные доводы в пользу того, что всё-таки неплохо объектно-ориентированно.

во-первых, речь не об Win32, а об MFC.
Во-вторых, одно дело говорить о достижениях plain C API в свете объектной ориентированности, а совсем другое — о требованиях к библиотеке на C++.
В-третьих, если всё же смотреть на то, чего MFC привносит своего, не сводящегося к тонкой обёртке над Win32, то там всё достаточно плохо. Хороший плохой пример — это как раз CString. Сочетает в себе все недостатки всех подходов к строкам. В точности как первый кадавр Выбегаллы.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: offtop
От: _FRED_ Черногория
Дата: 17.12.08 12:36
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

_FR>>-1. Поищи в этом же форуме топик о том, насколько объектно-ориентированно Win32 API. Были приведены, на мой взгляд, достоточно убедительные доводы в пользу того, что всё-таки неплохо объектно-ориентированно.

S>во-первых, речь не об Win32, а об MFC.
S>Во-вторых, одно дело говорить о достижениях plain C API в свете объектной ориентированности, а совсем другое — о требованиях к библиотеке на C++.
S>В-третьих, если всё же смотреть на то, чего MFC привносит своего, не сводящегося к тонкой обёртке над Win32, то там всё достаточно плохо. Хороший плохой пример — это как раз CString. Сочетает в себе все недостатки всех подходов к строкам. В точности как первый кадавр Выбегаллы.

Не надо мне ругать MFC, я сам его ругал в своё время SchweinDeBurg-у в течении нескольких кру… часов
Хотел только сказать, что это не "просто куча слобоструктурированного кода". Структурированность там есть, как раз за счёт Win32, не более того. Расширяемость, удобство и т.п. хвалить не буду.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Help will always be given at Hogwarts to those who ask for it.
Re[32]: Override для произвольного метода.
От: LaPerouse  
Дата: 18.12.08 07:31
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, LaPerouse, Вы писали:

LP>>Ну а тут будут методы-члены. Это со строкой такой пример удачный попался, ибо они обычно иммутабельные, вообще говоря возможны методы, которые деструктивны.
LP>> Вот их лучше делать как члены, а не хелперы.
S>Не вижу никакой связи между мутабельностью и мемберами-членами.

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

S>Если требуемый эффект достижим через public интерфейс, то его крайне вредно делать членом.

S>По той же причине: когда я займусь своей реализацией, мне придется наследоваться, либо дублировать функциональность.

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

S>Вот смотри: возьмем стандартный HttpResponse. Он, естественно, никакой не stateless.

S>Есть у него, допустим, метод Redirect(Url redirectTarget).
S>В принципе, метод ничего военного не делает.
S>Это всего лишь последовательность из .SetLocation; .SetStatus; .End. Все они публичные.
S>Тем не менее, он засунут туда как член.
S>Это — совершенно неверный подход.
S>В этот метод захардкожено использование статус-кода 302.
S>Я хочу уметь делать Redirect с любым из 4х статус-кодов, описанных в RFC2616,
S>Как решить эту проблему?

S>Например, можно добавить его в наследнике HttpResponse.


S>Ага, теперь мне нужно найти то место, где в недрах фреймворка создаётся экземпляр HttpResponse, и заменить там класс. Ну, то есть, конечно, не заменить, а перекрыть тот метод, который создает экземпляр, в своём наследнике от HttpContext, и идти дальше искать то место, где создается экземпляр HttpContext.

S>Это — как раз то, чего хочет Павел Дворкин. "Дайте мне распечатанный класс, и я переверну мир".

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

S>Как бы делал я?

S>Можно дооборудовать каждый HttpResponse методом Redirect(Url redirectTarget, RedirectType redirectType):
S>
S>public enum RedirectType
S>{
S>  MovedPermanently = 301,
S>  Found = 302,
S>    SeeOther = 303,
S>    RetryAt = 307
S>}

S>public static class ResponseHelper
S>{
S>  public static void Redirect(this HttpResponse response, Url redirectTarget, RedirectType redirectType)
S>    {
S>        response.Location = redirectTarget;
S>        response.StatusCode = redirectType;
S>        response.StatusText = redirectType.ToString();
S>        response.End();
S>    }
S>}
S>


S>Это позволило бы мне в тех местах, где я раньше пользовался простым response.Redirect, писать вот так:

S>
S>response.Redirect(redirectTarget, RedirectType.SeeOther);
S>


S>И это никак не зависит от того, как устроен response внутри. Это никак не конфликтует с другими расширениями Response.


Проблема-то не в члене. Тут совершенно другая проблема. Очень простая. Называется — закардкоженная реализация. Если бы указанный Responce осуществлялся точно также захардкоржено внешним сервисным методом, и это был бы единственным способом сделать редирект, ты бы точно также ругался бы, что не сделали внешний Redirect(Url redirectTarget, RedirectType redirectType).

Кстати, по поводу разумности твоего варианта Responce я согласен. Правильно. Но решается она совсем не ту проблему, о которой мы говорим. Предложенный тобой вариант члена Responce — единственной возможный разумный. Всякие частные случаи должны реализовываться в сервисах. Тут с тобой даже никто не спорит, это и так очевидно.

LP>>Нет, вот так

S>>>
S>>>IString name = request["name"];
S>>>Match m = nameReqex.Match(name.Characters);
S>>>

S>А зачем нам тот факт, что из request приезжает IString?

Больше — нам вообще тогда строка не нужна

IEnum name = request["name"];
Match m = nameReqex.Match(name);

LP>>Для меня — не криминально. Если напрягает, тогда IString можно заставить реализовать IEnumerable. В таком случае для пользователя будет все также, как и в твоем примере, просто это будет деталью реализации, улучшающий внутренний дизайн класса.

S>Пока улучшения дизайна не видно.

Очень даже видно. В твоем варианте в реализации IString будет каша, приправленная велосипедами. Функциональность, свойственная чисто Char-последовательностям, будет смешана с типично алгоритмическими методами, характерными для любой последовательности, причем эти методы будут либо тупо копировать уже имеющуюся в любом списке функциональность, либо будут использовать хелперы типа List.subList(IList list, Iter i1, Iter i2).
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[25]: offtop
От: LaPerouse  
Дата: 18.12.08 07:40
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, LaPerouse, Вы писали:


4>>>>Практика бывает плохая и хорошая, собственно как и теория, и MFC приводить в качестве примера хорошей практики очень сомнительно.

PD>>>MFC, конечно, устарела по концепциям, но по качеству кода (в рамках своих концепций) — она на порядок лучше. Во всяком случае, такого безобразия, как пересоздания listview с переливанием данных ради того, чтобы установить флаг сортировки, там не найдешь.
LP>>MFC — просто куча слобоструктурированного кода, по сути, это тончайшая обертка на ситсемным апи, приправленная макросами, проектирования там ноль — просто нет. Говорить о каких-то там концепциях MFC просто смешно. Нет там никаких концепций, нет там никаких идей.

_FR>-1. Поищи в этом же форуме топик о том, насколько объектно-ориентированно Win32 API. Были приведены, на мой взгляд, достоточно убедительные доводы в пользу того, что всё-таки неплохо объектно-ориентированно.


При чем тут объектно-ориентированное программирование? Где связь между кривой реализацией MFC и объектно-ориентированностью?

P.S. А концепций в MFC как не было, так и нет. Концепции были у того, кто писал Platform SDK.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[33]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.12.08 10:29
Оценка:
Здравствуйте, LaPerouse, Вы писали:

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

Хотелось бы какого-то обоснования этой идеи. Хотя бы теоретического, если не удается подобрать практический пример.


LP>А кто мешает тебе прямо сегодня сделать точно такую же внешнюю последовательность вызовов тех же методов?

Я так и делаю.

LP>Нифига не так. Это получается пергрузка ради перегрузки. Перегружают не от балды, а с той целью, чтобы изменить поведение объекта. В данном случае этого совершенно не требутся. Не нужна тут никакая перегрузка.

Воот! "чтобы изменить поведение объекта". Это очень правильно.
Вот только поведение, на мой взгляд, никак не ограничено mutable/immutable. Мы можем захотеть переопределить метод так, чтобы он возвращал другой результат (не меняя состояние самого объекта).

LP>Кстати, по поводу разумности твоего варианта Responce я согласен. Правильно. Но решается она совсем не ту проблему, о которой мы говорим. Предложенный тобой вариант члена Responce — единственной возможный разумный. Всякие частные случаи должны реализовываться в сервисах. Тут с тобой даже никто не спорит, это и так очевидно.

Ну, насчет никто ты конечно погорячился, но я рад, что удалось прийти к согласию.



LP>Больше — нам вообще тогда строка не нужна

Верно.
LP>IEnum name = request["name"];
LP>Match m = nameReqex.Match(name);

LP>Очень даже видно. В твоем варианте в реализации IString будет каша, приправленная велосипедами. Функциональность, свойственная чисто Char-последовательностям, будет смешана с типично алгоритмическими методами, характерными для любой последовательности, причем эти методы будут либо тупо копировать уже имеющуюся в любом списке функциональность, либо будут использовать хелперы типа List.subList(IList list, Iter i1, Iter i2).

Вот это мне непонятно. Посмотри на класс Enumerable из фреймворка 3.5. Совершенно ненужно все эти методы всовывать внутрь реализации.
Они и должны быть внешними хелперами, которые работают с достаточно худым интерфейсом.
Вот только надо как следует понять, что пойдет в интерфейс строки, а что — уедет в хелперы. Это не так очевидно, о чем я сразу и пожаловался. Вот, к примеру, вопросы ToLower/ToUpper однозначно можно отдать наружу. Вопросы конверсии символов в байты уходят в классы Encoding.
Но это только те вопросы, ответы на которые мне известны. А есть еще масса вопросов, которые не так легко и очевидно решить.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: Override для произвольного метода.
От: LaPerouse  
Дата: 18.12.08 12:15
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, LaPerouse, Вы писали:


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

S>Хотелось бы какого-то обоснования этой идеи. Хотя бы теоретического, если не удается подобрать практический пример.

Как раз таки наоборот, практический пример легче, чем найти теоретическое обоснование. Попробую формализовать свои инстинктивные представления, потом приведу пример.
Некоторые используют сервисные функции как дешевую приправы к объекту. Безусловно, их можно (и нужно) использовать и в таком качестве, но это далеко не самое полезное применение таких функций. Можно легко убедиться, что это не просто приправа, а таки целый бульон, в котором могут вариться самые разные объекты.
1. Объекты — это способ представления предметной области с помощью машины состояний. Иначе говоря — это декомпозиция по состоянию или так называемая объектная декомпозиция. Есть еще другая форма декомпозиции, функциональная. Отличие между ними одно — если первая использует для хранения состояния объекты с identity, вторая хранит состояние на стеке. Соотвественно, при сбалансированном дизайне должны присутсвовать обе формы декомпозиции. (Очень хорошо на эту тему написал Gaperton, у меня так не получится). Предметная область должна выражаться ввиде объектов с identity, а вот конкретная функциональность, с использованием этих объектов — в виде внешних функций. А теперь ключевой вопрос — почему эти самые внешние функции делать иммутабельными?. Да потому, что если бы они изменяли бы состояние объекта, то они ничем не отличались бы от типичной функции-члена. Тем самым, они относились бы больше к объектной составляющей декомпозиции, нежели к функциональной. Вот такое вот объяснение.
2. У таких функций есть еще одно преимущество, не связанное с состоянием и временем выполнения. Осуществляя склейку различных модулей, они позволяют избежать излишней зависимости между модулями. Ну, это настолько очевидно, что прибавить сюда особенно нечего.

LP>>Нифига не так. Это получается пергрузка ради перегрузки. Перегружают не от балды, а с той целью, чтобы изменить поведение объекта. В данном случае этого совершенно не требутся. Не нужна тут никакая перегрузка.

S>Воот! "чтобы изменить поведение объекта". Это очень правильно.
S>Вот только поведение, на мой взгляд, никак не ограничено mutable/immutable. Мы можем захотеть переопределить метод так, чтобы он возвращал другой результат (не меняя состояние самого объекта).

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

S>Вот это мне непонятно. Посмотри на класс Enumerable из фреймворка 3.5. Совершенно ненужно все эти методы всовывать внутрь реализации.

S>Они и должны быть внешними хелперами, которые работают с достаточно худым интерфейсом.
S>Вот только надо как следует понять, что пойдет в интерфейс строки, а что — уедет в хелперы. Это не так очевидно, о чем я сразу и пожаловался. Вот, к примеру, вопросы ToLower/ToUpper однозначно можно отдать наружу. Вопросы конверсии символов в байты уходят в классы Encoding.
S>Но это только те вопросы, ответы на которые мне известны. А есть еще масса вопросов, которые не так легко и очевидно решить.

Давай разберемся еще раз.
Я на самом деле недопонял твой вариант, недооценив худость интерфейса IEnum. Я думал, ты чуть ли полноценный список собрался там реализовывать.
Теперь я понимаю, что ты реализуешь в классе строки интерфейс IEnumerable. Вопрос, что туда входит? Если он достаточно бедный, то это хорошо. Тогда возможно строку, реализующие этот бедный IEnumerable для типично-списочных преобразований отдать в спец. хелперы типа ListHelper.reverse(IEnumerable enumerable), а для типично строковые реализовать либо внутри класса, либо в спец. хелпере StringHelper. Я ж тебя правильно понял?
Мой вариант — строка использует объект Enumerable, только в отличие от твоего бедного iEnumerable, этот побогаче будет, да и откровенно говоря, не Enumerable вовсе, а полноценный List. Соотвественно, все те списочные опрерации реализованы именно в нем. Строковые операции — непосредственно в String. Что-то в хелперах, не принципиально. Мой String не поддерживает IEnumerable, нужно делать .getCharacters(), что имхо не смертельно.

Резюмируя: у тебя полиморфное поведение инкапсулировано в IEnumerable. Та самая структура выделяемой памяти отражена именно в IEnumerable. А в хелперах находятся обобщенные функции, которые используют этот полиморфный IEnumerable.
У меня же в нем помимо полиморфного поведения есть еще типичная списковая функциональность.

Теперь, с учетом твоего "обновленного" варианта, я уже не знаю, что лучше.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[35]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.12.08 05:02
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>Как раз таки наоборот, практический пример легче, чем найти теоретическое обоснование. Попробую формализовать свои инстинктивные представления, потом приведу пример.

LP>2. У таких функций есть еще одно преимущество, не связанное с состоянием и временем выполнения. Осуществляя склейку различных модулей, они позволяют избежать излишней зависимости между модулями. Ну, это настолько очевидно, что прибавить сюда особенно нечего.
Уфф. Не, в пятницу с утра я про баланс идентичности со стеком понять не могу
Про избавление от зависимостей я понял.

Я вот что хочу сказать — правильный баланс чего угодно в коде отличается от неправильного в основном тем, что
а) кода в целом мало
б) когда мы хотим внести изменения функциональности, изменения кода локализованы и невелики.

Всё остальное, в общем-то, попытки заранее прикинуть а) и б) "в среднем по больнице".

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

А вот проведение границы между объектами и сервисными функциями мне не до конца понятно. Потому что то, что в одном контексте выглядит как сервисная функция, в другом контексте оказывается виртуальным методом у другого объекта, инкапсулирующего в себе алгоритм.
Типичный пример — Encoding.GetBytes(string str).
То есть вместо того, чтобы засовывать в строку метод string.GetBytes(int encodingId), мы вводим целый класс алгоритмов сериализации/десериализации строк.
Почему?

Я предпочитаю рассматривать процесс порождения таких методов в два этапа:
1. Выделение GetBytes во внешний метод. Делается по банальному критерию: для него заведомо достаточно публичного интерфейса. Смысл метода так устроен, что ничего, кроме возможности перебирать символы, ему не надо. Значит, ему не место в контракте класса.
Получаем что-то типа
static byte[] Encoding.GetBytes(string, int encodingId);
2. Понимаем, что вместо полиморфизма по второму аргументу мы можем использовать полиморфизм по this, если заменим encodingId на полноценный encoding.
Это достаточно нетривиальный процесс, потому что в него вовлечены и методы GetString(byte[]), и политики поведения метода при встрече непредставимого в енкодинге символа, и так далее.
Но идея — в том, что начинаем мы всё равно с первого шага: отделением предоставляемого контракта от его потребителей.

LP>Я на самом деле недопонял твой вариант, недооценив худость интерфейса IEnum. Я думал, ты чуть ли полноценный список собрался там реализовывать.

LP>Теперь я понимаю, что ты реализуешь в классе строки интерфейс IEnumerable. Вопрос, что туда входит? Если он достаточно бедный, то это хорошо. Тогда возможно строку, реализующие этот бедный IEnumerable для типично-списочных преобразований отдать в спец. хелперы типа ListHelper.reverse(IEnumerable enumerable), а для типично строковые реализовать либо внутри класса, либо в спец. хелпере StringHelper. Я ж тебя правильно понял?
Совершенно верно.

LP>Резюмируя: у тебя полиморфное поведение инкапсулировано в IEnumerable. Та самая структура выделяемой памяти отражена именно в IEnumerable. А в хелперах находятся обобщенные функции, которые используют этот полиморфный IEnumerable.

LP>У меня же в нем помимо полиморфного поведения есть еще типичная списковая функциональность.

LP>Теперь, с учетом твоего "обновленного" варианта, я уже не знаю, что лучше.

У твоего варианта есть только один, имхо, тонкий момент. Итак, вот у нас строка, которая является собственно оболочкой над некоторым "character storage".
Примерно так же, как TextReader едет верхом на Stream.
Благодаря этому, мы можем выбирать разные storage и параметризовывать ими строку.
Но вот такой есть интересный вопрос: конкатенация двух строк возвращает что?
Строку? Какой storage у нее использован?
Интуитивно мы ожидаем получить от двух строк, построенных на массивах, в результате строку на новом массиве, в который скопированы оба старых.
А для хаскельной строки, естественно, "цепочку" из двух IEnumerable (а как они устроены внутри — неважно).
Но строка ничего не знает про реализацию storage. Все решения, которые приходят мне в голову, неизбежно приводят к тому, что типично "строковые" операции уезжают в character storage, и класс собственно строки оказывается вырожденным.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 19.12.08 06:54
Оценка:
Здравствуйте, Sinclair, Вы писали:

PD>>Безусловно. Только кто тут голосование устраивал ?

S>Ты. Ты апеллируешь к тому, что раз есть классы, значит они кому-то полезны.

Ну полезны они или нет — об этом можно просто по ссылкам на них судить.

S>Вообще-то, Павел, я приводил конкретные агрументы. Со сравненим строчек кода и объемов лишней работы. Эти аргументы при всём желании нельзя свести к тому, что "это должно быть так, потому что в .Net это так". А вот ты как раз наоборот аргументируешь только тем, что раз какой-то индус выложил наследник CString, значит это априори хорошо, независимо от практики применения.


Индус он или китаец — меня очень мало интересует. Качество этого класса меня будет интересовать только если я решусь его применить (это, впрочем, верно для любых классов). Я же аргументирую тем, что такое делается, и это норма.

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


PD>>А кто его пытался дискредитировать ? Не я, по крайней мере.

S>Ты пытался к нему апеллировать. Типа "раз вы не можете доказать, что этот сайт — отстой, значит любой код оттуда — жемчужина".

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

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

PD>>Во-во. Как CxxxEx — так неизбежно все они унылые.

S>Конечно унылые. Я тебя носом тыкаю в проблемы, проистекающие из CxxxEx. Да, я себя предлагаю в арбитры

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

PD>>И при этом ты себя предлагаешь в арбитры. При том. что с помощью этих Cxxx сделана весьма приличная часть софта, который работает на миллионах компьютеров, в отличие от софта, написанного с помощью неунылых классов .Net, который чаще всего на одном компьютере и работает, ну на нескольких. Ничего вас не учит.

S>Ну так покажи мне софт с использованием CStringEx, который работает на миллионах компьютеров. Обсудим устройство этого софта и посмотрим, можно было бы его сделать лучше без CStringEx, или его использование вызвано травмой мозга.

Опять демагогия. Покажи мне софт (да еще с исходниками, надо полагать, для обсуждения устройства-то) и тогда обсудим, мол. Софта, написанного с помощью MFC, сколько угодно, а какие там расширения ее используются, я, естественно, не знаю, так как исходников у меня нет.

PD>>Кстати, ответь на вопрос. 10 с лишним лет Микрософт не занималась MFC. Почему они вдруг к ней вернулись ?

S>Павел, меня парит давать новые ответы людям, которые не могут прочитать старые.




PD>>Слушай, ты это серьезно ?

S>Абсолютно.
PD>>Если да — хоть расскажи, где эти хелперные функции искать-то ?
S>А там же и искать, где ты ищешь эти CMsg, CStringEx и прочие. В чем проблема-то?

Проблема очень простая. Вот я хочу найти всякие расширения CString, к примеру. Идем на google, ищем "public CString" и на первой же странице имеем

http://www.google.ru/search?hl=ru&amp;newwindow=1&amp;q=%22public+CString%22&amp;lr=&amp;aq=f&amp;oq=

CResString, LString , CStringEx

а ты что будешь искать ? У меня есть база, от которой я могу начать поиск, а у тебя ?

PD>>Как классы эти хелперные называются хоть ? Вот и будут все плодить эти хелперные классы, друг с другом никак не связанные (невозможно! они же sealed).

S>Совершенно верно, несвязанные. А зачем их связывать? Они же ортогональы.

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

PD>> Кстати, а как их (хелперные клаасы то есть) мерджить-то ? Или пусть живут как есть ? Sinclair.IsPalindrom, Dvorkin.IsRussianWord, IB.IsNonCensored ? .

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

Это все было бы ничего, если бы мы были членами одной команды и разделили работу. Тогда да, согласен. Но мы не члены одной команды, а поэтому перекрытия возможны и почти обязательно будут. В итоге, если их не мерджить, то просто получим набор перекрывающихся по функциям (полностью или частично) методов, в которых нет ни логики, ни какой-то организации. Каждый делал как мог и как хотел, а тот, кто эти 3 чуда захочет использовать, будет сидеть и плеваться. потому что он будет использовать один метод из Dvorkin, 2 из Sinclair и т.д, а знать должен о всех.

Вот смотри, простой пример, из твоей любимой .Net. Класс

System.Object
System.MarshalByRefObject
System.ComponentModel.Component
System.Windows.Forms.Control
System.Windows.Forms.ListView

Работая с ним. я имею дело с документацией на ListView. Мне в большинстве случаев не надо смотрть документацию по предкам. А в твоем варианте с множественными хелперами придется их все изучать.

S>Я чувствую, такими темпами лет через восемь-десять ты начнешь понимать основы ООП. Ну там, разделение обязанностей, инкапсуляцию состояния.
With best regards
Pavel Dvorkin
Re[26]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 19.12.08 07:00
Оценка:
Здравствуйте, IB, Вы писали:

IB>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Безусловно. Только кто тут голосование устраивал ?

IB>Твою аппеляцию к количеству ссылок на ресурс иначе как голосованием не назовешь.

Ну и ну!

PD>>Давай внятно. Это — заблуждения с твоей и твоих коллег точки зрения . С точки зрения других — это не заблуждения, а нормальный подход.

IB>Так где эта точка зрения? Где этот нормальный подход и какие задачи он решает? Опиши это Павел, не стесняйся, мы уже десяток постов пытаемся от тебя добиться именно этого, а ты все изворачиваешься.

PD>>Никаких оснований объявлять их заблуждениями у тебя нет, кроме туманных рассуждений о том, почему должно быть так, а не иначе,

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

М-да... Я привожу эти аргументы, а мне в ответ — приведи аргументы. Не знаю, что еще тут сказать. Могу лишь одно место из Герцена процитировать

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
У старика генерала Тучкова был процесс с казной. Староста его взял какой-то подряд, наплутовал и попался под нечет. Суд велел взыскать деньги с помещика, давшего доверенность старосте. Но доверенности на этот предмет вовсе не было дано. Тучков так и отвечал. Дело пошло в Сенат, Сенат снова решил: «Так как отставной генерал-лейтенант Тучков дал доверенность... то...» На что Тучков опять отвечал: «А так как генерал-лейтенант Тучков доверенности на этот предмет не давал, то...» Прошел год, снова полиция объявляет с строжайшим подтверждением: «Так как генерал-лейтенант... то...» — и опять старик пишет свой ответ. Не знаю, чем это интересное дело кончилось. Я оставил Россию, не дождавшись решения.

Герцен А. И. Поли. собр. соч. М.—-Л., 1956. Т. IX, с. 217.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
With best regards
Pavel Dvorkin
Re[26]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 19.12.08 07:35
Оценка: -1
Здравствуйте, 4058, Вы писали:

PD>>С точки зрения других — это не заблуждения, а нормальный подход.


4>Это нормальный подход, с точки зрения начинающих программистов (в области ООП),

4>которые пока не в состоянии отличить хорошее от плохого.

Ну значит все, кто этот подход используют, начинающие. Вот, например, некий начинающий программист из Microsoft писал Wordpad

class CColorMenu : public CMenu
class CDocOptPage : public CCSPropertyPage
class CTrackFile : public CFile
class COptionSheet : public CCSPropertySheet
class CComboRulerItem : public CRulerItem
class CRulerBar : public CControlBar
class CEmbeddedItem : public COleServerItem

и т.д. Там их много. Он же не знал, как правильно, он же начинающий , он же не умел отличить хорошее от плохого. А MS , вместо того, чтобы стыдиться такого продукта от начинающих, взяла да и выставила его на всеобщее обозрение в качестве примеров. Для других начинающих, надо полагать

Я так подозреваю, что если бы исходники других приложений были доступны, то выяснилось бы, что многие приложения от MS писали начинающие. Включая .Net

PD>>Кстати, ответь на вопрос. 10 с лишним лет Микрософт не занималась MFC. Почему они вдруг к ней вернулись ?


4>1. Есть проекты, которые никто не станет переписывать с нуля более "кошерными" средствами, но которые тем не менее требуют доработок.


А что же они 10 с лишним лет ее не требовали, и MFC не развивалась, а тут вдруг потребовали ? Что изменилось-то ?

4>2. Осталось большое сообщество консервативно настроенных пользователей, которым просто в лом посмотреть по сторонам. Их тоже приходится поддерживать.


. Нет, ребята, с вашей логикой не соскучишься . Зачем их поддерживать-то ? Наоборот, их надо ограничивать, чтобы они на новые прогрессивные технологии переходили. Вот, к примеру, когда переход от Win16 к Win32 произходил (я имею в виду Windows 95), то было сразу сказано, что common controls не будут доступны в Win16, а только в Win32. И действительно, в течение нескольких лет все перешли на Win32. А тут уже более 5 лет прошло, как .Net существует, настольных приложений кот наплакал, так MS , вместо того, чтобы стимулировать программистов переходить на эти новые технологии, вдруг начинает устаревшие развивать. Что-то тут не так...

А вообще забавно смотреть, как вы из кожи лезете вон, пытаясь во что бы то ни стало доказать, что то, чем вы занимаетесь, и есть единственно правильное, а все остальное устарело, консервативно, смотреть по сторонам не хотят и т.д. Забавно.
With best regards
Pavel Dvorkin
Re[27]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 19.12.08 07:49
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Ну полезны они или нет — об этом можно просто по ссылкам на них судить.
Это и есть "голосование".

PD>Индус он или китаец — меня очень мало интересует. Качество этого класса меня будет интересовать только если я решусь его применить (это, впрочем, верно для любых классов). Я же аргументирую тем, что такое делается, и это норма.

Это и есть "голосование". Можно, я аргументирую правильность ежедневного приема героина внутривенно тем, что такое делается? Уверяю тебя, эта практика значительно более распространена, чем использование класса CStringEx.
Понятно, почему голосования не помогают?

PD>Передергиваем опять. Ссылку в студию, где я сказал, что любой код оттуда жемчужина ?

Ты считаешь сам факт наличия этого класса там свидетельством того, что это "норма".

PD>Опять демагогия. Покажи мне софт (да еще с исходниками, надо полагать, для обсуждения устройства-то) и тогда обсудим, мол. Софта, написанного с помощью MFC, сколько угодно, а какие там расширения ее используются, я, естественно, не знаю, так как исходников у меня нет.

Ну, а если ты не знаешь, то зачем привлекаешь частоту использования в качестве аргумента?
Или ты частоту самого MFC записываешь в аргументы в пользу тезиса "наследоваться от строки с целью добавления туда функций, которые с тем же успехом могли бы быть внешними — это лучше, чем делать их внешними"? Это, пардон, передергивание.


PD>а ты что будешь искать ? У меня есть база, от которой я могу начать поиск, а у тебя ?

Павел, это несеръезно. Такого поиска в природе не бывает. Реальный разработчик будет искать не класс, а функциональность. Если нужны палиндромы — будут искать palindrome, а не всех мыслимых наследников от строки.

PD>Это почему же ? Я напишу свой хелпер, ты свой (мы же не договаривались), кто-то еще — свой. С чего это им ортогональными бцть ?

Ты понимаешь смысл термина "ортогональны"? Без договоренностей хелперы всегда будут ортогональными.
Вот ты же сам привел список — какая будет зависимость между IsPalindrome и IsNormalized?


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

С чего бы это? Это жертвы MFC пихают в своего наследника от CString все расширения, без всякой логики или организации. Просто потому, что строка у них вынуждена быть ровно одного класса, а значит все методы надо запихать в нее. И по работе с ресурсами, и по форматированию.
А поскольку мы с Иваном думаем по-другому, каждый будет делать хелпер исходя из Single Responsibility Principle.
И за палиндромы будет отвечать хелпер палиндромов, за поиск регулярных выражений — регулярные выражения, за конверсию в определенную кодировку — Encoding.

По факту оказывается, что это гораздо более логичный и организованный код, чем беспорядочное наследование и всовывание методов по принципу "свалим всё в один класс, чтобы было проще найти".

PD>Каждый делал как мог и как хотел, а тот, кто эти 3 чуда захочет использовать, будет сидеть и плеваться. потому что он будет использовать один метод из Dvorkin, 2 из Sinclair и т.д, а знать должен о всех.

Он и так должен знать обо всех.
Ты всё еще мне не ответил на вопрос — что же делать в такой же ситуации в твоем подходе. Вот, допустим, мы все послушались тебя, и вместо внешних хелперов каждый написал свой наследник от CString. Что делает прикладной программист, который хочет воспользоваться всеми тремя группами функций?


PD>Работая с ним. я имею дело с документацией на ListView. Мне в большинстве случаев не надо смотрть документацию по предкам. А в твоем варианте с множественными хелперами придется их все изучать.

Объем изучения будет точно такой же — ведь в моём подходе в самом ListView не будет помойки методов. Он будет тоненький и простой.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 19.12.08 07:53
Оценка:
Здравствуйте, IB, Вы писали:

IB>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Глупо.

IB>Вот и я говорю, глупо ты себя ведешь Павел, глупо и не дальновидно.

М-да, ну и логика.

PD>>Потому что в отличие от програмистов на .Net нам приходится не только пользоваться запечатанными классами, но и создавать свои.

IB>Ты хочешь сказать, что программисты на .Net своих классов не создают?

Создают. Только делятся они на 2 категории — те, кто создает, и те, кто использует, а создает преимущественно наследников от Form

IB>Да хоть двести. Я тебе заранее не советую меряться серьезностью вопросов и уводить разговор в эту область. У меня по любому толще и длинее, а уж на пару с Антоном у нас их вообще два, так что лучше даже не начинай.


В таком стиле я уж точно и начинать не буду. Коль уж других аргументов нет — что поделаешь...


IB>И за всеми этими разглагольствованиями, ты так и не ответил на прямо поставленный вопрос, я все еще жду внятных аргументов, а не отсылок к крутизне проектов и левые ресурсы.


Ну на тебе еще ссылку — wordpad. Я никак не пойму, что ты хочешь — исходники приложений, которые используют эти классы ? Так ты прекрасно знаешь, что исходников обычно никто не дает. А приводишь пример класса самого с исходниками — сразу вопль — это левое.

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

IB>Павел. Я совершенно точно могу сказать, что не красит тебя. Вместо внятных аргументов в пользу своей точки зрения или признания того что ты не прав и вообще не очень разбираешься в данной области, ты начинаешь отмазываться тем, что другие так делают и значит это хорошо. А когда тебя приперли к стенке, ты начинаешь доматываться к манере ведения дискуссии.

Да брось ты чушь городить. Я четко и внятно сказал, что это общепринятый подход в программах на С++ вообще и MFC в частности. Я нигде не говорил, хорошо это или плохо сделано в абстрактном плане — хорошо или плохо это сделано, можно судить только для конкретного класса. А вот сам подход является нормальным и общепринятым, и это факт, от которого не уйдешь.

И не надо мне объяснять, что меня красит и что нет. Предоставь мне эти вопросы самому решать.


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


Я не признаю, что я неправ. Я привел тебе примеры, где это используется, но ты в ответ — это не пример, он левый. Ну вот тебе не левый пример — исходники WordPad. Назвать этот продукт левым ты не сможешь. Классов-наследников от MFC классов там немало. Так что будь добр найди какое-нибудь объяснение этому феномену, а мы послушаем.

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


Естественно. Нет концепции и все тут. Ясно.
With best regards
Pavel Dvorkin
Re[27]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 19.12.08 08:32
Оценка:
Не смог еще от одной цитаты удержаться . Если не знаешь, откуда она — спроси Антона, он должен знать.

– Есть предложение, – продолжал Лавр Федотович. – Ввиду представления собой дела номер тридцать восемь под названием «Коровье Вязло» исключительной опасности для народа, подвергнуть данное дело высшей мере рационализации, а именно: признать названное необъясненное явление иррациональным, трансцендентным, а следовательно, реально не существующим и как таковое исключить навсегда из памяти народа, то есть из географических и топографических карт.

Хлебовводов и Фарфуркис бешено захлопали в ладоши. Лавр Федотович извлек из-под сиденья свой гигантский портфель и положил его плашмя себе на колени.

– Акт! – воззвал он.

На портфель лег акт о высшей мере.

– Подписи!!

На акт пали подписи.

– Печать!!!

Лязгнула дверца сейфа, волной накатила канцелярская затхлость, и перед Лавром Федотовичем возникла Большая Круглая Печать. Лавр Федотович взял ее обеими руками, занес над актом и с силой опустил. Мрачная тень прошла по небу, автомобиль слегка присел на рессорах. Лавр Федотович убрал портфель под сиденье и продолжал:

– Коменданту Колонии товарищу Зубо за безответственное содержание в Колонии иррационального, трансцендентного, а следовательно, реально не существующего болота «Коровье Вязло», за необеспечение безопасности работы Тройки, а также за проявленный при этом героизм объявить благодарность с занесением. Есть еще предложения?
With best regards
Pavel Dvorkin
Re[27]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 19.12.08 09:19
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Создают. Только делятся они на 2 категории — те, кто создает, и те, кто использует, а создает преимущественно наследников от Form

Детский сад. Проекты уровня твоих MFC-шных, у меня студенты и стажеры делают, прежде чем я их к серьезным вещам допущу. )

PD>В таком стиле я уж точно и начинать не буду.

Ты уже начал. Я лишь призываю тебя остановиться, пока ты себя совсем в неловкую позицию не поставишь.

PD>Коль уж других аргументов нет — что поделаешь...

То есть, ты признаешь, что других аргументов у тебя нет?

PD> Я никак не пойму, что ты хочешь — исходники приложений, которые используют эти классы ?

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

PD>Да брось ты чушь городить.

Чушь, Павел, городишь ты, когда уворачиваешься от четкого ответа на вопрос.

PD> Я четко и внятно сказал, что это общепринятый подход в программах на С++ вообще и MFC в частности.

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

PD> Я нигде не говорил, хорошо это или плохо сделано в абстрактном плане —

Тогда зачем ты это вообще говорил? Речь-то шла не о том, кто как делает, а о том хорошо это или плохо.

PD>хорошо или плохо это сделано, можно судить только для конкретного класса.

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

PD>А вот сам подход является нормальным и общепринятым, и это факт, от которого не уйдешь.

Во-первых, как тебе уже говорили, количество реализаций не является критерием нормальности подхода. А во-вторых, он общепринятый у тех кто в ООП не разбирается, вот это точно факт.
Скажем, stl в C++ принятый пообщее чем MFC, так что насчет общепринятости ты тоже загнул.

PD>И не надо мне объяснять, что меня красит и что нет. Предоставь мне эти вопросы самому решать.

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

PD>Я не признаю, что я неправ.

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

PD>Я привел тебе примеры, где это используется,

Павел, пойми, не нужны примеры, нужны твои объяснения, почему это хорошо и правильно с твоей точки зрения.

PD> Ну вот тебе не левый пример — исходники WordPad. Назвать этот продукт левым ты не сможешь.

Гы.. Запросто.

PD> Классов-наследников от MFC классов там немало. Так что будь добр найди какое-нибудь объяснение этому феномену, а мы послушаем.

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

PD>Естественно. Нет концепции и все тут. Ясно.

То есть ты признаешь, что просто поболтать пришел?
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[27]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 19.12.08 09:19
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ну и ну!

То есть, ты настаиваешь на том, что количество ссылок на ресурс является критерием его правильности?

PD>М-да... Я привожу эти аргументы, а мне в ответ — приведи аргументы.

Забавный какой.. Твой аргумент заключается в тезисе "это общепринятый подход, значит это хорошо". Но для нас, в отличии от тебя, общапринятость подхода не является достаточным критерием для его правильности. Вообще, на поводу у толпы идти вредно. По этому мы просим тебя объяснить, по какой причине этот подход настолько хорош, что стал общепринятым. Именно этих аргументов мы от тебя ждем.
Или ты сам не понимаешь почему они так делают? Ну так признайся, не таись.. )
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[28]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 19.12.08 09:29
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Не смог еще от одной цитаты удержаться .

О да, "сказка о тройке" очень к месту.. Отлично прослеживается аллюзия на твое "общепринятый подход, значит так правильно". )
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[36]: Override для произвольного метода.
От: LaPerouse  
Дата: 19.12.08 10:51
Оценка: 60 (1)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, LaPerouse, Вы писали:


LP>>Как раз таки наоборот, практический пример легче, чем найти теоретическое обоснование. Попробую формализовать свои инстинктивные представления, потом приведу пример.

LP>>2. У таких функций есть еще одно преимущество, не связанное с состоянием и временем выполнения. Осуществляя склейку различных модулей, они позволяют избежать излишней зависимости между модулями. Ну, это настолько очевидно, что прибавить сюда особенно нечего.
S>Уфф. Не, в пятницу с утра я про баланс идентичности со стеком понять не могу
S>Про избавление от зависимостей я понял.

S>Я вот что хочу сказать — правильный баланс чего угодно в коде отличается от неправильного в основном тем, что

S>а) кода в целом мало
S>б) когда мы хотим внести изменения функциональности, изменения кода локализованы и невелики.

Я бы еще прибавил легкость использования кода без изменения в разных сценариях.

S>Всё остальное, в общем-то, попытки заранее прикинуть а) и б) "в среднем по больнице".


Может быть.

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


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

S>А вот проведение границы между объектами и сервисными функциями мне не до конца понятно. Потому что то, что в одном контексте выглядит как сервисная функция, в другом контексте оказывается виртуальным методом у другого объекта, инкапсулирующего в себе алгоритм.

S>Типичный пример — Encoding.GetBytes(string str).
S>То есть вместо того, чтобы засовывать в строку метод string.GetBytes(int encodingId), мы вводим целый класс алгоритмов сериализации/десериализации строк.
S>Почему?

S>Я предпочитаю рассматривать процесс порождения таких методов в два этапа:

S>1. Выделение GetBytes во внешний метод. Делается по банальному критерию: для него заведомо достаточно публичного интерфейса. Смысл метода так устроен, что ничего, кроме возможности перебирать символы, ему не надо. Значит, ему не место в контракте класса.
S>Получаем что-то типа
S>static byte[] Encoding.GetBytes(string, int encodingId);
S>2. Понимаем, что вместо полиморфизма по второму аргументу мы можем использовать полиморфизм по this, если заменим encodingId на полноценный encoding.
S>Это достаточно нетривиальный процесс, потому что в него вовлечены и методы GetString(byte[]), и политики поведения метода при встрече непредставимого в енкодинге символа, и так далее.
S>Но идея — в том, что начинаем мы всё равно с первого шага: отделением предоставляемого контракта от его потребителей.

Я руководствуюсь следующими соображениями:

1. Самое главное — если метод требует классов из другого пакета, от которых он напрямую не зависист (например, не использует их в своих полях), не задумываясь выношу его во внешнюю функцию. Очень болезненно отношусь к левым зависимостям.
2. Если метод реализует какой-то частный случай работы с объектом, совершенно однозначно делаю его внешним. Публичные функции должны обеспечивать только самые общие возможности по управлению объектом, не привязанные к контексту его использования в каком-то определенном случае. Как следствие получаем, что изменение этого контекста вообще ничего не затрагивает. Клиентский код лишь реализует свой сервис для работы с объектом. Этот пункт частично пересекается с пунктом один. Если, скажем, некоторый метод частный для какого-то случая да еще испльзует какие-то зависимости из этого контекста, то в топку его сразу по двум причинам
3. То, что ты уже привел в 1. Для реализации метода достаточно публичного интерфейса. Это увеличивает инкапсуляцию — метод гарантированно пользуется открытым интерфейсом объекта.

Эти самые пункты очень легко и не задумываясь можно применять к неполиморфным методам. Если же метод полиморфный, то приходится дважды думать. Жалко, что нет в Java и C++, которые я использую, мультиметодов или сопоставления с образцом (которого тоже хватило бы).
Итак, что мы имеем: метод, который никак не может оставаться членом, так как подходит под 1, 2, 3 но при этом, зараза, полиморфен. Решаем по одному из следующих сценариев:
1. Выделять полиморфную часть метода, которую можно сделать членом класса исходя из соображений 1-3. То есть разлагаем на неполиморфную часть, удовл. критериям 1-3, которую выносим в сервис, и полимфорную, которую реализуем в классе.
2. Внешний метод делаем полимфорным. Случай хреновый, так как язык, к сожалению, не поддерживает это автоматом. Не использую Visitor, вместо него испльзую рантаймовую информацию о типе, чтобы создать соотвествующий сервис для данного объекта. Но это уже детали.



S>У твоего варианта есть только один, имхо, тонкий момент. Итак, вот у нас строка, которая является собственно оболочкой над некоторым "character storage".

S>Примерно так же, как TextReader едет верхом на Stream.
S>Благодаря этому, мы можем выбирать разные storage и параметризовывать ими строку.
S>Но вот такой есть интересный вопрос: конкатенация двух строк возвращает что?
S>Строку? Какой storage у нее использован?
S>Интуитивно мы ожидаем получить от двух строк, построенных на массивах, в результате строку на новом массиве, в который скопированы оба старых.
S>А для хаскельной строки, естественно, "цепочку" из двух IEnumerable (а как они устроены внутри — неважно).
S>Но строка ничего не знает про реализацию storage. Все решения, которые приходят мне в голову, неизбежно приводят к тому, что типично "строковые" операции уезжают в character storage, и класс собственно строки оказывается вырожденным.

Конкатенация двух строк — это совершенно не строковая операция, а самая что ни на есть списочная. Правда, придется конкату передать в качестве параметра порождающую фабрику, чтобы знать, какую именно реализацию будет использовать новая строка. Но от этого, заметь, и твоя реализация не свободна. В C++ это решается с помощью шаблонов, то есть тип storage становится параметром шаблона, и всего делов. В Java — никак не решить, и в C# тоже.
Собственно строковых операций не так-то уж много, это да. Но они есть. Ну ладно, format уедет в Format. Останутся toUpperCase, toLowerCase, getBytes можно разместить в классе строки, так что не совсем верно, что этот класс будет вырожденным. Хотя у тебя будут возражения по этому поводу (мне о них известно, ты уже писал об этом).
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.