Re[30]: Мэйнстрим vs. Самосовершенствование :)))
От: Павел Кузнецов  
Дата: 02.11.04 22:43
Оценка:
Undying:

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


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

> ПК> Ситуация еще осложнится, если между нашим Wrapper'ом, и Array будет еще один-два слоя "библиотечных" оберток Wrapper1, Wrapper2 etc.


> Это увеличит объем ручной работы, но принципиально ситуация не меняется.


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

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


Кстати, автоматическое делегирование, фактически, эквивалентно наследованию, минус автоматическое приведение к базовому классу.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[28]: Мэйнстрим vs. Самосовершенствование :)))
От: Undying Россия  
Дата: 02.11.04 22:56
Оценка: +1 :)
Здравствуйте, Павел Кузнецов, Вы писали:

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


ПК>Никаких из этих проблем не возникает, если "вспомогательные" алгоритмы (то есть не основные для самого класса, в данном случае SomeList) будут вынесены за пределы класса.


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

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

Реальный код часто одновременно является и прикладным и оберткой, в этом случае он должен пользоваться обертками для всех ситуаций, кроме тех, которые он оборачивает.
... << RSDN@Home 1.1.2 stable >>
Re[31]: Мэйнстрим vs. Самосовершенствование :)))
От: Undying Россия  
Дата: 02.11.04 23:06
Оценка: :)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>В "Дизайн и эволюция C++" Страуструп описывал, что в ранних редакциях C++ такая возможность была, но ввиду того, что пользователи очень много ошибались, ее используя (подробности, по-моему, не приведены), ее решили убрать.


Как я понимаю, концепции интерфейсов тогда еще не было или уже была?

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


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

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


Кто ж спорит-то.

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


Так в этом-то и достоинство. В случае делегирования мы можем выбрать только те интерфейсы, которые нам действительно нужны, в случае же наследования мы такой возможности лишены.
... << RSDN@Home 1.1.2 stable >>
Re[29]: Мэйнстрим vs. Самосовершенствование :)))
От: Павел Кузнецов  
Дата: 02.11.04 23:34
Оценка:
Undying:

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


> Например, заменить пузырьковую сортировку быстрой.


Если речь идет о функции с абстрактным названием sort, то это же можно сделать и для "внешней" функции...

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


Уж точно не буду под это дело модифицировать функцию sort() класса Array Это как раз тот случай, когда я говорил о знании контекста. Для контейнера деталей у нас будет свой класс, изолирующий нас от знания, на каком из "базовых" контейнеров он построен. У этого класса, оперирующего понятиями предметной области, вполне может быть функция sort(), т.к. она является одной из его прямых обязанностей. Правда, скорее, не в самом классе контейнера деталей, а в каком-то классе, обозначающем стратегию его сортировки, с которым у контейнера деталей, если и будет связь, то ассоциативная (в смысле association — без понятия, как правильно переводится ). Вот ее-то и можно будет менять и в хвост, и в гриву по требованию заказчика.

> Кстати, в stl какой механизм используется для указания того каким образом сравниваются два элемента?


По умолчанию в подобных алгоритмах используется функтор std::less<T>, который, в свою очередь, по умолчанию использует операцию "<" для данного типа. Соответственно, пользователь имеет выбор из трех возможностей настройки поведения "стандартных" алгоритмов:
  • определить для своего типа операцию "<" (наиболее простой вариант)
  • передать в алгоритм свой функтор (самый гибкий вариант, позволяющий задавать критерии сортировки для каждого вызова каждого из алгоритмов отдельно)
  • написать специализацию для std::less<> для своего типа (пожалуй, наиболее редко используемая возможность)

    > ПК> Сначала я бы, все-таки, хотел получить представление о каких изменениях ты вел речь, а то, похоже, мы рассинхронизовались.

    >
    > Надеюсь, объяснил.

    См. выше соответствующий комментарий

    > ПК> если всем подряд приходится "толкать шарик", вовсе не факт, что хорошим решением является наследование их всех от какого-то общего класса только для того, чтобы выполнять какое-то действие с внешним объектом.


    > По-идее, каждый объект который может толкаться должен реализовывать IТолкатель, т.е. уметь возвращать характеристики толкания, далее уже эти характеристики передаются в соответствующий метод шарика и он как-то реагирует.


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

    > ПК> "Мой" подход — в том, чтобы помещать в интерфейс класса те функции, которые необходимы для обеспечения сохранности инвариантов класса (плюс устойчивость к изменениям реализации, но это уже другой разговор). Соответственно, работа с данными напрямую такому критерию не отвечает.


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


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

    > ПК> Рефакторинг я очень люблю и уважаю. Но для "внутренних" проектов, где весь код находится под контролем разработчиков. И с определенными ограничениями. Для библиотек же, "торчащих" наружу, я больше люблю и уважаю обратную совместимость.


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


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

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

    Как ты часто повторяешь одно из моих любимых высказываний: there's no silver bullet
    Posted via RSDN NNTP Server 1.9 gamma
  • Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[31]: Мэйнстрим vs. Самосовершенствование :)))
    От: prVovik Россия  
    Дата: 02.11.04 23:48
    Оценка: 1 (1)
    Здравствуйте, Павел Кузнецов, Вы писали:

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

    Ну не совсем. Тут ведь вся фишка в том, что делегированного объекта можно в рантайме задавать.
    ... << RSDN@Home 1.1.4 @@subversion >>
    лэт ми спик фром май харт
    Re[32]: Мэйнстрим vs. Самосовершенствование :)))
    От: Павел Кузнецов  
    Дата: 02.11.04 23:55
    Оценка:
    prVovik,

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


    > Ну не совсем. Тут ведь вся фишка в том, что делегированного объекта можно в рантайме задавать.


    Тоже дельное замечание. Я подразумевал статическую делегацию. Согласен, динамическая тоже вполне имеет право на жизнь.
    Posted via RSDN NNTP Server 1.9 gamma
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[29]: Мэйнстрим vs. Самосовершенствование :)))
    От: Павел Кузнецов  
    Дата: 03.11.04 01:05
    Оценка: +1
    Undying,

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


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

    И при таком разделении есть наблюдение, что периодически компоненты, которые повторно не предполагалось использовать, перетекают в категорию повторно используемых, и в этот момент хочется делать их дизайн более гибким. Поэтому обычно я люблю перестраховываться, и заранее проектировать компоненты чуть гибче, чем нужно в данный момент. Но здесь, согласен, очень важно не переступать грань, иначе overengineering ("избыточно общее проектирование"?) уже начинает становиться неудобным, затрудняя понимание системы в целом.
    Posted via RSDN NNTP Server 1.9 gamma
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[32]: Мэйнстрим vs. Самосовершенствование :)))
    От: Павел Кузнецов  
    Дата: 03.11.04 04:47
    Оценка: 40 (5)
    Undying,

    > ПК> В "Дизайн и эволюция C++" Страуструп описывал, что в ранних редакциях C++ такая возможность была, но ввиду того, что пользователи очень много ошибались, ее используя (подробности, по-моему, не приведены), ее решили убрать.


    > Как я понимаю, концепции интерфейсов тогда еще не было или уже была?


    Была. Кстати, оказалось, что я помнил неверно, и некоторые трудности, с которыми столкнулись пользователи, Страуструп привел:

    Делегирование

    В первоначальном проекте множественного наследования, который был представлен на Европейской конференции группы пользователей UNIX, состоявшейся в Хельсинки в мае 1987 г. [Stroustrup, 1987], фигурировало понятие делегирования [Agha, 1986].

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

    class B { int b; void f(); };
    class C : *p { B* p; int c; };

    Нотация : *p означает, что объект, на который указывает p, будет использоваться так, будто он представляет базовый класс для C.
    void f(C* q)
    {
       a->f(); // означает q->p->f()
    }

    <...>

    Концепция выглядела многообещающей для представления структур, требующих большей гибкости, чем может дать обычное наследование. В частности, присваивание делегирующему указателю могло бы использоваться для изменения конфигурации объекта во время исполнения. Реализация была бы тривиальной, затраты — минимальными. Поэтому данную идею испытали несколько пользователей. Много времени и сил здесь пололжил Билл Хопкинс (Bill Hopkins). К сожалению, все пользователи, применившие механизм делегирования, пострадали от серьезных ошибок и путаницы. Из-за этого возможность была исключена как из проекта, так и из Cfront версии 2.0.

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

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

    Сегодня мне кажется, что указанные проблемы имеют фундаментальный характер. Для решения первой потребовалось бы изменять таблицу виртуальных функций объекта, которому делегируется управление, если он связан с делегирующим объектом. Это плохо согласуется с языком в целом и с большим трудом поддается разумному определению. Кроме того, обнаружились примеры, когда мы хотели, чтобы два разных объекта делегировали управление одному и тому же "разделяемому" объекту. Нашлись и такие задачи, в которых нужно было делегировать управление через B* объекту производного класса D.


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


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


    Да уж... Что есть, то есть: язык монстриком получился. И со временем упрощаться не собирается...
    Posted via RSDN NNTP Server 1.9 gamma
    Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[31]: Мэйнстрим vs. Самосовершенствование :)))
    От: AndrewVK Россия http://blogs.rsdn.org/avk
    Дата: 03.11.04 09:14
    Оценка: 16 (1)
    Здравствуйте, Павел Кузнецов, Вы писали:

    >> Дотнет умеет при помощи TransparentProxy, но ценой заметной потери производительности.


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


    Увы, ценой все той же потери производительности, притом уже везде.

    ПК>Кстати, вопрос: а производительность "просаживается" и в том случае, если вызываемый метод явно определен в делегирующем классе, или только в случае, когда происходит "автоматическое" делегирование? Например:

    ПК>
    ПК>// Класс, которому будем делегировать.
    ПК>class A
    ПК>{
    ПК>   public void a() { }
    ПК>   public void b() { }
    ПК>};
    
    ПК>// Класс, который делегирует
    ПК>class B
    ПК>{
    ПК>   // Явное делегирование
    ПК>   public void a() { a_.a(); }
    
    ПК>   // Какая-то "магия" c TransparentProxy, чтобы остальные методы тоже делегировались.
    ПК>   // . . .
    
    ПК>   private A a_;
    ПК>};
    ПК>

    ПК>Будет ли в данном случае потеря производительности при вызове обоих методов, a() и b(), через интерфейс класса B, или же только при вызове b(), который делегируется неявно?

    TP работает иначе. Класс В создается неявно рантаймом. Один из способов примерно такой:
    MyRealProxy rp = new MyRealProxy(classAInstance);
    ClassA classAWrapper = (ClassA)rp.GetTransparentProxy();


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

    После этого все обращения к методам ClassA будут проходить через вызовы MyRealProxy.Invoke, который может выглядеть примерно так:
    public override IMessage Invoke(IMessage msg)
    {
        IMethodCallMessage mcm = (IMethodCallMessage)msg;
        IMethodReturnMessage rm = RemotingServices.ExecuteMessage(m_Instance, mcm);
        // Some stuff
        return rm;
    }


    Т.е. схема примерно такая — реальная работа по обработке вызовов производится RealProxy, но RP по типам с оборачиваемым классом несовместим. Для совместимости рантайм генерирует специальный псевдообъект — TP, единственная работа которого состоит в трансляции всех вызовов родительскому RP.
    ... << RSDN@Home 1.1.4 beta 3 rev. 219>>
    AVK Blog
    Re[32]: Мэйнстрим vs. Самосовершенствование :)))
    От: prVovik Россия  
    Дата: 03.11.04 09:28
    Оценка:
    Здравствуйте, AndrewVK, Вы писали:

    AVK>Т.е. схема примерно такая — реальная работа по обработке вызовов производится RealProxy, но RP по типам с оборачиваемым классом несовместим. Для совместимости рантайм генерирует специальный псевдообъект — TP, единственная работа которого состоит в трансляции всех вызовов родительскому RP.


    Я плохо рарзбираюсь в дотнете, а потому есть пара вопросов.

    1) Можно ли этот ТР использовать для своих нужд, то есть не только для ремотинга?
    2) А как оно работает? Через рефлекшн + эмит?
    ... << RSDN@Home 1.1.4 @@subversion >>
    лэт ми спик фром май харт
    Re[33]: Мэйнстрим vs. Самосовершенствование :)))
    От: AndrewVK Россия http://blogs.rsdn.org/avk
    Дата: 03.11.04 09:45
    Оценка: 10 (1)
    Здравствуйте, prVovik, Вы писали:

    V>1) Можно ли этот ТР использовать для своих нужд, то есть не только для ремотинга?


    Можно. Хотя "не для ремоутинга" не очень корректно говорить, поскольку TP это собственно ремоутинг и есть. Есть даже специальная штука для его использования в собственных нуждах в пределах одного домена — ContextBoundObject.

    V>2) А как оно работает? Через рефлекшн + эмит?


    Что именно? Если вызов метода закрываемого класса, то по дефолту рефлекшен, хотя ты можешь придумать что то свое. Если трансляция в TP, то это unmanaged stub, даже джитом не обрабатываемый.
    ... << RSDN@Home 1.1.4 beta 3 rev. 219>>
    AVK Blog
    Re[28]: Мэйнстрим vs. Самосовершенствование :)))
    От: AndrewVK Россия http://blogs.rsdn.org/avk
    Дата: 03.11.04 11:01
    Оценка: 57 (2)
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Сортировка не является основной функциональностью SomeList


    Вопрос спорный. Не стоит кидаться в крайности. Затаскивание всего в класс глупо и сложно поддерживаемо. Но ровно так же глупо следование принципам до конца — многие вещи неразрывно связаны с контейнерами, выносить их наружу неудобно, поскольку усложняет структуру библиотеки. Осюда оптимальным является некоторое среднее решение, когда часто используемые и семантически (прошу обратить внимание, семантически, а не формально) неразрывно связанные вещи вносятся в класс, а более отдаленные выносятся наружу.
    Пример из дотнета — подсистема, о которой уже неоднократно здесь упоминалось, но исключительно по ее кусочкам, без знания картины в целом. Подсистема преобразования типов.
    Преобразования большинства примитивных типов из строки присутствуют ввиде статических методов в интерфейсах самих типов, преобразование объекта в строку вобще является методом общего корня всех объектов. Это первый, самый жесткий уровень, поскольку преобразования из строки/в строку используются очень часто. Заметь, признак неформальный, формально строка среди всех прочих типов ничем не выделяется. При том всем прекрасно понятно что фактически строка является важнейшим способом представления данных для человека, и некий оверхед по наличию преобразований вполне оправдан.
    Следующий уровень, менее жесткий — преобразования некоего набора типов между собой. Набор этот выведен исходя опять же из фактического набора неких базовых типов, применяющихся очень часто.
    bool
    byte
    char
    DateTime
    decimal
    double
    short
    int
    long
    sbyte
    single
    string
    Type
    ushort
    uint
    ulong

    Типы эти между собой конертируюся классом Convert и преобразуются при помощи интерфейса IConvertible. Набор этот частично можно расширить, реализовав IConvertible в собственном классе.
    Наконец самый гибкий, но притом и самый сложный способ преобразования — механика, предоставляемая TypeDescriptor — специализированные классы, наследники TypeConverter. Эта механика предоставляет возможность преобразования произвольных тппов между собой.
    Итого мы имеем трехуровневую систему преобразований, гибкую и удобную одновременно, свободную от недостатков обоих крайностей. Для обучения(вспоминая исходную тему обсуждения) это конечно не зашибись, зато обалденно удобно.

    ПК>Есть множество аналогичных алгоритмов, которые нужны пользователю


    См. выше.

    ПК>Повторное использование алгоритмов


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

    ПК>Расширяемость множества алгоритмов


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


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


    ПК>Никаких из этих проблем не возникает, если "вспомогательные" алгоритмы (то есть не основные для самого класса, в данном случае SomeList) будут вынесены за пределы класса.


    Опять то же самое — ты подменяешь проблемы интерфейсов проблемами реализации.
    ... << RSDN@Home 1.1.4 beta 3 rev. 219>>
    AVK Blog
    Re[34]: Мэйнстрим vs. Самосовершенствование :)))
    От: prVovik Россия  
    Дата: 03.11.04 11:25
    Оценка:
    Здравствуйте, AndrewVK, Вы писали:

    V>>1) Можно ли этот ТР использовать для своих нужд, то есть не только для ремотинга?

    AVK>Можно. Хотя "не для ремоутинга" не очень корректно говорить, поскольку TP это собственно ремоутинг и есть. Есть даже специальная штука для его использования в собственных нуждах в пределах одного домена — ContextBoundObject.
    Хм, а уменя при первом знакомстве с ремоутингом, сложилось впечатление что ТР — это средство для работы с ContextBoundObject а не наоборот...

    V>>2) А как оно работает? Через рефлекшн + эмит?


    AVK>Что именно? Если вызов метода закрываемого класса, то по дефолту рефлекшен, хотя ты можешь придумать что то свое.

    это понятно.

    AVK>Если трансляция в TP, то это unmanaged stub, даже джитом не обрабатываемый.

    хех, интересно, спасибо.
    ... << RSDN@Home 1.1.4 @@subversion >>
    лэт ми спик фром май харт
    Re[34]: Мэйнстрим vs. Самосовершенствование :)))
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 17:55
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Смотрел я когда-то на него. Как скриптовый язык хорош. Для написания больших систем — вряд ли. Можно ограничиться одним моментом:

    ПК>

    ПК>In Ruby, classes are never closed: you can always add methods to an existing class.

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

    Не о том говоришь. Я тебе предлагал на общую канву изложения концепций ООП обратить внимание. И на общее видение ООП в этом языке.

    Язык не типизированный и с большим количеством своих тараканов. Но как в нем сделан ООП мне понравилось. А синглтон-методы вообще красота.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[32]: Мэйнстрим vs. Самосовершенствование :)))
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 17:55
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    Да ты чтобы не повторяться нашел бы хотя бы один реальный случай когда ArrayList.Sort помешал бы кому нибудь. Тогда можно было бы обсудить как это подтверждается твоей теорией. А так пустые разговоры. "Большие проекты", "проблемы". Тут не только ты занимашся большими проектами. И поверь, проблем подобного рода я что-то на практике не встречал.

    Вот давича добавил в AST-класс RTypeUdt описывающий определяемые пользователем типы (интерфейсы, классы, структуры) следующий набор методов:
    public void ForEachMember<T>(Action<T> action)
            where T : RTypeMember
    public RMemberMethod[] FindMethods(string name)
    public T[] FindMember<T>(RModifier modifiers)
            where T : RTypeMember
    public T[] FindMember<T>(Predicate<T> predicate)
            where T : RTypeMember
    public int RemoveAll<T>()
        where T : RTypeMember
    public int RemoveAll<T>(RModifier modifiers)
        where T : RTypeMember
    public int RemoveAll<T>(Predicate<T> predicate)
        where T : RTypeMember


    Потенциально их конечно можно было бы впихнуть куда угодно. Но тут они удобнее. Что касается поддрежки... Всего классов в проекте около 200. У RTypeUdt есть несколько наследников (RTypeInterface, RTypeClass, RTypeStruct). И никаких проблем с поддержкой. И вообще, никаких проблем. Все удобно, красиво и шустро. Когда пишешь код, то мыслишь в свете объектов. Найти все методы класса. Удалить публичные свойства класса. И т.п.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[21]: Обновление
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 22:06
    Оценка: +1
    Здравствуйте, Сергей Губанов, Вы писали:

    СГ>Обероны, еще со времен Модулы регистрозависимые (БОЛЬШИЕ и маленькие буквы — считаются разными символами), это только Паскаль был регистронезависимым.


    Ключевые слова заглавными буквами читаются крайне тяжело. Так что это еще один минус.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[23]: Обновление
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 22:06
    Оценка:
    Здравствуйте, Сергей Губанов, Вы писали:

    СГ>ЭТО ВСЕГО ЛИШЬ ВОПРОС ПРИВЫЧКИ.


    А што ви так волнуетэсь и кричите? Право не стоит.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[11]: Мэйнстрим vs. Самосовершенствование :)))
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 22:06
    Оценка:
    Здравствуйте, Serginio1, Вы писали:

    S> Ты немного противоречишь САМ СЕБЕ.


    Где?

    VD>>Ну, не просто так в Яве и Шарпе остались continue и есть return. Та же Дельфи и Васик долго жили без них, но в итоге иVD> в них были добавлены эти конструкции. Вред этих конструкций высасан из пальца.

    S> Так, что и тебя понять очень сложно

    А ты уверен, что мне что-то сложно понять?

    S> Всетаки не надо задевать огульно Delphi там, где его не знаешь .


    Где я ее задевал? А на счет не знаю. Я писал на дельфи 2-3 по более твоего. Просто вот уже лет 6 серьезно ею не занимался. Все не нужное со временем забывается.

    Но о Дельфи я в общем-то ничего и не говорил.

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


    Ну, ты как-нибудь определись с отношением. Дельфи и Васик среды/языки делящие одну рыночную нишу. И было бы глупо не ставить их в один ряд.

    S> Тогда лучше сравнивать ранний Паскаль с Ранним С. Во интересных сравнений найдется огромная куча.


    Небыло никакого раннего Паскаля. Был Паскль и его клоны вроде ТП и Дельфи. С тут вообще никто не бсуждал. В общем, я так и не понял цель твоего влезания в разговор.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[32]: Мэйнстрим vs. Самосовершенствование :)))
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 22:06
    Оценка: :)
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>1) Я не упоминал STL.


    Да ты из нее постоянно исходиш.

    ПК>3) В Java сделано не так, как в .Net.


    Ошибашся. Все практически идентично.

    ПК> А именно, в Java, как уже много раз было указано, функция sort() вместе с остальными утилитами типа binarySearch(), fill() и т.п. вынесена в "namespace" java.util.Arrays, который сделан классом только из-за невозможности иметь в Java "свободные" функции.


    В первый раз ты вообще-то другое написал. Ну, да ладно.

    Для особо разбирающихся в Яве и дотнете привиду другую ссылку:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemArrayClassTopic.asp

    Что называется найдите десять отличий. Те же статические сорты и бинарные поиски. Только класс называется Array. В дотнете вообще введена единая иерархия для всех типов. В Яве деление на системные и классы более явное. В дотнете даже полиморфизм массивов есть.

    ПК> Так что, если уж поминать STL, то в этом отношении в Java сделано скорее ближе к тому, как в STL, чем к тому, как в .Net


    И чем же ты возмущался тогда? Кстати, ради хомхмы попробуй найти в Яве метод сортировки для ArrayList (именно у него в дотнете метод сортировки сделан).

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


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

    >> И наезды на статические методы Sort в Яве.


    ПК>sort() в Java является статической функцией отдельного "класса" java.util.Arrays, не Array. Сделан он классом чисто номинально, т.к. "свободных" функций в Java нет.


    Модульность и области видимости однако. Понятно что после дремучего С++ — это кажется странным. Но поверь — это очень разумно.

    ПК> Никаких претензий или наездов на библиотеку Java по этому поводу у меня нет.


    Ссылку я вроде давал.

    ПК> Единственное, на что я обратил внимание, так это на то, что авторам библиотеки пришлось имитировать namespace с помощью класса из-за своеобразности языка.


    Ничего им имитировать не пришлось. В Яве есть пакеты. 1:1 нэймспэйсы. Просто язык ОО, и модульность делается на уровне классов. Класс == модуль. Плюсь собрали все связанные вещи в одном классе. Хотя бы не нужно мучиться искать. Я вот всегда хренел с того насколько сложно найти СТЛ-ные методы. Их нужно или заучить или рыться по инклюдам.

    ПК> Об этом же, насколько я его понял, говорил и INTP_mihoshi. Синклер попросил пример — ему его привели. Точка.


    Он говорил вообще о другом. Он все гнет линию, что лучшие ЯП — это ФЯ, а остальное бренно.

    ПК>Вся дальнейшая дискуссия — результат твоих реплик по совершенно другой теме, а именно предпочтению тобой размещения sort() "в самом классе, к которому она относится", "чтобы IDE показывала список методов при нажатии на точку".


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

    ПК>И? Как это все относится к тому, помещать ли функцию sort() в класс Array?


    Про сортировку ты разговор начал
    Автор: Павел Кузнецов
    Дата: 29.10.04
    . Так что с тебя и спрос.

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


    А про объект Синклер у меня спрашивал? Или вот это не твои слова:

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

    Ты говоришь о другой ситуации, а именно о помещении функции sort в класс Array. Дело спорное, т.к. нарушает Open-Closed Principle, но вопрос совсем отдельный.


    >> Хотя как в Яве могут быть методы не экземплярные и не статические одновременно?


    ПК>Елки-палки, лес густой Я именно об этом вместе с INTP_mihoshi и говорил,


    Напомню, утверждение INTP_mihoshi-а:

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


    ПК> что в Java нет "свободных" функций, и поэтому приходится создавать "липовые" "классы" вместо namespace.


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

    ПК> Никаких претензий к дизайну библиотеки Java в этом отношении у меня нет и не было: разработчики сделали лучшее, что позволил им язык.


    Разработчики сделали язык таким чтобы он позволял в основном лучшее.

    ПК>Чтобы тебе было окончательно ясно, вот ссылка
    Автор: Павел Кузнецов
    Дата: 29.10.04
    на мое первое к тебе сообщение, в котором я, на мой взгляд, вполне ясно говорю о том, что твои претензии совершенно не по адресу, и что положение функции sort() вопрос абсолютно отдельный, не связанный с тем примером, который я привел.


    Гы. Именно в этом сообщении ты Sort и приплел. Заметь, я тебе сказал:

    И вообще, если все методы (пусть и статические) помещать в класс к которому они относятся, то любой дурак нажав точку в IDE получит их список.


    На что ты ответил:

    Ты говоришь о другой ситуации, а именно о помещении функции sort в класс Array.


    При том, что я ни слова не сказал, ни про Array (хотя какая разница Array или Arrays?), ни про sort.

    ПК>P.S. Честно говоря, я уже окончательно потерял надежду что-то тебе объяснить.


    А что объяснить то пытался?

    ПК> Сам не знаю, зачем я это сообщение написал, ибо, думаю, абсолютно бесполезно это...


    Да, уж больно тяжело навязывать нудобные подходы обосновывая их необходиость простотой поддржки и гибкостью. Хотя ни одного примера усложнения или негибкости привести не удается.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
    Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Re[32]: Мэйнстрим vs. Самосовершенствование :)))
    От: VladD2 Российская Империя www.nemerle.org
    Дата: 03.11.04 22:06
    Оценка: +1 -1
    Здравствуйте, Павел Кузнецов, Вы писали:

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


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

    ПК>
  • Есть два класса: Date и String. Методом какого класса является функции: 1) преобразования даты в строку; 2) преобразования строки в дату?

    Очень сильно зависит от того как интерпретировать Date (в дотнете он называется DateTime) строку у же давно почти все рассматривают как встроенный тип. По этому наличие в интерфейсе других типов методов преобразования в строку уже никого не спущет. Ну, почти никого. Стало быть метод типа to_s/ToStrong() прекрасно проходит. C Date сложнее. Тут можно считать, что это такой же системный тип и его применение тастолько часто, что удобно иметь его под ругой. С другой стороны можно скзать, что тип вроде DateTime все же не стольк часто используем и метод преобразования в строке хотя и был бы наиболее удобен, но приведет к захламлению строкового класса. В этом случае имеет смысл вынести метод преобразования в отдельный класс. Однако уж если мы работаем с DateTime, то преобразование в строку точно является часто используемой операцией.

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

    Однако ребатки из МС все же дадумались реализовать специальный интерфейс для IConvertible позволющий преобразовывать стандартные типы универсальным обрзом. К сожалению реализация этого интерфейса не выведена наружу. Но если очень хочется можно воспользоваться приведением. Опять же в дело вступает ООП со вторым своим принципом — полиморфизмом:
    // Вариант с динамической типизацией
    static DateTime ToDateTime(object obj)
    {
        return ((IConvertible)obj).ToDateTime(null);
    }
    
    static string ToString(object obj)
    {
        return ((IConvertible)obj).ToString(null);
        // или: return obj.ToString();
    }
    
    // Вариант со статической типизацией в C# 2.0
    static DateTime ToDateTime<T>(T value) where T : IConvertible
    {
        return value.ToDateTime(null);
    }
    
    static string ToString<T>(T value) where T : IConvertible
    {
        return value.ToString(null); // IConvertible.ToString(IFormatProvider)
    }
    
    static void Main(string[] args)
    {
        Console.WriteLine(ToDateTime("01.02.2004").AddYears(2));
        Console.WriteLine(DateTime.Parse("01.02.2004").AddMinutes(10));
    }


    Кроме того имеется класс Convert туевой хучей методов, но они уже не примитивный парсинг или первед в строку, а довольно сложный и интеллектуальный конвертер иногда делающий дополнительные неявные приведения типов и т.п.


    ПК>
  • Методом какого класса является функции преобразования: 1) целого в строку; 2) строки в целое? Есть ли какое-либо отличие этого примера от предыдущего?

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

    ПК>
  • Есть два класса: Date и DateDifference. Методом какого класса являются функции: суммы/разницы двух дат, суммы/разницы двух DateDifference, суммы Date и DateDifference?

    Сумма двух дат это полный бред, а разница совершенно нормальное явление. Собственно разница и есть то что ты называешь DateDifference. В дотнете это называется TimeSpan. Совершенно интуитивно понятно, что работать в этом случае удобно (а значит нужно) с помощью перегруженных операторов. Честно говоря где объявлены эти операторы мне по барабану. Главное чтобы они не были объявлены глобальными функциями

    Пошел... глянул как осбтоят дела в дотнете. Операторы DateTime/TimeSpan и DateTime/DateTime объявлены в классе DateTime. Операторы TimeSpan/TimeSpan в классе TimeSpan. DateTime/TimeSpan можно было бы разместить где и в TimeSpan, а DateTime/DateTime физически нелзя разместить в чужом классе (намеренные ограничения языка).

    ПК>
  • Есть классы: Matrix и Vector. Методами какого класса являются функции: 1) умножения матрицы на вектор (результат — матрица); 2) умножения двух векторов по схеме "строка на столбец" (результат — матрица); 3) скалярного умножения векторов (результат — число); 4) афинных трансформаций вектора в соответствии с заданной матрицей преобразования?

    Пусть о Matrix и Vector голова болит у тех кто занимается математикой. Думаю, что рзницы с теми же DateTime/TimeSpan особой нет.

    ПК>И, наконец:


    ПК>
  • Есть классы, контролирующие размерность: Velocity (v, скорость), Acceleration (a, ускорение), Length (l, длина), Time (t, время). Методами каких классов являются функции, соответствующие следущим выражениям: 1) l = v * t; 2) v = l / t; 3) v2 = v * v; 4) a = v / t; 5) v = a * t; 6) t2 = t * t; 6) l = 1 / 2 * a * t * t

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

    Вот, кстати, хорошим прмером являются методы AddXxx из того же дотнетного DateTime-а:
    public DateTime Add(TimeSpan value);
    public DateTime AddDays(double value);
    public DateTime AddHours(double value);
    public DateTime AddMilliseconds(double value);
    public DateTime AddMinutes(double value);
    public DateTime AddMonths(int months);
    public DateTime AddSeconds(double value);
    public DateTime AddTicks(long value);
    public DateTime AddYears(int value);

    конечно без проблем было бы вынести это дело в отдельные функции. Но это было бы неудобно и приводило бы к возможности случайного неверного использования. Не создавать же для минут, секунд, часов и т.п. отдельные типы данных? Или не заниматься явной конвертацией этих понятий в TimeSpan? Когда я вызвают данне методы у экземляра даты, я прекрасно понимаю, что делаю и мои действия идут четко в конве моего мышления. Если же я вынесу их в глобальные функции, то я срузу получу:
    1. Жутчайшее неудобство поиска этих функций. На практике это приведет к тому, что многие их просто ненайдут и, в итоге, напишут собственные реализации (обычно более кривые).
    2. Мышление в привычных мозгу терминах и понятиях (добавить к дате временной срез, вычесть и даты другую...).
    3. Меньшую длинну имени функции, так как AddYearsToDateTime. Ну, или имена приводящие к неверному использованию этих методов.

    При этом я не вижу ни одного минуса у данного подхода в данном случае. И не нужно тут петь про наследование и т.п. Это, во-первых, не проблема (придуманная проблема не существующая в реальной жизни), а во-вторых, DateTime — это структура от котрой нельзя наследоваться.
    ... << RSDN@Home 1.1.4 beta 3 rev. 207>>
  • Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.