Re[4]: Насколько необходима множ. диспетчеризация?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 08.03.06 20:19
Оценка:
Здравствуйте, remark, Вы писали:

R>Не согласен. Визитор просто позволяет вынести виртуальный метод из иерархии классов в один отдельный класс.


Мы точно под визитором одно и том же понимаем?

R>Нет, его конечно можно назвать мультиметодом для объектов (тип действия, класс),


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

R> но это называется просто методом. Диспетчерезацию по типу метода всегда выполняет сам программист, когда после точки пишет имя метода.


В классической реализации визитора имя метода Visit всегда одно и то же, а диспетчеризацию выполняет компилятор за счет перегрузки этого метода по типу возвращаемого значения.
... << RSDN@Home 1.2.0 alpha rev. 644 on Windows XP 5.1.2600.131072>>
AVK Blog
Re[4]: Насколько необходима множ. диспетчеризация?
От: VladGalkin Украина  
Дата: 08.03.06 20:30
Оценка:
Здравствуйте, remark, Вы писали:

R>Не согласен. Визитор просто позволяет вынести виртуальный метод из иерархии классов в один отдельный класс.

Но это всё равно, что сказать: "пиво просто позволяет чаще посещать туалет", умолчав о вкусовых качествах этого напитка.
Одна из основных идея visitor'а — именно полиморфизм со множественной диспетчеризацией. Можете вот книжку Александреску почитать про это.
... << RSDN@Home 1.1.4 stable rev. 510>>
ДЭ!
Re[2]: Насколько необходима множ. диспетчеризация?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 08.03.06 20:34
Оценка:
Здравствуйте, remark, Вы писали:

R>И сейчас в промышленных языках (С++/С#/Java) эту задачу просто не решить (я имею в виду, что решить, но извращаться нужно).


На C# эта задача просто решается без каких либо извращений при помощи атрибутов и делегатов. Вот реальный код, использующий это:
internal class TagLineListForm : Form
{
    public TagLineListForm()
    {
        ...

        _toolStrip.Items.AddRange(
            StripSerializer.LoadFromXmlWithDispatch(
                typeof (TagLineListForm).Assembly.GetManifestResourceStream(
                    "Rsdn.Janus.Features.MessageEditor.TagLine.EditorToolbar.xml"),
                this, // передаем указатель на обработчик типа object
                true));
                
        ...
    }

    [StripEventHandler("del")]
    private void DeleteTagLine()
    {
        ...
    }

    [StripEventHandler("edit")]
    private void EditTagLine()
    {
        ...
    }

    [StripEventHandler("add")]
    private void AddTagLine()
    {
        ...
    }
}

<items>
    <button text="Config.TagLine.Editor.Add" event-id="add" image="new"/>
    <button text="Config.TagLine.Editor.Edit" event-id="edit" image="editmsg"/>
    <button text="Config.TagLine.Editor.Delete" event-id="del" image="del"/>
</items>

Как видишь, без проблем обошлись без мультиметодов, встроенных в язык.
... << RSDN@Home 1.2.0 alpha rev. 644 on Windows XP 5.1.2600.131072>>
AVK Blog
Re[5]: Насколько необходима множ. диспетчеризация?
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.03.06 21:22
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>В классической реализации визитора имя метода Visit всегда одно и то же, а диспетчеризацию выполняет компилятор за счет перегрузки этого метода по типу возвращаемого значения.


Классических вариантов два. Один с перегрузкой, другой нет. Я видил даже где-то спор как лучше методы называть. Одни орали, что перегрузка удобнее, а другие, что мол так понятнее.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Насколько необходима множ. диспетчеризация?
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.03.06 21:22
Оценка:
Здравствуйте, VladGalkin, Вы писали:

VG>Одна из основных идея visitor'а — именно полиморфизм со множественной диспетчеризацией. Можете вот книжку Александреску почитать про это.


В Посетителе диспечерезация двойная (по типу объекта коллекции и по типу объекта которому передается обработка). Это конечто наверно относится к множественной диспечеризации, но это все же частный случай.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Насколько необходима множ. диспетчеризация?
От: VladGalkin Украина  
Дата: 09.03.06 07:15
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В Посетителе диспечерезация двойная (по типу объекта коллекции и по типу объекта которому передается обработка). Это конечто наверно относится к множественной диспечеризации, но это все же частный случай.


Частный случай, но уже множественной диспетчеризации . Если не изменяет память, тот же Александреску делал Visitor с более чем двойной диспетчеризацией, с помощью TypeList'ов, хотя кто его знает...
... << RSDN@Home 1.1.4 stable rev. 510>>
ДЭ!
Re: Простой пример
От: fionbio  
Дата: 10.03.06 07:50
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Собственно сабж.

К>Много читал про то, что в ряде языков мультиметоды реализуются в самом языке (CLOS, Cecil, Dylan, Self), только разбираемые примеры выглядят несколько искуственными с той точки зрения, что подобные задачи (когда результат определяется как некое "пересечение" 2-х и более типов объектов) встречаются, на мой взгляд, относительно редко. Поэтому есть мысль, что, несмотря на крутость "встроенности" мультиметодов, в реальной жизни они не так часто дают выгоду, т.к. являются интересной фенечкой лишь иногда позволяющей изящно решить задачу.

Простой, может быть, конечно, несколько дурацкий пример — GUI'шная либа со стилями. Подобная
задача обычно решается при помощи visitor / acyclic visitor, и выходит достаточно неудобоваримо.
Есть набор контролов (или виджетов, кому как больше нравится) — кнопка, поле ввода, скроллбар и пр.,
а также набор стилей — виндоус, аква, мотиф и пр. Стиль имеет вид вроде

public class Style: BaseStyle
{
  ...

  public override void Paint(Button button, ...)
  {
    ...
  }

  public override void Paint(TextBox textBox, ...)
  {
    ...
  }

  public override void Paint(ScrollBar scrollBar, ...)
  {
    ...
  }

  ...
}


соответственно в каждом контроле есть метод Paint, например

public class Button: Control
{
  ...
  public override void Paint(Style style, ...)
  {
    style.Paint(this, ...)
  }
  ...
}


Это, собственно, визитор — вызов style.Paint выбирает нужный метод
через оверлоадинг в период компиляции. В чём неудобство?
Допустим, пользователю библиотеки надо добавить ещё какой-то контрол,
например, PornView. Более того, допустим, у пользователя библиотеки есть чёткое
представление, как этот контрол должен выглядеть в стиле виндоус, аква
и пр. Что придётся делать пользователю? Извращаться — ведь интерфейс
стиля не расширишь, придётся проверять тип стиля в Paint, затем
для каждого стиля рисовать по-своему, или ещё что похуже. Нету в
BaseVisitor метода Paint(PornView pornView, ...), и ничего тут неэ
попишешь. Библиотеку менять нельзя. В общем, фигня. Подобные вещи
можно до какой-то степени облегчить при помощи Acyclic Visitor, но
это тоже не фунт изюму, и потом ещё в этом самому разбираться
придётся...

Рассмотрим, как такое решается в языке с поддержкой мультиметодов —
например, Common Lisp. (троеточия здесь, как и в случае C#, не являются
синтаксической конструкцией, а обозначают опущенные параметры)

Есть generic function, вообще не привязанный ни к какому классу:
(defgeneric paint (style control ...)
  (:documentation "Paint the CONTROL using STYLE"))


Когда делается контрол, к нему приделывается дефолтный метод
рисования, который вызывается, когда специфического метода для
данного стиля не определено. В этом случае отрисовка идёт самым
простым путём — чтоб хоть как-то отрисовать. Например, для кнопки

(defmethod paint (style (control button) ...)
  ;; рисуем плоскую некрасивую кнопку
  ...)


или для скроллбара

(defmethod paint (style (control scrollbar) ...)
  ;; рисуем плоский некрасивый скроллбар
  ...)


(другой вариант — сделать дефолтный базовый стиль и запихать все подобные
методы в один и тот же файл, это как кому удобнее)

Когда делаются стили, то в них описываются методы отрисовки известных
контролов, например для аквы

(defmethod paint ((style aqua) (conrol button) ...)
  ;; рисуем водянистую кнопку
  ...)

(defmethod paint ((style aqua) (conrol scrollbar) ...)
  ;; рисуем водянистый скроллбар
  ...)

(defmethod paint ((style aqua) (conrol textbox) ...)
  ;; рисуем водянистый текстбокс
  ...)


или для виндоус

(defmethod paint ((style windows) (conrol button) ...)
  ;; рисуем виндообразную кнопку
  ...)

(defmethod paint ((style windows) (conrol scrollbar) ...)
  ;; рисуем виндообразный скроллбар
  ...)

(defmethod paint ((style windows) (conrol textbox) ...)
  ;; рисуем виндообразный текстбокс
  ...)


Когда пользователь делает контрол porn-view, он может
сопроводить его не только дефолтной рисовалкой

(defmethod paint (style (control porn-view) ...)
  ;; нарисовать по-простому
  ...)


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

(defmethod paint ((style aqua) (control porn-view) ...)
  ;; нарисовать porn-view по-водянистому
  ...)

(defmethod paint ((style windows) (control porn-view) ...)
  ;; нарисовать porn-view по-виндовски
  ...)

(defmethod paint ((style motif) (control porn-view) ...)
  ;; нарисовать porn-view на мотив мотифа
  ...)


в свою очередь, если какой-либо ещё дядя вася использует
основную библиотеку, контрол porn-view и ещё одну либу с набором
стилей, и ему не нравится, что в стиле super-puper porn-view
рисуется по-дефолтному, он может дописать

(defmethod paint ((style super-puper) (control porn-view) ...)
  ;; нарисовать porn-view в стиле супер-пупер
  ...)


В общем, экстенсибилити не знает границ
В языках типа C# можно ещё извращаться с Reflection, всякие
Type.InvokeMember, но гораздо приятнее, когда есть поддержка языка.
Re: Насколько необходима множ. диспетчеризация?
От: Gaperton http://gaperton.livejournal.com
Дата: 10.03.06 14:38
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Собственно сабж.

К>Много читал про то, что в ряде языков мультиметоды реализуются в самом языке (CLOS, Cecil, Dylan, Self), только разбираемые примеры выглядят несколько искуственными с той точки зрения, что подобные задачи (когда результат определяется как некое "пересечение" 2-х и более типов объектов) встречаются, на мой взгляд, относительно редко. Поэтому есть мысль, что, несмотря на крутость "встроенности" мультиметодов, в реальной жизни они не так часто дают выгоду, т.к. являются интересной фенечкой лишь иногда позволяющей изящно решить задачу.

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

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

Мультиметоды решают эту проблему, устраняя вредный паттерн проектирования.
Re[5]: Насколько необходима множ. диспетчеризация?
От: remark Россия http://www.1024cores.net/
Дата: 22.04.06 22:14
Оценка: 6 (1)
Здравствуйте, AndrewVK, Вы писали:

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


R>>Не согласен. Визитор просто позволяет вынести виртуальный метод из иерархии классов в один отдельный класс.


AVK> Мы точно под визитором одно и том же понимаем?


GOF?


R>>Нет, его конечно можно назвать мультиметодом для объектов (тип действия, класс),


AVK>Мультиметод чистейшей воды, просто реализация несколько неуклюжа.


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



R>> но это называется просто методом. Диспетчерезацию по типу метода всегда выполняет сам программист, когда после точки пишет имя метода.


AVK>В классической реализации визитора имя метода Visit всегда одно и то же, а диспетчеризацию выполняет компилятор за счет перегрузки этого метода по типу возвращаемого значения.


Сейчас попробую объяснить, что я имею в виду.
Как обычно используется визитор:
IShape s = new Circle();
IVisitor v = new DrawShapeVisitor();
s->visit(v);


Что мы тут имеем? "Существительное" — фигура (IShape). "Сказуемое" — нарисовать (DrawShapeVisitor). Т.е. существует всего одно существительное, а не два (и не три). Для мультиметода надо хотя бы два существительных! Например:
IShape s1 = new Circle();
IShape s2 = new Square();
DrawInterseptionMultimethod(sq, s2);


Вот это мультиметод. Согласен. Существительных два. + есть ещё и действие — собственно мультиметодв.

А в первом случае. Есть только одно существительное и действие.
Сравним первый пример с таким:
IShape s = new Circle();
s->DrawShape();


Чем отличается? Кроме организации кода — ничем.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Насколько необходима множ. диспетчеризация?
От: remark Россия http://www.1024cores.net/
Дата: 22.04.06 22:54
Оценка:
Здравствуйте, AndrewVK, Вы писали:

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


R>>И сейчас в промышленных языках (С++/С#/Java) эту задачу просто не решить (я имею в виду, что решить, но извращаться нужно).


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


[skip]

AVK>Как видишь, без проблем обошлись без мультиметодов, встроенных в язык.


Ну возможно я немного загнул по поводу других языков, кроме с++. У C# тоже (как и у С++) есть много очень сильных сторон (в плане реализации интересных/полезных моментов). Это я полностью согласен.

А, кстати, в приведённом тобой примере можно с событием типобезопасно передать и произвольный объект с параметрами?


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Насколько необходима множ. диспетчеризация?
От: Дарней Россия  
Дата: 23.04.06 06:19
Оценка:
Здравствуйте, remark, Вы писали:

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


у GOF прямо написано, что визитор — это эмуляция множественной диспетчеризации, которая в других языках поддерживается напрямую. И в качестве примера приводится CLOS. О чем тут спорить то?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[4]: Насколько необходима множ. диспетчеризация?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 23.04.06 14:08
Оценка:
Здравствуйте, remark, Вы писали:

R>А, кстати, в приведённом тобой примере можно с событием типобезопасно передать и произвольный объект с параметрами?


Соответствие типов обеспечивается только в рантайме.
... << RSDN@Home 1.2.0 alpha rev. 646 on Windows XP 5.1.2600.131072>>
AVK Blog
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.