Re[15]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 10.12.08 11:47
Оценка: +7 -1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Слушай, не придуривайся сам. Из того, что в существующем FW никто с ним работать иначе как со string не будет (еще бы!) вовсе не следует, что в расширении FW его нельзя будет использовать.

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

PD>Какой к богу проверки ? Создаем наследника от TextBox, к примеру. Кладем его на форму. В нем поле MyString Text1. В него считываем из Win32 edit, создавая при этом экземпляр MyString. Проверяем его на палиндром — здесь же, в наследнике TextBox. Все.

Иными словами, у тебя появился контрол, который ты можешь переиспользовать только с определенным типом строк, и ни с чем другим он работать уже не сможет, зашил логику проверки в UI, что является грубейшей ошибкой, так как ни протестировать толком, ни переиспользовать эту логику так же не получится, ну и финальный гвоздь в монолитность своего приложения ты забил, когда завязался на конкретную реализацию TextBox.
Примерно так проектируют приложение люди познакомившиеся с основами ООП по книжкам, примерно месяц назад и теперь активно спешащие применить все новые фенечки на практике..

PD>Что у вас за дурная манера , господа, называть все, с чем вы не согласны, бредом ?

Мы с этим не просто не согласны, мы знаем, что так делать нельзя и даже пытаемся тебе объяснить почему, но очевидно бесполезно... =)

PD> Логичность в том, что класс их объединяет в нечто логически целое — в данном случае (static class) вот и все.

Объеденить в "логически целое" можно кучей других способов, почему они тебя не устраивают?

PD>Самое прямое. Если я расширяю класс Directory — я создаю более мощный "Directory". То есть static класс есть логически собранный набор методов для определенной области.

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

PD>Слова, слова...

Это не слова, это суровая практика. Вот что по этому поводу пишет Меерс:

...
If you reflect a bit and are honest with yourself, you'll admit that you have this alleged inconsistency with all the nontrivial classes you use, because no class has every function desired by every client. Every client adds at least a few convenience functions of their own, and these functions are always non-members. C++ programers are used to this, and they think nothing of it. Some calls use member syntax, and some use non-member syntax. People just look up which syntax is appropriate for the functions they want to call, then they call them. Life goes on. It goes on especially in the STL portion of the Standard C++ library, where some algorithms are member functions (e.g., size), some are non-member functions (e.g., unique), and some are both (e.g., find). Nobody blinks. Not even you.


PD>Если ты не понимаешь разницу между введением еще одного класса, не имеющего никакого отношения к данному и созданием наследника, расширяющего возможности данного и лишь подсчитываешь число классов — о чем тогда вообще говорить!

Мы-то как раз очень хорошо понимаем разницу и все ее последствия.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[45]: Override для произвольного метода.
От: LaPerouse  
Дата: 29.12.08 14:28
Оценка: 1 (1) +6
Здравствуйте, Pavel Dvorkin, Вы писали:

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


PD>Если же вопрос относится именно к методу concat, то на вопрос, зачем мне наследоваться, ответ предельно прост — а с чего ты решил, что я наследовать собрался именно ради concat ? concat мне даром не нужен, но из этого вовсе не следует, то мне не нужно наследование. Я вообще о concat речи не вел, ты ее предложил зачем-то, а теперь, выходит, мне не нужно наследование, поскольку мне не нужна эта concat ? Интересная логика.


Полиморфизм от наследования тебе не нужен, и лишние методы от родителя в конракте CPalindrom не нужны, назови же тогда причину зачем тебе нужно наследование?

Итак, получаем:
1. Бенефит от наследования — полиморфизм — тебе не нужен
2. Метод concat, который тебе достался от предка и который тебе не нужен, мешается.

Так на кой черт тогда использовать наследование?

LP>>То есть ты намерен запрещать пользователю библиотеки вызывать метод concat у твоего CPolindrom?


PD>Обсуждаемо. Может, я вообще закрою его , может, просто соглашусь на InvalidCast, поскольку мне эта проверка на палиндром нужна только на входном контроле( не допускать ввода не палиндромов, например). Если, к примеру. я хочу , чтобы в программе все экземпляры CPalindrom были обязательно палиндромами, то на входном контроле эта проверка и будет делаться, а всякие прочие операции просто не нужны, а concat так просто смысла не имеет. От ситуации зависит.


Ты собрался закрыть в наследнике публичный метод предка? Вот тебе еще один гвоздь в твою идею
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[19]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.12.08 08:05
Оценка: 4 (1) +4
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ну и т.д. Было бы у меня времени больше — мог бы целый список составить. Да только незачем — это настолько обычная практика в MFC, что как-то даже неудобно доказывать ее право на существование.

Неудобно ее доказывать, Павел, вовсе не потому, что она "обычная". А потому, что доказательств нету. Весь этот топик наглядно это показывает.


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


Очередной пассаж с называнием черного белым.
Поясняю мысль: Нет, Павел, всё как раз наоборот. Мы никак не относимся к правилам как к скрижалям. Мы просто понимаем, зачем придумываются правила, и по каким критериям нужно сравнивать решения.

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

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

PD>А критерием истины, как тут Антон заметил (а впрочем, и до него другие замечали является практика. А поэтому я имею полное основание утверждать, что то, что я говорю, имеет полное право на существование.

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

Если же ты реально веришь, что CStringEx хоть в чём-то лучше, чем PalindromManager.IsPalindrome(this string str), то мне тебя жалко.

PD>Потому что я в своей практике все и всяческие каноны нарушал многократно, да еще как нарушал, и ничего — все работает уже много лет, и никто не жалуется, и работает не на 2-3 компьютерах и не в фирме "Рога и копыта"



PD>А в применении к вопросу, из-за которого сыр-бор разгорелся (sealed классы) — я просто одну простую вещь хочу сказать. Не надо меня от меня защищать. Или по крайней мере дайте мне легальную возможность эту защиту отменить. Да, я могу, если мне разрешить, накосячить с реализацией. Да, это будет плохо. Но могу и не накосячить. А поэтому не принимайте за меня решения, оставьте их мне. Накосячу — сам виноват и буду.

Вот самое что мне нравится в этой дискуссии (как и многих других с тобой), что ты замечательным образом доказываешь правоту своих оппонентов. Ну вот смотри — делается абстрактное заявление "sealed есмь зло, потому что иногда оно может мне помешать". Но когда в течение недели ты не в состоянии привести ни одного примера, где оно реально мешает, посторонний читатель делает совершенно верный вывод: "Раз даже мегаопытный Павел Дворкин не может придумать конкретного примера, значит это действительно практически никогда не нужно. Тогда зачем требовать возможность, которая помогает 1% программистов в 1% их задач, но при этом мешает 90% программистов в 10% их задач?". Всё, бухгалтерия свернулась.

И еще раз поясню, что заблуждения твои связаны с тем, что ты писал исключительно одноразовый прикладной софт. Вопросы повторного использования тебя не волнуют, равно как и вопросы выполнения каких-либо гарантий.
Одно дело, когда ты пишешь своё приложение — как я уже говорил, там можешь хоть на коболе интегралы вычислять, хоть подчерками все переменные называть. С тебя не убудет.
А вот если ты выпускаешь библиотеку, целевая аудитория которой — миллион программистов, то приходится думать и о том, как будет выпускаться версия 2.0.
Это ты за себя можешь сказать "оставьте их мне; сам накосячу — сам виноват и буду". А для вендора библиотеки шанс сломать что-то у 2% use base — смерти подобен.
Потому, что от одного миллиона — это 20000 реквестов "подонки, вы сломали моё приложение". Один ответ от саппорта "сами виноваты" стоит примерно $10. Вот и посчитай, во что выльется одно отдельно взятое счастье Павла Дворкина автору популярной библиотеки.

Поэтому в языке важны средства, позволяющие уменьшить процент недовольных апгрейдом до приемлемого. А в практике вендора библиотеки важно пользоваться этими средствами. О чем я и написал.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 08.12.08 03:32
Оценка: -5
Здравствуйте, Sinclair, Вы писали:

S>1. Классы по умолчанию должны быть sealed. Распечатывать их можно только в том случае, когда вы тщательно продумали то, как ваш код будет работать с произвольными наследниками.


Если речь идет о классах приложения, то с этим можно и согласиться. Если речь идет о классах библиотеки общего назначения — извольте тщательно продумывать , коль вы взялись эту библиотеку писать, а не закрывать классы на том основании, что вам лень было продумывать и писать как следует. Потому что иначе вы пользователям этой библиотеки ненужные проблемы создаете.
With best regards
Pavel Dvorkin
Re[36]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 02:35
Оценка: -3 :))
Здравствуйте, Sinclair, Вы писали:

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

S> Ай, молодца. А теперь покажи такой же трюк для не-void оператора?

Это ты трюком называешь ? Ну-ну... Это самая обычная реализация.

Насчет не void — please



#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include "malloc.h"

class A {
private :
    char* m_str;
public:

    operator int()
    {
        return atoi(m_str); // error handling skipped
    }
    operator char*()
    {
        return m_str;
    }
    A(char* p = NULL)
    {
        m_str = strdup(p);
    }
    virtual ~A()
    {
        free(m_str);
    }
};

class B :public A
{
public :
    B(char* p = NULL) : A(p) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
    B b("123");
    int i = b;
    return 0;
}




>Покажи-ка мне хоть один void оператор в классе CString!


Учи язык прежде чем что-то заявлять!!



S>На всякий случай напомню глубоким знатокам языка, что в CString есть 8 конструкторов, 8 операторов и 5 функций, которые возвращают CString. В твоем CPavelDvorkinIdioticStringWithIsPalindrome тебе придется перегрузить их все.


Да, плохо твое дело, если уж не остается ничего, кроме оскорблений. Впрочем, я тебя понимаю. Такой великий специалист и так глупо прокололся


PD>>Я так понимаю, что разработчики более поздних Явы и .Net ту же глупость сделали ? String.IndexOf — это не то же самое ?

S>Да, это тоже плохое решение. Я об этом писал в параллельной ветке.

Как хорошо, что авторы MFC, Java и C# ее не читали


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

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

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

S>В принципе, понятно, что ты мало знаком с реалиями промышленной разработки софта.


С Вашими реалиями я , может, и не очень знаком, да и не нужны они мне. У меня своих реалий хватит, ну а насчет промышленного
With best regards
Pavel Dvorkin
Re[21]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.12.08 05:03
Оценка: 32 (2) +2
Здравствуйте, Lazy Cjow Rhrr, Вы писали:
LCR>1. Автор фреймворка Moq говорит, что запечатанные классы — не рулят. По крайней мере первый пункт железобетонный — запечатанный класс невозможно мОкнуть обычными средствами.
Это никак не противоречит тем максимам, которые вызвали столь бурную реакцию у Павла Дворкина. Фишка в том, что именно наследование реализации может вызывать неожиданные спецэффекты. А вот реализация интерфейса — нет. Поэтому совершенно нормально иметь sealed class, реализующий целую пачку интерфейсов.


LCR>2. Как реализовать идею escaped string? Смысл в том, что обычный String передавать нельзя в некоторые места без предварительной "эскепизации", однако в остальных случаях это нормальная строка:

LCR>
LCR>class EscapedString : String { ... }
LCR>class UnescapedString : String { ... }

Прекрасный пример. Вот как раз наследование для него - худший вариант. 
Просто потому, что "в остальных случаях" EscapedString - вовсе не "нормальная строка". В частности, операции взятия подстроки и замены символов приведут к тому, что результат перестанет быть EscapedString. 
Есть пара исключений. Например, сериализация в стрим должна вести себя так же, как и в случае обычной строки. Тем не менее, говорить о каком-либо наследовании слишком смело.
Поэтому самый грамотный вариант - ввести новый тип EscapedString, который никак со строкой не связан. 
Точнее, у него должны быть определены два преобразования в строку. Примерно так:
[c#]
public class EscapedString
{
  public EscapedString(string unescaped)
    {
    }
    
  public string GetRawString(); 
    public string UnEscape();

    public static implicit operator string(EscapedString estr)
    {
      return estr.UnEscape();
    }
    public static implicit operator EscapedString(string str)
    {
      return new EscapedString(string);
    }
}

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

LCR>3. Как добавить к int, double етц информацию о том, что он реализует IAddable, ISubtractable, IDividable, IMultipliable? Чтобы иметь возможность написать:

LCR>Конечно, тут sealed не при чём, тут немного другая проблема.
Это проблема дизайна CLR. Точно так же, как в 2.0 задним числом добавили в int[] поддержку IEnumerable<int>, такие вещи надо было бы делать именно в CLR.
Даже в языке делать это уже поздно. Тем более в библиотеке.

LCR>Это больше относится к тому, что неплохо бы иметь больше рукояток
Автор: Lazy Cjow Rhrr
Дата: 14.12.08
для воздействия на стандартные классы.

То, что ты предлагаешь — это фактически накат патчей на CLR. Которые, в том числе, будут страдать от всё тех же зависимостей от деталей реализации.
Если интересуют compile-time возможности, работающие без правок CLR, то нужно смотреть на Nemerle или F#.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.12.08 12:33
Оценка: 12 (2) +2
Здравствуйте, LaPerouse, Вы писали:

LP>Да, это может быть плохо. Собственно, это единственная причина наследоваться, больше нет.

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

Есть так называемые "хаскелевские" строки, которые оформлены в виде связного списка фрагментов-подстрок.
Естественно, они тоже иммутабельные.
Но, в отличие от дотнетовых строк, операции конкатенации для них выполняются за O(1).
Дупа дотнета — в том, что интерфейс строки — слишком жирный.
Если бы бабушка была бы дедушкой, то регексы бы требовали не string, а, скажем, IEnumerable<char>. Или ICollection<char>.
А стринг бы их нативно реализовывал на интернальном array[char].
Тогда можно было бы сделать свою реализацию этих примитивов, построенную на списке или дереве блоков.

Увы. Всё, что можно сделать сейчас — это получить совершенно отдельный класс MyString, для которого определены операторы преобразования в стринг и обратно.
К сожалению, это не приведет ни к чему полезному — поскольку за пределами своего фреймворка мы всё равно будем вынуждены пользоваться обычным string, преобразования туда и обратно убьют всю выигранную производительность.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 08.12.08 12:20
Оценка: 4 (1) +3
Здравствуйте, Кэр, Вы писали:

Кэр>А вы можете изложить свою точку зрения? Это должно быть интересно. Без иронии.

Ну, прежде всего, полиморфизм отнюдь не ограничивается ООП, таким образом утверждать, что полиморфизм предполагает какие-то "отношения между типами по принципу генерализация-специализация" — несколько опрометчиво. Более того, даже если брать ООП, то, например, в динамически типизированных языках, как правило любая переменная полиморфна безовсяких отношений.
Собственно, наследование (отношения между типами по принципу генерализация-специализация) — это способ получить полиморфизм в статически типизированных языках.
В статически типизированных языках, где есть только наследование реализации, оное наследование используется и для получения ad-hoc полиморфных функций и для сокращения количества кода. В языках же оборудованных механизмом явной декларации контракта (e.g. interface), эти самые механизмы предназначены именно для получения полиморфизма в чистом виде, без побочных эффектов в виде унаследованной реализации.
Таким образом, утверждать, что абстрактный код через интерфейсы "не полиморфизм в прямом смысле слова" — довольно смело, но не верно..

Собственно, это и побудило меня в очередной раз спросить ВВ, что именно он имеет ввиду под означенными терминами, особенно меня интересует "полиморфизм в прямом смысле слова" =)
Вообще, у меня складывается впечатление, что ВВ просто выдает знакомые слова в случайном порядке, как только похожий контекст увидит, так как ни одного используемого им термина он так и не смог объяснить своими словами и рассказать что же именно имеется ввиду...
Только и умеет, что на каждую просьбу минус ставить..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[3]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.08 12:18
Оценка: +4
Здравствуйте, Chrome, Вы писали:

C>У меня постоянно возникает необходимость через Reflection менять приватные члены классов и вызывать приватные методы.

C>а кое что даже при помощи Reflection невозможно.
C>Так что необходимость есть.
Вот когда я работал с Delphi, необходимость "вскрывать" неудачно заprivate-нные классы из VCL быстро падала с ростом моей квалификации.

C>Для массовых библиотек такой подход — зло.

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

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

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

C>Не открыл метод — лишил клиента возможности доработать и использовать свой класс — заставил его написать собственный подобный — обесценил свою библиотеку.

Неверно. Можно привести пример возможности использования, которой тебя лишила запечатанность класса string? А вообще, наследование — далеко не лучший, и уж точно не единственный способ "доработки и использования".

C>Ноль проблем — если накосячит — сам виноват, никого больше это не заденет.

C>Твой код готов получать в параметрах вместо string какой-нибудь ImprovedString, который исправлен произвольным образом?
C>Так это будет мой код и мой ImprovedString, какие проблемы? Ну в крайнем случае мой код и ВАСИН ImprovedString, пойду к Васе и проблему решу, А вот в Microsoft не могу пойти решать проблему.
Налицо полное непонимание сути вещей. Разъясняю подробнее: ты используешь библиотеку, разработанную Колей. В библиотеку передаются параметры класса string. Кроме этого, ты используешь другую библиотеку, разработанную Васей. Васина библиотека возвращает объекты, отнаследованные от string, с тонким образом перекрытым методом Equals. В итоге Колина библиотека, естественно, падает. Потому что она рассчитывает на те инварианты string, которые описаны в MSDN.
Ни к Васе ни к Коле ты пойти не можешь — визы и билеты в те места, где они живут, стоят дороже разработки всего того же с нуля.

Что тебе остается? Переделывать обе библиотеки, обучая их работать друг с другом? Отлично, через полгода твоя программа работает, но Коля выпустил новую версию своей либы, в которой пофиксена критическая ошибка. Твои переделки волшебным образом перестают работать. Потому что ты наследовался от Колиных классов, а их устройство теперь изменилось трудносовместимым образом.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: Override для произвольного метода.
От: Cyberax Марс  
Дата: 15.12.08 02:17
Оценка: +4
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Все, дальше не стоит обсуждать.

PD>И все эти люди , в том числе уважаемый SchweinDeBurg, который регулярно выдает [ANN} по этому сайту, используют индуссские поделки ради строчки и т.д.
На Codeproject таки, действительно, полно поделок. Их там как раз большая часть и есть.
Sapienti sat!
Re[24]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.12.08 10:26
Оценка: +3 :)
Здравствуйте, LaPerouse, Вы писали:

LP>Такое бывает, однако, постоянно и кривость реализации тут не при чем. Наследник должен минимально зависеть от реализации базового класса, в идеале — совсем не зависеть. Поэтому многие (и Sinlair с IB в частности) советуют совершенно отказываться от наследования реализации, однако я считаю, что это уже другая крайность.

Не-не-не. Я не настолько фанатичен. Речь всего лишь о том, что разрешать наследование реализации нужно с большой осторожностью, вот и всё. Совсем его изничтожить не получится (да и не нужно).
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[40]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 12:20
Оценка: -2 :))
Здравствуйте, LaPerouse, Вы писали:

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

LP>2. Если не нужен, тогда зачем тебе наследоваться?

Что-то я не пойму, с чего ты решил, что не нужен ?

LP>3. Почему он тебе не нужен? Я что, пользуясь твоим классом, при сложении двух полиндромов и ожидая получить полиндром, получу вмесо него CString?

Тогда в топку.

А с чего это ты решил, что складывая два палиндрома (конкатенируя то есть) ты всегда получишь палиндром ?
With best regards
Pavel Dvorkin
Re[17]: Override для произвольного метода.
От: 4058  
Дата: 11.12.08 10:06
Оценка: 7 (2) +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вот, например класс CStringEx — расширяет стандартный класс CString из MFC


1. System.String в отличие от CString иммутабелен, в частности по этому класс запечатан.

Пример:


class PDString : String
{
    bool MySuperFunc();    
}


PDString pds ...;
... pds.Replace('asdas', 'asdasd')

— вуалья, возвращается System.String.
Я думаю дальше не имеет смысла описывать суть проблемы, наследования от иммутабельных классов.

2. Переопределенные операторы не наследуются (как минимум прийдется переопределить операторы конкатенации).

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

P.S. Наследование с целью расширения функциональности достаточно распространенная ошибка, об этом еще давно Страуструп упонинал в своей немногочисленной литературе.
мой первый супер string
Re[3]: Override для произвольного метода.
От: fddima  
Дата: 02.12.08 22:04
Оценка: +3
Здравствуйте, Cyberax, Вы писали:

C>Кстати, в Java все методы по умолчанию виртуальные.


Кстати, не факт что это хорошо.
Re: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.12.08 05:49
Оценка: +2 -1
Здравствуйте, Chrome, Вы писали:

C>Мне кажется, в .Net runtime можно без особых проблем привнести возможность переписать код произвольного метода.

Главное при рассмотрении любой возможности — задуматься о ее необходимости.
Большинство современных теоретиков ОО-архитектуры сходятся на том, что
а) наследование реализации — это зло, которого нужно по возможности избегать
б) проектирование виртуальных методов — сложное искусство.
Из этого делается два вывода:
1. Классы по умолчанию должны быть sealed. Распечатывать их можно только в том случае, когда вы тщательно продумали то, как ваш код будет работать с произвольными наследниками.
2. Методы класса по умолчанию должны быть невиртуальными. Виртуальными нужно делать только те методы, перегрузка которых не нарушит инварианты класса.

Исправление ошибок — интересная гипотеза. Давайте посмотрим на класс System.String. Что, если любой желающий сможет исправлять в нем "ошибки"? Твой код готов получать в параметрах вместо string какой-нибудь ImprovedString, который исправлен произвольным образом?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Override для произвольного метода.
От: fmiracle  
Дата: 04.12.08 14:16
Оценка: +3
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Есть полиморфизм через интерфейсы. Есть полиморфизм построенный на виртуальности.


Полиморфизм — он всегда через интерфейсы.
То что ты называешь "полиморфизм построенный на виртуальности" это уже комбинация полиморфизма и повторного использования кода базового класса. Для полиморфизма при наследовании используется "интерфейс" (при этом самого ключевого слова interface в языке может и не быть) базового класса.

Так что "Наследование нужно для полиморфизма" — неверно. Если нужен именно полиморфизм, то его замечательно можно получить через интерфейсы. Особенно если они поддерживаются в языке как базовые конструкции языка.
Re[8]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 09.12.08 09:14
Оценка: -3
Здравствуйте, Sinclair, Вы писали:

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


PD>>Но она на тебя сильно повлияла в этом плане. В Delphi, насколько мне известно, аналога sealed нет. В С++ тоже.

S>В Delphi достаточно не сделать метод virtual, или оставить что-то важное private для того, чтобы свести возможности перегрузки к нулю. В С++ — тоже.

Ну если об этом речь идет — то и в C# это вроде бы не запрещено. Класс-то зачем закрывать ?
Вот в java — точно не выйдет


PD>>А почему это , собственно, я должен писать свой класс, если по смыслу мне надо именно расширить функциональность существующего. Directory в ФС он и есть directory, почему должно быть 2 класса ?

S>Гм. Это — сервисный класс. У него нет экземпляров. Чью функциональность ты собрался расширять?

Вполне возможно, что придется и расширить. Вот сделает MS SQLFS , там, возможно, придется новые методы/свойства добавить. Кстати, и сейчас есть что добавить. Как там, к примеру, насчет хардлинков ? точек соединения ?

S>Если бы это был класс некоторых объектов, то еще можно было бы поныть насчет возможности отнаследовать MyDirectory от Directory и пользоваться возможностью передавать экземпляры MyDirectory везде, где нужен Directory.


Нет, не принципиально. Дело не в виртуальности, это лишь один из моментов. Расширить класс можно переопределением виртуальных методов, верно, но и просто добавлением методов тоже можно. Никаких проблем здесь не будет. Кстати, о string. Вот хочу такое

class MyString : String {
public IsPalindrom() {//...}
}

ну и что тут криминального ?

Кстати, в C++ это выглядело бы так

class MyString : public String {
public IsPalindrom() const {//...}
};

и тем самым явно сказано, что менять состояние объекта она не может.

Предлагаю не искать альтернативные решения для добавления "палиндромности". Ты их найдешь, не сомневаюсь. Но не в этом вопрос, а только в одном — что криминального в том, что я предложил ?

S>Но в данном случае такое использование невозможно, поэтому совершенно понятно даже невооруженному мозгу, что нет никакой разницы, будет ли MyDirectory наследником Directory или object.


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

Не согласен ? OK. Мысленный эксперимент.

Нет больше класса Directory. Исчез неизвестно куда. Поэтому тебе или мне предстоит его написать. Работа не бог весть какой сложности, думаю, дня за 2 справимся .

Так вот, скажи — ты будешь его разбивать на 2 класса по непонятно каким соображениям ? Получить всю коллекцию — в один класс, а энумеровать с колбэком — в другой ? ИМХО чушь получится, вот и все.

S>Повторяю — это хреновый пример. Покажи мне код предполагаемого наследника и пример его использования.


Писать код нет времени, поэтому только наметки

class MyDir : Directory {
MyFileData public static FindFirstFile(string path) {..}
bool public static FindNextFile(MyFileData data) {...}
void public static FindClose(MyFileData data) {...}
}



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

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



PD>>Do not seal classes without having a good reason to do so.

PD>>Это из MSDN.
PD>>http://msdn.microsoft.com/en-us/library/ms229023.aspx
S>Ок, в такой формулировке я оспаривать постулат не стану. Я не то чтобы на 100% верю в MSDN — его тоже не боги пишут; антипаттерны там встречаются налево и направо. Ок, давайте перевернём постулат: вместо "запечатывайте классы, наследование от которых не продумано", напишем "продумывайте наследование от всех классов, которые не запечатаны". Логически, это одно и то же, но тебе, наверное, будет комфортнее такая формулировка.

Хм... ИМХО это хорошая максима, а в реальности — бог его знает. То есть к этому надо стремиться (кто тут может возразить и сказать , что не надо продумывать . А вообще подумаю, может, завтра выскажусь.


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


Вполне допускаю, что есть и лучшие варианты, но ATL, MFC, VCL, .Net. — все они на этом построены.

S>Но в данном случае да, основной способ применения форм — наследование и перекрытие методов.


S>Вообще-то, правильный ответ на вопрос "почему запечатан класс Directory" дан прямо на той странице, на которую ты сослался: "The class is static".


Ну и что ? Да, по правилам языка static влечет sealed. Но это не ответ. Я не намерен обсуждать, правильно ли, что влечет, но уж никто не мешал объявить в нем все методы как static, а класс таковым не делать.

PD>>Так что дело не в том, что оконные классы так уж хорошо сделаны, что их кастомизацию можно позволить и не нарушить какие-то инварианты. Нарушить их там совсем не сложно. Вопрос лежит чисто в практической плоскости. Если бы окна не надо было бы кастомизировать — их бы тоже запечатали. На всякий случай — кому охота на себя лишних собак вешать из-за возможных ошибок кастомизаторов


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


Говорим-то мы одно и то же, а вот выводы разные делаем. Твоя позиция — надо бы и их запечатать, да вот приходится распечатывать. Моя позиция — не надо и Directory запечатывать, да и вообще не надо — как правило (исключения возможны). Из того факта, что некорректное расширение класса (любым способом) может повлечь за собой его неработоспособность, не следует, что это надо запретить. Да, некорректно расширенный MyString : string может привести к тому, что рухнет он при обращениии к нему как к string. Верно. Но это не причина, чтобы запретить вообще всякие изменения. ИМХО.


А вообще вопрос тоньше. Он , по существу, должен формулироваться так — каково соотношение между классами — инструментами и настраиваемыми классами, и где и когда должны использоваться те или другие.
With best regards
Pavel Dvorkin
Re[17]: Override для произвольного метода.
От: Klapaucius  
Дата: 11.12.08 08:03
Оценка: +2 -1
Здравствуйте, Pavel Dvorkin, Вы писали:

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


Не лучше ли было потратить 4 минуты и придумать пример получше?

PD>А суть проста — мы можем породить некий новый класс A1 от существующего класса A, и некий новый класс B1 от существующего класса B. Внутри класса A1 будет использоваться класс B1, в то время как в классе A экземпляры B1 будут выглядеть как B. При этом не возникает необходимости в полиморфизме-виртуальности. Примеров таких на свете сколько угодно.


Да все понятно.

Метод-расширение.

или

Класс A' наследник класса A. И N классов B'i, наследников классов Bi.

Это даже не геморрой. Это рак.

Разработчики библиотек прищемляют нашу свободу. Мешают пойти по второму пути. Запечатывают классы. Негодяи!
... << RSDN@Home 1.2.0 alpha 4 rev. 1110>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[23]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 15.12.08 09:52
Оценка: +3
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Все, дальше не стоит обсуждать.

Что ж, слив засчитан. Вообщем-то ожидалось, что ничего внятного ты больше не скажешь.. )

PD>http://img.meta.ua/rsdnsearch/?q=codeproject&amp;mode=rank&amp;group=5

PD>1194 ссылки только в форуме mfc
PD>http://img.meta.ua/rsdnsearch/?q=codeproject&amp;mode=rank&amp;group=N
PD>6423 ссылки всего.
Каким образом количество ссылок может влиять на качество кода? Самому не смешно?

PD>При таком уровне понимания дискутировать смысла просто нет.

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

PD>Предлагаю тебе сделать следующее. Выложи свои рассуждения насчет поделок на codeproject в форум MFC. Посмотрим на реакцию.

Мне здешнего паноптикума хватает, зачем я еще вражеский ресурс популяризовавать буду?
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[23]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.12.08 11:01
Оценка: +3
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Предлагаю тебе сделать следующее. Выложи свои рассуждения насчет поделок на codeproject в форум MFC. Посмотрим на реакцию.
Павел, демократическое голосование не может служить методом решения технических вопросов.

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

И не стоит сводить решение вопроса о том, хорошо ли сделан класс CStringEx, к вопросу о дискредитации codeproject. На нём есть вполне вменяемые поделки, как впрочем и килотонны мусора.

Надо применять либо собственный мозг к анализу решений, либо обращаться к людям, которые разбираются в предмете.
Членство на codeproject не даёт никаких гарантий профессионализма:

The author of CStringEX should run Purify(memory checker) on CStringEx. It particularly complains about writing out of bounds in the Delete() function.

(http://www.codeguru.com/forum/archive/index.php/t-42810.html)

Вот, к примеру, типичная проблема, которую огребает наивный пользователь унылых CxxxEx:
http://static.dreamincode.net/forums/showtopic5723.htm
Увы, за шесть лет никто не смог дать ему внятный ответ.

Вот что бывает с теми, кто неосторожно наследуется от чужого кода:
http://www.experts-exchange.com/Programming/Languages/CPP/Q_22500053.html

Я не смог найти ни одного примера применения этого CStringEx. Наверное, плохо искал. Либо он просто никому нафиг не нужен.
Зато нашел другой CStringEx. Опять же, бедному пользователю придется как-то выбирать одну из этих строк, либо руками мерджить реализации. Если бы это были хелперные функции, никакой проблемы бы не возникло. Увы, понять это люди, укушенные MFC, могут только с большим напряжением всех усилий.

Вот еще один букет поделок на основе CString: http://69.10.233.10/KB/string/stringtable.aspx
Такое впечатление, что эти люди реально не знают другого способа программировать, кроме как наследоваться от строки.
То есть чувак изобретает целый новый класс CMsg чтобы писать вот так:
SetWindowText(CMsg(IDS_MYSTRING)); // This is straightforward!

То, что это заработает безо всякого класса, ему недоступно:
СString CMsg(int resourceID)
{
  return CString(MAKEINTRESOURCE(resourceID));
}

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

Впрочем, достаточно прочесть его рекомендацию использовать числовые идентификаторы вместо мнемонических констант, чтобы сделать однозначный вывод о его уровне как архитектора.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.12.08 11:20
Оценка: +2 -1
Здравствуйте, Pavel Dvorkin, Вы писали:

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


Фи. Детский сад, штаны на лямках.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[25]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 16.12.08 11:30
Оценка: +3
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Глупо.

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

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

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

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

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

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

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

PD>Популяризовать ? Где ? В форуме MFC ? Там его популяризовать не надо, он там и так известен.

Вот именно, тебе уже объяснили, как он известен..

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

Концепции, Павел, тут непричем. О концепциях можно было бы говорить, если бы ты мог ее внятно сформулировать. А в твоем случае этого явно не наблюдается, так что и разговаривать не очем..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
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[21]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 12.12.08 15:38
Оценка: 30 (1) -1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Я тебе их 4 штуки привел.

Еще раз: с каких пор кривые реализации левых библиотек стали являться аргументом?

PD> Еще раз — такое сплошь и рядом делается в MFC

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

PD>и их приводит сайт, котррый считается одним из наиболее авторитетных источников в плане расширений существующих библиотек.

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

PD> Если ты считаешь все это левым и кривым — это твое право, но я не вижу оснований для таких утверждений.

А я вижу. Более того, и я и Антон на пальцах тебе объяснили, откуда берутся эти основания и почему. Ты же, со своей стороны, себя аргументами не утруждаешь, не к лицу это как-то преподавателю.. =)

PD>См. выше. Лично для меня рейтинг этих классов на codeproject является гораздо более серьезным аргументом, чем твои с Антоном рассуждения.

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

PD>Все начинает напоминать разгоаор глухих.

О да, ты соверщенно не слушаешь, что тебе говорят.

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

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

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

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

PD>Да просто как пример. Легкость сопровождения vs быстродействие.

К чему он тут? Какой выигрыш в быстродействии даст твой подход?

PD> Можно и другие придумать.

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

PD>А может, предоставишь мне самому решить, кого я буду винить, а ? . Какие у тебя основания утверждать, что буду винить не себя ? Мы лично не знакомы, как я работаю — ты не видел, зачем же такое утверждать ?

Я людей знаю, да и "практика говорит"..

Возвращаясь к сути спора — существует множество других способов, которыми можно расширить грамотно написанную библиотеку. Можешь привести хоть один аргумент, почему твой способ лучше и зачем предоставлять такую возможность?
Предупреждаю сразу "все так делают" — не аргумент, надеюсь ты на своих студентов так авторитетом не давишь..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[31]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.12.08 06:33
Оценка: 15 (1) +1
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Извини, но не согласен. О качестве конкретного материала — да, а о качестве ресурса — дает основание делать вывод.
А нас качество ресурса вообще не интересует. Это ты начал доказывать, что он замечательный, в контексте разговора о качестве конкретных классов.

IB>>Так что Павел, прекращай заниматься подменой понятий.


PD>Я ничего не подменяю. Я нигде не утверждал, что CStingEx — высококачественный продукт, я его и не смотрел всерьез вообще-то. Я его просто привел как пример того, что такое возможно. Вот и все.

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

PD>А не мог ли уважаемый оппонет дать хоть какой-нибудь критерий, позволяющий отличать кривой код от не-кривого ? У меня, например, есть основание утверждать, что код, реализующий litview в .NET — кривой.

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

PD>Подумал сам еще раз над вашими аргументами.

Это хорошо.
PD>ИМХО здесь некие понятия смешаны в одну кучу и говорим мы о разных вещах. Отсюда, может быть, и возинкает непонимание и несогласие.

PD>Здесь вопрос-то не о наследовании, а о добавлении новой функциональности. Регекспы, конечно, со стрингами работают, но они отнюдь не часть стринга.

Правильно! Не часть. Single Responsibility Principle.
PD>Много чего еще можно придумать, что со стрингами работать будет. Например, class russianword, со всякими склонениями и спряжениями. Едва ли стоит такую фунциональность в стринг пихать, хелпер явно лучше.
Правильно.

PD>Но есть и другое. Вот сделал ты (не ты, MS) CString. А теперь посмотри CStringEx. Не будем сейчас обсуждать качество реализации, возьмем идею — зачем сделано.

Да, давай обсудим идею.
PD>Оказывается, чтобы улучшить существующую функциональность. Если в твоем классе string есть поиск вперед, а поиск назад почему-то отсутствует, так что приходится ревертировать строки для такого поиска — что плохого, если я напишу наследника, который этот поиск назад будет делать ?
Еще раз: плохо то, что такой наследник накладывает совершенно лишние требования на использующий его код. Ты не можешь выполнить поиск назад по любой строке. Для использования этого наследника нужно обязательно сменить тип существующей строки, полученной от стороннего кода.
Ты попробуй сесть и написать пример приложения, которое пользуется этим поиском назад. И ты быстро поймешь, что
а) этот пример получается компактнее, если использовать внешний хелпер
б) либо он получается такой же, но для этого нужно написать очень-очень толстый CStringEx.
Я тебе уже приводил пример с классом CMsg, где функционал, для которого достаточно однострочной функции, реализуется через целый отдельный класс.

PD>Естественный вопрос — а где граница ? Да, улучшая поиск, можно и до регекспов дойти, и до trie-деревьев, и до хешей. Ответа точного, естественно, нет, но его и вообще нет.

Ну конечно же ответ есть. Правило большого пальца:

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

Вот тебе и граница.
PD>Если бы ты string и regexp делал бы сам — почему ты не уложил бы regexp внутрь стринга ? По-видимому. из неких соображений, связанных с OOD. Ну вот и здесь так же.
Эти соображения очень просты: нужно всегда писать так, чтобы пользоваться библиотекой было удобно. Вначале карьеры архитектору тяжело в уме прикинуть все случаи использования. Поэтому у него есть два средства:
1. Писать прототипы прикладного кода для типичных случаев, сравнивая их характеристики
2. Пользоваться эвристиками, вроде той, которую я процитировал
3. Помнить о том, что 2 — это всего лишь эвристика для 1. Поэтому иногда 1 может потребовать отойти от 1.

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

PD>Так-таки никогда ? А как же быть с наследованием от Control и т.д. Ты же не в неймспейс , где Control, это помещаешь, а в свой неймспейс, да с наследованием. Или это не есть организация кода ? Тогда какая тут организация ?

Неймспейс = организация кода. Наследование != организация кода. Что тут непонятно?

PD>Я бы согласился с этим, если бы они употреблялись именно с этой целью. Увы, они слишком общие. Это во-первых. А во-вторых, может, я не прав, но вроде бы не принято лезть со своими классами/методами в чужой неймспейс ? Как посмотрят люди, если я захочу кое-что добавить к System.Drawing ?

А зачем тебе лезть в чужой неймспейс? Лезь в свой. Вот, к примеру, ты не обратил внимание, что методы из System.Text относятся вроде бы ко строкам, но не запиханы в System?
Или что GZipStream помещен не в System.IO, а в System.IO.Compression?
Ну так вот обрати.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.12.08 03:45
Оценка: 3 (1) +1
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это есть некая подмена понятий, довольно-таки тонкая.
Павел, никакой подмены понятий нет. Как только ты начинаешь привлекать к рассмотрению популярность, ты выходишь за рамки технической дискуссии.
Совершенно неважно, явно ли проводится голосование, или по посещаемости, или по подсчету ссылок на ресурс — в любом случае речь идет о популярности. Которая может определяться техническим совершенством, а может — массовым заблуждением. Поэтому предлагаю завязать с популярностью. Иначе окажется, что лучшее применение наследования — это Стас Пьеха.


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

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


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

Это называть — типичными для тебя попытками вывернуться наизнанку, лишь бы не признавать своих заблуждений.
Если твои аргументы не относились к классу CStringEx, то давай их просто выбросим как нерелевантные и всё. Поскольку ты избегаешь прямолинейных утверждений, мне приходится догадываться, что именно ты имел в виду. Вот ты привлек (1)популярность (2)всего ресурса к обоснованию правильности одного конкретного класса. Как мне это трактовать? Как демагогию? В одном посте применено сразу три демагогических приема.


PD>Как практику — критерий истины

Ну так ведь практики-то нет!

PD>Похоже, мы под словами "ортогональность" понимаем разное. Для меня ортогональный АПИ — это АПИ, в котором любое действие можно сделать одним и только одним способом. В этом смысле такие хелперы не будут ортогональными, так как без договоренностей неизбежно эти хелперы будут пересекаться (Dvorkin.IsPalindom и Sinclair.IsStringPalindrom, даже имена могут не совпасть. Только если одна команда будет делать эти хелперы — можно на что-то надеяться.

Это понятно. Поясняю еще раз, специально для тех, кто не знает, что такое Single Responsibility Principle:
Два хелпера, написанные для разных целей, никогда не будут пересекаться по функциональности.
Не может быть такого, чтобы в PalindromManager был метод .GetBytesCount, а в Encoding — .IsPalindrome.
Я вижу, что с пониманием этого у тебя проблемы. Ты вот в качестве примеров привел классы с характерными именами — Dvorkin и Sinclair. Это показывает, что ты трактуешь класс как помойку с методами, классифицированную как угодно, кроме функциональности.

Я предлагаю делить хелперы не по имени автора или еще чему-нибудь, а по Responsibility.

Теперь вернемся к твоему примеру. Ситуация, которую ты привел, может иметь место в таком варианте: есть два класса (в разных неймспейсах, естественно), которые называются, к примеру, PalindromManager. Это само по себе редкая штука — в реальном мире не существует даже одного PalindromManager — но даже если так, то в 99% окажется, что один из классов полностью включает в себя функциональность другого. Тогда мы выкидываем более убогий вариант, и продолжаем пользоваться полным.





PD>Эхе-хе. Мы же не договариваемся, мы же члены разных команд. Я же о твоих действиях ничего не знаю. Вот и сделаю я PalindromHelper и ConversionHelper и т.д. А ты, ничего об мне не зная, свои такие (да нет, не такие, а несколько иные) соорудишь. Иван о нас тоже не знает, он свои сделает. В каждом из них чего-то не хватать будет, а что-то не лучшим образом сделано будет. Было бы наследование — не стал бы я свой хелпер делать, зная о том, что твой сущетсвует, а попробовал бы его улучшить. А ты потом мой. А Иван твой.

Противоречия выделены. Попробуй подумать на ту же тему еще раз.


PD>Э нет, не все так просто. См выше о PalindromHelper и BestPalindromHelper. Впрочем, хелперы уберем, вернемся к классу. В итоге получится класс CSuperString, в котором сделано именно лучшим образом. И вскоре всем становится известно, что лучшего средства для работы со строками, чем этот CSuperString, и не существует. Ссылок на него море , все его любят и за него голосуют , все им довольны и используют.

Пока что не видно, каким образом получится этот класс, если его разрабатывает не одна команда, а несколько несвязанных.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.12.08 07:12
Оценка: 1 (1) +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Для меня абсолютно несущественно, короче или нет. Для меня существенно — эффективнее или нет. Ради нее я готов написать в 5 раз больше текста. Критерий не принимается.

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

PD>Критерий совершенно кривой сам. Сколько будет ошибок — зависит от того, кто писать будет.

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

PD>А вот о качестве кода ты ничего не сказал. Из этого следует, что код, который позволяет писать "короче и с меньшим...", но внутри себя реализован так, что хоть святых выноси, а чтобы его не попробовали расширить, установлен как sealed — не есть кривой ? Да или нет ?

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

PD>А по моему критерию код, который для сортировки листвью его пересоздает — не просто кривой, а вообще загогулина какая-то.

С этим никто не спорил.

PD>Разумееется.



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


PD>class DString // уже готов, но в нем нет поиска назад


PD>class D1String : DString // в нем будет добавлен поиск назад


PD>class HString // а это твой хелпер


PD>ну вот и докажи.

Ну, ок. Поскольку DSting — это класс из стандартной библиотеки, все сторонние библиотеки построены на нем. В частности, есть, допустим, метод DString HttpRequest::GetParameter(DString paramName).

Вот простейший фрагмент кода, который ищет последнее вхождение одного параметра в другом:

int GetLastPos(HttpRequest &request)
{
  return HString::ReverseFind(request.GetParameter("one"), request.GetParameter("two"));
}

Здесь используется два факта:
1. У DString есть конструктор от char*, благодаря чему в него легко кормить константы.
2. HString::ReverseFind принимает аргументы типа DString
Давай перепишем его с применением твоего наследника:
int GetLastPos(HttpRequest &request)
{
  DlString temp = request.GetParameter("one"); // Здесь мы вынуждены создать копию строки, что вряд ли скажется позитивно на производительности
    return temp.ReverseFind(request.GetParameter("two"));
}

Это я еще предположил, что наследник писался в расчете на то, что в параметре ReverseFind ему передадут DStirng, а не DlString.
Итого мы имеем создание лишнего экземпляра и дополнительную строчку кода. Мы, конечно, можем и этот код записать в одну строку, но тем не менее останется лишний вызов конструктора:
int GetLastPos(HttpRequest &request)
{
  DlString temp =  // Здесь мы вынуждены создать копию строки, что вряд ли скажется позитивно на производительности
    return DlString(request.GetParameter("one")).ReverseFind(request.GetParameter("two"));
}

Это, Павел, самый-самый примитивный пример. Как только речь зайдет о чем-то более интересном, окажется, что плата за использование наследника еще возрастёт.

PD>Писать что в наследнике, что в хелпере придется одно и то же — обертку над strrchr.

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

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

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

PD>Второй аналогичный вопрос. Почему в классе Directory метод GetFiles как он сейчас есть, должен быть в этом классе, а метод GetNextFile (реализующий по сути ту же функциональность , но по другому — надо ? А если бы ее MS реализовала сама внутри нынешнего Directory (ей-то ничто не мешало это сделать!) — то не надо ?

Поясняю еще раз: по-хорошему, с самого начала должен был быть ровно один метод — тот, который возвращает ленивый список — IEnumerable<string>/IEnumerable<FileSystemInfo>.
Но в реальной жизни мы имеем дело с реальными программистами. Невозможно с первого раза реализовать идеальную библиотеку. Но есть способ дать возможность расширения библиотеки. Эта возможность — есть. Никакого unsealed она не требует.

PD>+1. Но все это не суть важно, интуиция или что-то еще. Важно одно — есть некие соображения о делении на классы.

Важно то, что ничего сверхъестественного в этих соображениях нет. Им можно научить любого человека, если он перестанет кочевряжиться и начнет думать головой.

PD>Я просто с этим не согласен. Наследование несет на себе много всякого, в том числе и организацию кода тоже. ИМХО.

Наследование нужно ровно для двух вещей:
1. Полиморфизм
2. Повторное использование реализации.
Применение его для всего остального — misuse. Ты, конечно, можешь думать как угодно, но это то же самое, что раскладывать иконки приложений в Start Menu по цветам.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Override для произвольного метода.
От: Chrome  
Дата: 02.12.08 15:32
Оценка: -1 :)
Мне кажется, в .Net runtime можно без особых проблем привнести возможность переписать код произвольного метода.
Любого метода любой managed DLL. Кроме того, любой невиртуальный метод класса можно сделать виртуальным.
Добавить поля в существующие sealed классы. И много чего еще.
Нужно это, что бы преодолеть ошибки проектирования существующих библиотек.
Из минусов вижу некоторые проблемы с безопасностью в trusted environment, но эти проблемы преодолимы.
Еще возможно, в следующей версии библиотеки автор откажется от поддержки метода, который мы переопределили. Но вероятность этого мала. И я бы пошел на такой риск ради потенциальных преимуществ.
Почему официальная практика повторного использования кода не движется в этом направлении?
Зачем проектировщики библиотек заранее гадают, какие возможности понадобится переопределить пользователям их продукта и через раз не угадывают?(Ведь, чем раньше принято решение — тем больше вероятность ошибки).
Re[2]: Override для произвольного метода.
От: Chrome  
Дата: 03.12.08 11:08
Оценка: :))
Здравствуйте, Sinclair, Вы писали:
S>Главное при рассмотрении любой возможности — задуматься о ее необходимости.

У меня постоянно возникает необходимость через Reflection менять приватные члены классов и вызывать приватные методы.
а кое что даже при помощи Reflection невозможно.
Так что необходимость есть.

S>Большинство современных теоретиков ОО-архитектуры сходятся на том, что

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

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

S>Из этого делается два вывода:

S>1. Классы по умолчанию должны быть sealed. Распечатывать их можно только в том случае, когда вы тщательно продумали то, как ваш код будет работать с произвольными наследниками.

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

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


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

S>Исправление ошибок — интересная гипотеза. Давайте посмотрим на класс System.String. Что, если любой желающий сможет исправлять в нем "ошибки"?

Ноль проблем — если накосячит — сам виноват, никого больше это не заденет.
Твой код готов получать в параметрах вместо string какой-нибудь ImprovedString, который исправлен произвольным образом?
Так это будет мой код и мой ImprovedString, какие проблемы? Ну в крайнем случае мой код и ВАСИН ImprovedString, пойду к Васе и проблему решу, А вот в Microsoft не могу пойти решать проблему.
Re[3]: Override для произвольного метода.
От: fmiracle  
Дата: 03.12.08 11:22
Оценка: +2
Здравствуйте, Chrome, Вы писали:

S>Твой код готов получать в параметрах вместо string какой-нибудь ImprovedString, который исправлен произвольным образом?

C>Так это будет мой код и мой ImprovedString, какие проблемы? Ну в крайнем случае мой код и ВАСИН ImprovedString, пойду к Васе и проблему решу, А вот в Microsoft не могу пойти решать проблему.

А если не твой и не Васин? Если ImprovedString из библиотеки от Оракла, которая тебе тоже до жути нужна? К кому пойдешь решать проблему — к Микрософту или к Ораклу?

А сколько ты времени потратишь, прежде чем поймешь, что проблема имеется в неожиданном изменении какого-то класса, который раньше всегда вел себя одним образом а теперь вдруг (с новой версии какой-то третьей библиотеки) вдруг стал вести себя иначе (но ты, заметим, не ожидаешь, что вести он себя стал иначе)?
Re[5]: Override для произвольного метода.
От: Воронков Василий Россия  
Дата: 04.12.08 11:01
Оценка: +2
Здравствуйте, Chrome, Вы писали:

C>Наиболее часто хочется модифицировать методы .Net framework. Эти сборки лежат в GAG. Если я их отредактирую, во первых отвалится подпись, во вторых эти изменения отразятся на других программах.

C>Чего хотелось бы от CLR — что бы он во время JIT компиляции заменял стандартные функции на пропатченные варианты.
C>Естественно, все это должно действовать локально в рамках моей программы, на основе ее конфигурационного файла.

А зачем модифицировать методы стандартных классов? Какого эффекта хочется добиться? Хак какой-нибудь учудить зачастую можно и через рефлекшин — но при этом надо быть готовым к тому, что все это может спокойно отвалиться в будущем.
Принцип я могу отнаследоваться от любого класса и перекрыть любой метод в корне неправильный. И он на самом деле скорее противоречит ОО-принципам. Я вот не считаю, что наследование — это зло, при грамотном использовании одна из основных фишек ООП, при этом у меня на проектов процентов 90 классов — sealed.
Если мы разрешаем наследование, то класс сам по себе должен быть изначально спроектирован с учетом этого. Не говоря уж о том, что во многих случаях наследование просто бессмысленно. Наследование нужно для полиморфизма. Но даже если наш класс предполагает наследование от него это не означает того, что должна быть возможность перекрыть все методы. Как раз наоборот — должна быть возможность лишь внести некоторые коррективы в поведение класса, специализировать его, не изменяя общий функционал. Все остальное — антипаттерн.
А то, что методы виртуальные по умолчанию — это ошибочный дизайн в джава.

AVK>>>>Могу посоветовать очень хорошее решение проблемы — совсем не использовать наследование в качестве публичного интерфейса. Тогда и угадывать ничего не придется.

C>>>- я имею в виду очень конкретный случай — программирование под .Net с использованием его стандартных библиотек
AVK>>Как будто на практике всерьез можно рассматривать их неиспользование
C>>>, куда там без наследования?
AVK>>Давай конкретные примеры, иначе это воду в ступе толочь.

C>Нуу эээ — предположим, мы программируем под ASP.Net — и как то так получается, вунуждены создавать наследников от Web.UI.Page

C>откажемся от наследования? Будем IHttpHanler имплементировать?

Кстати, неплохая идея

C>захотели добавить свой контрол — будьте добры унаследоваться от Web.UI.Control — иначе не сможете добавить его ни в одну иерархию. А если унаследовались — вынуждены мириться с его реализацией. Как от нее отказаться?

C>Вот и мечтаю я о патчах.

А что конкретно хочется изменить в асп.нет?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[7]: Override для произвольного метода.
От: Воронков Василий Россия  
Дата: 04.12.08 13:55
Оценка: +1 -1
Здравствуйте, AndrewVK, Вы писали:

ВВ>>Наследование нужно для полиморфизма.

AVK>Для полиморфизма нужно наследование интерфейсмов, а здесь речь о наследовании реализаций.

Есть полиморфизм через интерфейсы. Есть полиморфизм построенный на виртуальности. Я не считаю последнее злом, вполне уместное во многих случае решение с т.з. дизайна.

А о чем речь тут можно будет полностью понять, когда автор-таки приведет пример, чего в конкретном случае он хочет добиться через наследование
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[9]: Override для произвольного метода.
От: Воронков Василий Россия  
Дата: 04.12.08 14:46
Оценка: -2
Здравствуйте, fmiracle, Вы писали:

F>То что ты называешь "полиморфизм построенный на виртуальности" это уже комбинация полиморфизма и повторного использования кода базового класса. Для полиморфизма при наследовании используется "интерфейс" (при этом самого ключевого слова interface в языке может и не быть) базового класса.

F>Так что "Наследование нужно для полиморфизма" — неверно. Если нужен именно полиморфизм, то его замечательно можно получить через интерфейсы. Особенно если они поддерживаются в языке как базовые конструкции языка.

Вы не путаете интерфейсы как контракты и полиморфизм через интерфейсы? Полиморфизм предполагает что один тип может быть использован в качестве другого если он имеет с ним отношения по принципу генерализация-специализация. Повторное использование кода тут вообще не причем. Каждый класс в иерархии наследования должен специализировать поведение вышестоящего класса, а весь код можно хоть во внешние хелперы вынести.
И да, наследование нужно именно для полиморфизма. А вот для того, чтобы писать более "абстрактный" код через интерфейсы наследование действительно не нужно. Только это не полиморфизм в прямом смысле слова.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[3]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.12.08 11:10
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Если речь идет о классах приложения, то с этим можно и согласиться.
Классы приложения никого не интересуют. Их вообще никто не собирается использовать повторно, поэтому sealed они или не sealed — вопрос второстепенный.
PD>Если речь идет о классах библиотеки общего назначения — извольте тщательно продумывать , коль вы взялись эту библиотеку писать, а не закрывать классы на том основании, что вам лень было продумывать и писать как следует. Потому что иначе вы пользователям этой библиотеки ненужные проблемы создаете.
Налицо трагическое непонимание сути вещей.
Автор библиотеки берет на себя некоторые обязательства. Он обещает, что библиотека выполняет некоторые функции, при штатном ее использовании. При этом очень важно объяснить, какое использование — штатное, а какое — нет. Простой вопрос: нужно ли вызывать в overriden методе метод предка? Если да, то в какой момент? Будет ли работать библиотека, если не вызвать предка? Или получится трудноуловимый баг?
Сама подстановка вопроса подсказывает пытливому уму, что не все методы одинаково полезно перекрывать.

По вопросу запечатывания класса поясняю еще раз: да, допустим я всё продумал. И вижу, что никакие модификации поведения этого класса путем наследования не могут гарантировать выполнение инвариантов. Повторно вопрошаю: какие изменения вы хотите сделать в классе System.String?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 09.12.08 10:22
Оценка: :))
Здравствуйте, Klapaucius, Вы писали:

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


PD>>Моя позиция — не надо и Directory запечатывать, да и вообще не надо — как правило (исключения возможны).


K>Вы понимаете разницу между static class и sealed class?


Я понимаю, что

Static Classes

They are sealed.

Это из MSDN. И это все, что я хотел сказать. Другие особенности static классов я здесь не рассматриваю.
With best regards
Pavel Dvorkin
Re[7]: Override для произвольного метода.
От: EvilChild Ниоткуда  
Дата: 09.12.08 17:11
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А почему это , собственно, я должен писать свой класс, если по смыслу мне надо именно расширить функциональность существующего. Directory в ФС он и есть directory, почему должно быть 2 класса ?


Почему для расширения функциональности необходимо наледоваться?
Я ещё понимаю для кастомизации поведения.
Тебе знаком принцип подстановки Лисков?
Можешь продемонстрировать его применение на статических классах?

PD>Ларчик открывается просто. Если оконный класс запечатать — кому он нужен будет ? Что я могу с окнами делать, если я не в состоянии их кастомизировать ? Ну Move, ну Resize, а даже Redraw не получится (в Windows), так как потянет OnPaint. Толку от такого оконного класса никакого. Именно кастомизация (==создание наследника) оконных классов и есть создание GUI (я говорю о десктопных приложениях и не о WPF).


Как вариант решения этой проблемы ты можешь передавать в конструктор колбеки для всех точек кастомизации.
now playing: Boris Brejcha — Die Maschinen Marschieren
Re[13]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.12.08 08:18
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Я просто имел в виду, что все методы в Яве виртуальные.

Я просто имел в виду, что это неправда.

PD>Перечитал. Те, кто используют обычный string — да, должны. Те, кто будут использовать MyString — не должны. Вот напишу свою PalindroManager и в нем будет исключительно MyString использоваться.

Павел, ты правда не понимаешь, или придуряешься?
Твоим MyString не пользуется никто. Текстбоксы не возвращают MyString. TextReader не читает MyString из стрима. StringBuilder не собирает MyString. Нет ни одного метода во всем огромном множестве кода, который бы вернул тебе MyString.
Твоя библиотека или приложение не будет работать в вакууме. Придется как-то интероперировать с окружающим миром. И ты на полном серъезе предлагаешь только ради проверки на палиндромность порождать новый класс, который потребует предварительной конверсии каждой строки для выполнения проверки?


Какая идея может оправдать этот немыслимый бред? По-моему, никакая.

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

Идея — в том, чтобы не заставлять пользователей твоего метода IsPalindrome заниматься непроизводительной работой. То, на чем ты так упорно настаиваешь, отвратительно сказывается на производительности как программиста, так и программы.

PD>Нет.

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

PD>Понят, понят. См. выше.

Нет, не понят. Ты попробуй все же придумать, хотя бы в уме, реалистичный пример реализации хотя бы того же PalindroManager. Я тебе заранее говорю: как бы ты ни подгонял задачу под свое решение, extension method будет комфортнее в использовании. С ним PalinroManager будет короче и понятнее.

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

Ничего подобного. Я просто пытаюсь тебе показать, что все вопросы правильно/неправильно решаются исключительно сравнением кода. Если для использующего кода нет никакой разницы, что там написано, то нет смысла и настаивать на своем. Получается, что ты жалуешься на несуществующее ограничение. Задача, которую ты поставил — написать класс с другими методами итерирования по каталогу — решается на существуюшем языке, и невозможность наследования от класса Directory никак этому не мешает.

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

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

PD>Вот ответь на вопрос — а зачем в C# вообще static классы ? Инстансов от них не дождешься, это просто набор методов. Почему бы просто внеклассовые функции не разрешить, как в С++ ? Упаковать их в namespace и дело с концом, туда никто не запрещает добавлять. Так нет же, все же в класс их поместили. И правильно.

И какое отношение этот вопрос имеет к разрешению наслледоваться от класса Directory?


PD>Так все же был бы один класс! Тогда ответь на вопрос — а почему ? Иными словами, какие идейные соображения движут тобой, когда ты принимаешь решение — быть тут одному классу или нескольким ? Подчеркиваю, речь идет о static классах, так чтт без виртуальных рассуждений, please.

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


PD>Да и вообще модификации — это и замена, и добавление. А замена, в свою очередь — замена виртуальных и невиртуальных. А добавление — инстансных или статических. ИМХО вместо того, чтобы чохом запрещать все, надо было более гибкую политику вести. Например, запретить переопределение виртуальных методов базового класса, но разрешить добавление новых методов.

Это делается путем запечатывания отдельных методов.
PD>И т.д. Возможно, следовало бы вместо sealed аттрибуты использовать или играть с модификаторами доступа.
Рекомендую сначала ознакомиться с матчастью. После этого внятно сформулировать свои претензии к ней. Желательно в виде примеров. Пока что оба примера не выдерживают никакой критики: в одном случае использование наследования не играет никакой роли, в другом приводит к ухудшению свойств решения.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 10.12.08 11:17
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Слушай, не придуривайся сам. Из того, что в существующем FW никто с ним работать иначе как со string не будет (еще бы!) вовсе не следует, что в расширении FW его нельзя будет использовать.

Павел, я в четвертый раз настаиваю на том, что даже "в расширении FW" с твоей строкой будет работать менее удобно, чем с внешним методом IsPalindrome.
S
PD>Какой к богу проверки ? Создаем наследника от TextBox, к примеру.
Отлично. То есть нам уже нужно создавать наследника от TextBox. Спрашивается — нахрена? Это что, более удобно, чем пользоваться стандартным TextBox?
А если строку надо читать из файла, то будем наследоваться от TextReader?

PD>Кладем его на форму. В нем поле MyString Text1. В него считываем из Win32 edit, создавая при этом экземпляр MyString.

Отлично. То есть вместо использования существующей строки, мы создаем ее дубликат. Точнее, в данном контексте уже предлагается отказаться от готовой инфраструктуры WinForms, и напрямую бегать в Win32 через интероп. И всё это ради того, чтобы узнать, не является ли введенная пользователем строка палиндромом?

S>>Какая идея может оправдать этот немыслимый бред? По-моему, никакая.

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

PD>Обоснуй насчет производительности программы на примере моего расширения MyString и твоей Utility. Имей в виду — функция не виртуальная, так что насчет callvirt — не надо.

Обосновываю: вместо того, чтобы проверить статус существующей строки, нужно породить новый экземпляр MyString.


PD>А какая логичность в том, что в классе MyDirectory обраны эти методы, а не создано 3 класса, по которым их бы разнесли ?

Какие методы? Твои три метода вместо одного, который возвращает IEnumerable? Никакой логичности, очевидно, нет. Глядя на код я сразу вижу, что его писал человек, не знакомый с .Net Framework.

S>>И какое отношение этот вопрос имеет к разрешению наслледоваться от класса Directory?

PD>Самое прямое. Если я расширяю класс Directory — я создаю более мощный "Directory". То есть static класс есть логически собранный набор методов для определенной области. Средство организации, так сказать. И поэтому все средства для работы с этой областью должны быть в этом классе, а не где угодно еще. Или в расширенном классе.
Ну они и так в расширенном классе. По прежнему жду примера кода, который пользуется твоим MyDirectory, и при этом ты не можешь написать этот MyDirectory на существующем C#.

PD>Если ты с этим не согласен — тогда зачем вообще этот класс ? Разместить их по namespace и дело с концом. Зачем класс нужен ?

Я потерял нить рассуждений.

PD>Если ты не понимаешь разницу между введением еще одного класса, не имеющего никакого отношения к данному и созданием наследника, расширяющего возможности данного и лишь подсчитываешь число классов — о чем тогда вообще говорить!

Да, я не вижу никакой разницы. И ты пока что не смог ее продемонстрировать. Говорить, в принципе, действительно не о чем.

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

Ничего плохого, очевидно, не будет. Скорее наоборот — будет набор ортогональных утилитных классов. Ими можно будет пользоваться достаточно удобным способом.
А ты лучше на досуге подумай, как будет выглядеть аналог с наследованием. От кого я буду наследовать MyDirectory — от Directory или от YourDirectory? Почему? Как быть, если мы не знали о библиотеках друг друга во время разработки?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 12.12.08 07:29
Оценка: -2
Здравствуйте, IB, Вы писали:

Я же привел тебе CStringEx

PD>>Вот, например класс CStringEx — расширяет стандартный класс CString из MFC

IB>Если в одном месте накосячили, значит везде нужно? Тут ребята наступили ровно на те же грабли, более того, они это явно осознают:
IB>Some of the CStringEx functions use knowledge of the internal structure of the CString object so there is a small chance that these functions might break if the CString implementation changes.
IB>Это настолько явный косяк, что тут даже говорить не о чем. И вообще, с каких пор кривые реализации левых библиотек стали аргументом?
IB>Эти ребята, всего лишь, в очередной раз показали как нельзя делать.

Ясно.

Вот этот тоже показал, как нельзя делать

http://www.codeproject.com/KB/string/cstringex.aspx


И вот этот

http://www.codeproject.com/KB/GDI/akBufferedDC.aspx

и еще

http://www.codeproject.com/KB/GDI/CBufferDC.aspx

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

А примеры того, где это может быть нужно, можешь там и посмотреть. Там demo есть.

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


Беда в том, что и ты, и Антон, да и не только вы, а многие здесь, относятся к правилам как к чему-то такому, что нарушать нельзя ни в коем случае. Запрещено, и точка. Все равно, что попытка нарушить закон сохранения энергии — того, кто в своих рассуждениях ему противоречит, надо пригвоздить к позорному столбу, вот и все. И если чье-то решение подпадает под некий анти-паттерн, к примеру — анафема, и все.
Что же касается меня, то я к ним отношусь как не более чем неким рекомендациям. Им можно следовать, им, наверное, даже лучше следовать, но если есть к тому основание, ими вполне можно пренебречь. И не бояться при этом обвинений в незнании принципов ООП или некошерности в каком бы то ни было ином смысле, или даже в кривизне решения. Просто надо сравнить проигрыш от неследования этим правилам и выигрыш от этого же неследования. Если второе перевешивает — спокойно нарушаем эти правила и посылаем куда угодно критиков. А перевешивает или нет — зависит от задачи и целей. Кому-то очень важна легкость сопровождения, и ради нее он готов пожертвовать быстродействием, а кому-то (мне) нужно получить максимальное быстродействие любой ценой, потому что все прочие нарушения заказчик мне простит, а вот потерю быстродействия — нет.

А критерием истины, как тут Антон заметил (а впрочем, и до него другие замечали является практика. А поэтому я имею полное основание утверждать, что то, что я говорю, имеет полное право на существование. Потому что я в своей практике все и всяческие каноны нарушал многократно, да еще как нарушал, и ничего — все работает уже много лет, и никто не жалуется, и работает не на 2-3 компьютерах и не в фирме "Рога и копыта"


А в применении к вопросу, из-за которого сыр-бор разгорелся (sealed классы) — я просто одну простую вещь хочу сказать. Не надо меня от меня защищать. Или по крайней мере дайте мне легальную возможность эту защиту отменить. Да, я могу, если мне разрешить, накосячить с реализацией. Да, это будет плохо. Но могу и не накосячить. А поэтому не принимайте за меня решения, оставьте их мне. Накосячу — сам виноват и буду.
With best regards
Pavel Dvorkin
Re[21]: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 13.12.08 17:26
Оценка: +1 -1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Их приводит один из наиболее авторитетных источников — codeproject


Гы гы.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[22]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 15.12.08 02:08
Оценка: :))
Здравствуйте, IB, Вы писали:

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


Все, дальше не стоит обсуждать.

http://img.meta.ua/rsdnsearch/?q=codeproject&amp;mode=rank&amp;group=5

1194 ссылки только в форуме mfc

http://img.meta.ua/rsdnsearch/?q=codeproject&amp;mode=rank&amp;group=N

6423 ссылки всего.

И все эти люди , в том числе уважаемый SchweinDeBurg, который регулярно выдает [ANN} по этому сайту, используют индуссские поделки ради строчки и т.д.

При таком уровне понимания дискутировать смысла просто нет.



IB>Во-первых, то что там так принято — это исключительно их проблемы, ктож им доктор?

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

Предлагаю тебе сделать следующее. Выложи свои рассуждения насчет поделок на codeproject в форум MFC. Посмотрим на реакцию.
With best regards
Pavel Dvorkin
Re[23]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 15.12.08 09:09
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А теперь ответ на твой вопрос. Собственно, я уже его давал. Повторю


PD>class A{};

PD>class B{};

PD>class A1 : A {};

PD>class B1 : B {};

PD>Внутри класса B1 используется класс A1. Он больше нигде не виден и не нужен. Он расширяет возможности A. Везде за пределами B1 (то есть в B , А также в других местах) экземпляры A1 выглядят как A. Виртуальности здесь нет вообще.

А класс B1 где используется? Если он используется неполиморфно, то он сам может быть заменен классом-хелпером или аггрегацией.
Если рассматривать не сферического коня в вакууме, а рельный код, то окажется что наследования без полиморфизма почти всегдпа возможно заменить хелперами или аггрегацией. Аггрегация гораздо больше соотвествует принципам хорошего ОО-дизайна, таким как Interface Segregation Principle и Dependency Injection Principle.

PD>В общем, полиморфизм без наследования невозможен, а вот наследование без полиморфизма

Моя плакать...

LP>>Люди, привыкшие к такой ублюдочной библиотеке, как MFC, могут выдержать многое. В этом случае никакой это не критерий.

PD>Люди, считающие, что аргументы такого рода вообще являются аргументами, вряд ли заслуживают того, чтобы их аргументы всерьез обсуждались. Тавк что лучше сними это заявление.
Зря ты так говоришь. Люди часто путают удобство\правильность и привычность. Если кому-то привычно писать на MFC и в духе MFC, то не значит так писать правильно.
Есть принципы и паттерны проектирования ПО, следование которым дает вполне определенные преимущества (выявленные анализом многих программ). А ты пытаешься показать что нарушение принципов может дать какие-то преимущества, причем доказательства сводятся к примерам библиотек (возможно очень тебе привычных), нарушающих эти принципы.
Re[23]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 15.12.08 11:43
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>В общем, полиморфизм без наследования невозможен, а вот наследование без полиморфизма

Павел, ты бы прежде чем рассуждать про ООП, наследование и правильность MFC, хоть основы бы выучил, а то вообще как-то не серьезно. =)
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[24]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 16.12.08 10:50
Оценка: :))
Здравствуйте, IB, Вы писали:

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


PD>>Все, дальше не стоит обсуждать.

IB>Что ж, слив засчитан. Вообщем-то ожидалось, что ничего внятного ты больше не скажешь.. )

Глупо.

PD>>http://img.meta.ua/rsdnsearch/?q=codeproject&amp;mode=rank&amp;group=5

PD>>1194 ссылки только в форуме mfc
PD>>http://img.meta.ua/rsdnsearch/?q=codeproject&amp;mode=rank&amp;group=N
PD>>6423 ссылки всего.
IB>Каким образом количество ссылок может влиять на качество кода? Самому не смешно?

PD>>При таком уровне понимания дискутировать смысла просто нет.

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

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


IB>И при таком уровне понимания, действительно разговаривать не очем, бесполезно что-то объяснять человеку, вся аргументация которого совдится к "они же так делают", если при этом он сам не понимает почему они так делают.


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

PD>>Предлагаю тебе сделать следующее. Выложи свои рассуждения насчет поделок на codeproject в форум MFC. Посмотрим на реакцию.

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

Популяризовать ? Где ? В форуме MFC ? Там его популяризовать не надо, он там и так известен. А вот себя ты точно там так отпопуляризуешь, если с таким заявлением выступишь, что я тебе не завидую

А насчет вражеского ресурса — вот это, скорее всего, и есть истина. Видимо, для тебя те, кто не принимают твои концепции (ваши концепции) — враги. Ну что же...
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[32]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 25.12.08 06:10
Оценка: :))
Здравствуйте, Sinclair, Вы писали:

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

PD>>Извини, но не согласен. О качестве конкретного материала — да, а о качестве ресурса — дает основание делать вывод.
S>А нас качество ресурса вообще не интересует. Это ты начал доказывать, что он замечательный, в контексте разговора о качестве конкретных классов.

Да, начал.


PD>>Я ничего не подменяю. Я нигде не утверждал, что CStingEx — высококачественный продукт, я его и не смотрел всерьез вообще-то. Я его просто привел как пример того, что такое возможно. Вот и все.

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

Возможность, а не необходимость.

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


Для меня абсолютно несущественно, короче или нет. Для меня существенно — эффективнее или нет. Ради нее я готов написать в 5 раз больше текста. Критерий не принимается.

>и с меньшим количеством ошибок.


Критерий совершенно кривой сам. Сколько будет ошибок — зависит от того, кто писать будет.

А вот о качестве кода ты ничего не сказал. Из этого следует, что код, который позволяет писать "короче и с меньшим...", но внутри себя реализован так, что хоть святых выноси, а чтобы его не попробовали расширить, установлен как sealed — не есть кривой ? Да или нет ?

> Поэтому "проверяльщик на палиндромы", который требует, к примеру, сабклассинга TextBox — кривой.


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


PD>>Но есть и другое. Вот сделал ты (не ты, MS) CString. А теперь посмотри CStringEx. Не будем сейчас обсуждать качество реализации, возьмем идею — зачем сделано.

S>Да, давай обсудим идею.
PD>>Оказывается, чтобы улучшить существующую функциональность. Если в твоем классе string есть поиск вперед, а поиск назад почему-то отсутствует, так что приходится ревертировать строки для такого поиска — что плохого, если я напишу наследника, который этот поиск назад будет делать ?
S>Еще раз: плохо то, что такой наследник накладывает совершенно лишние требования на использующий его код. Ты не можешь выполнить поиск назад по любой строке. Для использования этого наследника нужно обязательно сменить тип существующей строки, полученной от стороннего кода.

Разумееется.

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

S>а) этот пример получается компактнее, если использовать внешний хелпер

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

class DString // уже готов, но в нем нет поиска назад

class D1String : DString // в нем будет добавлен поиск назад

class HString // а это твой хелпер

ну вот и докажи.

S>б) либо он получается такой же, но для этого нужно написать очень-очень толстый CStringEx.


Писать что в наследнике, что в хелпере придется одно и то же — обертку над strrchr.

PD>>Естественный вопрос — а где граница ? Да, улучшая поиск, можно и до регекспов дойти, и до trie-деревьев, и до хешей. Ответа точного, естественно, нет, но его и вообще нет.

S>Ну конечно же ответ есть. Правило большого пальца:
S>

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

S>Вот тебе и граница.

Ну что же, давай обсудим. Объясни с этой точки зрения, почему прямой поиск не надо было выносить во внешний код, а обратный поиск (коль скоро его в базовом классе нет) — надо.
Второй аналогичный вопрос. Почему в классе Directory метод GetFiles как он сейчас есть, должен быть в этом классе, а метод GetNextFile (реализующий по сути ту же функциональность , но по другому — надо ? А если бы ее MS реализовала сама внутри нынешнего Directory (ей-то ничто не мешало это сделать!) — то не надо ?

Вот можешь прямо на эти два примера ответить ?




PD>>Если бы ты string и regexp делал бы сам — почему ты не уложил бы regexp внутрь стринга ? По-видимому. из неких соображений, связанных с OOD. Ну вот и здесь так же.

S>Эти соображения очень просты: нужно всегда писать так, чтобы пользоваться библиотекой было удобно. Вначале карьеры архитектору тяжело в уме прикинуть все случаи использования. Поэтому у него есть два средства:
S>1. Писать прототипы прикладного кода для типичных случаев, сравнивая их характеристики
S>2. Пользоваться эвристиками, вроде той, которую я процитировал
S>3. Помнить о том, что 2 — это всего лишь эвристика для 1. Поэтому иногда 1 может потребовать отойти от 1.

S>Ну, а после некоторой практики, вырабатывается интуиция, подсказывающая, как действовать. Твоя ошибка в том, что ты считаешь интуицию самостоятельным источником для принятия решений. А на самом деле интуиция — всего лишь невербальное обобщение практического опыта.


+1. Но все это не суть важно, интуиция или что-то еще. Важно одно — есть некие соображения о делении на классы.

PD>>Так-таки никогда ? А как же быть с наследованием от Control и т.д. Ты же не в неймспейс , где Control, это помещаешь, а в свой неймспейс, да с наследованием. Или это не есть организация кода ? Тогда какая тут организация ?

S>Неймспейс = организация кода. Наследование != организация кода. Что тут непонятно?

Я просто с этим не согласен. Наследование несет на себе много всякого, в том числе и организацию кода тоже. ИМХО.
With best regards
Pavel Dvorkin
Re[35]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 08:52
Оценка: +1 -1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Не приходилось тебе, видимо, этим заниматься.

Приходилось.
PD>Ускорить прямой код — иногда это означает полное его переписывание с нуля. Выбраны неправильные подлежащие структуры данных — и все, привет, ничего ты не ускоришь.
Если код написан хорошо, то замена "подлежащих структур данных" делается легко и приятно. В том смысле, что изменения локальны и невелики.
Видимо, тебе не приходилось иметь дела с хорошо написанным кодом.

PD>А можно узнать, почему обязательно если уж наследование, то бездумное ? Я вроде к бездумному не призывал. И потом, если уж ты против бездумного — так с обдуманным наследованием ты согласен ?

Конечно согласен. Можешь перечитать тот самый первый постинг, с которым ты начал спорить.



PD>Все, что тебе удалось здесь обосновать — это то, что прочие библиотеки не будут работать с наследником как с наследником, а будут — как с предком. Поэтому тебе и понадобилось сюда передать этот HttpRequest, в котором нет D1String, а есть DString. Я уже на этот вопрос отвечал.

Плохо отвечал. Некачественно. Тебе до сих пор непонятно, что в твоем подходе для достижения аналогичной производительности придется писать много лишнего кода? Ок, я тебе больше отвечать не буду, пока ты не приведешь полный компилирующийся пример, иллюстрирующий твой подход.
PD> С учетом того, что новых параметров здесь нет, это очень-очень сложно
А ты код в студию приведи.
PD>Слушай, ты хоть по языку руководство почитал бы, что ли... . С чего это им всем не наследоваться-то, если это просто функции со специфическим именем ?
Ай, молодца. А теперь покажи такой же трюк для не-void оператора? Покажи-ка мне хоть один void оператор в классе CString!
На всякий случай напомню глубоким знатокам языка, что в CString есть 8 конструкторов, 8 операторов и 5 функций, которые возвращают CString. В твоем CPavelDvorkinIdioticStringWithIsPalindrome тебе придется перегрузить их все.

PD>Ну если начинающие архитекторы последуют рекомендациям столь крупных специалистов по языку, то тогда, конечно, они не один лишний Кб кода напишут.

То есть по делу сказать нечего.

PD>Я так понимаю, что разработчики более поздних Явы и .Net ту же глупость сделали ? String.IndexOf — это не то же самое ?

Да, это тоже плохое решение. Я об этом писал в параллельной ветке.

PD>Ну с самого начала его быть не могло в таком виде по причине отсутствия темплейтов в 1.1

Правильно.

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

Павел, пока что ты добиваешься только того, что полфорума здесь станут считать тебя идиотом.
Я тебе уже один раз сказал: я не следую жестко выдуманным правилам. Я просто, в отличие от тебя, знаю, почему имеет смысл применять те или иные эвристики.
А ты мало того, что не знаешь, так еще и отрицаешь любой анализ на эту тему. Прикрываясь либо ссылками на то, что "вот я нашел кусок говнокода — значит так писать можно", либо неотносящимися к делу рассуждениями о перформансе и неважности выбора базового класса для наследования.

Примеры, которые ты приводишь, не выдерживают никакой критики. Вот ты утверждаешь, что наследование даст возможность получить "один самый лучший класс". Ну, и где он? Я беглым просмотром нашел не то три, не то четыре разных реализации CStringEx. Что-то не видно, чтобы их авторы отреагировали на твои мечты и добавили функции друг в друга.
Не работает модель. А в случае хелперов прикладному программисту не нужно выбирать ровно один класс из кучи малопригодных инвалидов. Он может совместно использовать хелперы.
В принципе, понятно, что ты мало знаком с реалиями промышленной разработки софта. Но вот то, что ты не хочешь прислушаться к тем, кто знаком — вот это уже непонятно.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[37]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.12.08 09:20
Оценка: +1 :)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Учи язык прежде чем что-то заявлять!!

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

PD>Да, плохо твое дело, если уж не остается ничего, кроме оскорблений. Впрочем, я тебя понимаю. Такой великий специалист и так глупо прокололся

На мой взгляд, прокололся тот, кто продолжает гнуть пальцы в ответ на предложение привести код наследника от CString, который полностью поддерживает его интерфейс. Впрочем, продолжай — мне нравится твой энтузиазм, с которым ты хоронишь свое реноме
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[43]: поправка
От: Pavel Dvorkin Россия  
Дата: 29.12.08 13:56
Оценка: :))
PD>Нет. 'Concat' : is not a member of ...

Сорри, не то написал. Да, InvalidCast. Совершенно верно. Нет такого преобразования потому что.
With best regards
Pavel Dvorkin
Re[46]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 30.12.08 07:13
Оценка: -1 :)
Здравствуйте, LaPerouse, Вы писали:

LP>Полиморфизм от наследования тебе не нужен, и лишние методы от родителя в конракте CPalindrom не нужны, назови же тогда причину зачем тебе нужно наследование?


На тебе ( и Синклеру) пример. Правда, вместо CString я использовал string из STL — CString с консольными приложениями не очень уместен (хотя и возможен), а флейма на тему "почему это так в MFC и так ли это должно быть" я не хочу




#include <string>
#include <iostream>

using namespace std;

void DoSomething(string& str)
{
}

void test()
{
    class pstring : public string
    {
    public :
        pstring(char* p = "") : string(p) {}
        bool IsPalindrom()
        {
            const char* start = c_str(), *end = start + length() - 1;
            for ( ; start < end &&  *start == *end; start++, end--);
            return start >= end;
        }
    };
    
    pstring str;
    cin >> str;
    if(str.IsPalindrom())
     DoSomething(str);
}

int main()
{
    test();
    return 0;
}



LP>Итак, получаем:

LP>1. Бенефит от наследования — полиморфизм — тебе не нужен

Сейчас нет. В дальнейшем может , и понадобится.

LP>2. Метод concat, который тебе достался от предка и который тебе не нужен, мешается.


Абсолютно не нужен здесь. И масса других не нужна.

LP>Так на кой черт тогда использовать наследование?


Посмотри пример.

LP>Ты собрался закрыть в наследнике публичный метод предка? Вот тебе еще один гвоздь в твою идею


А мне его и закрывать не надо. По умолчанию в языке C++ все закрывается (наследование по умолчанию приватно), так что мне здесь, наоборот, открыть их пришлось. А , собственно, что в этом плохого ? Создается специализированная версия класса, естественно, я вполне могу не хотеть, чтобы те методы, которые я считаю некорректным здесь вызывать, вызывались, так что можно и скрыть. Впрочем, ничего не скрыто в примере. Да и неважно это — класс локализован, за пределами test его просто не существует.

Да, конечно, IsPalindrom можно было бы реализовать хелпером (в данном случае даже без дополнительного класса. хватит просто функции). Но сейчас она инкапсулирована в класс и только для его экзмепляров может вызываться, в то время как в случае хелпера ее можно будет вызывать где угодно и для любых string, чего я вовсе не хочу. А не хочу потому, что мне надо ней полная власть нужна. В пределах pstring понятие "палиндром" существует и определяется приведенным алгоритмом, который я вправе изменить, если хочу. Нигде, кроме как в pstring (то есть в test) об этом никто и узнать не сможет. А выпускать эту IsPalindrom во внешний мир я вовсе не желаю.
Есть и еще один момент против хелпера. Ему protected поля и методы класса string недоступны, а мне — вполне доступны. Я этим здесь не воспользовался, а в другом случае мог бы.

Разумеется, это лишь один из возможных вариантов. Могут быть и другие.
With best regards
Pavel Dvorkin
Re[20]: Override для произвольного метода.
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 14.12.08 21:45
Оценка: 87 (1)
Sinclair,

PD>>А критерием истины, как тут Антон заметил (а впрочем, и до него другие замечали является практика. А поэтому я имею полное основание утверждать, что то, что я говорю, имеет полное право на существование.

S>Павел, я даже допускаю, что в реальной жизни ты не пишешь такую херню, как в примерах с MyDirectory и MyString.IsPalindrome. Наверное, тебе просто трудно придумать удачный пример, где запечатанность реально мешает.

Я попробую привести примеры, можно?

1. Автор фреймворка Moq говорит, что запечатанные классы — не рулят. По крайней мере первый пункт железобетонный — запечатанный класс невозможно мОкнуть обычными средствами.

I hate sealed classes!!!

Sealed keyword is by far the most annoying showstopper to extensibility. I hate it so much. I wish there was an FxCop rule that would enforce that:
1 — If a class is sealed, then it *must* implement an interface that extenders can implement to hook custom implementations.
2 — The sealed class cannot be used *anywhere* in an "if (foo is MyDamnSealedClass)" statement. The required interface from 1) must be used instead.
3 — If a method is sealed, the class should be sealed too, or an equivalent method called from the sealed one is provided for inheritors (implementation of the template method pattern). There's no point in providing a non-sealed class where it's most important behavior (say an Execute method in a Command class or something like that) is sealed and there's no way to change its core behavior.

Although the third one is a little bit extreme, the first two are a MUST. Another day I'll tell you where I found a few key such annoying combinations...


2. Как реализовать идею escaped string? Смысл в том, что обычный String передавать нельзя в некоторые места без предварительной "эскепизации", однако в остальных случаях это нормальная строка:
class EscapedString : String { ... }
class UnescapedString : String { ... }

class LoginManager
{
    public void Login(EscapedString username, EscapedString password)
    {
        // затолкать username и password в sql
    } 
}

Просьба не цепляться к слову sql, здесь могла быть любая обработка или вызов какого-либо интерпретатора.

3. Как добавить к int, double етц информацию о том, что он реализует IAddable, ISubtractable, IDividable, IMultipliable? Чтобы иметь возможность написать:
public class BasicMath<T> where T : IAddable, ISubstractable, IDividable, IMultipliable
{
public T Add(T arg1, T arg2)
{ return arg1 + arg2; }
public T Subtract(T arg1, T arg2)
{ return arg1 — arg2; }
public T Multiply(T arg1, T arg2)
{ return arg1 * arg2; }
public T Divide(T arg1, T arg2)
{ return arg1 / arg2; }
}
Конечно, тут sealed не при чём, тут немного другая проблема. Это больше относится к тому, что неплохо бы иметь больше рукояток
Автор: Lazy Cjow Rhrr
Дата: 14.12.08
для воздействия на стандартные классы.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
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>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 02.12.08 19:00
Оценка: +1
Здравствуйте, Chrome, Вы писали:

C>Из минусов вижу некоторые проблемы с безопасностью в trusted environment, но эти проблемы преодолимы.


Главный минус — эта мегафича для оптимизатора все равно что серпом по яйцам. Да, кстати, через profiler api все это уже сейчас имеется.

C>Зачем проектировщики библиотек заранее гадают, какие возможности понадобится переопределить пользователям их продукта и через раз не угадывают?(Ведь, чем раньше принято решение — тем больше вероятность ошибки).


Могу посоветовать очень хорошее решение проблемы — совсем не использовать наследование в качестве публичного интерфейса. Тогда и угадывать ничего не придется.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[6]: Override для произвольного метода.
От: prVovik Россия  
Дата: 04.12.08 09:46
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Я и говорю — пофиксили ошибку. Это потребовало изменений во внутреннем устройстве классов библиотеки; ты был заточен на это внутреннее устройство.


Еще веселее будет, если посмотреть на это с точки зрения Майкрософта: при любом изменении деталей реализации фреймворка будут переставать работать приложения, заточенные под эти изменённые детали реализации. На кой хрен оно надо Майкрософту?
лэт ми спик фром май харт
Re[10]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 05.12.08 11:51
Оценка: -1
Здравствуйте, Воронков Василий, Вы писали:

ВВ> Полиморфизм предполагает что один тип может быть использован в качестве другого если он имеет с ним отношения по принципу генерализация-специализация.

Ничего подобного полиморфизм, конечно же не предполагает.. Это лишь один из способов достижения полимофизма.

ВВ> Повторное использование кода тут вообще не причем.

Конечно же причем.

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

Опять вынужнден тебя определиться с терминами. Что ты понимаешь под терминами "тип", "интерфейс", "полиморфизм" и как они соотносятся друг с другом...
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[3]: Override для произвольного метода.
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 07.12.08 00:46
Оценка: +1
Здравствуйте, Chrome, Вы писали:

S>>Главное при рассмотрении любой возможности — задуматься о ее необходимости.

C>У меня постоянно возникает необходимость через Reflection менять приватные члены классов и вызывать приватные методы.
C>а кое что даже при помощи Reflection невозможно.
C>Так что необходимость есть.

Есть необходимость поменять твой подход к использованию библиотек.

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


Ты не понял. Автор предписывает определённые способы использования. Другая часть задачи того же автора — сделать так, чтобы библиотеку нельзя было использовать способом, отличным от предписанного. Для этого и нужны модификаторы доступа.

C>Не открыл метод — лишил клиента возможности доработать и использовать свой класс — заставил его написать собственный подобный — обесценил свою библиотеку.


Какой пафос...
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[5]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.12.08 08:16
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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

G>>Если пишите библиотеку, то лучше предусмотреть точки расширения с помощью интерфейсов и атрибутов, если язык поддерживает. А классы таки лучше делать sealed по-умолчанию. Но это не касается графических компонент, которые традиционно реализуются через наследование

PD>1.Графические — включая оконные или только собственно графика ? 2. Почему такой отбор ? Традиционно — не аргумент.

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

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

Все что вы делаете внутри своего приложения — исключительно ваша проблема. Если вы создаете классы и выставляете их другим разработчикам без возможности изменения исходного кода, то уже надо быть аккуратнее.
Re[5]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.12.08 13:54
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Например


PD>Directory Class

PD>Exposes static methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited.

PD>Да, тут не просто sealed, а sealed поскольку static, но все равно — нельзя расширить функциональность. А что, собственно, будет плохого, если я устрою в наследнике enumerating без коллекций, а по одному через PInvoke ? О виртуальности тут и речи нет, методы статические, почему я не могу еще один добавить. И какие инварианты здесь нарушаются ?

Я плакал... писать MyDirectory.StaticMethod уже религия не позволяет?

PD>И таких примеров десятки, если не сотни.

Давай еще.

Вообще-то тебя называется "Override для произвольного метода", свои эротические фантазии тут не стоит писать.
Re[11]: Override для произвольного метода.
От: EvilChild Ниоткуда  
Дата: 08.12.08 17:31
Оценка: +1
Здравствуйте, GarryIV, Вы писали:

A>>А как же Template method pattern? Всегда вместо него делать через стратегии, чтобы не было наследования реализации?


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


А можно раскрыть мысль?
now playing: Boris Brejcha — Die Maschinen Marschieren
Re[7]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.12.08 06:33
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

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


G>>Я плакал... писать MyDirectory.StaticMethod уже религия не позволяет?


PD>То есть сделать свой класс MyDirectory, не производный от Directory ?

Что значит "производный" в контексте static класа?
Кстати в F# вроде можно в существющие модули (типа статик классы) добавлять функции.

PD>>>И таких примеров десятки, если не сотни.

G>>Давай еще.

PD>Please. Вот хотя бы из IO


PD>File

PD>FileInfo

А что в них не устраивает? Тоже методы подобавлять хочется?
Так можно для FileInfo писать экстеншены, а также написать обычные статик метод для своих нужд.

А по теме есть что сказать?
Re[11]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.12.08 15:35
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>не делать virtual не выйдет.

Не понял. final method — вполне нормальное явление.

PD>А почему ты решил, что расширяют функциональность только объектов ?


S>>В этом — ничего. Но разрешение делать такие вещи позволило бы тебе делать и более криминальные вещи.


PD>Можно. Все можно. Можно char* откастить во float*. Только нечего ерундой заниматься.


PD>Хм, непонятно зачем. Проверка будет идти для текущего инстанса.

Я же пример привел. Перечитай его еще раз.

PD>Нет разницы в принципе между моим IsPalindrom и String.IsNormalized.

В принципе — нету. Более того, я тебе показал, как делать IsPalindrom, который ведет себя как IsNormalized (а не как твой), при этом безо всякого наследования.

S>>В результате, внешний метод bool IsPalindrom(string) получается гораздо более удобным в использовании.


PD>А почему тогда IsNormalized не внешний ?

По соображениям эффективности. Реализацию смотрел?

PD>Пример skipped, поскольку IsNormalized как раз из этой оперы, только вместо проверки на URL проверяет на Юникод. Один черт.

Пример не понят.

PD>>>Писать код нет времени, поэтому только наметки



PD>MyFileData mfd = MyDir.FindFirstFile("*.*));

PD>while (MyDir.FindNextFile(mfd))
PD>// и т.д.

PD>В итоге нет коллекции. На все файлы, хоть их там тысячи, используется один экземпляр MyFileData.

Ок. А теперь покажи мне, где в этом коде используется тот факт, что MyDir наследник от Directory? Правильно, нигде. Ну так и нехрен заниматься ерундой.

PD>Я бы согласился, если бы можно было бы имплементировать в наследнике IEnumerable.

Можно и реализовать. Но не в наследнике, и это никому не мешает. Не стесняемся учить матчасть.

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

А наследник это что, не "еще один класс"?

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

Какая разница? Был бы один класс. Но это не имеет никакого отношения к вопросу о том, от чего наследовать MyDirectory — от Object или от Directory.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.12.08 06:49
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>>>В итоге нет коллекции. На все файлы, хоть их там тысячи, используется один экземпляр MyFileData.

S>>Ок. А теперь покажи мне, где в этом коде используется тот факт, что MyDir наследник от Directory? Правильно, нигде. Ну так и нехрен заниматься ерундой.

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

Это не ошибка а правда жизни. Наследование радо добавления методов — ерунда. Это было модно 10-15 лет назад, сейчас пришло просветление в головы теоретиков ООП.

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

Это действительно ерунда.

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

Во первых это бред. Во вторых гораздо проще разбираться в логической организации когда методы фреймворка отделены от методов, паписанных пользователем.
Re[15]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.12.08 08:03
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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

G>>Это не ошибка а правда жизни. Наследование радо добавления методов — ерунда. Это было модно 10-15 лет назад, сейчас пришло просветление в головы теоретиков ООП.

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

G>>Это действительно ерунда.

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

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

PD>Ну когда аргументы на таком уровне приводят (см. выделенное), то дискутировать дальше нет смысла.


Да что аргументов и не видно было. Все на уровне "мне так хочется".
Re[15]: Override для произвольного метода.
От: EvilChild Ниоткуда  
Дата: 10.12.08 20:56
Оценка: +1
Здравствуйте, GarryIV, Вы писали:

GIV>Шаблонный метод == абстрактный метод => класс абстрактный.

Т.е. виртуальная функция с реализацией уже не канает?
now playing: Oliver Koletzki — Requiem Für Die Vernunft (Lützenkirchen Dub Edit)
Re[17]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 11.12.08 11:18
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

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

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

PD>А суть проста — мы можем породить некий новый класс A1 от существующего класса A, и некий новый класс B1 от существующего класса B. Внутри класса A1 будет использоваться класс B1, в то время как в классе A экземпляры B1 будут выглядеть как B.

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

PD> Примеров таких на свете сколько угодно.

Ну давай, практический пример, где бы это было оправдано, хоть один?

PD>Вот, например класс CStringEx — расширяет стандартный класс CString из MFC

Если в одном месте накосячили, значит везде нужно? Тут ребята наступили ровно на те же грабли, более того, они это явно осознают:
Some of the CStringEx functions use knowledge of the internal structure of the CString object so there is a small chance that these functions might break if the CString implementation changes.
Это настолько явный косяк, что тут даже говорить не о чем. И вообще, с каких пор кривые реализации левых библиотек стали аргументом?
Эти ребята, всего лишь, в очередной раз показали как нельзя делать.

PD>Естественно, внутри каркаса MFC экземпляры CStringEx выглядят как CString. Но в нем есть дополнительные средства, которые удобны.

Тебе Антон уже на пальцах показал, все последствия этой кажимой удобности.

PD>Ну тогда объясни это же тем, кто написал этот класс и кто его использует.

Вот я тебе и объясняю, что это не просто криво, а является грубейшей ошибкой в следствии не понимания того, что собственно представляет собой ООП и как им правильно пользоваться.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[21]: Override для произвольного метода.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 12.12.08 12:06
Оценка: +1
Здравствуйте, LaPerouse, Вы писали:

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


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


LP>>>Если бы String создавался только через фабрику и мы бы имели бы возможность сделать String.setCurrentFactoty(myStringFactory), то такое очень даже имело бы смысл.


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


LP>А сторонние библиотеки и не дожны это делать — это дела целевого клиента выбирать реализации, с которым он будет работать.

Если бы была глобальная фабрика строк и возможность ее подменять, то уверен, что каждая пятая библиотека ее бы подменяла. Кому-то нужны бы были мутабельные строки, кто-то бы переписал Intern механизмы, а кто-то прикрутил бы ASCII строки. Любителей написать собственную строку слишком много! Дальше это счастье обрастает хучей конвертеров из одного в другое, которые тоже растут из какой-нибудь глобальной фабрики и т.п. Нет уж, меня запечатанный класс String более чем устраивает.

LP>Представь себе такое — я сделал Engine.setRenderer(new DirectXrenderer()), а какой-нибудь SceneGraph переопределил Engine.setRenderer(new OpenGLrenderer()) (техническую невозможность проделать такое опустим).

Если возможность будет, то кто-то непременно ей воспользуется и будут жертвы.
Re[24]: Override для произвольного метода.
От: LaPerouse  
Дата: 16.12.08 11:40
Оценка: +1
LCR>>С другой стороны, случай со String особый, потому что
LCR>>1. Строки иммутабельны, следовательно все операции которые оформлены методами ведут себя как внешние функции.

LP>Не понятно, причем здесь иммутабельность. Совершенно не обязательно быть методу иммутабельным, чтобы быть оформленным как внешняя функция с первым параметром-объектом.


Тут, конечно, надо было дописать: и иммутабельные методы могут быть полиморфными. Это абсолютно не критерий.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[25]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.12.08 12:50
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

Я чувствую, такими темпами лет через восемь-десять ты начнешь понимать основы ООП. Ну там, разделение обязанностей, инкапсуляцию состояния.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 16.12.08 13:01
Оценка: -1
Здравствуйте, Pavel Dvorkin, Вы писали:

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

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

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

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

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

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

PD> которые в конечном счете сводятся к тому, что это должно быть так, потому что в .Net это так.

Не передергивай, кроме тебя про .Net тут никто ничего не говорил.

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

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

PD>Слушай, ты это серьезно ? Если да — хоть расскажи, где эти хелперные функции искать-то ? Как классы эти хелперные называются хоть ? Вот и будут все плодить эти хелперные классы, друг с другом никак не связанные (невозможно! они же sealed). Кстати, а как их (хелперные клаасы то есть) мерджить-то ? Или пусть живут как есть ? Sinclair.IsPalindrom, Dvorkin.IsRussianWord, IB.IsNonCensored ? .

Тебе еще раз Меерса процитировать, что он думает по этому поводу? Мне не сложно, ты же любишь авторитеты.. И с ним согласны и Саттер и Мак-Конел и Александреску, а этих ребят ты уж никак в поклонников .Net не зачислишь..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[25]: Override для произвольного метода.
От: 4058  
Дата: 16.12.08 14:47
Оценка: :)
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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

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


1. Есть проекты, которые никто не станет переписывать с нуля более "кошерными" средствами, но которые тем не менее требуют доработок.
2. Осталось большое сообщество консервативно настроенных пользователей, которым просто в лом посмотреть по сторонам. Их тоже приходится поддерживать.
Re[26]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.12.08 08:54
Оценка: +1
Здравствуйте, LaPerouse, Вы писали:

LP>Наверное, имеется ввиду производительность работы программиста? Это да. (Операторам преобразования не обязательно делать это преобразования каждый раз, более правильно хранить raw string, об этом я писал в пред. посте).

Нет, речь о производительности кода. Вот я пользуюсь у себя хаскельной строкой; у меня всё хорошо, код типа

foreach(var str in stringFragments))
  joined += str;

работает шустро, потому что у меня конкатенация стоит O(1).

Но вот я вызываю какой-нибудь банальный String.Compare. А он построен на вызове в нативный код, куда передается fixed char array.
Значит, для этого вызова придется "выпрямить" строку, что стоит O(N). То же самое касается IsNormalized.
Фишка в том, что строки внутри хардкорно оптимизированы. Большинство народу, загибающего тут пальцы по поводу неудачной архитектуры дотнета, представления не имеет о том, что там "под капотом". Я могу выиграть немного на одних операциях, но тут же огребу с десятком других. И мне либо придется дублировать у себя всю подсистему win32 по работе с уникодом, либо заниматься "маршаллингом" как в примере выше.

И это всё применимо даже в гипотетическом случае изготовления своего наследника от string.
В случае же реального дотнета, моя "хаскелевская" строка доживет до первого вызова за пределы моего крошечного фреймворка. Простейшая запись в TextWriter потребует конверсии в "обычный string". Да, для таких случаев, как TextWriter, предусмотреть нарошные операции в своей строке. Но что-то более другое — запись в Label.Text к примеру — всё еще будут стоить O(N).
... << 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[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 для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 19.12.08 09:19
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ну и ну!

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

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

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

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


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


PD>class CColorMenu : public CMenu

PD>class CDocOptPage : public CCSPropertyPage
PD>class CTrackFile : public CFile
PD>class COptionSheet : public CCSPropertySheet
PD>class CComboRulerItem : public CRulerItem
PD>class CRulerBar : public CControlBar
PD>class CEmbeddedItem : public COleServerItem

1. Где детали? Ты уверен, что здесь используется наследование в чистом виде (без полиморфизма)?
2. Еще раз. MFC тонкая прослойка над WINAPI, поэтому делегирование сообщений осуществляется в тупую через наследование (но никто сейчас не станет спорить, что это правильный и изящный способ).

PD>и т.д. Там их много. Он же не знал, как правильно, он же начинающий , он же не умел отличить хорошее от плохого.


Вообщем недалеко от истины.
Правда у нас очень разные представления на счет "начинающих".

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


Ну и кому еще нужны такие примеры, кроме как начинающих?

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


Исходники многих компонентов .NET доступны (в том числе VM), поэтому положительная динамика, с точки зрения качества кода имеется.

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


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


M$ надеялась, что сможет пересадить львиную долю formo-кодеров на .NET, не получилось...

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


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


Пытались, но до добра это дело не довело (см. про formo-кодеров).

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


Павел, с MFC основательно имел дело эдак 10-ть лет назад, с того времени много воды утекло — STL/ATL/WTL/Java/.NET + *nix. Поэтому я (да и многие другие кто пытается тебе тут объяснить, что 2*2=4) не упустили возможность не однократно пересмотреть свои убеждения.
Re[30]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 24.12.08 05:59
Оценка: :)
Здравствуйте, IB, Вы писали:

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


PD>> А поэтому такая оценка (рейтинга) дает основание делать выводы о популярности ресурса.

IB>Однако популярность ресурса не дает основания делать выводы о качестве выложенных там материалов и тем более о качестве какого либо конкретного материала.

Извини, но не согласен. О качестве конкретного материала — да, а о качестве ресурса — дает основание делать вывод.


IB>Так что Павел, прекращай заниматься подменой понятий.


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

PD>>Как практику — критерий истины

IB>Данная практика подтверждает, что кривой код существует — это истина.

А не мог ли уважаемый оппонет дать хоть какой-нибудь критерий, позволяющий отличать кривой код от не-кривого ? У меня, например, есть основание утверждать, что код, реализующий litview в .NET — кривой.

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

PD>>Нет, это очень даже серьезно. Попробуй поискать на google "palindrome" и у тебя сразу настроение испортится.
IB>

IB>...
IB>If you reflect a bit and are honest with yourself, you'll admit that you have this alleged inconsistency with all the nontrivial classes you use, because no class has every function desired by every client. Every client adds at least a few convenience functions of their own, and these functions are always non-members. C++ programers are used to this, and they think nothing of it. Some calls use member syntax, and some use non-member syntax. People just look up which syntax is appropriate for the functions they want to call, then they call them. Life goes on. It goes on especially in the STL portion of the Standard C++ library, where some algorithms are member functions (e.g., size), some are non-member functions (e.g., unique), and some are both (e.g., find). Nobody blinks. Not even you.

IB>(c)Scott Meyers

Я что-то не пойму, зачем ты это мне второй раз привел. Да, в С++ статические функции можно вызывать через точку или двоеточие. ИМХО зря. Ну и что ?

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


Подумал сам еще раз над вашими аргументами.

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

Вот Антон привел мне регэкс и говорит — зачем его в стринг пихать, не место ему там. Согласен. не место. Но!

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

Варианты

1. class string, class regexp
2. class string, class regexpstring : string

Какой лучше ? Ты явно за первый. Я тоже.

Здесь вопрос-то не о наследовании, а о добавлении новой функциональности. Регекспы, конечно, со стрингами работают, но они отнюдь не часть стринга. Много чего еще можно придумать, что со стрингами работать будет. Например, class russianword, со всякими склонениями и спряжениями. Едва ли стоит такую фунциональность в стринг пихать, хелпер явно лучше.

Но есть и другое. Вот сделал ты (не ты, MS) CString. А теперь посмотри CStringEx. Не будем сейчас обсуждать качество реализации, возьмем идею — зачем сделано. Оказывается, чтобы улучшить существующую функциональность. Если в твоем классе string есть поиск вперед, а поиск назад почему-то отсутствует, так что приходится ревертировать строки для такого поиска — что плохого, если я напишу наследника, который этот поиск назад будет делать ?

Естественный вопрос — а где граница ? Да, улучшая поиск, можно и до регекспов дойти, и до trie-деревьев, и до хешей. Ответа точного, естественно, нет, но его и вообще нет. Если бы ты string и regexp делал бы сам — почему ты не уложил бы regexp внутрь стринга ? По-видимому. из неких соображений, связанных с OOD. Ну вот и здесь так же.

PD>>вы получите фактически возврат к языку С, так как каждый из ваших хелперов, если они static, по существу представляет собой набор отдельных функций, объединенных именем класса.

IB>Хоть горшком назови.. Ты воспринимаешь наследование, как средство организации кода, но оно для этого не предназначено и никогда не было.

Так-таки никогда ? А как же быть с наследованием от Control и т.д. Ты же не в неймспейс , где Control, это помещаешь, а в свой неймспейс, да с наследованием. Или это не есть организация кода ? Тогда какая тут организация ?

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

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

Я бы согласился с этим, если бы они употреблялись именно с этой целью. Увы, они слишком общие. Это во-первых. А во-вторых, может, я не прав, но вроде бы не принято лезть со своими классами/методами в чужой неймспейс ? Как посмотрят люди, если я захочу кое-что добавить к System.Drawing ?
With best regards
Pavel Dvorkin
Re[32]: еще один кривой пример
От: Pavel Dvorkin Россия  
Дата: 25.12.08 08:24
Оценка: :)
Только что наткнулся

http://www.rsdn.ru/forum/message/3225099.1.aspx
Автор: muse
Дата: 23.12.08
и ссылки там на codeproject

public class OAKListView : ListView

А ведь C#
With best regards
Pavel Dvorkin
Re[33]: еще один кривой пример
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 25.12.08 13:36
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Только что наткнулся

PD>http://www.rsdn.ru/forum/message/3225099.1.aspx
Автор: muse
Дата: 23.12.08
и ссылки там на codeproject

PD>public class OAKListView : ListView
PD>А ведь C#

Очередное свидетельство убогости архитектуры WinForms, о чем я буквально недавно писал.
... << RSDN@Home 1.2.0 alpha 4 rev. 1132 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[34]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 26.12.08 06:31
Оценка: :)
Здравствуйте, IB, Вы писали:

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


PD>>Нет

IB>Ок, продолжим, мне не сложно..

Можно, конечно и продолжить, но все же ИМХО не стоит тянуть эту дискуссию в 2009 год . Так что предоставляю тебе возможность ответить, если хочешь, но я уже отвечать не буду больше. В общем, все и так ясно.

PD>>Ну что же, ясно, впрочем, и изначално ясно было. Я с этим не согласен. Вот и все.

IB>То есть, ты продолжаешь настаивать на том, что раз кто-то сделал криво, значит повторить это не только не зазорно, но и нужно?

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

PD>>Можно ссылку ? Не помню, чтобы мы с тобой это обсуждали. Склероз...

IB>Да пол-топика обсуждений. Наследоваться для расширения функциональности — это криво.

Вот тут мы и не сходимся и не сойдемся.

PD>>Просто если он кривой, то тогда он такой же аргумент, как и CStringEx

IB>А я его и не использовал в качестве аргумента. Я в принципе не считаю наличие конкретной реализации аргументом в пользу того, что так нужно делать всегда.

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

PD>>-1.

IB>Ну вот, а Саттер, Александреску и Меерс с тобой не согласны..

Ну и бога ради. Я же 100 раз говорил — для меня почти любые "законы" есть не более чем рекомендации, от которых можно и отступить, если есть причины. Иногда лучше сделать хелпер, иногда наследоваться. От ситуации зависит.

PD>>Слишком уж серьезно это не самое лучшее проявление. Убери класс CStringEx — в общем, никто и не почешется, напишем иной. А вот выкинь это наслелование с полиморфизмом — и не останется в .Net никакого GUI, одни консольные приложения писать будем

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

Не удастся. Слишком уж часто он используется. Выкинуть его можно только вместе с почти всеми настольными GUI приложениями и всем ASP.NET. На WINAPI и PHP вернемся ?

IB>Ну и, наконец, в третих, GUI как раз останется, причем существенно лучший чем WinForms, потому что есть WPF, который еще не идеал, конечно, но поддерживает отличнейшие возможности расширения без наследования, чем очень выгодно отличается от WinForms.




У WPF масса преимуществ, но только один недостаток — десктопных приложений на нем еще меньше, чем на WinForms, а их там кот наплакал. Судить о пригодности WPF в web-приложениях не берусь, но что касается десктопных — извини.

И потом — как это без наследования? Вот сейчас сделал приложение и что я вижу ?

public partial class Window1 : Window

Window Class
Provides the ability to create, configure, show, and manage the lifetime of windows and dialog boxes.

Если это не наследование, то я китайский император

PD>> Аргумент насчет не лучшего дизайна не приму — почему во всех библиотеках этот не лучший дизайн используется ?

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

. Где эти настольные приложения на swing и WPF ?

PD>>В пределах одной библиотеки ты, надеюсь, не против наследования ?

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

Так тогда просто сказал бы с самого начала, что тебе сама идея наследования кода (не контрактов) вообще не нравится! Я-то полагал, что речь идет о наследовании от чужого класса, а ты, оказывается, против наследования вообще. Это несколько меняет дело.

PD>> Очевидно, не против, иначе тебе придется всю .Net похоронить.

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

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

На этом дискуссию заканчиваю. За тобой право ответа в этой ветке, если хочешь. С Новым Годом!
With best regards
Pavel Dvorkin
Re[35]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 26.12.08 09:34
Оценка: :)
Здравствуйте, Pavel Dvorkin, Вы писали:

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

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

PD>В общем, все и так ясно.

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

PD>Не надо все же демагогии. Ты счтаешь, что этот подход кривой, я — нет. Вот и все.

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

PD>Я считаю, что наличие некоторой работающей практики есть основание чтобы к ней по крайней мере относиться как к реальной альтернативе вместо того, чтобы из каких-то соображений объявлять ее кривой.

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

PD>Ну и бога ради. Я же 100 раз говорил — для меня почти любые "законы" есть не более чем рекомендации, от которых можно и отступить, если есть причины.

Ну так назови причину, Павел! Ну хоть одну!! =) Что, нету? Ну я так и думал..

PD>Не удастся.

Ну почему, мне как-то удается.

PD> Слишком уж часто он используется.

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

PD> Выкинуть его можно только вместе с почти всеми настольными GUI приложениями и всем ASP.NET. На WINAPI и PHP вернемся ?

ASP.Net отлично без этого обходится, в настольных тоже есть альтернативы, так что, не стоит лезть в незнакомую область с шашкой на голо..

PD>У WPF масса преимуществ, но только один недостаток — десктопных приложений на нем еще меньше, чем на WinForms, а их там кот наплакал. Судить о пригодности WPF в web-приложениях не берусь, но что касается десктопных — извини.

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

PD>И потом — как это без наследования?

Вопервых, не говорил, что WPF обошелся вообще без наследования, а во-вторых, ты забываешь про полиморфизм.

PD>. Где эти настольные приложения на swing и WPF ?

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

PD>Это несколько меняет дело.

В данной дискуссии, ничего не меняет.

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

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

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

Так оглянись, Павел, достань уже голову из MFC. Добро пожаловать в реальный мир..
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[44]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 14:11
Оценка: :)
Здравствуйте, LaPerouse, Вы писали:

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

LP>>>2. Если не нужен, тогда зачем тебе наследоваться?

LP>Ты неправильно понял мой пункт 2: "Если не нужен, тогда зачем тебе наследоваться?". Имелось ввиду, "если не нужен метод concat, тогда зачем тебе наследоваться?".


Я, конечно, могу неправильно понимать, но фраза в пункте 1 говорит именно о классе, а не о методе concat. А в пункте 2 "если не нужен", что ИМХО относится к производному классу, а не к concat, о которой тут и речи нет. Я не телепат, чтобы угадывать.

Если же вопрос относится именно к методу concat, то на вопрос, зачем мне наследоваться, ответ предельно прост — а с чего ты решил, что я наследовать собрался именно ради concat ? concat мне даром не нужен, но из этого вовсе не следует, то мне не нужно наследование. Я вообще о concat речи не вел, ты ее предложил зачем-то, а теперь, выходит, мне не нужно наследование, поскольку мне не нужна эта concat ? Интересная логика.


LP>То есть ты намерен запрещать пользователю библиотеки вызывать метод concat у твоего CPolindrom?


Обсуждаемо. Может, я вообще закрою его , может, просто соглашусь на InvalidCast, поскольку мне эта проверка на палиндром нужна только на входном контроле( не допускать ввода не палиндромов, например). Если, к примеру. я хочу , чтобы в программе все экземпляры CPalindrom были обязательно палиндромами, то на входном контроле эта проверка и будет делаться, а всякие прочие операции просто не нужны, а concat так просто смысла не имеет. От ситуации зависит.
With best regards
Pavel Dvorkin
Re[2]: Override для произвольного метода.
От: Cyberax Марс  
Дата: 02.12.08 19:07
Оценка:
Здравствуйте, AndrewVK, Вы писали:

C>>Из минусов вижу некоторые проблемы с безопасностью в trusted environment, но эти проблемы преодолимы.

AVK>Главный минус — эта мегафича для оптимизатора все равно что серпом по яйцам. Да, кстати, через profiler api все это уже сейчас имеется.
Просто нужна поддержка динамической рекомпиляции кода при изменении иерархии. Т.е. то что уже есть многие годы в Sun HotSpot JVM

Кстати, в Java все методы по умолчанию виртуальные.
Sapienti sat!
Re[4]: Override для произвольного метода.
От: Cyberax Марс  
Дата: 03.12.08 01:07
Оценка:
Здравствуйте, fddima, Вы писали:

C>>Кстати, в Java все методы по умолчанию виртуальные.

F> Кстати, не факт что это хорошо.
Скажем так, мешает это намного реже, чем помогает.
Sapienti sat!
Re[2]: Override для произвольного метода.
От: Chrome  
Дата: 03.12.08 11:18
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


C>>Из минусов вижу некоторые проблемы с безопасностью в trusted environment, но эти проблемы преодолимы.


AVK>Главный минус — эта мегафича для оптимизатора все равно что серпом по яйцам. Да, кстати, через profiler api все это уже сейчас имеется.

Не проблема это вовсе. В оптимизации нуждаются считанные проценты кода, не факт, что этот код пересекается с тем, который вы собиратесь модифицировать. Кроме того исходный код состоит из оптимизированного MSIL, наш патч компилируется в оптимизированный MSIL, потом .Net Runtime должен их соединить и откомпилировать в native код, опять же имеет возможность оптимизировать. Где тут проблемы?

C>>Зачем проектировщики библиотек заранее гадают, какие возможности понадобится переопределить пользователям их продукта и через раз не угадывают?(Ведь, чем раньше принято решение — тем больше вероятность ошибки).


AVK>Могу посоветовать очень хорошее решение проблемы — совсем не использовать наследование в качестве публичного интерфейса. Тогда и угадывать ничего не придется.

— я имею в виду очень конкретный случай — программирование под .Net с использованием его стандартных библиотек, куда там без наследования? Или заставить microsoft перепроектировать их билблиотеку — я за!!!
Re[3]: Override для произвольного метода.
От: Aikin Беларусь kavaleu.ru
Дата: 03.12.08 11:26
Оценка:
Здравствуйте, Chrome, Вы писали:

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

S>>Главное при рассмотрении любой возможности — задуматься о ее необходимости.

C>У меня постоянно возникает необходимость через Reflection менять приватные члены классов и вызывать приватные методы.

А пример можно? Что-то у меня не часто такое желание возникает

S>>Большинство современных теоретиков ОО-архитектуры сходятся на том, что

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

C>Печальная история. И очень типичная в нашем мире. Теоретики изобретают теорию. Практики воплощают ее в жизнь.

C>НО!! То ли первые забыли описать область определения своей теории, то ли практики не удосужились обратить свое внимание на этот аспект, но теория внедряется там, где ее выводы неуместны.
C>Для массовых библиотек такой подход — зло.
бла-бла-бла

S>>Из этого делается два вывода:

S>>1. Классы по умолчанию должны быть sealed. Распечатывать их можно только в том случае, когда вы тщательно продумали то, как ваш код будет работать с произвольными наследниками.
C>Автор библиотеки обычно сильно заблуждается относительно того, как тысячи клиентов будут ее использовать, даже если он очень умный человек — он один, а клиентов — тысячи. Не может он ничего "тщательно продумать"
Поменять билиотеку? Связаться с автором? И наконец, разобраться как же нужно правильно использовать эту библиотеку.

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

C>Не открыл метод — лишил клиента возможности доработать и использовать свой класс — заставил его написать собственный подобный — обесценил свою библиотеку.
Зачем клиенту понадобилось ее дорабатывать???



И еще: переиспользовать класс можно не только наследованием, но и агрегацией.

СУВ, Aikin
Re[3]: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 03.12.08 11:34
Оценка:
Здравствуйте, Chrome, Вы писали:

AVK>>Главный минус — эта мегафича для оптимизатора все равно что серпом по яйцам. Да, кстати, через profiler api все это уже сейчас имеется.

C>Не проблема это вовсе.

Аргументированно

C> В оптимизации нуждаются считанные проценты кода




C> Кроме того исходный код состоит из оптимизированного MSIL, наш патч компилируется в оптимизированный MSIL


Если тебе нужно патчить MSIL, то инструментов для этого хватает, бери да пользуйся. Только при чем тут тогда CLR?

AVK>>Могу посоветовать очень хорошее решение проблемы — совсем не использовать наследование в качестве публичного интерфейса. Тогда и угадывать ничего не придется.

C>- я имею в виду очень конкретный случай — программирование под .Net с использованием его стандартных библиотек

Как будто на практике всерьез можно рассматривать их неиспользование

C>, куда там без наследования?


Давай конкретные примеры, иначе это воду в ступе толочь.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[4]: Override для произвольного метода.
От: Chrome  
Дата: 03.12.08 15:10
Оценка:
C>> В оптимизации нуждаются считанные проценты кода
AVK>
А в чем юмор?

AVK>Если тебе нужно патчить MSIL, то инструментов для этого хватает, бери да пользуйся. Только при чем тут тогда CLR?


Наиболее часто хочется модифицировать методы .Net framework. Эти сборки лежат в GAG. Если я их отредактирую, во первых отвалится подпись, во вторых эти изменения отразятся на других программах.
Чего хотелось бы от CLR — что бы он во время JIT компиляции заменял стандартные функции на пропатченные варианты.
Естественно, все это должно действовать локально в рамках моей программы, на основе ее конфигурационного файла.


AVK>>>Могу посоветовать очень хорошее решение проблемы — совсем не использовать наследование в качестве публичного интерфейса. Тогда и угадывать ничего не придется.

C>>- я имею в виду очень конкретный случай — программирование под .Net с использованием его стандартных библиотек
AVK>Как будто на практике всерьез можно рассматривать их неиспользование
C>>, куда там без наследования?
AVK>Давай конкретные примеры, иначе это воду в ступе толочь.

Нуу эээ — предположим, мы программируем под ASP.Net — и как то так получается, вунуждены создавать наследников от Web.UI.Page
откажемся от наследования? Будем IHttpHanler имплементировать?
захотели добавить свой контрол — будьте добры унаследоваться от Web.UI.Control — иначе не сможете добавить его ни в одну иерархию. А если унаследовались — вынуждены мириться с его реализацией. Как от нее отказаться?

Вот и мечтаю я о патчах.
Re[4]: Override для произвольного метода.
От: Chrome  
Дата: 03.12.08 15:31
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


S>Вот когда я работал с Delphi, необходимость "вскрывать" неудачно заprivate-нные классы из VCL быстро падала с ростом моей квалификации.


C>>Для массовых библиотек такой подход — зло.

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

Зачем контролировать? Выпустили библиотеку .Net framework v 2.0. Ушла она в свободное плавание. Фиксите иногда критические баги, но это доли процента кода.
Сами работаете над V3.0.
А кому надо использует 2.0, так, как считает нужным.
И зачем что то контролировать?

C>>Не открыл метод — лишил клиента возможности доработать и использовать свой класс — заставил его написать собственный подобный — обесценил свою библиотеку.

S>Неверно. Можно привести пример возможности использования, которой тебя лишила запечатанность класса string? А вообще, наследование — далеко не лучший, и уж точно не единственный способ "доработки и использования".

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

S>Налицо полное непонимание сути вещей. Разъясняю подробнее: ты используешь библиотеку, разработанную Колей. В библиотеку передаются параметры класса string. Кроме этого, ты используешь другую библиотеку, разработанную Васей. Васина библиотека возвращает объекты, отнаследованные от string, с тонким образом перекрытым методом Equals. В итоге Колина библиотека, естественно, падает. Потому что она рассчитывает на те инварианты string, которые описаны в MSDN.


Так это ведь Я использую Колину и Васину библиотеку, и если Колина библиотека падает от того, что Я передал ей обьекты, которые ей не подходят — я и виноват. Хотя сценарий возврата так тонко испоганеных строк экзотичен.

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

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

Нормальные вендоры фиксят ошибки в старых версиях продукта,
и отдельно выпускают новые версии.
Re[5]: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 03.12.08 15:35
Оценка:
Здравствуйте, Chrome, Вы писали:

C>>> В оптимизации нуждаются считанные проценты кода

AVK>>
C>А в чем юмор?

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

C>Наиболее часто хочется модифицировать методы .Net framework. Эти сборки лежат в GAG.


Если ты будешь модифицировать содержимое сборок, тебе в любом случае понадобится снести подпись. Следовательно, GAC с немодифицированными сборками тебе уже никак не помеха.

C> Если я их отредактирую, во первых отвалится подпись


Да, что логично

C>, во вторых эти изменения отразятся на других программах.


Нет.

C>Чего хотелось бы от CLR — что бы он во время JIT компиляции заменял стандартные функции на пропатченные варианты.


Profiler API.

AVK>>Давай конкретные примеры, иначе это воду в ступе толочь.


C>Нуу эээ — предположим, мы программируем под ASP.Net — и как то так получается, вунуждены создавать наследников от Web.UI.Page


Проблема в чем?

C>захотели добавить свой контрол — будьте добры унаследоваться от Web.UI.Control


Проблема в чем?

C> Как от нее отказаться?


Никак. Эта задача в рамках дизайна вебформсов нерешаема. Только написанием своего собственного Page.ё

C>Вот и мечтаю я о патчах.


Бесполезно патчить внутренние детали реализации чужого фреймворка — первый же сервиспак порушит все твое приложение напрочь. И чинить будет ой как больно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[5]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.12.08 05:25
Оценка:
Здравствуйте, Chrome, Вы писали:


C>Зачем контролировать? Выпустили библиотеку .Net framework v 2.0. Ушла она в свободное плавание. Фиксите иногда критические баги, но это доли процента кода.

Ну и что, что доли процента.

C>И зачем что то контролировать?

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

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

C>а вы что предложите в рамках существующей платформы .Net?
Я предлагаю агрегацию.

C>Так это ведь Я использую Колину и Васину библиотеку, и если Колина библиотека падает от того, что Я передал ей обьекты, которые ей не подходят — я и виноват.

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

C>Нормальные вендоры фиксят ошибки в старых версиях продукта,

C>и отдельно выпускают новые версии.
Я и говорю — пофиксили ошибку. Это потребовало изменений во внутреннем устройстве классов библиотеки; ты был заточен на это внутреннее устройство.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 04.12.08 13:46
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Наследование нужно для полиморфизма.


Для полиморфизма нужно наследование интерфейсмов, а здесь речь о наследовании реализаций.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[9]: Override для произвольного метода.
От: artelk  
Дата: 04.12.08 15:24
Оценка:
Здравствуйте, fmiracle, Вы писали:

F>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Есть полиморфизм через интерфейсы. Есть полиморфизм построенный на виртуальности.


F>Полиморфизм — он всегда через интерфейсы.

F>То что ты называешь "полиморфизм построенный на виртуальности" это уже комбинация полиморфизма и повторного использования кода базового класса. Для полиморфизма при наследовании используется "интерфейс" (при этом самого ключевого слова interface в языке может и не быть) базового класса.

F>Так что "Наследование нужно для полиморфизма" — неверно. Если нужен именно полиморфизм, то его замечательно можно получить через интерфейсы. Особенно если они поддерживаются в языке как базовые конструкции языка.


А как же Template method pattern? Всегда вместо него делать через стратегии, чтобы не было наследования реализации?
Re[10]: Override для произвольного метода.
От: fmiracle  
Дата: 05.12.08 16:06
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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

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

У любого типа всегда есть интерфейс И это да, именно контракт. Интерфейс — это по сути своей контракт. А наличие или отсутствие в языке ключевого слова "interface" это уже детали.
Если нет переиспользования кода, то наследование самих классов друг от друга нафиг не уперлось.

Если брать С++, то у нас цепочка наследования ClassA->ClassB->ClassC. Так вот, добавляем чисто абстрактный класс, имеющий сигнатуру класса А, но не имеющей реализации.
AbstractA->ClassA->ClassB->ClassC

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

Собственно, если нас нужна только перегрузка виртуальных методов в наследниках (специализацию с дополнительными полями рассмотрим ниже), то можно смело переписывать иерархию:

AbstractA->ClassA
AbstractA->ClassB
AbstractA->ClassC

Все обобщенные методы перевести на работу AbstractA. Конкретное поведение реализовывать в ClassA, ClassB, ClassC. Что важно, реализация классов вообще не зависит друг от друга. Что значительно упрощает тестирование и внесение изменений (нет шансов, что изменение класса А вызвало случайный глюк в классе С).


Теперь идем дальше. Потребовалась специализация наследников, т.е. на нижних уровнях иерархии появляются дополнительные поля, которых не было ранее.
Ну так пожалуйста, вводим чисто абстрактный класс уже для ClassB:

AbstractA->AbstractB

и сразу становится очевидно, что наша иерархия по сути равна:
AbstractA->ClassA->(+AbstractB->)ClassB->ClassC

Продолжаем для С:
AbstractA->AbstractB->AbstractC

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

AbstractA->ClassA
AbstractB->ClassB
AbstractC->ClassC

Код работает с AbstractA, AbstractB, AbstractC и наслаждается всеми радостями специализации. А мы опять же независимо друг от друга реализуем А, Б и С. И опять у нас нет шансов, что при модификации А у нас появился случайный баг в С.

Минус — больше кода писать, т.е. отсутствует переиспользование кода при наследовании. Заметим в скобочках, что в иерархии ClassB->ClassC получение классом С интерфейса AbstractB тоже по сути своей является переиспользованием кода (не требуется вводить явно специальный AbstractC и указывать его связь с AbstractB, как это приходится делать в приведенной выше схеме.)


З.Ы. Я не иду так далеко, чтобы отказываться от наследования реализации, и по-прежнему его использую. Но я уже не раз и не два имел проблемы при внесении изменений в системы с развесистым деревом наследования. Потому к наследованию реализации теперь подхожу очень осторожно.
Ну а собственно построение иерархии интерфейсов и имплементация в классах именно интерфейсов — это надежный способ не допустить случайного наследования реализации (не обязательно тобой, но, возможно, соседом, потом ты изменишь свой класс, а у соседа сорвутся сроки ).
Re: Override для произвольного метода.
От: Alexander G Украина  
Дата: 06.12.08 16:16
Оценка:
Здравствуйте, Chrome, Вы писали:

C>Мне кажется, в .Net runtime можно без особых проблем привнести возможность переписать код произвольного метода.

C>Любого метода любой managed DLL. Кроме того, любой невиртуальный метод класса можно сделать виртуальным.
C>Добавить поля в существующие sealed классы. И много чего еще.

Возможно Вы никогда не слышали про NVI. Но про инкапсуляцию Вы знать должны
Русский военный корабль идёт ко дну!
Re[11]: Override для произвольного метода.
От: Кэр  
Дата: 08.12.08 03:17
Оценка:
Здравствуйте, IB, Вы писали:

IB>Опять вынужнден тебя определиться с терминами. Что ты понимаешь под терминами "тип", "интерфейс", "полиморфизм" и как они соотносятся друг с другом...


А вы можете изложить свою точку зрения? Это должно быть интересно. Без иронии.
Re[3]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 08.12.08 05:46
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


S>>1. Классы по умолчанию должны быть sealed. Распечатывать их можно только в том случае, когда вы тщательно продумали то, как ваш код будет работать с произвольными наследниками.


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

Если речь идет о приложениях, то код всегда можно переписать\изменить.

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

Если пишите библиотеку, то лучше предусмотреть точки расширения с помощью интерфейсов и атрибутов, если язык поддерживает. А классы таки лучше делать sealed по-умолчанию. Но это не касается графических компонент, которые традиционно реализуются через наследование
Re[4]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 08.12.08 07:41
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>Если пишите библиотеку, то лучше предусмотреть точки расширения с помощью интерфейсов и атрибутов, если язык поддерживает. А классы таки лучше делать sealed по-умолчанию. Но это не касается графических компонент, которые традиционно реализуются через наследование

1.Графические — включая оконные или только собственно графика ? 2. Почему такой отбор ? Традиционно — не аргумент.

И опять-таки, есть разница между наследованием от класса в моем приложении и при расширении бибилиотеки (написании новой). В свое время я отнаследовался от ifstream и ничего плохого в этом не было. Но я вряд ли решился бы выставить этого наследника в качестве расширения библиотеки iostream — покусают
With best regards
Pavel Dvorkin
Re[6]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 08.12.08 08:37
Оценка:
Здравствуйте, gandjustas, Вы писали:

PD>>1.Графические — включая оконные или только собственно графика ? 2. Почему такой отбор ? Традиционно — не аргумент.

G>Еще как аргумент. Если вы создаете кастомный контрол в WinForms, то не используя наследование от наиболее подходящего предка можно потратить много времени в пустую.

+1

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

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

Да, но я это сделать не могу. Он же sealed
With best regards
Pavel Dvorkin
Re[4]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 08.12.08 12:21
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

S>Налицо трагическое непонимание сути вещей.

Да, только твоим. Вызванное многократным употреблением библиотеки классов .Net

S>Автор библиотеки берет на себя некоторые обязательства. Он обещает, что библиотека выполняет некоторые функции, при штатном ее использовании. При этом очень важно объяснить, какое использование — штатное, а какое — нет. Простой вопрос: нужно ли вызывать в overriden методе метод предка? Если да, то в какой момент? Будет ли работать библиотека, если не вызвать предка? Или получится трудноуловимый баг?

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

А я заявил, что надо перекрывать все ? Где ? Я этого вовсе не утверждал.

S>По вопросу запечатывания класса поясняю еще раз: да, допустим я всё продумал. И вижу, что никакие модификации поведения этого класса путем наследования не могут гарантировать выполнение инвариантов. Повторно вопрошаю: какие изменения вы хотите сделать в классе System.String?


Не пойдет. Кроме System.String (о нем предпочту не высказываться, ибо он притча во языцех) в .Net еще десятки классов, где изменения я вполне готов сделать и обосновать.

Например


Directory Class
Exposes static methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited.

Да, тут не просто sealed, а sealed поскольку static, но все равно — нельзя расширить функциональность. А что, собственно, будет плохого, если я устрою в наследнике enumerating без коллекций, а по одному через PInvoke ? О виртуальности тут и речи нет, методы статические, почему я не могу еще один добавить. И какие инварианты здесь нарушаются ?

И таких примеров десятки, если не сотни.
With best regards
Pavel Dvorkin
Re[5]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.12.08 15:37
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Да, только твоим. Вызванное многократным употреблением библиотеки классов .Net
Хм. Вообще-то это далеко не единственная библиотека, с которой я имел счастье столкнуться в своей девелоперской жизни.


PD>А я заявил, что надо перекрывать все ? Где ? Я этого вовсе не утверждал.

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

PD>Не пойдет. Кроме System.String (о нем предпочту не высказываться, ибо он притча во языцех) в .Net еще десятки классов, где изменения я вполне готов сделать и обосновать.

PD>Например

PD>Directory Class

PD>Exposes static methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited.
Это какой-то неудачный пример. Пару лет назад аналогичный пример приводил тут кто-то, желающий либо запихать в Math всю математику вообще (см. справочних Г. и Т. Корн). Или, по крайней мере, дать наследоваться от Math.
В данном случае совершенно понятно, что это совершенно ненужно. Пиши свой класс, со своими методами — и всё будет работать. Главное — не пытаться подменить задачу некоторым конкретным решением.
PD>И таких примеров десятки, если не сотни.
Пока ни одного примера в топике не прозвучало. Только абстрактные пожелания встроить прямо в платформу перекрывать вообще нахрен всё.

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

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

Более того, большинство из тех примеров, которые встречались лично мне, впоследствии имели более аккуратное решение, предусмотренное (sic!) автором библиотеки.
Ну, вот простой пример: как сделать WebRequest к некоторому адресу, и передать ему некий нестандартный Host header?
На первый взгляд, библиотеку делали тупые козлы, потому что Host Header намертво зашит в реализацию, и никакого способа порулить им вручную нет. И все способы перекрытия методов стандартных классов закрыты разработчиком.
Упс! Неужели нам придется применять хардкорный reflection, profiler API, или copy-paste 90% system.net для того, чтобы это обойти?
Оказывается, нет. Штатный способ добиться результата — это указать адрес целевой машины в качестве Proxy, а нужный хост указать в виде URL.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Override для произвольного метода.
От: GarryIV  
Дата: 08.12.08 17:23
Оценка:
Здравствуйте, artelk, Вы писали:

F>>Полиморфизм — он всегда через интерфейсы.

F>>То что ты называешь "полиморфизм построенный на виртуальности" это уже комбинация полиморфизма и повторного использования кода базового класса. Для полиморфизма при наследовании используется "интерфейс" (при этом самого ключевого слова interface в языке может и не быть) базового класса.

F>>Так что "Наследование нужно для полиморфизма" — неверно. Если нужен именно полиморфизм, то его замечательно можно получить через интерфейсы. Особенно если они поддерживаются в языке как базовые конструкции языка.


A>А как же Template method pattern? Всегда вместо него делать через стратегии, чтобы не было наследования реализации?


А он почти как синглетон — антипатерн. Но не такой разрушительной силы слава богу.
WBR, Igor Evgrafov
Re[6]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 09.12.08 05:59
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Я плакал... писать MyDirectory.StaticMethod уже религия не позволяет?


То есть сделать свой класс MyDirectory, не производный от Directory ? Можно, конечно, а почему ?

PD>>И таких примеров десятки, если не сотни.

G>Давай еще.

Please. Вот хотя бы из IO

File
FileInfo
With best regards
Pavel Dvorkin
Re[6]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 09.12.08 06:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


Но она на тебя сильно повлияла в этом плане. В Delphi, насколько мне известно, аналога sealed нет. В С++ тоже.


PD>>А я заявил, что надо перекрывать все ? Где ? Я этого вовсе не утверждал.

S>Ты, вроде как, спорил с моей точкой зрения. Она совершенно недвусмысленным образом изложена в сообщении, которому ты поставил минус.

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

PD>>Не пойдет. Кроме System.String (о нем предпочту не высказываться, ибо он притча во языцех) в .Net еще десятки классов, где изменения я вполне готов сделать и обосновать.

PD>>Например

PD>>Directory Class

PD>>Exposes static methods for creating, moving, and enumerating through directories and subdirectories. This class cannot be inherited.
S>Это какой-то неудачный пример. Пару лет назад аналогичный пример приводил тут кто-то, желающий либо запихать в Math всю математику вообще (см. справочних Г. и Т. Корн). Или, по крайней мере, дать наследоваться от Math.
S>В данном случае совершенно понятно, что это совершенно ненужно.

А нельзя ли как-то обосновать, что это ненужно. "Совершенно понятно" — не аргумент.

>Пиши свой класс, со своими методами — и всё будет работать.


А почему это , собственно, я должен писать свой класс, если по смыслу мне надо именно расширить функциональность существующего. Directory в ФС он и есть directory, почему должно быть 2 класса ?

>Главное — не пытаться подменить задачу некоторым конкретным решением.


Это все пустословие.

PD>>И таких примеров десятки, если не сотни.

S>Пока ни одного примера в топике не прозвучало. Только абстрактные пожелания встроить прямо в платформу перекрывать вообще нахрен всё.

Что-то я не понял. Я тебе пример с Directory привел. Это раз. Во-вторых, где это я предлагал перекрывать все ? Ссылку !!! Опять передергиваешь.

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

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


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


Топик-стартер может заказывать что угодно, я на его пост не отвечал, а ответил на твой. Универсальное распечатывание я не отстаиваю. А вот с мнением, что надо запечатывать по умолчанию — не согласен. И не я только

Do not seal classes without having a good reason to do so.

Это из MSDN.

http://msdn.microsoft.com/en-us/library/ms229023.aspx

S>Более того, большинство из тех примеров, которые встречались лично мне, впоследствии имели более аккуратное решение, предусмотренное (sic!) автором библиотеки.

S>Ну, вот простой пример: как сделать WebRequest к некоторому адресу, и передать ему некий нестандартный Host header?
S>На первый взгляд, библиотеку делали тупые козлы, потому что Host Header намертво зашит в реализацию, и никакого способа порулить им вручную нет. И все способы перекрытия методов стандартных классов закрыты разработчиком.
S>Упс! Неужели нам придется применять хардкорный reflection, profiler API, или copy-paste 90% system.net для того, чтобы это обойти?
S>Оказывается, нет. Штатный способ добиться результата — это указать адрес целевой машины в качестве Proxy, а нужный хост указать в виде URL.

Не берусь оценивать это решение, не мой профиль. Вполне допускаю, что оно верно. "Нормальные герои всегда идут в обход"

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

Вот есть "оконные" классы. Они не запечатаны. А есть Directory. Он запечатан. Почему ?

Ларчик открывается просто. Если оконный класс запечатать — кому он нужен будет ? Что я могу с окнами делать, если я не в состоянии их кастомизировать ? Ну Move, ну Resize, а даже Redraw не получится (в Windows), так как потянет OnPaint. Толку от такого оконного класса никакого. Именно кастомизация (==создание наследника) оконных классов и есть создание GUI (я говорю о десктопных приложениях и не о WPF).

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

А вот если бы директории были кастомизируемыми и суть работы была бы именно в этой кастомизации, то либо класс Directory распечатали бы, либо выбросили как практически бесполезный. И в распечатанном классе были бы OnFileAdd, OnFileRemove, OnSubDirAdd, ... OnReorder и т.д.

Так что дело не в том, что оконные классы так уж хорошо сделаны, что их кастомизацию можно позволить и не нарушить какие-то инварианты. Нарушить их там совсем не сложно. Вопрос лежит чисто в практической плоскости. Если бы окна не надо было бы кастомизировать — их бы тоже запечатали. На всякий случай — кому охота на себя лишних собак вешать из-за возможных ошибок кастомизаторов
With best regards
Pavel Dvorkin
Re[7]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.12.08 08:06
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Но она на тебя сильно повлияла в этом плане. В Delphi, насколько мне известно, аналога sealed нет. В С++ тоже.

В Delphi достаточно не сделать метод virtual, или оставить что-то важное private для того, чтобы свести возможности перегрузки к нулю. В С++ — тоже.

PD>А нельзя ли как-то обосновать, что это ненужно. "Совершенно понятно" — не аргумент.

Обоснование приведено в соседнем ответе. Впрочем, я поясню чуть ниже.

PD>А почему это , собственно, я должен писать свой класс, если по смыслу мне надо именно расширить функциональность существующего. Directory в ФС он и есть directory, почему должно быть 2 класса ?

Гм. Это — сервисный класс. У него нет экземпляров. Чью функциональность ты собрался расширять?
Если бы это был класс некоторых объектов, то еще можно было бы поныть насчет возможности отнаследовать MyDirectory от Directory и пользоваться возможностью передавать экземпляры MyDirectory везде, где нужен Directory.
Но в данном случае такое использование невозможно, поэтому совершенно понятно даже невооруженному мозгу, что нет никакой разницы, будет ли MyDirectory наследником Directory или object.

PD>Что-то я не понял. Я тебе пример с Directory привел.

Повторяю — это хреновый пример. Покажи мне код предполагаемого наследника и пример его использования.

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

Павел, не стоит обсуждать, без чего я не могу. Это оффтоп.

PD>Топик-стартер может заказывать что угодно, я на его пост не отвечал, а ответил на твой. Универсальное распечатывание я не отстаиваю. А вот с мнением, что надо запечатывать по умолчанию — не согласен. И не я только

PD>Do not seal classes without having a good reason to do so.
PD>Это из MSDN.
PD>http://msdn.microsoft.com/en-us/library/ms229023.aspx
Ок, в такой формулировке я оспаривать постулат не стану. Я не то чтобы на 100% верю в MSDN — его тоже не боги пишут; антипаттерны там встречаются налево и направо. Ок, давайте перевернём постулат: вместо "запечатывайте классы, наследование от которых не продумано", напишем "продумывайте наследование от всех классов, которые не запечатаны". Логически, это одно и то же, но тебе, наверное, будет комфортнее такая формулировка.

PD>Не берусь оценивать это решение, не мой профиль. Вполне допускаю, что оно верно. "Нормальные герои всегда идут в обход"


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


PD>Вот есть "оконные" классы. Они не запечатаны. А есть Directory. Он запечатан. Почему ?


PD>Ларчик открывается просто. Если оконный класс запечатать — кому он нужен будет ? Что я могу с окнами делать, если я не в состоянии их кастомизировать ? Ну Move, ну Resize, а даже Redraw не получится (в Windows), так как потянет OnPaint. Толку от такого оконного класса никакого. Именно кастомизация (==создание наследника) оконных классов и есть создание GUI (я говорю о десктопных приложениях и не о WPF).

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

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

Вообще-то, правильный ответ на вопрос "почему запечатан класс Directory" дан прямо на той странице, на которую ты сослался: "The class is static".

PD>Так что дело не в том, что оконные классы так уж хорошо сделаны, что их кастомизацию можно позволить и не нарушить какие-то инварианты. Нарушить их там совсем не сложно. Вопрос лежит чисто в практической плоскости. Если бы окна не надо было бы кастомизировать — их бы тоже запечатали. На всякий случай — кому охота на себя лишних собак вешать из-за возможных ошибок кастомизаторов


Правильно. Ты говоришь практически то же самое, что и я: если бы не тяжкая нужда оставить их распечатанными, их бы запечатали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Override для произвольного метода.
От: Klapaucius  
Дата: 09.12.08 09:19
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Моя позиция — не надо и Directory запечатывать, да и вообще не надо — как правило (исключения возможны).


Вы понимаете разницу между static class и sealed class?
... << RSDN@Home 1.2.0 alpha 4 rev. 1110>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[9]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.12.08 12:05
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ну если об этом речь идет — то и в C# это вроде бы не запрещено. Класс-то зачем закрывать ?

PD>Вот в java — точно не выйдет
Что не выйдет? public final class? Конечно же выйдет.

PD>Вполне возможно, что придется и расширить. Вот сделает MS SQLFS , там, возможно, придется новые методы/свойства добавить. Кстати, и сейчас есть что добавить. Как там, к примеру, насчет хардлинков ? точек соединения ?

Ты не понял вопрос. Где объект, функциональность которого ты собрался расширять?

PD>class MyString : String {

PD> public IsPalindrom() {//...}
PD>}

PD>ну и что тут криминального ?

В этом — ничего. Но разрешение делать такие вещи позволило бы тебе делать и более криминальные вещи.
PD>Кстати, в C++ это выглядело бы так

PD>class MyString : public String {

PD> public IsPalindrom() const {//...}
PD>};

PD>и тем самым явно сказано, что менять состояние объекта она не может.

Да ну. Мало ли чего там сказано. конст_каст от this и вперед, на танки.

PD>Предлагаю не искать альтернативные решения для добавления "палиндромности". Ты их найдешь, не сомневаюсь. Но не в этом вопрос, а только в одном — что криминального в том, что я предложил ?

Да, в общем-то, ничего, кроме того, что твоя строка практически бесполезна. Все библиотеки возвращают обычный string. Мне, чтобы проверить их строки на палиндромность, придется каждый раз порождать новый инстанс MyString.

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

В результате, внешний метод bool IsPalindrom(string) получается гораздо более удобным в использовании. А если повезло писать на языке, который поддерживает extension methods, то еще и синтаксис становится мягким и шеловистым. Сравним:

...
string name = HttpUtility.UrlDecode(nameParam);
MyString str = new str(name); // Pavel Dvorkin's style of doing things
if (str.IsPalindrom())
  resultLabel.Text = str + "is a palindrom"
...    
string name = HttpUtility.UrlDecode(nameParam);
if (name.IsPalindrom()) // qualified developer approach
  resultLabel.Text = name + " is a palindrom";



PD>Писать код нет времени, поэтому только наметки


PD>class MyDir : Directory {

PD>MyFileData public static FindFirstFile(string path) {..}
PD>bool public static FindNextFile(MyFileData data) {...}
PD>void public static FindClose(MyFileData data) {...}
PD>}
Прекрасно. А теперь приведи примерный код использования этого класса. Может быть, тогда тебе станет понятно, что никаких преимуществ этот маленький фрагмент ": Directory" тебе не даст.

Вот, кстати, как этот класс пишут простые джедаи, без омского образования:
public static sealed class MyDirectory
{
  public IEnumerable<string> GetFileSystemEntries(string path)
    {...}
}

Потому что незачем плодить свои аналоги IEnumerable.

PD>Вполне допускаю, что есть и лучшие варианты, но ATL, MFC, VCL, .Net. — все они на этом построены.

Я в курсе. Практика — критерий истины.

PD>Говорим-то мы одно и то же, а вот выводы разные делаем. Твоя позиция — надо бы и их запечатать, да вот приходится распечатывать. Моя позиция — не надо и Directory запечатывать, да и вообще не надо — как правило (исключения возможны). Из того факта, что некорректное расширение класса (любым способом) может повлечь за собой его неработоспособность, не следует, что это надо запретить. Да, некорректно расширенный MyString : string может привести к тому, что рухнет он при обращениии к нему как к string. Верно. Но это не причина, чтобы запретить вообще всякие изменения. ИМХО.

По мне — так это вполне достаточная причина.

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

Дело далеко не только в классах-инструментах. Дело в контрактах и способах обеспечения extensibility. Во времена OOP Hype казалось, что implementation inheritance — это прямо таки silver bullet. Прошло двадцать лет активного использования OOP в стиле С++; оказалось, что оно совсем не так здорово, как казалось. Многим это показалось намного раньше. Ты ведь наверняка читал критику ООП от Степанова (который STL)?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 09.12.08 14:25
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


PD>>Ну если об этом речь идет — то и в C# это вроде бы не запрещено. Класс-то зачем закрывать ?

PD>>Вот в java — точно не выйдет
S>Что не выйдет? public final class? Конечно же выйдет.

не делать virtual не выйдет.

PD>>Вполне возможно, что придется и расширить. Вот сделает MS SQLFS , там, возможно, придется новые методы/свойства добавить. Кстати, и сейчас есть что добавить. Как там, к примеру, насчет хардлинков ? точек соединения ?

S>Ты не понял вопрос. Где объект, функциональность которого ты собрался расширять?

А почему ты решил, что расширяют функциональность только объектов ?

S>В этом — ничего. Но разрешение делать такие вещи позволило бы тебе делать и более криминальные вещи.


+1. Но см то, что я писал.

PD>>Кстати, в C++ это выглядело бы так


PD>>class MyString : public String {

PD>> public IsPalindrom() const {//...}
PD>>};

PD>>и тем самым явно сказано, что менять состояние объекта она не может.

S>Да ну. Мало ли чего там сказано. конст_каст от this и вперед, на танки.

Можно. Все можно. Можно char* откастить во float*. Только нечего ерундой заниматься.

S>Да, в общем-то, ничего, кроме того, что твоя строка практически бесполезна. Все библиотеки возвращают обычный string. Мне, чтобы проверить их строки на палиндромность, придется каждый раз порождать новый инстанс MyString.


Хм, непонятно зачем. Проверка будет идти для текущего инстанса. Нет разницы в принципе между моим IsPalindrom и String.IsNormalized.

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


И что ? Тем и не надо, они и не знают, что есть IsPalindrom, а другим (при разработке которых использовался MyString) — надо. Несерьезно это.

S>В результате, внешний метод bool IsPalindrom(string) получается гораздо более удобным в использовании.


А почему тогда IsNormalized не внешний ?

Пример skipped, поскольку IsNormalized как раз из этой оперы, только вместо проверки на URL проверяет на Юникод. Один черт.


PD>>Писать код нет времени, поэтому только наметки


PD>>class MyDir : Directory {

PD>>MyFileData public static FindFirstFile(string path) {..}
PD>>bool public static FindNextFile(MyFileData data) {...}
PD>>void public static FindClose(MyFileData data) {...}
PD>>}
S>Прекрасно. А теперь приведи примерный код использования этого класса. Может быть, тогда тебе станет понятно, что никаких преимуществ этот маленький фрагмент ": Directory" тебе не даст.

MyFileData mfd = MyDir.FindFirstFile("*.*));
while (MyDir.FindNextFile(mfd))
// и т.д.

В итоге нет коллекции. На все файлы, хоть их там тысячи, используется один экземпляр MyFileData.


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

S>
S>public static sealed class MyDirectory
S>{
S>  public IEnumerable<string> GetFileSystemEntries(string path)
S>    {...}
S>}
S>

S>Потому что незачем плодить свои аналоги IEnumerable.

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


PD>>Говорим-то мы одно и то же, а вот выводы разные делаем. Твоя позиция — надо бы и их запечатать, да вот приходится распечатывать. Моя позиция — не надо и Directory запечатывать, да и вообще не надо — как правило (исключения возможны). Из того факта, что некорректное расширение класса (любым способом) может повлечь за собой его неработоспособность, не следует, что это надо запретить. Да, некорректно расширенный MyString : string может привести к тому, что рухнет он при обращениии к нему как к string. Верно. Но это не причина, чтобы запретить вообще всякие изменения. ИМХО.

S>По мне — так это вполне достаточная причина.

OK.


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

S>Дело далеко не только в классах-инструментах. Дело в контрактах и способах обеспечения extensibility. Во времена OOP Hype казалось, что implementation inheritance — это прямо таки silver bullet. Прошло двадцать лет активного использования OOP в стиле С++; оказалось, что оно совсем не так здорово, как казалось. Многим это показалось намного раньше. Ты ведь наверняка читал критику ООП от Степанова (который STL)?

Времени уже нет на серьезный ответ, да и подумать надо.
With best regards
Pavel Dvorkin
Re[11]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 09.12.08 17:00
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>>>и тем самым явно сказано, что менять состояние объекта она не может.

S>>Да ну. Мало ли чего там сказано. конст_каст от this и вперед, на танки.
PD>Можно. Все можно. Можно char* откастить во float*. Только нечего ерундой заниматься.
В нормальных языках такое нельзя сделать.

S>>Да, в общем-то, ничего, кроме того, что твоя строка практически бесполезна. Все библиотеки возвращают обычный string. Мне, чтобы проверить их строки на палиндромность, придется каждый раз порождать новый инстанс MyString.

PD>Хм, непонятно зачем. Проверка будет идти для текущего инстанса. Нет разницы в принципе между моим IsPalindrom и String.IsNormalized.

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

PD>И что ? Тем и не надо, они и не знают, что есть IsPalindrom, а другим (при разработке которых использовался MyString) — надо. Несерьезно это.

Считали мы значение свойства TextBox1.Text (которое типа string) как проверить является ли оно палиндромом с помощью вашего класса?

Или вы предлагаете весь .NET переписать на использование MyString?

S>>В результате, внешний метод bool IsPalindrom(string) получается гораздо более удобным в использовании.

PD>А почему тогда IsNormalized не внешний ?
Потому что так захотели создатели .NET. У них есть возможность сделать метод не статическим и не переписывать при этом весь фреймворк.

PD>Пример skipped, поскольку IsNormalized как раз из этой оперы, только вместо проверки на URL проверяет на Юникод. Один черт.

Если внимательно почитаете MSDN выясните что есть еще метод Normalize, выносить IsNormalized в статик было бы неправльно.
С другой стороны можно было Normalize и IsNormalized оба сделать статиком. Но также посмотрев список методов класса String можно понять что все методы (кроме Intern) выполняющие преобразования строки являются инстанс методами.

PD>Но вот из каких идейных соображений здесь должен быть еще один класс, а не наследник — я так от тебя ответа и не получил. Подчеркиваю, идейных соображений.


Объясняю. Наследование в ООП используется для: 1)внесения полиморфизма по неявному нулевому агрументу методов 2)повторного использования кода предков.
Ваш класс MyDir не использует ни одно, ни другое. Так из каких идейных соображений вам нужен наследник статик класса?
Re[12]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 04:57
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>В нормальных языках такое нельзя сделать.




G>Считали мы значение свойства TextBox1.Text (которое типа string) как проверить является ли оно палиндромом с помощью вашего класса?


Никак. Но если я буду писать свой наследник от TextBox, то в нем может использоваться MyString.

G>Или вы предлагаете весь .NET переписать на использование MyString?


Нет, зачем же. Наследовать там, где надо.

G>Потому что так захотели создатели .NET. У них есть возможность сделать метод не статическим и не переписывать при этом весь фреймворк.


Вот это верно. Просто потому, что они так захотели

G>Если внимательно почитаете MSDN выясните что есть еще метод Normalize, выносить IsNormalized в статик было бы неправльно.


С таким же успехом я мог бы добавить ну пусть не MakePalindrom , но что-то аналогичное


PD>>Но вот из каких идейных соображений здесь должен быть еще один класс, а не наследник — я так от тебя ответа и не получил. Подчеркиваю, идейных соображений.


G>Объясняю. Наследование в ООП используется для: 1)внесения полиморфизма по неявному нулевому агрументу методов 2)повторного использования кода предков.

G>Ваш класс MyDir не использует ни одно, ни другое.
Так из каких идейных соображений вам нужен наследник статик класса?

А почему вы так в этом уверены ? Я, вполне возможно, вызову в своем методе, какой-то из методов Directory.

Это раз. А во-вторых, кроме этих 2 есть и третья причина — расширение возможностей класса.
With best regards
Pavel Dvorkin
Re[13]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.12.08 05:22
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


G>>Считали мы значение свойства TextBox1.Text (которое типа string) как проверить является ли оно палиндромом с помощью вашего класса?

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

G>>Или вы предлагаете весь .NET переписать на использование MyString?

PD>Нет, зачем же. Наследовать там, где надо.
То есть переписать пол фреймворка. Удачи.

G>>Потому что так захотели создатели .NET. У них есть возможность сделать метод не статическим и не переписывать при этом весь фреймворк.

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

G>>Если внимательно почитаете MSDN выясните что есть еще метод Normalize, выносить IsNormalized в статик было бы неправльно.

PD>С таким же успехом я мог бы добавить ну пусть не MakePalindrom , но что-то аналогичное
Так создавайте свой фреймворк, кто же вам мешает?


PD>>>Но вот из каких идейных соображений здесь должен быть еще один класс, а не наследник — я так от тебя ответа и не получил. Подчеркиваю, идейных соображений.


G>>Объясняю. Наследование в ООП используется для: 1)внесения полиморфизма по неявному нулевому агрументу методов 2)повторного использования кода предков.

G>>Ваш класс MyDir не использует ни одно, ни другое.
PD>Так из каких идейных соображений вам нужен наследник статик класса?
PD>А почему вы так в этом уверены ? Я, вполне возможно, вызову в своем методе, какой-то из методов Directory.
А вы его и без неследования можете вызвать.


PD>Это раз. А во-вторых, кроме этих 2 есть и третья причина — расширение возможностей класса.

Неправльно. Если у вас есть String, то какого бы наследника String вы не писали никто кроме вас о нем знать не будет и не сможет использовать его возможности.
Для вашего класса MyString вам придется написать библиотеку, которая понимает MyString. А если подумать то оказывается в таком случае необязательно наследоваться от String, чтобы получить туже функциональность, можно воспользоваться агрегацией.
Re[10]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 06:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

S>
S>public static sealed class MyDirectory
S>{
S>  public IEnumerable<string> GetFileSystemEntries(string path)
S>    {...}
S>}
S>

S>Потому что незачем плодить свои аналоги IEnumerable.

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

Error 1 'WindowsFormsApplication6.MyDirectory': a class cannot be both static and sealed E:\WindowsFormsApplication6\Form1.cs 12 32 WindowsFormsApplication6

После того, как я sealed убрал, получил

Error 1 'GetFileSystemEntries': cannot declare instance members in a static class E:\WindowsFormsApplication6\Form1.cs 14 36 WindowsFormsApplication6

With best regards
Pavel Dvorkin
Re[12]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 06:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


PD>>не делать virtual не выйдет.

S>Не понял. final method — вполне нормальное явление.

Я просто имел в виду, что все методы в Яве виртуальные.

PD>>Хм, непонятно зачем. Проверка будет идти для текущего инстанса.

S>Я же пример привел. Перечитай его еще раз.

Перечитал. Те, кто используют обычный string — да, должны. Те, кто будут использовать MyString — не должны. Вот напишу свою PalindroManager и в нем будет исключительно MyString использоваться.

PD>>Нет разницы в принципе между моим IsPalindrom и String.IsNormalized.

S>В принципе — нету. Более того, я тебе показал, как делать IsPalindrom, который ведет себя как IsNormalized (а не как твой), при этом безо всякого наследования.

Я разве утверждаю, что это нельзя? Я не согласен, что это правильно. С идейной, а не технической точки зрения.


PD>>А почему тогда IsNormalized не внешний ?

S>По соображениям эффективности. Реализацию смотрел?

Нет.

PD>>Пример skipped, поскольку IsNormalized как раз из этой оперы, только вместо проверки на URL проверяет на Юникод. Один черт.

S>Пример не понят.

Понят, понят. См. выше.

PD>>>>Писать код нет времени, поэтому только наметки



PD>>MyFileData mfd = MyDir.FindFirstFile("*.*));

PD>>while (MyDir.FindNextFile(mfd))
PD>>// и т.д.

PD>>В итоге нет коллекции. На все файлы, хоть их там тысячи, используется один экземпляр MyFileData.

S>Ок. А теперь покажи мне, где в этом коде используется тот факт, что MyDir наследник от Directory? Правильно, нигде. Ну так и нехрен заниматься ерундой.

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

Вот ответь на вопрос — а зачем в C# вообще static классы ? Инстансов от них не дождешься, это просто набор методов. Почему бы просто внеклассовые функции не разрешить, как в С++ ? Упаковать их в namespace и дело с концом, туда никто не запрещает добавлять. Так нет же, все же в класс их поместили. И правильно.


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

S>А наследник это что, не "еще один класс"?
PD>> Подчеркиваю, идейных соображений. И ты не ответил — если бы пришлось писать все это самому — ты бы два класса сделал или все же один ?
S>Какая разница? Был бы один класс. Но это не имеет никакого отношения к вопросу о том, от чего наследовать MyDirectory — от Object или от Directory.

Так все же был бы один класс! Тогда ответь на вопрос — а почему ? Иными словами, какие идейные соображения движут тобой, когда ты принимаешь решение — быть тут одному классу или нескольким ? Подчеркиваю, речь идет о static классах, так чтт без виртуальных рассуждений, please.

А теперь кое-что добавлю. Это должно было бы быть в ответе на предыдущий твой постинг, но не хочу дерево устраивать.

ИМХО sealed — слишком жесткое и категоричное утверждение. Оно запрещает любую модификацию. Между тем модификация модификации рознь. Одни модификации могут действительно разрушить функционирование кода базового класса, другие — не могут.

Да и вообще модификации — это и замена, и добавление. А замена, в свою очередь — замена виртуальных и невиртуальных. А добавление — инстансных или статических. ИМХО вместо того, чтобы чохом запрещать все, надо было более гибкую политику вести. Например, запретить переопределение виртуальных методов базового класса, но разрешить добавление новых методов. И т.д. Возможно, следовало бы вместо sealed аттрибуты использовать или играть с модификаторами доступа.

Ты же рассматриваешь только в одной плоскости — замена виртуального метода, и делаешь на основе этого все выводы. Хорошо, давай теперь и это рассмотрим.

Вот ты писал

S>Ок, давайте перевернём постулат: вместо "запечатывайте классы, наследование от которых не продумано", напишем "продумывайте наследование от всех классов, которые не запечатаны".


Можешь ты гарантировать, что даже если ты продумал это наследование до предела, код наследника не порушит функционирование кода твоего базового класса ? Если да — обоснуй. Если нет — какой критерий позволит определить, когда этот метод можно объявить virtual , а когда нет , коль скоро порушить все же можно всегда ?
With best regards
Pavel Dvorkin
Re[12]: Override для произвольного метода.
От: GarryIV  
Дата: 10.12.08 06:45
Оценка:
Здравствуйте, EvilChild, Вы писали:

A>>>А как же Template method pattern? Всегда вместо него делать через стратегии, чтобы не было наследования реализации?


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


EC>А можно раскрыть мысль?


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

Я не говорю что его нельзя использовать, он довольно употребим из-за его простоты. В качества внутренностей реализации какого-нибудь интерфейса — почему бы и нет. В качестве публичного контракта — ну его нафиг.
WBR, Igor Evgrafov
Re[14]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 07:37
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Или вы предлагаете весь .NET переписать на использование MyString?

PD>>Нет, зачем же. Наследовать там, где надо.
G>То есть переписать пол фреймворка. Удачи.

Что за чепуха ? Мне это нужно для своих целей, допустим. Я в тех классах, что перепишу, буду использовать этот свой MyString. Зачем фреймворку IsPalindrom ? Он мне нужен, а не ему.

G>Так создавайте свой фреймворк, кто же вам мешает?


Пошла уже демагогия. Я хочу расширить его для своих целей и на это я имею право. Создавать новый оснований требовать у вас нет.


PD>>Это раз. А во-вторых, кроме этих 2 есть и третья причина — расширение возможностей класса.

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

См. выше.

G>Для вашего класса MyString вам придется написать библиотеку, которая понимает MyString. А если подумать то оказывается в таком случае необязательно наследоваться от String, чтобы получить туже функциональность, можно воспользоваться агрегацией.


Агрегация — это как ? Написать свой класс, в нем в качестве поля string и экспонировать все его методы ? Спасибо. Во-первых, мне что, время не на что тратить ? А во-вторых, какая тут логика будет ? Чтобы строку проверять на палиндром, надо, оказывается, ее в другой класс засунуть . Появится желание еще что-то сделать — еще один класс и в нем тоже все экспонировать ? А если кто-то захочет мой класс расширить — он его тоже должен агрегировать и все экспонировать ? Так сказать, двойная агрегация. То-то весело будет...
With best regards
Pavel Dvorkin
Re[14]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 07:40
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>Это не ошибка а правда жизни. Наследование радо добавления методов — ерунда. Это было модно 10-15 лет назад, сейчас пришло просветление в головы теоретиков ООП.

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

G>Это действительно ерунда.

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

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

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

Поздравляю с просветлением
With best regards
Pavel Dvorkin
Re[15]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.12.08 07:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


G>>>>Или вы предлагаете весь .NET переписать на использование MyString?

PD>>>Нет, зачем же. Наследовать там, где надо.
G>>То есть переписать пол фреймворка. Удачи.
PD>Что за чепуха ? Мне это нужно для своих целей, допустим. Я в тех классах, что перепишу, буду использовать этот свой MyString. Зачем фреймворку IsPalindrom ? Он мне нужен, а не ему.
Тогда что вы пытаетесь доказать? Создавайте IsPalindrom который будете использовать.

G>>Так создавайте свой фреймворк, кто же вам мешает?

PD>Пошла уже демагогия. Я хочу расширить его для своих целей и на это я имею право. Создавать новый оснований требовать у вас нет.
Кого расширить?

PD>>>Это раз. А во-вторых, кроме этих 2 есть и третья причина — расширение возможностей класса.

G>>Неправльно. Если у вас есть String, то какого бы наследника String вы не писали никто кроме вас о нем знать не будет и не сможет использовать его возможности.
PD>См. выше.
Вы не можете расширить существующие классы так чтобы существующий код понимал расширения. Вы можете только специализировать их.
Вам придется создавать новый код, возможно аналогичный существующему, чтобы он понимал расширения.

G>>Для вашего класса MyString вам придется написать библиотеку, которая понимает MyString. А если подумать то оказывается в таком случае необязательно наследоваться от String, чтобы получить туже функциональность, можно воспользоваться агрегацией.

PD>Агрегация — это как ? Написать свой класс, в нем в качестве поля string и экспонировать все его методы ? Спасибо. Во-первых, мне что, время не на что тратить ? А во-вторых, какая тут логика будет ? Чтобы строку проверять на палиндром, надо, оказывается, ее в другой класс засунуть . Появится желание еще что-то сделать — еще один класс и в нем тоже все экспонировать ? А если кто-то захочет мой класс расширить — он его тоже должен агрегировать и все экспонировать ? Так сказать, двойная агрегация. То-то весело будет...
Ко всему надо подходить с умом, а не так как вы.
Re[16]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 08:44
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Да что аргументов и не видно было. Все на уровне "мне так хочется".


Я имею в виду качество твоих аргументов — см. выделенное в прошлом письме
With best regards
Pavel Dvorkin
Re[16]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 08:51
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Тогда что вы пытаетесь доказать? Создавайте IsPalindrom который будете использовать.


Не могу — класс String sealed.

G>>>Так создавайте свой фреймворк, кто же вам мешает?

PD>>Пошла уже демагогия. Я хочу расширить его для своих целей и на это я имею право. Создавать новый оснований требовать у вас нет.
G>Кого расширить?

Фреймворк.

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


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

class MyString : String
class MyFrameWork : FrameWork

в классе FrameWork никто про MyString не знает, верно. А в классе MyFrameWork знают и используют. И для этого мне не надо переписать весь FrameWork, хватит переписывания нескольких методов. Все остальное возьмем от FrameWork, в котором никто про MyString не знает — и не надо.

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


Не создавать, а расширять существующий — см. выше.

PD>>Агрегация — это как ? Написать свой класс, в нем в качестве поля string и экспонировать все его методы ? Спасибо. Во-первых, мне что, время не на что тратить ? А во-вторых, какая тут логика будет ? Чтобы строку проверять на палиндром, надо, оказывается, ее в другой класс засунуть . Появится желание еще что-то сделать — еще один класс и в нем тоже все экспонировать ? А если кто-то захочет мой класс расширить — он его тоже должен агрегировать и все экспонировать ? Так сказать, двойная агрегация. То-то весело будет...

G>Ко всему надо подходить с умом, а не так как вы.

А можно продемонстрировать подход с умом с агрегацией в примере IsPalindrom ? Мне просто интересно, как это в данном случае агрегировать с умом
With best regards
Pavel Dvorkin
Re[14]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 10.12.08 10:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


PD>>Я просто имел в виду, что все методы в Яве виртуальные.

S>Я просто имел в виду, что это неправда.

PD>>Перечитал. Те, кто используют обычный string — да, должны. Те, кто будут использовать MyString — не должны. Вот напишу свою PalindroManager и в нем будет исключительно MyString использоваться.

S>Павел, ты правда не понимаешь, или придуряешься?
S>Твоим MyString не пользуется никто. Текстбоксы не возвращают MyString. TextReader не читает MyString из стрима. StringBuilder не собирает MyString. Нет ни одного метода во всем огромном множестве кода, который бы вернул тебе MyString.

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

S>Твоя библиотека или приложение не будет работать в вакууме. Придется как-то интероперировать с окружающим миром. И ты на полном серъезе предлагаешь только ради проверки на палиндромность порождать новый класс, который потребует предварительной конверсии каждой строки для выполнения проверки?


Какой к богу проверки ? Создаем наследника от TextBox, к примеру. Кладем его на форму. В нем поле MyString Text1. В него считываем из Win32 edit, создавая при этом экземпляр MyString. Проверяем его на палиндром — здесь же, в наследнике TextBox. Все. Во всем остальном он ведет себя как обычный String и в таком виде может быть употреблен где угодно в существующем FW, которому совсем не надо знать, что он MyString. Никакая дополнительная виртуальность здесь не нужна.

S>Какая идея может оправдать этот немыслимый бред? По-моему, никакая.


Что у вас за дурная манера , господа, называть все, с чем вы не согласны, бредом ?

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

S>Идея — в том, чтобы не заставлять пользователей твоего метода IsPalindrome заниматься непроизводительной работой. То, на чем ты так упорно настаиваешь, отвратительно сказывается на производительности как программиста, так и программы.

Обоснуй насчет производительности программы на примере моего расширения MyString и твоей Utility. Имей в виду — функция не виртуальная, так что насчет callvirt — не надо.



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

S>А теперь ты лихорадочно пытаешься придумать еще хоть какие-то аргументы в защиту своего заблуждения. Ок, какая именно логичность появляется от того, что MyDirectory отнаследован от Directory.

А какая логичность в том, что в классе MyDirectory обраны эти методы, а не создано 3 класса, по которым их бы разнесли ? Логичность в том, что класс их объединяет в нечто логически целое — в данном случае (static class) вот и все.

PD>>Вот ответь на вопрос — а зачем в C# вообще static классы ? Инстансов от них не дождешься, это просто набор методов. Почему бы просто внеклассовые функции не разрешить, как в С++ ? Упаковать их в namespace и дело с концом, туда никто не запрещает добавлять. Так нет же, все же в класс их поместили. И правильно.

S>И какое отношение этот вопрос имеет к разрешению наслледоваться от класса Directory?

Самое прямое. Если я расширяю класс Directory — я создаю более мощный "Directory". То есть static класс есть логически собранный набор методов для определенной области. Средство организации, так сказать. И поэтому все средства для работы с этой областью должны быть в этом классе, а не где угодно еще. Или в расширенном классе.
Если ты с этим не согласен — тогда зачем вообще этот класс ? Разместить их по namespace и дело с концом. Зачем класс нужен ?


PD>>Так все же был бы один класс! Тогда ответь на вопрос — а почему ? Иными словами, какие идейные соображения движут тобой, когда ты принимаешь решение — быть тут одному классу или нескольким ? Подчеркиваю, речь идет о static классах, так чтт без виртуальных рассуждений, please.

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

Уход от ответа из-за его отсутствия. А если бы ты реально при изготовлении этого класса с нуля разбил его без всякого смысла и логики на 2 — сочувствую...

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


Слова, слова...

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


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

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

Ладно, все, хватит.
With best regards
Pavel Dvorkin
Re[15]: Override для произвольного метода.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.12.08 10:16
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Какой к богу проверки ? Создаем наследника от TextBox, к примеру. Кладем его на форму. В нем поле MyString Text1. В него считываем из Win32 edit, создавая при этом экземпляр MyString. Проверяем его на палиндром — здесь же, в наследнике TextBox. Все. Во всем остальном он ведет себя как обычный String и в таком виде может быть употреблен где угодно в существующем FW, которому совсем не надо знать, что он MyString. Никакая дополнительная виртуальность здесь не нужна.


Выделенное нужно только для того, чтобы обратиться к методу IsPalindrome? Не проще ли передать строку в статический метод Utils.IsPalindrome(string)? Или воспользоваться Extension методом?
Re[17]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.12.08 10:30
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


G>>Тогда что вы пытаетесь доказать? Создавайте IsPalindrom который будете использовать.

PD>Не могу — класс String sealed.
Создайте Extension метод, зачем вам наследование?
В любом случае придется писать новый класс, у String нету виртуальных методов, чтобы их можно было переопределить.
И вообще наследоваться от String — плохая идея, синклер уже объяснил.

G>>>>Так создавайте свой фреймворк, кто же вам мешает?

PD>>>Пошла уже демагогия. Я хочу расширить его для своих целей и на это я имею право. Создавать новый оснований требовать у вас нет.
G>>Кого расширить?
PD>Фреймворк.
Конкретнее, какие именно классы зачем расширить?
Про String и Directory уже объяснили что это не нужно или неправильно. Остальное — только ваши желания, имеющие мало общего с реальностью.

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

PD>Господи, да не объясняйте мне то, что я двадцать лет назад знал. Да, существующий код не будет не только понимать расширения, но даже и знать об их существовании. А расширенный код будет знать и использовать

PD>class MyString : String

PD>class MyFrameWork : FrameWork

PD>в классе FrameWork никто про MyString не знает, верно. А в классе MyFrameWork знают и используют. И для этого мне не надо переписать весь FrameWork, хватит переписывания нескольких методов. Все остальное возьмем от FrameWork, в котором никто про MyString не знает — и не надо.

Нескольких, это скольких? В реальном проекте окажется огромное количество.
Даже переписывания одного метода фреймворка уже слишком много для того чтобы добавить один, нафиг никому не нужный, метод в класс String.

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

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

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

PD>>>Агрегация — это как ? Написать свой класс, в нем в качестве поля string и экспонировать все его методы ? Спасибо. Во-первых, мне что, время не на что тратить ? А во-вторых, какая тут логика будет ? Чтобы строку проверять на палиндром, надо, оказывается, ее в другой класс засунуть . Появится желание еще что-то сделать — еще один класс и в нем тоже все экспонировать ? А если кто-то захочет мой класс расширить — он его тоже должен агрегировать и все экспонировать ? Так сказать, двойная агрегация. То-то весело будет...

G>>Ко всему надо подходить с умом, а не так как вы.

PD>А можно продемонстрировать подход с умом с агрегацией в примере IsPalindrom ? Мне просто интересно, как это в данном случае агрегировать с умом


Ничего агрегировать не надо, достаточно содзать extension
Re[17]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 10.12.08 10:31
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


G>>Да что аргументов и не видно было. Все на уровне "мне так хочется".

PD>Я имею в виду качество твоих аргументов — см. выделенное в прошлом письме

Это не агрументы, а оценка твоих слов.
Re[13]: Override для произвольного метода.
От: EvilChild Ниоткуда  
Дата: 10.12.08 16:52
Оценка:
Здравствуйте, GarryIV, Вы писали:

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


EC>>А можно раскрыть мысль?


GIV>Его недостатки происходят из-за того что в нем надо наследоваться от абстрактного класса.

Строго говоря класс не обязан быть абстрактным.

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


Как-то странно для меня звучит упрёк в адрес наследования, при обсуждении техники примененимой только в рамках наследования.
Или я трактую паттерн слишком узко?
now playing: Oliver Koletzki — Requiem Für Die Vernunft (Lützenkirchen Remix)
Re[14]: Override для произвольного метода.
От: GarryIV  
Дата: 10.12.08 20:26
Оценка:
Здравствуйте, EvilChild, Вы писали:

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


EC>>>А можно раскрыть мысль?


GIV>>Его недостатки происходят из-за того что в нем надо наследоваться от абстрактного класса.

EC>Строго говоря класс не обязан быть абстрактным.

Шаблонный метод == абстрактный метод => класс абстрактный.

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


EC>Как-то странно для меня звучит упрёк в адрес наследования, при обсуждении техники примененимой только в рамках наследования.

EC>Или я трактую паттерн слишком узко?

Ну я и говорю, наследование реализации вообще стремная штука а template method в частности
WBR, Igor Evgrafov
Re[16]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 11.12.08 06:04
Оценка:
Здравствуйте, IB, Вы писали:

IB>Иными словами, у тебя появился контрол, который ты можешь переиспользовать только с определенным типом строк, и ни с чем другим он работать уже не сможет, зашил логику проверки в UI, что является грубейшей ошибкой, так как ни протестировать толком, ни переиспользовать эту логику так же не получится, ну и финальный гвоздь в монолитность своего приложения ты забил, когда завязался на конкретную реализацию TextBox.

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

Неужели трудно понять , что этот пример просто-напросто придуман за 2 минуты, чтобы продемонстрировать суть того, о чем я говорю. А суть проста — мы можем породить некий новый класс A1 от существующего класса A, и некий новый класс B1 от существующего класса B. Внутри класса A1 будет использоваться класс B1, в то время как в классе A экземпляры B1 будут выглядеть как B. При этом не возникает необходимости в полиморфизме-виртуальности. Примеров таких на свете сколько угодно.

Вот, например класс CStringEx — расширяет стандартный класс CString из MFC

http://www.codeguru.com/cpp/cpp/string/ext/article.php/c2793

/////////////////////////////////////////////////////////////////
The constructors in the CStringEx class parallel the constructor in CString and in fact simply chains into the corresponding CString constructor. Some of the CStringEx functions use knowledge of the internal structure of the CString object so there is a small chance that these functions might break if the CString implementation changes.

The functions provided by CStringEx are quite easy to use and fairly simple to understand. The Insert() functions inserts a character or a sub-string within a string. The result is similar to inserting text in an edit control, the string is expanded to accommodate the sub-string. The Delete() function removes a segment from the string and shortens it. The Replace() function removes a sub-string and replaces it with another. Again, the string size is adjusted depending on the size of the sub-string that was removed and the size of the sub-string that was inserted.

The find family of functions, finds a sub-string in the forward or the reverse direction. The NoCase version of these functions are case insensitive. The FindReplace() and FindReplaceNoCase() functions searches for a sub-string and replaces the matching sub-string with another string. The GetField() and GetDelimitedField() functions find a token in the string. The table below exemplifies the uses of these functions.
/////////////////////////////////////////////////////////////////

Естественно, внутри каркаса MFC экземпляры CStringEx выглядят как CString. Но в нем есть дополнительные средства, которые удобны.




PD>>Что у вас за дурная манера , господа, называть все, с чем вы не согласны, бредом ?

IB>Мы с этим не просто не согласны, мы знаем, что так делать нельзя и даже пытаемся тебе объяснить почему, но очевидно бесполезно... =)

Ну тогда объясни это же тем, кто написал этот класс и кто его использует.
With best regards
Pavel Dvorkin
Re[16]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 11.12.08 06:21
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Отлично. То есть вместо использования существующей строки, мы создаем ее дубликат. Точнее, в данном контексте уже предлагается отказаться от готовой инфраструктуры WinForms, и напрямую бегать в Win32 через интероп. И всё это ради того, чтобы узнать, не является ли введенная пользователем строка палиндромом?


См. мой ответ IB.

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

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

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

S>А ты лучше на досуге подумай, как будет выглядеть аналог с наследованием. От кого я буду наследовать MyDirectory — от Directory или от YourDirectory? Почему? Как быть, если мы не знали о библиотеках друг друга во время разработки?


Вообще-то этот вопрос рассматривается во всех курсах по ООП — от какого базового класса надо производить наследование и в каком случае.
With best regards
Pavel Dvorkin
Re[18]: Override для произвольного метода.
От: LaPerouse  
Дата: 11.12.08 14:18
Оценка:
Здравствуйте, IB, Вы писали:

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


PD>> Примеров таких на свете сколько угодно.

IB>Ну давай, практический пример, где бы это было оправдано, хоть один?

Почему же, можно придумать такие примеры.

Собственно, какие преимущества могут быть у создания наследника с нужным методом по сравнению с тем случаем, когда этот метод — внешний (в делегирующем классе или вовсе статич.)? Только одно — полиморфное использование соотв. класса через библиотечный интерфейс — в данном случае String. Чтобы с новым объектом MyString можно было работать как со String. И чтобы библ. методы могли таким образом использовать эту реализацию. Если бы String создавался только через фабрику и мы бы имели бы возможность сделать String.setCurrentFactoty(myStringFactory), то такое очень даже имело бы смысл. Другое дело, что в этом случае автор библиотеки вряд ли стал бы закрывать String... Так как он был бы расчитан на такое вот применение.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[19]: Override для произвольного метода.
От: LaPerouse  
Дата: 11.12.08 14:27
Оценка:
Здравствуйте, LaPerouse, Вы писали:

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


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


PD>>> Примеров таких на свете сколько угодно.

IB>>Ну давай, практический пример, где бы это было оправдано, хоть один?

LP>Почему же, можно придумать такие примеры.


LP>Собственно, какие преимущества могут быть у создания наследника с нужным методом по сравнению с тем случаем, когда этот метод — внешний (в делегирующем классе или вовсе статич.)? Только одно — полиморфное использование соотв. класса через библиотечный интерфейс — в данном случае String. Чтобы с новым объектом MyString можно было работать как со String. И чтобы библ. методы могли таким образом использовать эту реализацию. Если бы String создавался только через фабрику и мы бы имели бы возможность сделать String.setCurrentFactoty(myStringFactory), то такое очень даже имело бы смысл. Другое дело, что в этом случае автор библиотеки вряд ли стал бы закрывать String... Так как он был бы расчитан на такое вот применение.


Да, еще один очевидный случай забыл написать, хотя и хотел.

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

MyString MyString.fromString(String).

Это, кстати, реальнейший пример такой необходимости. По сути, это единственная причина (если не считать сферовакуума с фабрикой, опис. в предыдущем моем посте), которая может завставить это делать.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[19]: Override для произвольного метода.
От: samius Япония http://sams-tricks.blogspot.com
Дата: 11.12.08 15:00
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>Если бы String создавался только через фабрику и мы бы имели бы возможность сделать String.setCurrentFactoty(myStringFactory), то такое очень даже имело бы смысл.


И каждая сторонняя библиотека пыталась бы установить свою фабрику и ломалась бы при работе с чужими фабриками. Нет уж, спасибо
Re[18]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 12.12.08 06:20
Оценка:
Здравствуйте, 4058, Вы писали:

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


PD>>Вот, например класс CStringEx — расширяет стандартный класс CString из MFC


4>1. System.String в отличие от CString иммутабелен, в частности по этому класс запечатан.


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

Этот-то класс запечатан, потому что он иммутабелен, ладно, пусть, а вот почему другие, не иммутабельные классы — то запечатаны ?
With best regards
Pavel Dvorkin
Re[19]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 12.12.08 08:12
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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

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

PD>Что же касается меня, то я к ним отношусь как не более чем неким рекомендациям. Им можно следовать, им, наверное, даже лучше следовать, но если есть к тому основание, ими вполне можно пренебречь. И не бояться при этом обвинений в незнании принципов ООП или некошерности в каком бы то ни было ином смысле, или даже в кривизне решения. Просто надо сравнить проигрыш от неследования этим правилам и выигрыш от этого же неследования. Если второе перевешивает — спокойно нарушаем эти правила и посылаем куда угодно критиков. А перевешивает или нет — зависит от задачи и целей.

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

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

А с чего ты взял что применение анти-паттернов приведет к увеличению быстродействия?

Кстаи по теме — override для произвольного метода бъет по JIT оптимизации, также как и не-sealed классы.

PD>А критерием истины, как тут Антон заметил (а впрочем, и до него другие замечали является практика. А поэтому я имею полное основание утверждать, что то, что я говорю, имеет полное право на существование. Потому что я в своей практике все и всяческие каноны нарушал многократно, да еще как нарушал, и ничего — все работает уже много лет, и никто не жалуется, и работает не на 2-3 компьютерах и не в фирме "Рога и копыта"

Про деньги см выше.


PD>А в применении к вопросу, из-за которого сыр-бор разгорелся (sealed классы) — я просто одну простую вещь хочу сказать. Не надо меня от меня защищать. Или по крайней мере дайте мне легальную возможность эту защиту отменить. Да, я могу, если мне разрешить, накосячить с реализацией. Да, это будет плохо. Но могу и не накосячить. А поэтому не принимайте за меня решения, оставьте их мне. Накосячу — сам виноват и буду.

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

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

Кроме того string имеет слишком низкоуровневую реализацию, чтобы позволять всем в ней ковыряться.
Re[19]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 12.12.08 09:54
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ну и т.д. Было бы у меня времени больше — мог бы целый список составить.

Да байта ради, только ты так и не ответил на вопрос, с каких пор кривые реализации левых библиотек стали являться аргументом?

PD> Да только незачем — это настолько обычная практика в MFC, что как-то даже неудобно доказывать ее право на существование.

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

PD>Беда в том, что и ты, и Антон, да и не только вы, а многие здесь, относятся к правилам как к чему-то такому, что нарушать нельзя ни в коем случае.

Какое правило, Павел? Что ты как маленький отмазываешься. Речь здесь ни о каком правиле не идет, мы тебе на пальцах объяснили, почему предложенное тобой решение не является рабочим, не ссылаясь на какие-то там правило, а наглядно расписав все последствия.
Ты же в ответ, кроме "ну другие же так делают", ничего возразить не смог — несерьезно как-то, особенно для преподавателя и практика с большим стажем.

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

Причем тут быстродействие?

PD>А в применении к вопросу, из-за которого сыр-бор разгорелся (sealed классы) — я просто одну простую вещь хочу сказать. Не надо меня от меня защищать. Или по крайней мере дайте мне легальную возможность эту защиту отменить. Да, я могу, если мне разрешить, накосячить с реализацией. Да, это будет плохо. Но могу и не накосячить. А поэтому не принимайте за меня решения, оставьте их мне. Накосячу — сам виноват и буду.

Это ты так говоришь, пока не накосячил. А когда накосячишь, винить будешь вовсе не себя, причем так, что только пыль столбом, и самое забавное, что будешь прав.
Проходили уже, разработчики библиотек, они, блин, опытные. Они именно так проектируют не по прихоти, а потому что уже ни раз на эти грабли наступали.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[19]: Override для произвольного метода.
От: 4058  
Дата: 12.12.08 11:06
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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


PD>>>Вот, например класс CStringEx — расширяет стандартный класс CString из MFC


4>>1. System.String в отличие от CString иммутабелен, в частности по этому класс запечатан.


PD>А я-то не знал .


Видимо не знал, если начал проводить аналогии между горе-классом из горе-библиотеки MFC. "С с классами" и ООП очень разные вещи.

PD>Дискуссию, почему он иммутабелен, открывать, надеюсь, не будем, а вот вопрос один есть.


Нет не будем, т.к. эта тема уже перемолота где только можно.

PD>Этот-то класс запечатан, потому что он иммутабелен, ладно, пусть, а вот почему другие, не иммутабельные классы — то запечатаны ?


Это смотря какие... Если идеологически не требуется переопределения поведения, то не грех и запечатать.
Наследование в чистом виде пригодно в ООЯ поддерживающих множественное наследование, если множественное наследование отсутствует, то остается только наследование пригодное для достижение полиморфизма.
Re[20]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 12.12.08 11:15
Оценка:
Здравствуйте, IB, Вы писали:

IB>Да байта ради, только ты так и не ответил на вопрос, с каких пор кривые реализации левых библиотек стали являться аргументом?


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

PD>> Да только незачем — это настолько обычная практика в MFC, что как-то даже неудобно доказывать ее право на существование.

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

См. выше. Лично для меня рейтинг этих классов на codeproject является гораздо более серьезным аргументом, чем твои с Антоном рассуждения.

PD>>Беда в том, что и ты, и Антон, да и не только вы, а многие здесь, относятся к правилам как к чему-то такому, что нарушать нельзя ни в коем случае.

IB>Какое правило, Павел? Что ты как маленький отмазываешься. Речь здесь ни о каком правиле не идет, мы тебе на пальцах объяснили, почему предложенное тобой решение не является рабочим, не ссылаясь на какие-то там правило, а наглядно расписав все последствия.

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


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


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

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

IB>Причем тут быстродействие?

Да просто как пример. Легкость сопровождения vs быстродействие. Можно и другие придумать.

PD>>А в применении к вопросу, из-за которого сыр-бор разгорелся (sealed классы) — я просто одну простую вещь хочу сказать. Не надо меня от меня защищать. Или по крайней мере дайте мне легальную возможность эту защиту отменить. Да, я могу, если мне разрешить, накосячить с реализацией. Да, это будет плохо. Но могу и не накосячить. А поэтому не принимайте за меня решения, оставьте их мне. Накосячу — сам виноват и буду.

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

А может, предоставишь мне самому решить, кого я буду винить, а ? . Какие у тебя основания утверждать, что буду винить не себя ? Мы лично не знакомы, как я работаю — ты не видел, зачем же такое утверждать ?
With best regards
Pavel Dvorkin
Re[20]: Override для произвольного метода.
От: LaPerouse  
Дата: 12.12.08 11:27
Оценка:
Здравствуйте, samius, Вы писали:

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


LP>>Если бы String создавался только через фабрику и мы бы имели бы возможность сделать String.setCurrentFactoty(myStringFactory), то такое очень даже имело бы смысл.


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


А сторонние библиотеки и не дожны это делать — это дела целевого клиента выбирать реализации, с которым он будет работать. Представь себе такое — я сделал Engine.setRenderer(new DirectXrenderer()), а какой-нибудь SceneGraph переопределил Engine.setRenderer(new OpenGLrenderer()) (техническую невозможность проделать такое опустим).
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[20]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 12.12.08 11:59
Оценка:
Здравствуйте, Sinclair, Вы писали:

PD>>Ну и т.д. Было бы у меня времени больше — мог бы целый список составить. Да только незачем — это настолько обычная практика в MFC, что как-то даже неудобно доказывать ее право на существование.

S>Неудобно ее доказывать, Павел, вовсе не потому, что она "обычная". А потому, что доказательств нету. Весь этот топик наглядно это показывает.

1. Есть классы. Их приводит один из наиболее авторитетных источников — codeproject. Есть рейтинг, он характеризует полезность этого кода для других. 2. Есть твои рассуждения в абстрактном плане. Я предпочитаю аргументы первого рода. Они для меня доказательство. Если тебе нужны иные доказательства — ищи ккие хочешь где хочешь. Мне и этого достаточно. Практика — критерий истины, не ты ли недавно это говорил ?


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


S>Очередной пассаж с называнием черного белым.

S>Поясняю мысль: Нет, Павел, всё как раз наоборот. Мы никак не относимся к правилам как к скрижалям. Мы просто понимаем, зачем придумываются правила, и по каким критериям нужно сравнивать решения.

Тогда ответь на вопрос — можно ли их нарушать и когда это может быть оправданно ?

S>А ты берешь заученные на плохих примерах решения, и не напрягая мысль ни на минуту, твердишь нам "это хорошо, потому что это очевидно хорошо, а кому не очевидно, тот не знает принципов ООП".


Неумно. Я привел реальный код, котрый люди используют. И если он существует и его используют — это хорошо.

S>Вот привел ты два примера. Оба не работают. Не потому, что нарушают какие-то догматические принципы, а потому, что делают код хуже. По объективным критериям: объем и стоимость поддержки.


Нет, я привел 4 примера классов с codeproject и все они, по-видимому и по отзывам других работают. Насчет того, что хуже — а возьми как да сделай лучше тот же CStringEx и попробуй выстави на codeproject. Посмотрим, что выйдет.

S>Павел, я даже допускаю, что в реальной жизни ты не пишешь такую херню, как в примерах с MyDirectory и MyString.IsPalindrome. Наверное, тебе просто трудно придумать удачный пример, где запечатанность реально мешает.


В реальной жизни я вообще предпочитаю виртуальности не использовать — мне даже то ничтожное замедление, что от нее возникает, слишком дорого может обойтись. А вот написать наследника от любого класса без полиморфизма — за милую душу. просто для лучшей организации кода. И доведись мне написать Directory (ну, скажем, на С++) как класс статических методов — спокойно сделал бы наследника с дополнительными методами, если бы не смог почему-то поместить их в исходный класс. Ну а насчет string — у меня нет психологии работы с immutable объектами, поэтому мне с ними лишь мириться приходится.
Придумать иной пример могу, но надо искать, к чему придраться

S>Если же ты реально веришь, что CStringEx хоть в чём-то лучше, чем PalindromManager.IsPalindrome(this string str), то мне тебя жалко.


Дело твое. Я могу лишь одно сказать — CStringEx существует и люди его используют. А StringHelper класса, в котором были бы реализованы те дополнения, которые есть в CStringEx, я не знаю. А практика — критерий истины.

Кстати, на тебе еще один класс — CImageEx.

S>Вот самое что мне нравится в этой дискуссии (как и многих других с тобой), что ты замечательным образом доказываешь правоту своих оппонентов. Ну вот смотри — делается абстрактное заявление "sealed есмь зло, потому что иногда оно может мне помешать". Но когда в течение недели ты не в состоянии привести ни одного примера, где оно реально мешает, посторонний читатель делает совершенно верный вывод: "Раз даже мегаопытный Павел Дворкин не может придумать конкретного примера, значит это действительно практически никогда не нужно. Тогда зачем требовать возможность, которая помогает 1% программистов в 1% их задач, но при этом мешает 90% программистов в 10% их задач?".


Ну насчет примера — я их привел аж 4, из MFC, правда, только ты их видеть не хочешь. А насчет того, что мешает — а в чем, собственно, мешает ? Ну сделал многоопытный и т.д. класс MyDirectory , ну выставил его на всеобщее обозрение — и чем же это кому-то мешает ? Кто их заставляет его использовать ? А если я его не в библиотеку для всеобщего обозрения выставил, а только в своем проекте использую — это уж и вообще никак никому мешать не может, так как о нем никто и знать не будет. У себя в проекте ты уж мне позволь такого наследника сделать , а ? Честное слово — это никому не помешает


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


Без комментариев. Что я писал ,я не обсуждаю. Что касается гарантий — они предельно жесткие, дальше некуда. А вот повторное использование меня, действительно, мало волнует.

S>А вот если ты выпускаешь библиотеку, целевая аудитория которой — миллион программистов, то приходится думать и о том, как будет выпускаться версия 2.0.


Интересно-то как ? Значит, MyDirectory или аналогичное ему (пусть и по иным канонам написанное) с нетерпением ждет миллион программистов. Гм. Надо подумать

S>Это ты за себя можешь сказать "оставьте их мне; сам накосячу — сам виноват и буду". А для вендора библиотеки шанс сломать что-то у 2% use base — смерти подобен.

S>Потому, что от одного миллиона — это 20000 реквестов "подонки, вы сломали моё приложение". Один ответ от саппорта "сами виноваты" стоит примерно
$10. Вот и посчитай, во что выльется одно отдельно взятое счастье Павла Дворкина автору популярной библиотеки.

Ладно. Убедил. Не буду я MyDirectory для миллиона программистов выпускать. Дай мне только возможность в своем одноразовом бесгарантийном софте его сделать, и все. Клянусь, я его никому не покажу. Дашь такую возможность ?

Кстати. Не мог бы ты привести пример библиотеки , которой пользуется миллион программистов. Я не .Net имею в виду, а что-нибудь еще. Мне просто интересно знать, какие такие библиотеки существуют .

""


S>Поэтому в языке важны средства, позволяющие уменьшить процент недовольных апгрейдом до приемлемого. А в практике вендора библиотеки важно пользоваться этими средствами. О чем я и написал.
With best regards
Pavel Dvorkin
Re[22]: Override для произвольного метода.
От: LaPerouse  
Дата: 12.12.08 12:11
Оценка:
Здравствуйте, samius, Вы писали:

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


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


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


LP>>>>Если бы String создавался только через фабрику и мы бы имели бы возможность сделать String.setCurrentFactoty(myStringFactory), то такое очень даже имело бы смысл.


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


LP>>А сторонние библиотеки и не дожны это делать — это дела целевого клиента выбирать реализации, с которым он будет работать.

S>Если бы была глобальная фабрика строк и возможность ее подменять, то уверен, что каждая пятая библиотека ее бы подменяла. Кому-то нужны бы были мутабельные строки, кто-то бы переписал Intern механизмы, а кто-то прикрутил бы ASCII строки. Любителей написать собственную строку слишком много! Дальше это счастье обрастает хучей конвертеров из одного в другое, которые тоже растут из какой-нибудь глобальной фабрики и т.п. Нет уж, меня запечатанный класс String более чем устраивает.

Меня тоже. Это лишь ведь пример.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[21]: Override для произвольного метода.
От: LaPerouse  
Дата: 12.12.08 13:43
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


PD>В реальной жизни я вообще предпочитаю виртуальности не использовать — мне даже то ничтожное замедление, что от нее возникает, слишком дорого может обойтись. А вот написать наследника от любого класса без полиморфизма — за милую душу. просто для лучшей организации кода. И доведись мне написать Directory (ну, скажем, на С++) как класс статических методов — спокойно сделал бы наследника с дополнительными методами, если бы не смог почему-то поместить их в исходный класс. Ну а насчет string — у меня нет психологии работы с immutable объектами, поэтому мне с ними лишь мириться приходится.

PD>Придумать иной пример могу, но надо искать, к чему придраться

А зачем наследование от библиотечного класса без полиморфизма? Назови, пожалуйста, хоть одно преимущества. Недостатки очевидны:
1. Пользуясь protected-методами в наследнике вместо контракта, ты можешь нарушить внутреннюю целостность объекта
2. Что хуже всего, появляется зависимость от непубличных методов, что может выйти боком в будущем при изменении их реализации разработчиком библиотеки.

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


S>>Если же ты реально веришь, что CStringEx хоть в чём-то лучше, чем PalindromManager.IsPalindrome(this string str), то мне тебя жалко.


PD>Дело твое. Я могу лишь одно сказать — CStringEx существует и люди его используют. А StringHelper класса, в котором были бы реализованы те дополнения, которые есть в CStringEx, я не знаю. А практика — критерий истины.


Люди, привыкшие к такой ублюдочной библиотеке, как MFC, могут выдержать многое. В этом случае никакой это не критерий.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[21]: offtop
От: 4058  
Дата: 13.12.08 18:19
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>1. Есть классы. Их приводит один из наиболее авторитетных источников — codeproject. Есть рейтинг, он характеризует полезность этого кода для других.


Индусам все полезно, они себе в код, что угодно накопипастают (зачастую забывая голову включить).

PD>Неумно. Я привел реальный код, котрый люди используют. И если он существует и его используют — это хорошо.


Здесь очень важно уточнить сферу применения.
В однодневой софтинке? В университетских липовых курсовых/докторских и т.п.?

PD>Нет, я привел 4 примера классов с codeproject и все они, по-видимому и по отзывам других работают.


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

PD>Насчет того, что хуже — а возьми как да сделай лучше тот же CStringEx и попробуй выстави на codeproject. Посмотрим, что выйдет.


Ну не модно сейчас строки "изобретать", лет 10-15 назад нормально, но никак не сейчас.
Так надежней, так скромней ...

PD>В реальной жизни я вообще предпочитаю виртуальности не использовать — мне даже то ничтожное замедление, что от нее возникает, слишком дорого может обойтись.


И inline-ить не получится, а как-же без этого? Ну если полиморфный вызов дорог, может выбранный ООЯ не подходит для решения задачи?

PD>А StringHelper класса, в котором были бы реализованы те дополнения, которые есть в CStringEx, я не знаю. А практика — критерий истины.


Практика бывает плохая и хорошая, собственно как и теория, и MFC приводить в качестве примера хорошей практики очень сомнительно.
Re: Override для произвольного метода.
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 14.12.08 20:49
Оценка:
Chrome,

C>Мне кажется, в .Net runtime можно без особых проблем привнести возможность переписать код произвольного метода.

C>Любого метода любой managed DLL. Кроме того, любой невиртуальный метод класса можно сделать виртуальным.
C>Добавить поля в существующие sealed классы. И много чего еще.
C>Нужно это, что бы преодолеть ошибки проектирования существующих библиотек.
C>Из минусов вижу некоторые проблемы с безопасностью в trusted environment, но эти проблемы преодолимы.
C>Еще возможно, в следующей версии библиотеки автор откажется от поддержки метода, который мы переопределили. Но вероятность этого мала. И я бы пошел на такой риск ради потенциальных преимуществ.
C>Почему официальная практика повторного использования кода не движется в этом направлении?
C>Зачем проектировщики библиотек заранее гадают, какие возможности понадобится переопределить пользователям их продукта и через раз не угадывают?(Ведь, чем раньше принято решение — тем больше вероятность ошибки).

Такая возможность избыточна в стандартных случаях и явно недостаточна в нестандартных [случаях].

Наиболее перспективно — в рантайме взять AST класса/метода/чего-угодно, поменять его нужным для себя образом и записать либо поверх источника, либо скопировав под именем MyCopy, а затем собственно вызвать. Открывающиеся возможности практически безграничны:
— вставка трейсинга в сторонние (в том числе и стандартные) библиотеки
— исправление глюков, ошибок дизайна в сторонних (в том числе и стандартных) библиотеках
— дополнение сторонних (в том числе и стандартных) классов полезной функциональностью (например, работа с escaped string)
— изоляция метода от левых зависимостей в сторонних (в том числе и стандартных) классах, примерно по принципу Typemock
— горячий фикс без остановки серверов
— ну и много много ещё возможностей
На данный момент реализация подобных возможностей весьма трудоёмка, хотя и возможна через специальные Profiler API (для .net, JVMPI для джавы).
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[22]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 15.12.08 02:19
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Гы гы.


Исключительной силы аргумент!

http://www.rsdn.ru/forum/message/3214195.1.aspx
Автор: Pavel Dvorkin
Дата: 15.12.08
With best regards
Pavel Dvorkin
Re[22]: offtop
От: Pavel Dvorkin Россия  
Дата: 15.12.08 02:22
Оценка:
Здравствуйте, 4058, Вы писали:

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


MFC, конечно, устарела по концепциям, но по качеству кода (в рамках своих концепций) — она на порядок лучше. Во всяком случае, такого безобразия, как пересоздания listview с переливанием данных ради того, чтобы установить флаг сортировки, там не найдешь.
With best regards
Pavel Dvorkin
Re[22]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 15.12.08 02:54
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>А зачем наследование от библиотечного класса без полиморфизма? Назови, пожалуйста, хоть одно преимущества. Недостатки очевидны:

LP>1. Пользуясь protected-методами в наследнике вместо контракта, ты можешь нарушить внутреннюю целостность объекта

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


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


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

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


А теперь ответ на твой вопрос. Собственно, я уже его давал. Повторю

class A{};
class B{};

class A1 : A {};
class B1 : B {};

Внутри класса B1 используется класс A1. Он больше нигде не виден и не нужен. Он расширяет возможности A. Везде за пределами B1 (то есть в B , А также в других местах) экземпляры A1 выглядят как A. Виртуальности здесь нет вообще.

Аналогично, внутри B2 может использоваться A2 и т.д. Или A1. Или A. В зависимосчти от того, что надо.

Имеем стройную иерархию. Тот, кто это захочет использовать, может взять A и не обращать внимания на его расширения. Или A1, при этом он не обязан помнить про его происхождение от A. Или A2. И т.д. А не иметь дело с несколькими хелперами, возможно, противоречащими друг другу. Автор A1 ведь продкмал его происхождение от A, а автор A2 — от A1, в то время как авторы хелперов совсем не обязаны думать ни о согласовании, ни о недублировании. И кроме того, если уж я нашел (поиском хотя бы) класс A5, значит, я имею все публичное от A1,A2,A3,A4. А хелперы — где они, сколько их, какие они, как их искать... Никакой логики в них нет.

В общем, полиморфизм без наследования невозможен, а вот наследование без полиморфизма

LP>Люди, привыкшие к такой ублюдочной библиотеке, как MFC, могут выдержать многое. В этом случае никакой это не критерий.


Люди, считающие, что аргументы такого рода вообще являются аргументами, вряд ли заслуживают того, чтобы их аргументы всерьез обсуждались. Тавк что лучше сними это заявление.
With best regards
Pavel Dvorkin
Re[23]: Override для произвольного метода.
От: LaPerouse  
Дата: 15.12.08 08:48
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


LP>>А зачем наследование от библиотечного класса без полиморфизма? Назови, пожалуйста, хоть одно преимущества. Недостатки очевидны:

LP>>1. Пользуясь protected-методами в наследнике вместо контракта, ты можешь нарушить внутреннюю целостность объекта

PD>Встречный вопрос — а зачем тогда protected методы вообще ? Ты же против наследования без полиморфизма, то есть наследование с полиморфизмом ты не отрицаешь ? Но ведь и там нарушить внутреннюю целостность объекта тоже возможно, да даже и легче. Но с этим ты согласен.


1. Ты считаешь protected-методы имеют смысл только при "наследовании без полиморфизма"? Вообще, наследование без полиморфизма и с полиморфизмом никак не отличается друг от друга. Просто в одном случае есть намерение использовать контракт наследника при доступе к объекту производного класса, во втором наследование делается лишь с целью повторного использования. В этом и заключается единственное различие между ними.

>>Но ведь и там нарушить внутреннюю целостность объекта тоже возможно


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

>>даже и легче


Почему это легче? Я разницы не вижу, почему — см. выше.

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


PD>protected методы, конечно, непубличны, но они на то и protected, чтобы их можно было вызывать из наследников. И если в следующей версии они вдруг исчезнут или изменится их сигнатуры — это и будет означать кривизну реализации. Вот представь себе, что завтра OnPaint вдруг поменяет сигнатуру


Такое бывает, однако, постоянно и кривость реализации тут не при чем. Наследник должен минимально зависеть от реализации базового класса, в идеале — совсем не зависеть. Поэтому многие (и Sinlair с IB в частности) советуют совершенно отказываться от наследования реализации, однако я считаю, что это уже другая крайность. Есть такой паттерн, который как правило работает всегда — "золотая середина". Здесь также. Наследовние без полиморфизма нерационально, полиморфизм без реализации — очень хорошо, но не всегда оптимально, ибо писанины больше, в некоторых случаях — значительно больше.


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


PD>А теперь ответ на твой вопрос. Собственно, я уже его давал. Повторю


PD>class A{};

PD>class B{};

PD>class A1 : A {};

PD>class B1 : B {};

PD>Внутри класса B1 используется класс A1. Он больше нигде не виден и не нужен. Он расширяет возможности A. Везде за пределами B1 (то есть в B , А также в других местах) экземпляры A1 выглядят как A. Виртуальности здесь нет вообще.


PD>Аналогично, внутри B2 может использоваться A2 и т.д. Или A1. Или A. В зависимосчти от того, что надо.


То есть ты говоришь о чем-то таком:

class A
{
    public String toString()
    {
        return "A";
    }
}

class B
{
    A a;
    
    public A getA()
    {
        return a;
    }
    
    public B(A a)
    {
        this.a=a;
    }
    
    public String toString()
    {
        return "B:" + getA().toString();
    }
}

class A1 : extends A
{
    public String toString()
    {
        return "A1";
    }
}

class B1 : extends B
{
    public B1(A1 a)
    {
        super(a)
    }
    
    String toString()
    {
        return "B1:" + getA().toString();
    }
}


Или я неправильно тебя понял?

PD>Имеем стройную иерархию. Тот, кто это захочет использовать, может взять A и не обращать внимания на его расширения. Или A1, при этом он не обязан помнить про его происхождение от A. Или A2. И т.д. А не иметь дело с несколькими хелперами, возможно, противоречащими друг другу. Автор A1 ведь продкмал его происхождение от A, а автор A2 — от A1, в то время как авторы хелперов совсем не обязаны думать ни о согласовании, ни о недублировании. И кроме того, если уж я нашел (поиском хотя бы) класс A5, значит, я имею все публичное от A1,A2,A3,A4. А хелперы — где они, сколько их, какие они, как их искать... Никакой логики в них нет.


PD>В общем, полиморфизм без наследования невозможен, а вот наследование без полиморфизма


Иерархия возможно и стройная, только никакого отношения к "наследованию без полиморфизма" не имеющая. В этом примере благодаря полиморфизму можно сделать например так:

A a = new A1();
B b = new B1();
b.toString();


Если же речь идет о т. н. "полиморфизме без наследования", то бишь о простом повторном использовании, то в данном случае идет речь о повторном использовании тех методов для работы с объектом класса A1 по интерфейсу A, которые есть в B. То есть именно для их использования ты порождаешь класс B1, наследующийся от B. В примере выше у тебя налицо повторное использование метода getA(). При этом ты получаешь доступ и к protected-методам класса B. Если тебе не нужно полиморфное поведение объекта класса B1, то вместо преусловутого "наследования без полиморфизма" лучше сделать так:

class B1
{
    B b;
    
    public toString()
    {
        return "B1:" + b.getA().toString();
    }
}


Зато в этом случае ты имеешь дело с инстансом B через его открытый интерфейс. Попробуй возрази против этого примера, чем твой случай, изображенный самым первым, лучше вот этого последнего?

LP>>Люди, привыкшие к такой ублюдочной библиотеке, как MFC, могут выдержать многое. В этом случае никакой это не критерий.


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


Да не заявление это и не аргумент вовсе, а, скажем так, комментарий человека, который использовал эту библиотеку. Если хочешь — не обращай на это внимания.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[23]: offtop
От: LaPerouse  
Дата: 15.12.08 10:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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


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


MFC — просто куча слобоструктурированного кода, по сути, это тончайшая обертка на ситсемным апи, приправленная макросами, проектирования там ноль — просто нет. Говорить о каких-то там концепциях MFC просто смешно. Нет там никаких концепций, нет там никаких идей.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[23]: offtop
От: 4058  
Дата: 15.12.08 10:19
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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


PD>MFC, конечно, устарела по концепциям, но по качеству кода (в рамках своих концепций) — она на порядок лучше.


Она не устарела по концепциям, т.к. оных посто нет, это тонкая обертка над WINAPI.
Модно было в то время переходить на C++, без малейшего представления о ООП.
В результате чего сформировался негласный диалет "C с классами".

Было:

struct HDC;
struct HWND;
HDC GetDC(HWND)


Стало:

class CWND
{
    CDC* GetDC()
}


Лично, для меня это одно и тоже.

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


Я правильно понимаю, что речь идет о System.Windows.Forms.ListView?
Re[23]: offtop
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 15.12.08 10:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>MFC, конечно, устарела по концепциям, но по качеству кода (в рамках своих концепций) — она на порядок лучше.


Лучше чего?
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[22]: Override для произвольного метода.
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 16.12.08 09:20
Оценка:
Sinclair,

S>Прекрасный пример. Вот как раз наследование для него — худший вариант. Просто потому, что "в остальных случаях" EscapedString — вовсе не "нормальная строка". В частности, операции взятия подстроки и замены символов приведут к тому, что результат перестанет быть EscapedString.

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

Еще пожалуй ToUpper/ToLower для некоторых типов эскейпинга. Но конечно таких "совсем одинаковых" операций для обычной и необычной строки немного. С фразой "в остальных случаях ведёт как обычная строка" я конечно поторопился. Нужно добавить ещё "если перекрыть методы взятия подстроки и замены символов". Теперь уже EscapedString не столь ущербный класс, как казалось ранее См. ниже.

S>Поэтому самый грамотный вариант — ввести новый тип EscapedString, который никак со строкой не связан.

S>Точнее, у него должны быть определены два преобразования в строку. Примерно так:
public class EscapedString { ... }

S>Естественно, неявные преобразования в строку и обратно делаются через ескейпинг. Для доступа к заексейпленным потрошкам нужно выполнить явный метод GetRawString(). Это гарантирует нам отсутствие побочных эффектов, в том числе, к примеру, невозможность случайно сконкатенировать EscapedString с UnescapedString, получив неприменимого монстра.

С одной стороны, выделяя EscapedString в отдельный класс ты ставишь крест на возможности использовать EscapedString полиморфно в классах, которые используют String, скажем библиотеку регэкспов.

С другой стороны, случай со String особый, потому что
1. Строки иммутабельны, следовательно все операции которые оформлены методами ведут себя как внешние функции.
1a. Следовательно, интерфейс IString пустой, и методов, которые хочется вызвать полиморфно нет.
1б. Следовательно, "методам" String можно безопасно иметь (и они имеют) наглухо прибитую зависимость от конструкторов String(...).
2. Функция escape :: String -> EscapedString биективна, то есть можно как передать EscapedString во внешний код, так и получить его обратно конвертацией.

Суммируя эти факты вынужден прийти к выводу , что да, EscapedString лучше оформить в самостоятельный класс. Замечу только, что если найдётся sealed класс, который не удовлетворяет пунктам 1 или 2, то значит sealed там стоит неудачно.

LCR>>Это больше относится к тому, что неплохо бы иметь больше рукояток
Автор: Lazy Cjow Rhrr
Дата: 14.12.08
для воздействия на стандартные классы.

S>То, что ты предлагаешь — это фактически накат патчей на CLR. Которые, в том числе, будут страдать от всё тех же зависимостей от деталей реализации.
Да, конечно будут. Что они будут использовать, от этого и будут страдать. Но можно регулировать зависимость: использовать чисто интерфейс, или чуть-чуть реализации, или очень много реализации.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[23]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.12.08 10:39
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Еще пожалуй ToUpper/ToLower для некоторых типов эскейпинга.

Ключевой момент выделен.
LCR>Но конечно таких "совсем одинаковых" операций для обычной и необычной строки немного. С фразой "в остальных случаях ведёт как обычная строка" я конечно поторопился. Нужно добавить ещё "если перекрыть методы взятия подстроки и замены символов". Теперь уже EscapedString не столь ущербный класс, как казалось ранее См. ниже.

LCR>С одной стороны, выделяя EscapedString в отдельный класс ты ставишь крест на возможности использовать EscapedString полиморфно в классах, которые используют String, скажем библиотеку регэкспов.

С чего бы это вдруг? Ну-ка, покажи мне пример кода, на котором стоит крест.

LCR>Суммируя эти факты вынужден прийти к выводу , что да, EscapedString лучше оформить в самостоятельный класс. Замечу только, что если найдётся sealed класс, который не удовлетворяет пунктам 1 или 2, то значит sealed там стоит неудачно.

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

LCR>Да, конечно будут. Что они будут использовать, от этого и будут страдать. Но можно регулировать зависимость: использовать чисто интерфейс, или чуть-чуть реализации, или очень много реализации.

Да-да. Как раз на прошлой неделе референдум одобрил выдачу героина швейцарским наркоманам за государственный счет. Вот она, регулировка зависимости в полный рост.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 16.12.08 10:53
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>На Codeproject таки, действительно, полно поделок. Их там как раз большая часть и есть.


Там все есть. И поделки, и серьезные вещи. Впрочем — давай сюда другой, более серьезный ресурс общего назначения, скажу спасибо. А пока что основное, что я вижу — это codeproject, codeguru. Для Delphi был еще какой-то сайт с собачьим именем, забыл название.
With best regards
Pavel Dvorkin
Re[23]: Override для произвольного метода.
От: LaPerouse  
Дата: 16.12.08 11:31
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Sinclair,


S>>Прекрасный пример. Вот как раз наследование для него — худший вариант. Просто потому, что "в остальных случаях" EscapedString — вовсе не "нормальная строка". В частности, операции взятия подстроки и замены символов приведут к тому, что результат перестанет быть EscapedString.

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

LCR>Еще пожалуй ToUpper/ToLower для некоторых типов эскейпинга. Но конечно таких "совсем одинаковых" операций для обычной и необычной строки немного. С фразой "в остальных случаях ведёт как обычная строка" я конечно поторопился. Нужно добавить ещё "если перекрыть методы взятия подстроки и замены символов". Теперь уже EscapedString не столь ущербный класс, как казалось ранее См. ниже.


S>>Поэтому самый грамотный вариант — ввести новый тип EscapedString, который никак со строкой не связан.

S>>Точнее, у него должны быть определены два преобразования в строку. Примерно так:
LCR>
LCR>public class EscapedString { ... }
LCR>

S>>Естественно, неявные преобразования в строку и обратно делаются через ескейпинг. Для доступа к заексейпленным потрошкам нужно выполнить явный метод GetRawString(). Это гарантирует нам отсутствие побочных эффектов, в том числе, к примеру, невозможность случайно сконкатенировать EscapedString с UnescapedString, получив неприменимого монстра.

LCR>С одной стороны, выделяя EscapedString в отдельный класс ты ставишь крест на возможности использовать EscapedString полиморфно в классах, которые используют String, скажем библиотеку регэкспов.


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

String escapeString(String str);

Минусы — из получившейся ескейпнутой строки нельзя получить rawString без обратного преобразования

String unescapeString(String str);

Зато все просто и не нужно на каждый вдох плодить по классу.

LCR>С другой стороны, случай со String особый, потому что

LCR>1. Строки иммутабельны, следовательно все операции которые оформлены методами ведут себя как внешние функции.

Не понятно, причем здесь иммутабельность. Совершенно не обязательно быть методу иммутабельным, чтобы быть оформленным как внешняя функция с первым параметром-объектом.

LCR>1a. Следовательно, интерфейс IString пустой, и методов, которые хочется вызвать полиморфно нет.

LCR>1б. Следовательно, "методам" String можно безопасно иметь (и они имеют) наглухо прибитую зависимость от конструкторов String(...).

Соответственно из некорректной посылки — некорректный вывод.

LCR>2. Функция escape :: String -> EscapedString биективна, то есть можно как передать EscapedString во внешний код, так и получить его обратно конвертацией.


Конвертация туда-сюда не есть хорошо. Во-первых, это потеря производительности, если конечно, не поддерживается мемоизация значений, а в .net она не поддерживается. Раз уж заводить для EscepadString отдельный класс с состоянием, лучше хранить в нем rawString и выдавать escapedString по требованию, кешируя результаты, благо строка иммутабельна. Ситуация казалось бы ортогональная, и тут и там надо кешировать, но у конвертации туда-сюда есть еще один минус — эту "биективность" (ну и термин) нужно будет в будущем поддерживать.

LCR>Суммируя эти факты вынужден прийти к выводу , что да, EscapedString лучше оформить в самостоятельный класс. Замечу только, что если найдётся sealed класс, который не удовлетворяет пунктам 1 или 2, то значит sealed там стоит неудачно.


Все-таки либо-либо... Либо полиморфизм, либо наследование...
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[24]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 16.12.08 11:48
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

PD>>Предлагаю тебе сделать следующее. Выложи свои рассуждения насчет поделок на codeproject в форум MFC. Посмотрим на реакцию.
S>Павел, демократическое голосование не может служить методом решения технических вопросов.

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

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


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

S>И не стоит сводить решение вопроса о том, хорошо ли сделан класс CStringEx, к вопросу о дискредитации codeproject. На нём есть вполне вменяемые поделки, как впрочем и килотонны мусора.


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

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


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

S>Членство на codeproject не даёт никаких гарантий профессионализма:


А какое членство его дает ? ИМХО никакое, даже в Академии наук.

S>

The author of CStringEX should run Purify(memory checker) on CStringEx. It particularly complains about writing out of bounds in the Delete() function.

S>(http://www.codeguru.com/forum/archive/index.php/t-42810.html)

S>Вот, к примеру, типичная проблема, которую огребает наивный пользователь унылых CxxxEx:


Во-во. Как CxxxEx — так неизбежно все они унылые. И при этом ты себя предлагаешь в арбитры. При том. что с помощью этих Cxxx сделана весьма приличная часть софта, который работает на миллионах компьютеров, в отличие от софта, написанного с помощью неунылых классов .Net, который чаще всего на одном компьютере и работает, ну на нескольких. Ничего вас не учит.

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


S>http://static.dreamincode.net/forums/showtopic5723.htm

S>Увы, за шесть лет никто не смог дать ему внятный ответ.

Я тоже не дам, да и смотреть некогда.

S>Вот что бывает с теми, кто неосторожно наследуется от чужого кода:

S>http://www.experts-exchange.com/Programming/Languages/CPP/Q_22500053.html

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


S>Зато нашел другой CStringEx. Опять же, бедному пользователю придется как-то выбирать одну из этих строк, либо руками мерджить реализации. Если бы это были хелперные функции, никакой проблемы бы не возникло. Увы, понять это люди, укушенные MFC, могут только с большим напряжением всех усилий.


Слушай, ты это серьезно ? Если да — хоть расскажи, где эти хелперные функции искать-то ? Как классы эти хелперные называются хоть ? Вот и будут все плодить эти хелперные классы, друг с другом никак не связанные (невозможно! они же sealed). Кстати, а как их (хелперные клаасы то есть) мерджить-то ? Или пусть живут как есть ? Sinclair.IsPalindrom, Dvorkin.IsRussianWord, IB.IsNonCensored ? .
With best regards
Pavel Dvorkin
Re[25]: Override для произвольного метода.
От: LaPerouse  
Дата: 16.12.08 11:55
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Слушай, ты это серьезно ? Если да — хоть расскажи, где эти хелперные функции искать-то ? Как классы эти хелперные называются хоть ? Вот и будут все плодить эти хелперные классы, друг с другом никак не связанные (невозможно! они же sealed). Кстати, а как их (хелперные клаасы то есть) мерджить-то ? Или пусть живут как есть ? Sinclair.IsPalindrom, Dvorkin.IsRussianWord, IB.IsNonCensored ? .


Очевидно там же, где и CxxxEx. Даже назвать их можешь также
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[26]: Override для произвольного метода.
От: LaPerouse  
Дата: 16.12.08 13:05
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


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

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

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

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

Можно добавить, что выигрыш идет от того, что по сравнению с отнаследованных классом (или даже делегирующем, не суть важно) сервисные методы (обычно) делают склейку не по состоянию. В результате приобретается невозможная дотоле гибкость. Это универсальный клей, который надо научиться использовать. Не сразу это приходит, нужен некоторый опыт. До меня например где-то год доходило.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[24]: Override для произвольного метода.
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 16.12.08 16:22
Оценка:
LaPerouse,

LP>Не понятно, причем здесь иммутабельность. Совершенно не обязательно быть методу иммутабельным, чтобы быть оформленным как внешняя функция с первым параметром-объектом.


Здесь импликация в другую сторону: если тип иммутабельный, то методы ведут себя как внешние функции. Но до меня немного позже дошло, что методы могут быть полиморфными для иммутабельных объектов, см. например stateless фабрики. Мне нужно ещё немного подумать над этим моментом.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[25]: Override для произвольного метода.
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 16.12.08 16:28
Оценка:
Sinclair,

LP>>Да, это может быть плохо. Собственно, это единственная причина наследоваться, больше нет.

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

Кстати, StringBuilder тоже sealed, но поскольку он мутабельный, то уже имеет смысл полиморфно работать с его состоянием! Скажем в EscapedStringBuilder (который :StringBuilder) перекрытие метода Append мне видится разумным решением для ситуации "хитрая строка — хитрый билдер".
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[26]: Override для произвольного метода.
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.12.08 19:53
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Кстати, StringBuilder тоже sealed


Он sealed скорее всего потому что его использование захардкожено в маршаллере, и он может полагаться на конкретный внутренний лейаут памяти с его состоянием. Оптимизация, короче.
... << RSDN@Home 1.2.0 alpha 4 rev. 1120 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[25]: Override для произвольного метода.
От: LaPerouse  
Дата: 17.12.08 08:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


LP>>Да, это может быть плохо. Собственно, это единственная причина наследоваться, больше нет.

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

S>Есть так называемые "хаскелевские" строки, которые оформлены в виде связного списка фрагментов-подстрок.

S>Естественно, они тоже иммутабельные.
S>Но, в отличие от дотнетовых строк, операции конкатенации для них выполняются за O(1).
S>Дупа дотнета — в том, что интерфейс строки — слишком жирный.
S>Если бы бабушка была бы дедушкой, то регексы бы требовали не string, а, скажем, IEnumerable<char>. Или ICollection<char>.
S>А стринг бы их нативно реализовывал на интернальном array[char].
S>Тогда можно было бы сделать свою реализацию этих примитивов, построенную на списке или дереве блоков.

Да, это было бы правильно. Только это уже было бы обычной реализацией интерфейса и к наследованию реализации отношения не имело бы. Насколько я понимаю, у нас тут идет спор про sealed классы => стоит ли идти на наследование реализации ради полиморфизма. Интерфейсы — понятное дело, там все классно.

Кстати, по поводу строк, как их лучше реализовать, имхо, есть другой более лучший вариант. Что такое строка, как не обычный список символов? (То есть как образец можно посмотреть на тот же haskell и немного на std::string.) Если же хочется получить строку, как у тебя написано, "на списке или дереве блоков", то реализуешь именно эти самые деревья и блоки через интерфейс списка (который используется строкой) и подсовываешь эту реализацию тому же string. Получается еще один уровень абстракции, который отделяет алогоритмическую часть (списки) от строково-ориентированный операция (строка).

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

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

Наверное, имеется ввиду производительность работы программиста? Это да. (Операторам преобразования не обязательно делать это преобразования каждый раз, более правильно хранить raw string, об этом я писал в пред. посте).
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[26]: Override для произвольного метода.
От: LaPerouse  
Дата: 17.12.08 08:14
Оценка:
Здравствуйте, LaPerouse, Вы писали:

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



LP>Кстати, по поводу строк, как их лучше реализовать, имхо, есть другой более лучший вариант. Что такое строка, как не обычный список символов? (То есть как образец можно посмотреть на тот же haskell и немного на std::string.) Если же хочется получить строку, как у тебя написано, "на списке или дереве блоков", то реализуешь именно эти самые деревья и блоки через интерфейс списка (который используется строкой) и подсовываешь эту реализацию тому же string. Получается еще один уровень абстракции, который отделяет алогоритмическую часть (списки) от строково-ориентированный операция (строка).


То есть вместо

public String implements IEnumerable<Char>
{

}


было бы

public String
{
    IEnumerable[Char] list;
    
    public String()
    {
        list = new DefaultList<Char>();
    }
    
    public String(IEnumerable[Char] list)
    {
        this.list = list;
    }
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[27]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.12.08 08:37
Оценка:
Здравствуйте, LaPerouse, Вы писали:
LP>>Кстати, по поводу строк, как их лучше реализовать, имхо, есть другой более лучший вариант. Что такое строка, как не обычный список символов?
Вот это — очень хороший вопрос.
Пример плохого ответа можно подсмотреть в MFC.
В Java и .Net, по крайней мере, разделили интерфейсы изменяемых и неизменяемых строк.

LP>>(То есть как образец можно посмотреть на тот же haskell и немного на std::string.) Если же хочется получить строку, как у тебя написано, "на списке или дереве блоков", то реализуешь именно эти самые деревья и блоки через интерфейс списка (который используется строкой) и подсовываешь эту реализацию тому же string. Получается еще один уровень абстракции, который отделяет алогоритмическую часть (списки) от строково-ориентированный операция (строка).

Совершенно непонятно в таком случае, что такое эта "строка". Чем она отличается от "просто списка", на основе которого она построена?
Мы опять получаем какую-то невнятицу: разработчики RegEx по-прежнему принимают на вход строку и возвращают строку.

Я вот сходу не готов накидать удачный IString для иммутабельной строки. Ну то есть, конечно же, готов, но непонятно, будет ли он удачным.
И непонятно, как защититься от любителей зависеть не от IString, а сразу от SystemString: IString.
Кроме того, большинство "военных" операций со строкой делаются через нативные вызовы. Эти нативные вызовы, естественно, построены на том, что строка — это непрерывный буфер символов. Как в свете этого сделать банальный хелпер IsNormalized для произвольного IString?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: Override для произвольного метода.
От: LaPerouse  
Дата: 17.12.08 09:08
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Совершенно непонятно в таком случае, что такое эта "строка". Чем она отличается от "просто списка", на основе которого она построена?


Список — это reverse, concat, replace и т п
Строка — это IString (to_lower_case, to_upper_case, asBytes)

S>Мы опять получаем какую-то невнятицу: разработчики RegEx по-прежнему принимают на вход строку и возвращают строку.


Нет, они принимают на вход IEnumerable[Char]. Просто клиентский код делает Regex.foo(str.getCharacter())

S>И непонятно, как защититься от любителей зависеть не от IString, а сразу от SystemString: IString.


Эти тонкости дотнета мне неизвестны (с .net дел не имею, читать мсдн сейчас времени нет)

S>Кроме того, большинство "военных" операций со строкой делаются через нативные вызовы. Эти нативные вызовы, естественно, построены на том, что строка — это непрерывный буфер символов. Как в свете этого сделать банальный хелпер IsNormalized для произвольного IString?


Точно также — придется релизовать интерфейс IString:

class MyString implements IString
{
    public MyString()
    {
        // непрер. буффер
        super(new Buffer());
    }
    
    public boolean isNormalized()
    {
        return true;
    }
}


public static boolean isNormalized(IString str)
{
    return str.isNormalized();
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[29]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.12.08 09:31
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>Список — это reverse, concat, replace и т п

LP>Строка — это IString (to_lower_case, to_upper_case, asBytes)
Зачем. ToLower, ToUpper — это всего лишь хелперы для того же IEnumerable<char>:
public static IEnumerable<char> String.ToLower(this IEnumerable<char> source)
{
  foreach(char c in source)
      yield return Char.ToLower(c);
}

Всех делов-то.

LP>Нет, они принимают на вход IEnumerable[Char]. Просто клиентский код делает Regex.foo(str.getCharacter())

А зачем?
Я вот воображаю такой код:
IEnumerable<char> name = request["name"];
string strName = new string(name);
Match m = nameReqex.Match(strName.Characters);

И не понимаю, зачем нам тут Name.

LP>Эти тонкости дотнета мне неизвестны (с .net дел не имею, читать мсдн сейчас времени нет)

Это не тонкости дотнета, это философский вопрос: как заставить авторов RegEx не требовать "полный string", а обойтись уместными интерфейсами.
Хорошо там, где рулит динамика — там невозможно потребовать больше, чем реально используешь. Если кроме foreach(var character in string) ты ничего не делаешь, то по факту достаточно подать на вход "утку" с GetEnumerator<char>().
А в статике постоянно влетаешь в такие вот грабли.


LP>Точно также — придется релизовать интерфейс IString:

Я же говорю — перформанс будет чудовищный. IsNormalized внезапно потребует O(N) дополнительной памяти.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[30]: Override для произвольного метода.
От: LaPerouse  
Дата: 17.12.08 10:22
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


LP>>Список — это reverse, concat, replace и т п

LP>>Строка — это IString (to_lower_case, to_upper_case, asBytes)
S>Зачем. ToLower, ToUpper — это всего лишь хелперы для того же IEnumerable<char>:
S>
S>public static IEnumerable<char> String.ToLower(this IEnumerable<char> source)
S>{
S>  foreach(char c in source)
S>      yield return Char.ToLower(c);
S>}
S>

S>Всех делов-то.

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

LP>>Нет, они принимают на вход IEnumerable[Char]. Просто клиентский код делает Regex.foo(str.getCharacter())

S>А зачем?
S>Я вот воображаю такой код:
S>
S>IEnumerable<char> name = request["name"];
S>string strName = new string(name);
S>Match m = nameReqex.Match(strName.Characters);
S>

S>И не понимаю, зачем нам тут Name.

Нет, вот так

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


S>Хорошо там, где рулит динамика — там невозможно потребовать больше, чем реально используешь. Если кроме foreach(var character in string) ты ничего не делаешь, то по факту достаточно подать на вход "утку" с GetEnumerator<char>().

S>А в статике постоянно влетаешь в такие вот грабли.

Для меня — не криминально. Если напрягает, тогда IString можно заставить реализовать IEnumerable. В таком случае для пользователя будет все также, как и в твоем примере, просто это будет деталью реализации, улучшающий внутренний дизайн класса.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[31]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.12.08 10:57
Оценка:
Здравствуйте, LaPerouse, Вы писали:
LP>Ну а тут будут методы-члены. Это со строкой такой пример удачный попался, ибо они обычно иммутабельные, вообще говоря возможны методы, которые деструктивны.
LP> Вот их лучше делать как члены, а не хелперы.
Не вижу никакой связи между мутабельностью и мемберами-членами.
Если требуемый эффект достижим через public интерфейс, то его крайне вредно делать членом.
По той же причине: когда я займусь своей реализацией, мне придется наследоваться, либо дублировать функциональность.

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

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

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

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

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


Это позволило бы мне в тех местах, где я раньше пользовался простым response.Redirect, писать вот так:
response.Redirect(redirectTarget, RedirectType.SeeOther);


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

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

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

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

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

Пока улучшения дизайна не видно.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
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[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: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[28]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 19.12.08 09:29
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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

О да, "сказка о тройке" очень к месту.. Отлично прослеживается аллюзия на твое "общепринятый подход, значит так правильно". )
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[28]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 23.12.08 07:30
Оценка:
Здравствуйте, 4058, Вы писали:

4>1. Где детали? Ты уверен, что здесь используется наследование в чистом виде (без полиморфизма)?


Нет, конечно. Детали — в исходниках, они доступны в Platform SDK. Копаться не буду, вполне возможно, что там полиморфизм есть.

4>2. Еще раз. MFC тонкая прослойка над WINAPI, поэтому делегирование сообщений осуществляется в тупую через наследование (но никто сейчас не станет спорить, что это правильный и изящный способ).


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

PD>>и т.д. Там их много. Он же не знал, как правильно, он же начинающий , он же не умел отличить хорошее от плохого.


4>Вообщем недалеко от истины.

4>Правда у нас очень разные представления на счет "начинающих".

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

Тем более что речь все же идет не о специально созданном примере, а об исходниках пусть не самого мощного , но все же штатного текстового редактора, который по идее должен использоваться для реальной работы с .doc файлами теми, кто не купил Office (OO тогда не было

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


4>Ну и кому еще нужны такие примеры, кроме как начинающих?


Даже если пример содержит только printf("Hello, World"), его писать и выставлять надо сделанным как следует.

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


4>Исходники многих компонентов .NET доступны (в том числе VM), поэтому положительная динамика, с точки зрения качества кода имеется.


Ох, сомневаюсь я в этой динамике. С точки зрения возможностей и набора средств — безусловно, .Net дает 100 очков вперед MFC. Библиотека богатейшая. Но вот с точки зрения реализации... Я уже как-то приводил пример, когда в listview для того, чтобы провести сортировку, они создают новый контрол (новое окно) и переливают в него все данные. За такие вещи раньше били шомполами, да и сейчас, если мне студент такое покажет, я его без лишних слов отправлю переделывать. MFC в этом смысле сделана на порядок лучше — я в ее исходниках не раз копался, могу сказать — некоторые фрагменты написаны так, что хоть вытаскивай их оттуда и используй в качестве демонстрационного пособия по Win32 — лучше все равно не напишешь.

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


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


4>M$ надеялась, что сможет пересадить львиную долю formo-кодеров на .NET, не получилось...


Что же ты многоточие поставил ? Надо закончить фразу. Не получилось — а почему ? И библиотека хорошая, и язык C# (взятый сам по себе) — лучше C++, логичнее, а вот не получилось. Почему ? Должны же быть причины ?

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


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


4>Пытались, но до добра это дело не довело (см. про formo-кодеров).


А почему в случае Win16 -> Win32 все прошло успешно ?

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


4>Павел, с MFC основательно имел дело эдак 10-ть лет назад, с того времени много воды утекло — STL/ATL/WTL/Java/.NET + *nix. Поэтому я (да и многие другие кто пытается тебе тут объяснить, что 2*2=4) не упустили возможность не однократно пересмотреть свои убеждения.


Что же, я с уважением готов относиться практически к любому чужому убеждению. Но все же останусь при своем
With best regards
Pavel Dvorkin
Re[28]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 23.12.08 08:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

PD>>Ну полезны они или нет — об этом можно просто по ссылкам на них судить.
S>Это и есть "голосование".

Это есть некая подмена понятий, довольно-таки тонкая. Если голосованияе проводится явно (то есть задается вопрос — счтаете ли вы codeproject серьезным ресурсом) — это и есть глосование. Но такого голосования никто не проводил. То, что я привел — есть результат подсчета популярности ресурса (аналогично рейтингам Гэллапа и т.д.) по независимым данным. Те, кто на этот ресурс ссылались — вовсе не думали о том, что кто-то будет этот факт использовать в каких-то целях. А поэтому такая оценка (рейтинга) дает основание делать выводы о популярности ресурса.

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

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

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


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

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

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

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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


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

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

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

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

Как практику — критерий истины

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


Опять! Говоря о частоте использования примеров с codeproject, мы говорили уже отнюдь не от CStringEx, а о ресурсе codeproject как таковом. И подсчеты мои именно к нему относились, а не к CStringEx ( не помню, чтобы я по этому классу подсчет ссылок приводил).


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

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

Нет, это очень даже серьезно. Попробуй поискать на google "palindrome" и у тебя сразу настроение испортится.

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

S>Ты понимаешь смысл термина "ортогональны"? Без договоренностей хелперы всегда будут ортогональными.

Похоже, мы под словами "ортогональность" понимаем разное. Для меня ортогональный АПИ — это АПИ, в котором любое действие можно сделать одним и только одним способом. В этом смысле такие хелперы не будут ортогональными, так как без договоренностей неизбежно эти хелперы будут пересекаться (Dvorkin.IsPalindom и Sinclair.IsStringPalindrom, даже имена могут не совпасть. Только если одна команда будет делать эти хелперы — можно на что-то надеяться.

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

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

А вы собираетесь все расширения в разные хелпры засунуть, что никак не лучше, потому что вместо иерархии, в которой можно разобраться, и в которой вполне достаточно иметь хелп по последнему (лучшему) наследнику, вы получите фактически возврат к языку С, так как каждый из ваших хелперов, если они static, по существу представляет собой набор отдельных функций, объединенных именем класса. Уберите класс — и чистый C перед вами, без всякой организации. А и не убирая — имеем набор отдельных кусков разного происхождения и никак не связанных логикой. Пользователю — сиди и ищи, в каком из этих кусков нужное ему есть и если есть в нескольких кусках — где лучше сделано. Голова пухнет


S>А поскольку мы с Иваном думаем по-другому, каждый будет делать хелпер исходя из Single Responsibility Principle.

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

Эхе-хе. Мы же не договариваемся, мы же члены разных команд. Я же о твоих действиях ничего не знаю. Вот и сделаю я PalindromHelper и ConversionHelper и т.д. А ты, ничего об мне не зная, свои такие (да нет, не такие, а несколько иные) соорудишь. Иван о нас тоже не знает, он свои сделает. В каждом из них чего-то не хватать будет, а что-то не лучшим образом сделано будет. Было бы наследование — не стал бы я свой хелпер делать, зная о том, что твой сущетсвует, а попробовал бы его улучшить. А ты потом мой. А Иван твой. И в итоге имели бы BestPalindromHelper и BestConversionHelper. А так вместо этого иметь будем 3 набора хелперов от меня , тебя и Ивана, и каждый из нас будет доказывать преимущества своего хелпера. А Вася Пупкин, ошалев от нашей дискуссии и поняв, что ему придется брать 2 метода из моего, 3 — из твоего и один — из Ивана, плюнет на нас троих и начнет свой Pupkin.PalindromHelper сочинять

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


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


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

S>Он и так должен знать обо всех.

Зачем. См выше — он должен знать только о BestPalindromHelper. Ты когда пишешь код для Listbox и вызываешь его методы — часто вспоминаешь, что он еще и Control, и Component, и MarshalByRefObject ? Знать об этом ты должен, да, но хелпа по ListBox тебе вполне хватит, как правило.


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


Э нет, не все так просто. См выше о PalindromHelper и BestPalindromHelper. Впрочем, хелперы уберем, вернемся к классу. В итоге получится класс CSuperString, в котором сделано именно лучшим образом. И вскоре всем становится известно, что лучшего средства для работы со строками, чем этот CSuperString, и не существует. Ссылок на него море , все его любят и за него голосуют , все им довольны и используют.

А некто X уже придумал как его расширить и улучшить. Уже зреет CCoolString
With best regards
Pavel Dvorkin
Re[29]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 23.12.08 09:03
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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

S>>Ты понимаешь смысл термина "ортогональны"? Без договоренностей хелперы всегда будут ортогональными.

PD>Похоже, мы под словами "ортогональность" понимаем разное. Для меня ортогональный АПИ — это АПИ, в котором любое действие можно сделать одним и только одним способом. В этом смысле такие хелперы не будут ортогональными, так как без договоренностей неизбежно эти хелперы будут пересекаться (Dvorkin.IsPalindom и Sinclair.IsStringPalindrom, даже имена могут не совпасть. Только если одна команда будет делать эти хелперы — можно на что-то надеяться.

Обычно под ортогональностью АПИ понимается возможность сделать что-то независимо от других частей АПИ.
Наследуясь от String с целью добавления метода IsPalindrome, а потом попытка использовать его вместо обычных строк — есть нарушение ортогональности. Потому что TextBoxу должно быть пофигу есть в классе метод IsPalindrome или нет. А вам придется сабклассить TextBox (и другие классы), которые рабоать будут со строками.

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


PD>А вы собираетесь все расширения в разные хелпры засунуть, что никак не лучше, потому что вместо иерархии, в которой можно разобраться, и в которой вполне достаточно иметь хелп по последнему (лучшему) наследнику, вы получите фактически возврат к языку С, так как каждый из ваших хелперов, если они static, по существу представляет собой набор отдельных функций, объединенных именем класса. Уберите класс — и чистый C перед вами, без всякой организации. А и не убирая — имеем набор отдельных кусков разного происхождения и никак не связанных логикой. Пользователю — сиди и ищи, в каком из этих кусков нужное ему есть и если есть в нескольких кусках — где лучше сделано. Голова пухнет

Вот stl так сделан. Ниче, людям нравится.
Поэтому в C# придумали Extensionы.
В F# (наверное как и в OCaml) следуют соглашению, если тип зовется vector, то хелперы к нему сгруппированы в модуле Vector.

Вообще вопрос группирования код не сильно связан с ООП, не надо его сюда приплетать.
Re[29]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 23.12.08 10:45
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD> А поэтому такая оценка (рейтинга) дает основание делать выводы о популярности ресурса.

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

PD>Как практику — критерий истины

Данная практика подтверждает, что кривой код существует — это истина.

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

PD>Нет, это очень даже серьезно. Попробуй поискать на google "palindrome" и у тебя сразу настроение испортится.

...
If you reflect a bit and are honest with yourself, you'll admit that you have this alleged inconsistency with all the nontrivial classes you use, because no class has every function desired by every client. Every client adds at least a few convenience functions of their own, and these functions are always non-members. C++ programers are used to this, and they think nothing of it. Some calls use member syntax, and some use non-member syntax. People just look up which syntax is appropriate for the functions they want to call, then they call them. Life goes on. It goes on especially in the STL portion of the Standard C++ library, where some algorithms are member functions (e.g., size), some are non-member functions (e.g., unique), and some are both (e.g., find). Nobody blinks. Not even you.

(c)Scott Meyers

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

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

PD>вы получите фактически возврат к языку С, так как каждый из ваших хелперов, если они static, по существу представляет собой набор отдельных функций, объединенных именем класса.

Хоть горшком назови.. Ты воспринимаешь наследование, как средство организации кода, но оно для этого не предназначено и никогда не было. И использовать его в этом качестве довольно дурацкая затея, которая ведет к описанным выше проблемам и никакой выгоды, даже в организации кода, не дает.
Для того чтобы логически группировать код — есть неймспейсы, вот их и используй.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[30]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 24.12.08 06:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

PD>>Это есть некая подмена понятий, довольно-таки тонкая.
S>Павел, никакой подмены понятий нет. Как только ты начинаешь привлекать к рассмотрению популярность, ты выходишь за рамки технической дискуссии.

Очень спорно. Если речь идет о популярности ресурса, и ресурс дейсивительно популярен (а это факт) — это означает, что качество техническое там для многих продуктов неплохое.

S>Совершенно неважно, явно ли проводится голосование, или по посещаемости, или по подсчету ссылок на ресурс — в любом случае речь идет о популярности. Которая может определяться техническим совершенством, а может — массовым заблуждением.


А вот это не аргумент вообще. Отвергаю полностью. Если ты будешь говорить о массовых заблуждениях в области политики или психологии — можно и обсуждать. Но здесь речь идет о технической области. Никаких оснований утверждать , что все те, кто придерживаются некоего подхода, который тебе не нравится, массово заблуждаются, у тебя нет. С таким же успехом можно заявить, что массовые заблуждения у противоположной стороны. И ни то, ни другое не доказать и не отвергнуть. Потому что практика — критерий истины, а практика есть и за ту, и за другую сторону. Так что на этом пути можно только пустословием и голословными обвинениями заниматься.

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

S>А вот тут происходит тонкая подмена понятий. Вместо практики, как примеров реального применения с иллюстрацией реального преимущества, приводится популярность. Ты сначала разберись с тем, является ли популярность связанной с качеством, или нет.

А популярность, вообще-то, именно отражает практику, то есть примеры реального применения и т.д. Мы же не за ЛДПР голосуем тут. Если есть продукт и его используют, причем грамотные люди, это и значит, что он востребован, что он лучший на данный момент, то есть качественный. Ну с какой стати я буду в своих программах некачественные компонентиы использовать ?

Так что связана, да. Может, не на 100%. Не линейно зависит, но коррелирует.


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

S>Это называть — типичными для тебя попытками вывернуться наизнанку, лишь бы не признавать своих заблуждений.
S>Если твои аргументы не относились к классу CStringEx, то давай их просто выбросим как нерелевантные и всё. Поскольку ты избегаешь прямолинейных утверждений, мне приходится догадываться, что именно ты имел в виду. Вот ты привлек (1)популярность (2)всего ресурса к обоснованию правильности одного конкретного класса.

Ссылку в студию, please, где я писал про "правильность одного конкретного класса". Нет такого. Я его привел как пример некоего подхода, и не больше. А правильный он или нет (==качественный) — не знаю, я и не смотрел-то всерьез его.

>Как мне это трактовать? Как демагогию? В одном посте применено сразу три демагогических приема.


Трактуй как хочешь, но сначала ссылку дай.

PD>>Как практику — критерий истины

S>Ну так ведь практики-то нет!

"Что же у вас, чего ни хватишься, ничего нет ?" (C) М. Булгаков


S>Это понятно. Поясняю еще раз, специально для тех, кто не знает, что такое Single Responsibility Principle:

S>Два хелпера, написанные для разных целей, никогда не будут пересекаться по функциональности.
S>Не может быть такого, чтобы в PalindromManager был метод .GetBytesCount, а в Encoding — .IsPalindrome.
S>Я вижу, что с пониманием этого у тебя проблемы. Ты вот в качестве примеров привел классы с характерными именами — Dvorkin и Sinclair. Это показывает, что ты трактуешь класс как помойку с методами, классифицированную как угодно, кроме функциональности.

См. мой ответ IB. Я там на этот вопрос ответил. Мы о разных вещах говорим, похоже.

S>Я предлагаю делить хелперы не по имени автора или еще чему-нибудь, а по Responsibility.


Во-во. Именно о разных вещах.






PD>>Эхе-хе. Мы же не договариваемся, мы же члены разных команд. Я же о твоих действиях ничего не знаю. Вот и сделаю я PalindromHelper и ConversionHelper и т.д. А ты, ничего об мне не зная, свои такие (да нет, не такие, а несколько иные) соорудишь. Иван о нас тоже не знает, он свои сделает. В каждом из них чего-то не хватать будет, а что-то не лучшим образом сделано будет. Было бы наследование — не стал бы я свой хелпер делать, зная о том, что твой сущетсвует, а попробовал бы его улучшить. А ты потом мой. А Иван твой.

S>Противоречия выделены. Попробуй подумать на ту же тему еще раз.

Да, неточно выразился. Исправляю.

PD>>Эхе-хе. Мы же не договариваемся, мы же члены разных команд. Я же о твоих действиях ничего не знаю. Вот и сделаю я PalindromHelper и ConversionHelper и т.д. А ты, ничего об мне не зная, свои такие (да нет, не такие, а несколько иные) соорудишь. Иван о нас тоже не знает, он свои сделает. В каждом из них чего-то не хватать будет, а что-то не лучшим образом сделано будет. И вот три хелпера сделаны, и каждый свой недостаток имеет. Теперь я узнал про твой. Он вроде лучше, чем мой, но в нем кое-чего, по моему мнению не хватает (или не так сделано). В общем, я за твой, но хочу в него кое-что из своего добавить. Далее по тексту.



PD>>Э нет, не все так просто. См выше о PalindromHelper и BestPalindromHelper. Впрочем, хелперы уберем, вернемся к классу. В итоге получится класс CSuperString, в котором сделано именно лучшим образом. И вскоре всем становится известно, что лучшего средства для работы со строками, чем этот CSuperString, и не существует. Ссылок на него море , все его любят и за него голосуют , все им довольны и используют.

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

Ну я вроде объяснил.
With best regards
Pavel Dvorkin
Re[31]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.12.08 06:50
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Очень спорно. Если речь идет о популярности ресурса, и ресурс дейсивительно популярен (а это факт) — это означает, что качество техническое там для многих продуктов неплохое.
Нет. Это не так. И даже если бы это было в целом так, это бы не означало, что любой взятый оттуда пример является образцом технического качества.
Это непонятно?

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

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

PD>А популярность, вообще-то, именно отражает практику, то есть примеры реального применения и т.д. Мы же не за ЛДПР голосуем тут. Если есть продукт и его используют, причем грамотные люди, это и значит, что он востребован, что он лучший на данный момент, то есть качественный. Ну с какой стати я буду в своих программах некачественные компонентиы использовать ?

Покажи мне грамотных людей, которые используют CStringEx.

PD>Ссылку в студию, please, где я писал про "правильность одного конкретного класса". Нет такого. Я его привел как пример некоего подхода, и не больше. А правильный он или нет (==качественный) — не знаю, я и не смотрел-то всерьез его.

Тогда зачем приводить некачественный пример в качестве оправдания практики наследования от класса строки?

PD>"Что же у вас, чего ни хватишься, ничего нет ?" (C) М. Булгаков

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


PD>>>Эхе-хе. Мы же не договариваемся, мы же члены разных команд. Я же о твоих действиях ничего не знаю. Вот и сделаю я PalindromHelper и ConversionHelper и т.д. А ты, ничего об мне не зная, свои такие (да нет, не такие, а несколько иные) соорудишь. Иван о нас тоже не знает, он свои сделает. В каждом из них чего-то не хватать будет, а что-то не лучшим образом сделано будет. И вот три хелпера сделаны, и каждый свой недостаток имеет. Теперь я узнал про твой. Он вроде лучше, чем мой, но в нем кое-чего, по моему мнению не хватает (или не так сделано). В общем, я за твой, но хочу в него кое-что из своего добавить. Далее по тексту.

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

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

PD>Ну я вроде объяснил.

Забавная теория. На практике мы почему-то видим несколько классов CStringEx, которые друг о друге ничего не знают. Если бы это были хелперы, то разработчик-прикладник мог бы пользоваться всей функциональностью без переделок. Увы, для наследников ему придется вручную объединять эти классы.
Понятно, что это непроизводительная работа?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[29]: Override для произвольного метода.
От: LaPerouse  
Дата: 24.12.08 07:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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

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

Если тебе так нравится MFC, советую обратить внимание на wxWidgets. Там тот же принцип (вместо виртуальных функций прямое связывание через макросы) и похожая архитектура. Но сделана, в отличие от MFC, более-менее по-человечески. Хотя с GUI-бибилотеками Java, которые в отличие от этих двух библиотек были спроектированы профессионалами, все равно конечно не сравнить.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[31]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 24.12.08 11:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Извини, но не согласен. О качестве конкретного материала — да, а о качестве ресурса — дает основание делать вывод.

Оставим качество ресурса в покое, не это тема дискуссии, хотя утверждение тоже весьма спорное.
Значит с тем, что пример не к селу ни к городу ты согласен?

PD>Я ничего не подменяю. Я нигде не утверждал, что CStingEx — высококачественный продукт, я его и не смотрел всерьез вообще-то. Я его просто привел как пример того, что такое возможно. Вот и все.

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

PD>А не мог ли уважаемый оппонет дать хоть какой-нибудь критерий, позволяющий отличать кривой код от не-кривого ?

Данный аспект мы уже обсудили выше.

PD>У меня, например, есть основание утверждать, что код, реализующий litview в .NET — кривой.

Охотно верю. WinForms (равно как и Web) местами вообще отличаются редкостной кривизной. Но какое это имеет отношение к данной дискуссии?

PD>Я что-то не пойму, зачем ты это мне второй раз привел.

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

PD>Но есть и другое. Вот сделал ты (не ты, MS) CString. А теперь посмотри CStringEx. Не будем сейчас обсуждать качество реализации, возьмем идею — зачем сделано. Оказывается, чтобы улучшить существующую функциональность. Если в твоем классе string есть поиск вперед, а поиск назад почему-то отсутствует, так что приходится ревертировать строки для такого поиска — что плохого, если я напишу наследника, который этот поиск назад будет делать ?

Ровно тоже самое, плохость никуда не делась. Там уже Антон все довольно подробно расписал... Могу лишь процитировать того же Меерса — "To put it bluntly, non-member functions happen..."

PD>Естественный вопрос — а где граница ? Да, улучшая поиск, можно и до регекспов дойти, и до trie-деревьев, и до хешей. Ответа точного, естественно, нет, но его и вообще нет. Если бы ты string и regexp делал бы сам — почему ты не уложил бы regexp внутрь стринга ? По-видимому. из неких соображений, связанных с OOD. Ну вот и здесь так же.

Конечно же есть. Есть очень хорошее правило большего пальца: Если функционал метода можно реализовать только с помощю публичного контракта класса, значит он должен находиться вне класса.

PD>Так-таки никогда ? А как же быть с наследованием от Control и т.д. Ты же не в неймспейс , где Control, это помещаешь, а в свой неймспейс, да с наследованием. Или это не есть организация кода ? Тогда какая тут организация ?

От Control-а нужно наследоваться потому, что библиотеку задизайнили не лучшим образом и заиспользовали полиморфизм через наследование реализации. Таким образом, ответ на твой вопрос — да, это не организация кода, а полиморфизм, в не самом лучшем своем проявлении.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[32]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 25.12.08 06:31
Оценка:
Здравствуйте, IB, Вы писали:

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


PD>>Извини, но не согласен. О качестве конкретного материала — да, а о качестве ресурса — дает основание делать вывод.

IB>Оставим качество ресурса в покое, не это тема дискуссии, хотя утверждение тоже весьма спорное.
IB>Значит с тем, что пример не к селу ни к городу ты согласен?

Нет

IB>Вот это и есть подмена понятий.. Уже несколько раз было сказано, что с тем что такое в принципе возможно и некоторые товарищи так делают — никто не спорит. Речь идет не об этом, а о том, что так делать нельзя и надо делать по другому. Не стоит использовать наследование как средство группировки кода. И тот факт, что кто-то так делает, совершенно не является аргументом в пользу того, что так делать надо.


Ну что же, ясно, впрочем, и изначално ясно было. Я с этим не согласен. Вот и все.

PD>>А не мог ли уважаемый оппонет дать хоть какой-нибудь критерий, позволяющий отличать кривой код от не-кривого ?

IB>Данный аспект мы уже обсудили выше.

Можно ссылку ? Не помню, чтобы мы с тобой это обсуждали. Склероз...

PD>>У меня, например, есть основание утверждать, что код, реализующий litview в .NET — кривой.

IB>Охотно верю. WinForms (равно как и Web) местами вообще отличаются редкостной кривизной. Но какое это имеет отношение к данной дискуссии?

Просто если он кривой, то тогда он такой же аргумент, как и CStringEx

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


-1.


PD>>Естественный вопрос — а где граница ? Да, улучшая поиск, можно и до регекспов дойти, и до trie-деревьев, и до хешей. Ответа точного, естественно, нет, но его и вообще нет. Если бы ты string и regexp делал бы сам — почему ты не уложил бы regexp внутрь стринга ? По-видимому. из неких соображений, связанных с OOD. Ну вот и здесь так же.

IB>Конечно же есть. Есть очень хорошее правило большего пальца: Если функционал метода можно реализовать только с помощю публичного контракта класса, значит он должен находиться вне класса.

См. ответ Антону . Как бы все это свести, чтобы мне не приходилось то ему, то тебе отвечать ? Может, вы с ним будете мне коллективно отвечать ?

PD>>Так-таки никогда ? А как же быть с наследованием от Control и т.д. Ты же не в неймспейс , где Control, это помещаешь, а в свой неймспейс, да с наследованием. Или это не есть организация кода ? Тогда какая тут организация ?

IB>От Control-а нужно наследоваться потому, что библиотеку задизайнили не лучшим образом и заиспользовали полиморфизм через наследование реализации. Таким образом, ответ на твой вопрос — да, это не организация кода, а полиморфизм, в не самом лучшем своем проявлении.

Слишком уж серьезно это не самое лучшее проявление. Убери класс CStringEx — в общем, никто и не почешется, напишем иной. А вот выкинь это наслелование с полиморфизмом — и не останется в .Net никакого GUI, одни консольные приложения писать будем А впрочем, и в Delphi, и в MFC, да и в Яве ИМХО (никогда в яве GUI не писал, так что не уверен). Все они нарушают этот ваш фундаментальный принцип, все используют наследование. Как-то это плохо вяжется с фундаментальностью принципа. Аргумент насчет не лучшего дизайна не приму — почему во всех библиотеках этот не лучший дизайн используется ?

И еще один вопрос к тебе, извини уж за его наивность . Как я понимаю, все твои возражения по наследованию относятся к тому варианту, когда некое третье лицо (фирма) начинает наследовать от не своего кода , так ? В пределах одной библиотеки ты, надеюсь, не против наследования ? Очевидно, не против, иначе тебе придется всю .Net похоронить. Так вот, вопрос такой. Пусть есть некий класс, сделанный фирмой X в составе библиотеки L версии 1. Имеет ли право фирма X в библиотеке Y версии 2 сделать наследника от этого класса ? Имеет ли право на это фирма X1, которая купила фирму X между выходами версий 1 и 2 ? Имеет ли право на это фирма Z, которая никакого отношения к X не имеет, но фирма X прекратила свое существование и перед смертью сделала все свои коды открытыми ?
With best regards
Pavel Dvorkin
Re[33]: Override для произвольного метода.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.12.08 06:33
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

>>и с меньшим количеством ошибок.

PD>Критерий совершенно кривой сам. Сколько будет ошибок — зависит от того, кто писать будет.

Статистика показывает что средняя плотность ошибок в программах на тыщу строк кода не зависит от языка.
Если писать будет больше чем один человек, то стоит использовать средства позволяющие писать меньше кода.
Re[32]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 25.12.08 06:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

PD>>Очень спорно. Если речь идет о популярности ресурса, и ресурс дейсивительно популярен (а это факт) — это означает, что качество техническое там для многих продуктов неплохое.
S>Нет. Это не так. И даже если бы это было в целом так, это бы не означало, что любой взятый оттуда пример является образцом технического качества.
S>Это непонятно?

Непонятно одно. Я уже 100 раз объяснял, что не считаю его образцом и не говорил о его качестве. А в ответ — опять то же самое.

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

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

Да, не хочу, не убеждают они меня. И других тоже.

Давай в иную плоскость это тогда переведем. Я утверждаю нечто, ты утверждаешь противоположное. За мной некая практика, за тобой тоже. Но ты еще вдруг утверждать начинаешь, что моя , мол, практика — это результат массового заблужденмя. Обоснуй критерии, которые дают тебе право такое утверждать. В общем виде, вне применения к данной проблеме потомков класса. Потому что без таких критериев остается только один аргумент — "по этому вопросу есть два мнения, одно мое, другое неправильное".


PD>>А популярность, вообще-то, именно отражает практику, то есть примеры реального применения и т.д. Мы же не за ЛДПР голосуем тут. Если есть продукт и его используют, причем грамотные люди, это и значит, что он востребован, что он лучший на данный момент, то есть качественный. Ну с какой стати я буду в своих программах некачественные компонентиы использовать ?

S>Покажи мне грамотных людей, которые используют CStringEx.

Ну опять Ей- богу, несерьезно. Ты прекрасно знаешь, что в C++ исходники промышленных продуктов никто не показывает. Поэтому показать тебе, кто и какое наследование в промышленных продуктах использует, я никак не могу. А пример Wordpad и его классы я приводил.

А вообще пора заканчивать эту дискуссию. Как говорится, позиции сторон ясны.
With best regards
Pavel Dvorkin
Re[3]: Override для произвольного метода.
От: Nicht Россия  
Дата: 25.12.08 07:29
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Кстати, в Java все методы по умолчанию виртуальные.


Кстати, это не правда.
private и static методы нифига не виртуальные. Так как они не наследуются.
Да и простые методы обычно хотспотом считаются невиртуальными пока в рантайме не появляются классы которые оверрайдят эти методы. Это дает возможность не парится с виртуальной таблицей до поры до времени из чего следует прирост производительности.
Re[33]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 25.12.08 09:57
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Нет

Ок, продолжим, мне не сложно..

PD>Ну что же, ясно, впрочем, и изначално ясно было. Я с этим не согласен. Вот и все.

То есть, ты продолжаешь настаивать на том, что раз кто-то сделал криво, значит повторить это не только не зазорно, но и нужно?

PD>Можно ссылку ? Не помню, чтобы мы с тобой это обсуждали. Склероз...

Да пол-топика обсуждений. Наследоваться для расширения функциональности — это криво.

PD>Просто если он кривой, то тогда он такой же аргумент, как и CStringEx

А я его и не использовал в качестве аргумента. Я в принципе не считаю наличие конкретной реализации аргументом в пользу того, что так нужно делать всегда.

PD>-1.

Ну вот, а Саттер, Александреску и Меерс с тобой не согласны..

PD>Слишком уж серьезно это не самое лучшее проявление. Убери класс CStringEx — в общем, никто и не почешется, напишем иной. А вот выкинь это наслелование с полиморфизмом — и не останется в .Net никакого GUI, одни консольные приложения писать будем

Ну, во-первых, я все-таки настаиваю на разделении этих понятий, для пущей корректности. Наследование, лишь один из возможных вариантов реализации ad-hoc полиморфизма, поэтому полиморфизм я бы вообще не трогал. Во-вторых, в данном случае мы обсуждаем исключительно кривость использования наследования для расширения. Этот функционал я бы выкинул с приогромным удовольствием.
Ну и, наконец, в третих, GUI как раз останется, причем существенно лучший чем WinForms, потому что есть WPF, который еще не идеал, конечно, но поддерживает отличнейшие возможности расширения без наследования, чем очень выгодно отличается от WinForms. Собственно, по похожему принципу спроектированы общепризнанно лучшие UI фреймворки (да, я сейчас использую твой аргумент ), явовский swing, напрмер.

PD> Аргумент насчет не лучшего дизайна не приму — почему во всех библиотеках этот не лучший дизайн используется ?

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

PD>В пределах одной библиотеки ты, надеюсь, не против наследования ?

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

PD> Очевидно, не против, иначе тебе придется всю .Net похоронить.

Павел, я уже много раз тебе говорил — наличие не правильных реализаций, не является аргументом. Никто не утверждает, что библиотека классов .Net задизайнена лучшим из возможных способов, там полно косяков в архитектуре.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[33]: Override для произвольного метода.
От: LaPerouse  
Дата: 25.12.08 10:39
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>>>Так-таки никогда ? А как же быть с наследованием от Control и т.д. Ты же не в неймспейс , где Control, это помещаешь, а в свой неймспейс, да с наследованием. Или это не есть организация кода ? Тогда какая тут организация ?

IB>>От Control-а нужно наследоваться потому, что библиотеку задизайнили не лучшим образом и заиспользовали полиморфизм через наследование реализации. Таким образом, ответ на твой вопрос — да, это не организация кода, а полиморфизм, в не самом лучшем своем проявлении.

PD>да и в Яве ИМХО (никогда в яве GUI не писал, так что не уверен). Все они нарушают этот ваш фундаментальный принцип, все используют наследование.


То, что не уверен — хорошо. Так как подобного маразма в java.swing нет. То есть ты конечно вполне можешь отнаследоваться от какого-то JFrame, но это нафиг не нужно (и вредно). Там event-based модель, без всякой виртуальщины. То разница будет между

this.setListener(new Listener...)

и

frame.setListener(new Listener...),

любой более-менее квалифицированный программист выберет второе.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[33]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 25.12.08 20:22
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Непонятно одно. Я уже 100 раз объяснял, что не считаю его образцом и не говорил о его качестве. А в ответ — опять то же самое.

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

PD> И других тоже.

Что-то никого другого неубежденного пока не видно..

PD>Давай в иную плоскость это тогда переведем. Я утверждаю нечто, ты утверждаешь противоположное. За мной некая практика, за тобой тоже.

Нету за тобой практики, потому что "практика" на которую ты ссылаешься не имеет никакого отношения к делу. Руководствуясь твоей логикой можно прийти к выводу, что нет удобней инструмента для вкалачивания шурупов, чем микроскоп. А что, опыт-то положительный есть.
... << RSDN@Home 1.2.0 alpha 4 rev. 1082>>
Мы уже победили, просто это еще не так заметно...
Re[30]: Override для произвольного метода.
От: Кэр  
Дата: 25.12.08 23:23
Оценка:
Здравствуйте, Sinclair, Вы писали:

LP>>Список — это reverse, concat, replace и т п

LP>>Строка — это IString (to_lower_case, to_upper_case, asBytes)
S>Зачем. ToLower, ToUpper — это всего лишь хелперы для того же IEnumerable<char>:
S>
S>public static IEnumerable<char> String.ToLower(this IEnumerable<char> source)
S>{
S>  foreach(char c in source)
S>      yield return Char.ToLower(c);
S>}
S>

S>Всех делов-то.

Только использовать это нельзя:

For example, There is a ΰ (U+03B0 greek small letter Upsilon with Dialytika and Tonos), however there's no equivilent capital letter. Trying to do ToUpper() ends up returning the same value, although you could perhaps argue for Ϋ́ (U+03AB + U+0301, greeke capital letter upsilon with dialytika, and then a combining tonos) Some other operating systems/environments choose that as the ToUpper() value for U+03B0, so then a single "char" ends up with a 2 "char" upper case form.


А так да — проблема решена...

Думаю, если вводить более удачную абстракцию, чем String — то надо смотреть в сторону IEnumerable<Symbol>, где Symbol может содержать один или два Char. Не факт, что такое решение все еще сможет похвастать хорошим перфомансом. Впрочем можно попробовать.
Re[31]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 03:43
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Только использовать это нельзя:


Кэр>

For example, There is a ? (U+03B0 greek small letter Upsilon with Dialytika and Tonos), however there's no equivilent capital letter. Trying to do ToUpper() ends up returning the same value, although you could perhaps argue for ?? (U+03AB + U+0301, greeke capital letter upsilon with dialytika, and then a combining tonos) Some other operating systems/environments choose that as the ToUpper() value for U+03B0, so then a single "char" ends up with a 2 "char" upper case form.

Кэр>А так да — проблема решена...
На самом деле — ничего страшного.
Просто код хелпера будет чуток посложнее
Кэр>Думаю, если вводить более удачную абстракцию, чем String — то надо смотреть в сторону IEnumerable<Symbol>, где Symbol может содержать один или два Char. Не факт, что такое решение все еще сможет похвастать хорошим перфомансом. Впрочем можно попробовать.
Нужно вводить IEnumerable<CodePoint>. Вот тогда будет почти щасте — с точностью до разных представлений одного и того же глифа при помощи кодепоинтов. "Один или два" — это малоинтересно. Тот char, о котором ты говоришь, это фактически уже UCS-2 encoding. А вовсе не текст.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[32]: Override для произвольного метода.
От: Кэр  
Дата: 26.12.08 04:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>На самом деле — ничего страшного.

S>Просто код хелпера будет чуток посложнее

Берем "чуток" в кавычки и я уже согласен Проблемы, которые возможны — для получения перфоманса нам возможно придется затачиваться на конкретную реализацию строки. Тот же IEnumberable очень беден, ни тебе каунта бесплатно, ни доступа по индексу. В частности поэтому мне IEnumerable<char> не очень нравится, как идея.

Кэр>>Думаю, если вводить более удачную абстракцию, чем String — то надо смотреть в сторону IEnumerable<Symbol>, где Symbol может содержать один или два Char. Не факт, что такое решение все еще сможет похвастать хорошим перфомансом. Впрочем можно попробовать.

S>Нужно вводить IEnumerable<CodePoint>. Вот тогда будет почти щасте — с точностью до разных представлений одного и того же глифа при помощи кодепоинтов.
Мне это больше нравится. Но не очень уверен насчет IEnumerable опять же. (Господи, когда же они уже передизайнят коллекции в .Net).

S>"Один или два" — это малоинтересно. Тот char, о котором ты говоришь, это фактически уже UCS-2 encoding. А вовсе не текст.

Вообще-то нет. Один .Net Char — это 16 бит. Таким образом два .Net Char'a могут закодировать все известные на текущий момент Unicode символы (описываются 21-битовым числом).
Re[33]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 04:37
Оценка:
Здравствуйте, Кэр, Вы писали:

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

Не, для ToLower — нет. Он же строго локален. Ну то есть для генерации очередного элемента может потребоваться несколько Char, но подряд.
Поэтому никакого особенного индексного доступа не нужно. Будет нормальный конечный автомат, который жует IEnumerable.

Кэр>Тот же IEnumberable очень беден, ни тебе каунта бесплатно, ни доступа по индексу. В частности поэтому мне IEnumerable<char> не очень нравится, как идея.

Вот он мне как раз этим и нравится. Не вполне понятно, с какой целью нужен доступ по произвольному индексу.

Кэр>Вообще-то нет. Один .Net Char — это 16 бит. Таким образом два .Net Char'a могут закодировать все известные на текущий момент Unicode символы (описываются 21-битовым числом).


В Unicode нет "символов". Есть код поинты. И, насколько я помню, в плохих случаях некий глиф может быть представлен то одним код поинтом, то, к примеру, четырьмя. В UCS-2 все эти поинты по-прежнему будут хавать по 16 бит каждый. В основном дело касается combining diacritics.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: Override для произвольного метода.
От: Кэр  
Дата: 26.12.08 05:34
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

S>Не, для ToLower — нет. Он же строго локален. Ну то есть для генерации очередного элемента может потребоваться несколько Char, но подряд.
S>Поэтому никакого особенного индексного доступа не нужно. Будет нормальный конечный автомат, который жует IEnumerable.
Кэр>>Тот же IEnumberable очень беден, ни тебе каунта бесплатно, ни доступа по индексу. В частности поэтому мне IEnumerable<char> не очень нравится, как идея.
S>Вот он мне как раз этим и нравится. Не вполне понятно, с какой целью нужен доступ по произвольному индексу.

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

Кэр>>Вообще-то нет. Один .Net Char — это 16 бит. Таким образом два .Net Char'a могут закодировать все известные на текущий момент Unicode символы (описываются 21-битовым числом).


S> В Unicode нет "символов". Есть код поинты.

Я символы называю код поинтами По моему мы это даже вживую обсуждали

S>И, насколько я помню, в плохих случаях некий глиф может быть представлен то одним код поинтом, то, к примеру, четырьмя. В UCS-2 все эти поинты по-прежнему будут хавать по 16 бит каждый. В основном дело касается combining diacritics.


Насколько я помню, UCS-2 просто делает вид, что не знает про символы (код поинты), для кодировки которых требуются более двух байт.
Re[35]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 06:03
Оценка:
Здравствуйте, Кэр, Вы писали:
Кэр>Для ToLower возможно. Для каких-нибудь регексов с лупбэками, или всяких алгоритмов поиска подстроки — точно мало.
Совершенно не уверен. Я, кстати, потому и написал в самом начале, что не могу сходу придумать IString.
Всякие "алгоритмы поиска подстроки" на самом деле тоже не пользуются индексным доступом — им достаточно кольцевого буфера с размером, зависящим только от размера искомой подстроки.
А вот насчет регекспов я не так уверен. Я в них не очень хорошо разбираюсь. Но есть подозрение, что им хватит поддержки ICloneable<IEnumerator<char>> у результата вызова IString.GetEnumerator()

Кэр>Я символы называю код поинтами По моему мы это даже вживую обсуждали

Так то когда было-то? Я уж не помню подробностей терминологии.
Кэр>Насколько я помню, UCS-2 просто делает вид, что не знает про символы (код поинты), для кодировки которых требуются более двух байт.
Дело, имхо, не в UCS2. Я так понял, что бывают такие сиквенсы кодпоинтов, которые могут вести себя неадекватно по отношению к ToLower/ToUpper. В том смысле, что
а) нельзя процессить их составляющие по отдельности
б) из одного code point на входе может получиться N code points на выходе.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: еще один кривой пример
От: Pavel Dvorkin Россия  
Дата: 26.12.08 06:08
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Очередное свидетельство убогости архитектуры WinForms, о чем я буквально недавно писал.


А что взамен (для десктопных) ? WPF ?
With best regards
Pavel Dvorkin
Re[36]: Override для произвольного метода.
От: Кэр  
Дата: 26.12.08 06:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

Кэр>>Для ToLower возможно. Для каких-нибудь регексов с лупбэками, или всяких алгоритмов поиска подстроки — точно мало.
S>Совершенно не уверен. Я, кстати, потому и написал в самом начале, что не могу сходу придумать IString.
S>Всякие "алгоритмы поиска подстроки" на самом деле тоже не пользуются индексным доступом — им достаточно кольцевого буфера с размером, зависящим только от размера искомой подстроки.
S>А вот насчет регекспов я не так уверен. Я в них не очень хорошо разбираюсь. Но есть подозрение, что им хватит поддержки ICloneable<IEnumerator<char>> у результата вызова IString.GetEnumerator()

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

Кэр>>Я символы называю код поинтами По моему мы это даже вживую обсуждали

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

Кэр>>Насколько я помню, UCS-2 просто делает вид, что не знает про символы (код поинты), для кодировки которых требуются более двух байт.

S>Дело, имхо, не в UCS2. Я так понял, что бывают такие сиквенсы кодпоинтов, которые могут вести себя неадекватно по отношению к ToLower/ToUpper. В том смысле, что
S>а) нельзя процессить их составляющие по отдельности
S>б) из одного code point на входе может получиться N code points на выходе.

Эээ, про UCS-2 у нас речь зашла, когда я предлагал IEnumerable<Symbol>, где Symbol — это один/два .Net Char. Подобная кодировка — это один в один UTF-16, но не UCS-2.

Про ToLower/ToUpper все вроде как верно. Просто опять же там нужно учитывать уйму специфичных случаев вроде немецкой ß, поэтому я и написал, что "чуток" надо взять в кавычки. Код метода должен это как-то учитывать. С другой стороны все эти культурно-зависимые потрошка должны уже в .Net Framework присутствовать. К сожалению .Net тут уходит в native, так что дальше я пока не смотрел.
Re[35]: еще один кривой пример
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 06:36
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А что взамен (для десктопных) ? WPF ?

Взамен в каком смысле? В смысле совершенства архитектуры — вот рядом пример привели
Автор: LaPerouse
Дата: 25.12.08
.
В смысле "конкретный фреймворк для UI на винде" — сразу не скажу; скорее всего HTMLayout будет в самый раз. Не факт, что он лучший из возможных.
А вообще практика показывает, что в UI наследование нужно очень-очень редко. Как правило, можно (и лучше) обойтись композицией.
Можно, конечно, и наследованием пользоваться, вот только результат получается хуже.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 26.12.08 06:39
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Статистика показывает что средняя плотность ошибок в программах на тыщу строк кода не зависит от языка.


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

G>Если писать будет больше чем один человек, то стоит использовать средства позволяющие писать меньше кода.


Хм... В теории — пожалуй, да. На практике — бог знает. От критериев зависит. Да и количество ошибок не самое главное. Ошибки раньше или позже будут исправлены (не все , а качество кода останется. Что мне за радость, если вместо 1000 строк я могу написать 100 , сделать это практически без ошибок, но в итоге все это будет в 5 раз медленнее работать из-за того, что недостающие 900 строк (а они есть, ты же это понимаешь, их же кто-то написал!) написаны в универсальном виде и поэтому для моей конкретной ситуации дают провал в производительности, например ?
With best regards
Pavel Dvorkin
Re[35]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 07:10
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Хм... В теории — пожалуй, да. На практике — бог знает. От критериев зависит. Да и количество ошибок не самое главное. Ошибки раньше или позже будут исправлены (не все , а качество кода останется. Что мне за радость, если вместо 1000 строк я могу написать 100 , сделать это практически без ошибок, но в итоге все это будет в 5 раз медленнее работать из-за того, что недостающие 900 строк (а они есть, ты же это понимаешь, их же кто-то написал!) написаны в универсальном виде и поэтому для моей конкретной ситуации дают провал в производительности, например ?


Ты очень ловко меняешь тему. Хочешь поговорить о производительности применительно к ОО-дизайну?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[37]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.12.08 07:27
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Про ToLower/ToUpper все вроде как верно. Просто опять же там нужно учитывать уйму специфичных случаев вроде немецкой ?, поэтому я и написал, что "чуток" надо взять в кавычки. Код метода должен это как-то учитывать. С другой стороны все эти культурно-зависимые потрошка должны уже в .Net Framework присутствовать. К сожалению .Net тут уходит в native, так что дальше я пока не смотрел.

Ну вот со строками в Нет именно та проблема и есть — что всё в натив. А натив написан в расчете на совершенно специфический layout строк.
И это, наверное, хорошо — в том смысле, что хаскелевские строки потребуют слишком много всего от рантайма.
Ну то есть, в частности, их эффективность сильно зависит от наличия GC, а также от нюансов поведения JIT. Иначе окажется, что в частоиспользуемых частных случаях простые операции привносят неприемлемый оверхед. Грубо говоря, ToUpper в рамках ASCII-7 представления вообще может делаться цепочкой int64-операций, то есть на строках вплоть до 8 символов это вообще один bitwise OR. В каких-то местах это может оказаться важнее, чем выигрышь от O(1)-конактенации.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 26.12.08 07:48
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


PD>>Для меня абсолютно несущественно, короче или нет. Для меня существенно — эффективнее или нет. Ради нее я готов написать в 5 раз больше текста. Критерий не принимается.

S>Отлично. Этот критерий, конечно же, не так важен — поскольку ускорить прямой код всегда проще, чем выпрямить быстрый



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


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


А можно узнать, почему обязательно если уж наследование, то бездумное ? Я вроде к бездумному не призывал. И потом, если уж ты против бездумного — так с обдуманным наследованием ты согласен ?

PD>>Критерий совершенно кривой сам. Сколько будет ошибок — зависит от того, кто писать будет.

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

См. мой ответ gandjustas.

PD>>А вот о качестве кода ты ничего не сказал. Из этого следует, что код, который позволяет писать "короче и с меньшим...", но внутри себя реализован так, что хоть святых выноси, а чтобы его не попробовали расширить, установлен как sealed — не есть кривой ? Да или нет ?

S>Нет, почему. При прочих равных код, сам написанный "короче и с меньшим...", лучше "хоть святых выноси".

Вот именно что при прочих равных. А они чаще всего совсем не равны.

S>Но это при прочих равных. Если код сам по себе написан замечательно, но требует от прикладного программиста большого объема работы и высокой дисциплины, то он однозначно кривее, чем код, которым легко пользоваться.


Ну и пусть кривее (в твоем понимании). Но он же написан замечательно, ты сам сказал. То есть код хорош, высокопроизводителен и т.д., но вот писать и поддерживать его сложно, да. Если ты в состоянии написать столь же хороший код другими средствами, и поддерживать его будет легче, я твой код приму. Но если он будет хуже, то иди-ка ты со всеми рассуждениями куда хочешь. Мне код нужен, а не рассуждения.
PD>>А по моему критерию код, который для сортировки листвью его пересоздает — не просто кривой, а вообще загогулина какая-то.
S>С этим никто не спорил.

PD>>Разумееется.

S>

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


PD>>class DString // уже готов, но в нем нет поиска назад


PD>>class D1String : DString // в нем будет добавлен поиск назад


PD>>class HString // а это твой хелпер


PD>>ну вот и докажи.

S>Ну, ок. Поскольку DSting — это класс из стандартной библиотеки, все сторонние библиотеки построены на нем. В частности, есть, допустим, метод DString HttpRequest::GetParameter(DString paramName).

S>Вот простейший фрагмент кода, который ищет последнее вхождение одного параметра в другом:


<skipped>

Все, что тебе удалось здесь обосновать — это то, что прочие библиотеки не будут работать с наследником как с наследником, а будут — как с предком. Поэтому тебе и понадобилось сюда передать этот HttpRequest, в котором нет D1String, а есть DString. Я уже на этот вопрос отвечал.

S>Да ну? Во-первых, в наследнике потребуется воспроизвести весь список конструкторов предка — они ведь не наследуются.


С учетом того, что новых параметров здесь нет, это очень-очень сложно


S>Во-вторых, потребуется повторно перегрузить все операторы — они тоже не наследуются.


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


class A {
private :
    int x;
public :
    A(int _x = 0 ) : x(_x) {}
    void operator++()
    {
        x++;
    }

};


class B : public A
{
public :
    B(int _x) : A(_x) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
    B b1(1);
    b1++;
        b1.operator++(); // можно и так, надеюсь, теперь ясно, что это просто функция

    return 0;
}



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


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

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

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

Я так понимаю, что разработчики более поздних Явы и .Net ту же глупость сделали ? String.IndexOf — это не то же самое ?

Или может, глупости ты говоришь ? Как бы мне правильный ответ тут выбрать?

PD>>Второй аналогичный вопрос. Почему в классе Directory метод GetFiles как он сейчас есть, должен быть в этом классе, а метод GetNextFile (реализующий по сути ту же функциональность , но по другому — надо ? А если бы ее MS реализовала сама внутри нынешнего Directory (ей-то ничто не мешало это сделать!) — то не надо ?

S>Поясняю еще раз: по-хорошему, с самого начала должен был быть ровно один метод — тот, который возвращает ленивый список — IEnumerable<string>/IEnumerable<FileSystemInfo>.

Ну с самого начала его быть не могло в таком виде по причине отсутствия темплейтов в 1.1

S>Но в реальной жизни мы имеем дело с реальными программистами. Невозможно с первого раза реализовать идеальную библиотеку. Но есть способ дать возможность расширения библиотеки. Эта возможность — есть. Никакого unsealed она не требует.


Возможность пусть и есть, но в итоге именно кривой код и получится. Один кусок там, другой здесь, а о твоей любимой ортогональности лучше уж и не заикаться.


PD>>+1. Но все это не суть важно, интуиция или что-то еще. Важно одно — есть некие соображения о делении на классы.

S>Важно то, что ничего сверхъестественного в этих соображениях нет. Им можно научить любого человека, если он перестанет кочевряжиться и начнет думать головой.

Именно этого я от тебя и добиваюсь, чтобы ты наконец перестал жестко следовать выученным тобой правилам и понял, что иногда надо от них отступать, а когда это можно делать и когда нельзя — тут как раз голова и требуется.
With best regards
Pavel Dvorkin
Re[37]: Override для произвольного метода.
От: LaPerouse  
Дата: 29.12.08 10:54
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


PD>Насчет не void — please


Не в void дело, а в том, что в CString создается экземпляр CString
Попробуй сделай класс B для такого класса A:


#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include "malloc.h"

[ccode]
class A {
private :
    char* m_str;
public:

operator int()
{
    return atoi(m_str); // error handling skipped
}
operator char*()
{
    return m_str;
}

A concat(A* a)
{
    char* m_result;
    ...
    A* result = new A(m_result);
    return result;
}

A(char* p = NULL)
{
    m_str = strdup(p);
}
virtual ~A()
{
    free(m_str);
}
};


Тебе придется перегрузить в B concat, что и имелось ввиду.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[29]: Override для произвольного метода.
От: 4058  
Дата: 29.12.08 11:59
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


Ответ выделен.

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


Противоречий нет. Есть время, и есть опыт. То что считалось нормальным при t0, может быть неприемлемо (или не желательно) при t1.

PD>Тем более что речь все же идет не о специально созданном примере, а об исходниках пусть не самого мощного , но все же штатного текстового редактора, который по идее должен использоваться для реальной работы с .doc файлами теми, кто не купил Office (OO тогда не было


Правильно поставлен смайл, т.к. определение "мощности" плохо сочетается с функциональностью и качеством софта. Причем для большинства word-овых файлов сложнее "Hello World" бывает очень сложно использовать этот инструмент.
Wordpad — это сборная солянка из набора готовых законченных компонент, поэтому дальнейший разговор на эту тему не интересен, т.к. аналогично можно приводить примеры для Calc-а и Notepad-а.

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


Совершенно верно.

4>>Ну и кому еще нужны такие примеры, кроме как начинающих?


PD>Даже если пример содержит только printf("Hello, World"), его писать и выставлять надо сделанным как следует.


В том и дело, что на таких примерах практически невозможно увидеть положительные/отрицательные стороны того или иного подхода.

4>>M$ надеялась, что сможет пересадить львиную долю formo-кодеров на .NET, не получилось...


PD>Что же ты многоточие поставил ? Надо закончить фразу. Не получилось — а почему ? И библиотека хорошая, и язык C# (взятый сам по себе) — лучше C++, логичнее, а вот не получилось. Почему ? Должны же быть причины ?


Причины:
1. Религия. Это очень долгий и неприятный разговор, которому пожалуй место в СВ.
Managed/Unmanaged, C# vs All и т.п.
2. "А мне и так хорошо". Многим вполне достаточно тех средств которые они используют (ибо "задачи" позволяют), зачем еще что-то изучать?
3. "ListView — плохой, не буду я это использовать". Правда есть, т.к. WinForm-ы прикручивали к .NET в очень сжатые сроки и => через .опу, т.к. основной приоритет значился за другими составляющими (мода на Web).

4>>Пытались, но до добра это дело не довело (см. про formo-кодеров).


PD>А почему в случае Win16 -> Win32 все прошло успешно ?


А почему Dos -> Win прошло успешно?
Потому что Win32 был необходим (как глаток долгожданного воздуха), а вот Java/.Net нет.
Re[38]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 12:00
Оценка:
Здравствуйте, LaPerouse, Вы писали:

LP>Тебе придется перегрузить в B concat, что и имелось ввиду.


Совершенно верно. Только один вопрос — а нужно ли мне это делать ? Так-таки мне нужна эта concat ? . Подумай, зачем мне этот производный класс нужен — и поймешь, что мне в нем может оказаться необходимым очень небольшое количество методов.
With best regards
Pavel Dvorkin
Re[39]: Override для произвольного метода.
От: LaPerouse  
Дата: 29.12.08 12:15
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


LP>>Тебе придется перегрузить в B concat, что и имелось ввиду.


PD>Совершенно верно. Только один вопрос — а нужно ли мне это делать ? Так-таки мне нужна эта concat ? . Подумай, зачем мне этот производный класс нужен — и поймешь, что мне в нем может оказаться необходимым очень небольшое количество методов.


1. Я как раз пытаюсь понять, зачем тебе нужен этот производный класс
2. Если не нужен, тогда зачем тебе наследоваться?
3. Почему он тебе не нужен? Я что, пользуясь твоим классом, при сложении двух полиндромов и ожидая получить полиндром, получу вмесо него CString? Тогда в топку.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[38]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 12:48
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


Ну держи


    class CMyString : public CString
    public:
        CMyString(TCHAR* p) : CString(p) {}
        ~CMyString(){}
        }


Можешь использовать operator[], например. Как ни странно, но он наследуется, несмотря на твои уверения, что все не наследуются. operator== хоть и не наследуется (он реализован не членом, а другом), но вполне работает (а с чего бы ему не работать ? передачу ссылки на производный объект методу, которому нужна ссылка на базовый, никто не отменял, а палиндромность при сравнении строк вроде бы роли не играет И т.д. Нельзя использовать только те, которые возвращают CString, но это само собой разумеется, и никакого отношения к наследованию операторов как таковых не имеет — просто метод унаследованного оператора возвращает базовый класс. Еще раз — дело здесь не в наследовании операторов, а в типе результата метода, это же верно для любого обычного метода (тот же concat, к примеру).

>Впрочем, уже к этому моменту ты написал 15 строчек кода, а поиска палиндромов в строке как не было, так и нет.


Поиска палиндромов в строке ? Можно ссылочку, где я обещал это сделать ? IsPalindrom проверяет, является ли строка палиндромом, а искать в строке все палиндромы — была мне нужда

PD>>Да, плохо твое дело, если уж не остается ничего, кроме оскорблений. Впрочем, я тебя понимаю. Такой великий специалист и так глупо прокололся

S>На мой взгляд, прокололся тот, кто продолжает гнуть пальцы в ответ на предложение привести код наследника от CString, который полностью поддерживает его интерфейс.

Хе-хе, батенька, а с чего это ты решил, что я вообще собираюсь полностью поддерживать его интерфейс ? Ссылочку, пожалуйста, где я обещал полностью. Я это вовсе не собираюсь делать, я намерен только то поддерживать, что мне нужно И скажу более — я не хочу, чтобы поддерживалось то, что мне не нужно, так что я (возможно) это вообще скрою. Тебе объяснить как ?

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


Какая трогательная забота о моем реноме
With best regards
Pavel Dvorkin
Re[41]: Override для произвольного метода.
От: IB Австрия http://rsdn.ru
Дата: 29.12.08 13:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А с чего это ты решил, что складывая два палиндрома (конкатенируя то есть) ты всегда получишь палиндром ?

Ну, то есть, ты считаешь нормальным, что:
CPalindromString s1;
CPalindromString s2;
...
CPalindromString s3 = s1.Concat(s2) // - Invalid Cast Exception

?
Если так, то вопросов больше нет.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[41]: Override для произвольного метода.
От: LaPerouse  
Дата: 29.12.08 13:17
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


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

LP>>2. Если не нужен, тогда зачем тебе наследоваться?

PD>Что-то я не пойму, с чего ты решил, что не нужен ?


Ты сам это сказал
>>Так-таки мне нужна эта concat

LP>>3. Почему он тебе не нужен? Я что, пользуясь твоим классом, при сложении двух полиндромов и ожидая получить полиндром, получу вмесо него CString?

PD>Тогда в топку.

PD>А с чего это ты решил, что складывая два палиндрома (конкатенируя то есть) ты всегда получишь палиндром ?


Э нет, подмена не пройдет. Мы говорим про объекты-полиндромы класса CPalindrome, у которых есть метод isPalindrome()
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[42]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 13:39
Оценка:
Здравствуйте, LaPerouse, Вы писали:

PD>>Что-то я не пойму, с чего ты решил, что не нужен ?


LP>Ты сам это сказал


Что я сказал ? Что класс, который я предлагаю, не нужен ? Или все же, что concat ?

Цитируем полностью. Выделено мной.

///////////////////////////////////////////////////////////////////////////////////////////////////

LP>Тебе придется перегрузить в B concat, что и имелось ввиду.


PD>Совершенно верно. Только один вопрос — а нужно ли мне это делать ? Так-таки мне нужна эта concat ? Подумай, зачем мне этот производный класс нужен — и поймешь, что мне в нем может оказаться необходимым очень небольшое количество методов.



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

LP>2. Если не нужен, тогда зачем тебе наследоваться?

PD>Что-то я не пойму, с чего ты решил, что не нужен ?


LP>Ты сам это сказал


///////////////////////////////////////////////////////////////////////////////////////////////////


Ну и как все это называется ? Я ему про то, что мне не нужна concat, а оказывается. я заявил, что мне этот класс не нужен.


>>>Так-таки мне нужна эта concat


LP>>>3. Почему он тебе не нужен? Я что, пользуясь твоим классом, при сложении двух полиндромов и ожидая получить полиндром, получу вмесо него CString?

PD>>Тогда в топку.

PD>>А с чего это ты решил, что складывая два палиндрома (конкатенируя то есть) ты всегда получишь палиндром ?


LP>Э нет, подмена не пройдет. Мы говорим про объекты-полиндромы класса CPalindrome, у которых есть метод isPalindrome()


Но отнюдь не метод конкатенации. Его просто не будет. Я не намерен позволять конкатенировать строки какого бы то ни было происхождения. И создавать их в программе тоже. Все, что мне надо — контроль на вводе, и это есть единственный способ их конструирования. См. в MFC DDX-DDV.
With best regards
Pavel Dvorkin
Re[42]: Override для произвольного метода.
От: Pavel Dvorkin Россия  
Дата: 29.12.08 13:43
Оценка:
Здравствуйте, IB, Вы писали:

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


PD>>А с чего это ты решил, что складывая два палиндрома (конкатенируя то есть) ты всегда получишь палиндром ?

IB>Ну, то есть, ты считаешь нормальным, что:
IB>[code]
IB>CPalindromString s1;
IB>CPalindromString s2;
IB>...
IB>CPalindromString s3 = s1.Concat(s2) // — Invalid Cast Exception

Нет. 'Concat' : is not a member of ...
With best regards
Pavel Dvorkin
Re[43]: Override для произвольного метода.
От: LaPerouse  
Дата: 29.12.08 13:47
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


PD>>>Что-то я не пойму, с чего ты решил, что не нужен ?


LP>>Ты сам это сказал


PD>Что я сказал ? Что класс, который я предлагаю, не нужен ? Или все же, что concat ?


PD>Цитируем полностью. Выделено мной.


PD>///////////////////////////////////////////////////////////////////////////////////////////////////


LP>>Тебе придется перегрузить в B concat, что и имелось ввиду.


PD>>Совершенно верно. Только один вопрос — а нужно ли мне это делать ? Так-таки мне нужна эта concat ? Подумай, зачем мне этот производный класс нужен — и поймешь, что мне в нем может оказаться необходимым очень небольшое количество методов.



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

LP>>2. Если не нужен, тогда зачем тебе наследоваться?

PD>>Что-то я не пойму, с чего ты решил, что не нужен ?


LP>>Ты сам это сказал


PD>///////////////////////////////////////////////////////////////////////////////////////////////////



PD>Ну и как все это называется ? Я ему про то, что мне не нужна concat, а оказывается. я заявил, что мне этот класс не нужен.


Ты неправильно понял мой пункт 2: "Если не нужен, тогда зачем тебе наследоваться?". Имелось ввиду, "если не нужен метод concat, тогда зачем тебе наследоваться?".


>>>>Так-таки мне нужна эта concat


LP>>>>3. Почему он тебе не нужен? Я что, пользуясь твоим классом, при сложении двух полиндромов и ожидая получить полиндром, получу вмесо него CString?

PD>>>Тогда в топку.

PD>>>А с чего это ты решил, что складывая два палиндрома (конкатенируя то есть) ты всегда получишь палиндром ?


LP>>Э нет, подмена не пройдет. Мы говорим про объекты-полиндромы класса CPalindrome, у которых есть метод isPalindrome()


PD>Но отнюдь не метод конкатенации. Его просто не будет. Я не намерен позволять конкатенировать строки какого бы то ни было происхождения. И создавать их в программе тоже. Все, что мне надо — контроль на вводе, и это есть единственный способ их конструирования. См. в MFC DDX-DDV.


То есть ты намерен запрещать пользователю библиотеки вызывать метод concat у твоего CPolindrom?
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
Re[39]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.12.08 05:18
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Хе-хе, батенька, а с чего это ты решил, что я вообще собираюсь полностью поддерживать его интерфейс ?
Ах, не обещал. Прекрасно. То есть теперь ты предлагаешь в качестве решения всех проблем плодить не просто наследников класса, но еще и более убогих наследников? Твою строку даже сконкатенировать корректно с другой такой же нельзя.

Спасибо, у меня на этом всё.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[47]: Override для произвольного метода.
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.12.08 07:56
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


D>


PD>#include <string>
PD>#include <iostream>

PD>using namespace std;

PD>void DoSomething(string& str)
PD>{
PD>}

PD>void test()
PD>{
PD>    class pstring : public string
PD>    {
PD>    public :
PD>        pstring(char* p = "") : string(p) {}
PD>        bool IsPalindrom()
PD>        {
PD>            const char* start = c_str(), *end = start + length() - 1;
PD>            for ( ; start < end &&  *start == *end; start++, end--);
PD>            return start >= end;
PD>        }
PD>    };
    
PD>    pstring str;
PD>    cin >> str;
PD>    if(str.IsPalindrom())
PD>     DoSomething(str);
PD>}

PD>int main()
PD>{
PD>    test();
PD>    return 0;
PD>}
PD>

А можно пояснить специально для неграмотных — благодаря какой магии работает строчка cin >> str?


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

Я так и думал, что всё упирается в вопрос власти.

PD>В пределах pstring понятие "палиндром" существует и определяется приведенным алгоритмом, который я вправе изменить, если хочу.

Ты в любом случае можешь изменить алгоритм IsPalindrom, где бы он ни находился.

PD>Нигде, кроме как в pstring (то есть в test) об этом никто и узнать не сможет. А выпускать эту IsPalindrom во внешний мир я вовсе не желаю.

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

PD>Есть и еще один момент против хелпера. Ему protected поля и методы класса string недоступны, а мне — вполне доступны. Я этим здесь не воспользовался, а в другом случае мог бы.

Как я и говорил в самом начале — в хелпер нужно выносить всё, что можно сделать через публичный интерфейс. В данном случае (отвлекаясь от вопросов обоснованности такой реализации) ты используешь внутренние подробности устройства своего pstring, поэтому реализация внутри — хоть и зло, но оправданное.

Кстати, аналогичные причины вынудили разработчиков дотнета включить многие методы в класс строки. Поскольку это — самый популярный класс (его инстансов в среднестатистическом приложении больше, чем любых других), то вопросы производительности очень важны. Ну вот и пришлось прогнуться под изменчивый мир.
Впрочем, это не исчерпывает список причин — сами разработчики достаточно скептически относятся ко многим дизайн-решениям FCL, и в частности класса System.String. Некоторые ошибки они признают и даже исправляют в новых версиях фреймворка.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[47]: Override для произвольного метода.
От: LaPerouse  
Дата: 30.12.08 08:23
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


LP>>Полиморфизм от наследования тебе не нужен, и лишние методы от родителя в конракте CPalindrom не нужны, назови же тогда причину зачем тебе нужно наследование?


PD>На тебе ( и Синклеру) пример. Правда, вместо CString я использовал string из STL — CString с консольными приложениями не очень уместен (хотя и возможен), а флейма на тему "почему это так в MFC и так ли это должно быть" я не хочу



PD>

Черным я дописал случай использования твоего полиндрома, где будет проблема.

#include <string>
#include <iostream>

using namespace std;

void DoSomething(string& str)
{
}

void test()
{
    class pstring : public string
    {
    public :
        pstring(char* p = "") : string(p) {}
        bool IsPalindrom()
        {
            const char* start = c_str(), *end = start + length() - 1;
            for ( ; start < end &&  *start == *end; start++, end--);
            return start >= end;
        }
    };
    
    pstring str;
    cin >> str;
    if(str.IsPalindrom())
     DoSomething(str);
    std::string res = str.substr(2, 4);
}

int main()
{
    test();
    return 0;
}


Значит, пользователь получает твой полиндром и, видя, что он поддерживает интерфейс string радостно начинает делать по-привычке substring — хоба, получает кривой каст. Кстати, вот еще одна проблемка: ты не просто должен будешь переопределить методы, где создается string, для удобного пользования твоим классом, нужно еще предоставить новые методы, возвращающие твой pstring. Двойной удар по печени на ровном месте, где достаточно одного статического метода isPloyndrom.

LP>>Итак, получаем:

LP>>1. Бенефит от наследования — полиморфизм — тебе не нужен

PD>Сейчас нет. В дальнейшем может , и понадобится.


LP>>2. Метод concat, который тебе достался от предка и который тебе не нужен, мешается.


PD>Абсолютно не нужен здесь. И масса других не нужна.


Именно. Абсолютно не нужен

LP>>Так на кой черт тогда использовать наследование?


PD>Посмотри пример.


Твой пример не отвечает на этот вопрос. Он почти один в один повторяет предыдущий и ничего не доказывает.

LP>>Ты собрался закрыть в наследнике публичный метод предка? Вот тебе еще один гвоздь в твою идею


PD>А мне его и закрывать не надо. По умолчанию в языке C++ все закрывается (наследование по умолчанию приватно), так что мне здесь, наоборот, открыть их пришлось. А , собственно, что в этом плохого ? Создается специализированная версия класса, естественно, я вполне могу не хотеть, чтобы те методы, которые я считаю некорректным здесь вызывать, вызывались, так что можно и скрыть. Впрочем, ничего не скрыто в примере. Да и неважно это — класс локализован, за пределами test его просто не существует.


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

PD>Да, конечно, IsPalindrom можно было бы реализовать хелпером (в данном случае даже без дополнительного класса. хватит просто функции). Но сейчас она инкапсулирована в класс и только для его экзмепляров может вызываться, в то время как в случае хелпера ее можно будет вызывать где угодно и для любых string, чего я вовсе не хочу. А не хочу потому, что мне надо ней полная власть нужна. В пределах pstring понятие "палиндром" существует и определяется приведенным алгоритмом, который я вправе изменить, если хочу. Нигде, кроме как в pstring (то есть в test) об этом никто и узнать не сможет. А выпускать эту IsPalindrom во внешний мир я вовсе не желаю.


Это чушь.

PD>Есть и еще один момент против хелпера. Ему protected поля и методы класса string недоступны, а мне — вполне доступны. Я этим здесь не воспользовался, а в другом случае мог бы.


Это не сила, а слабость. Чтобы понять это, достаточно взять любой учебник по основам ООП и дочитать до второго абзаца, где демонстрируется преимущество сокрытия данных.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
Социализм — это власть трудящихся и централизованная плановая экономика.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.