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[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[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[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[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[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[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 для произвольного метода.
От: 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[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[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[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[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[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
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.