Принцип подстановки Барбары Лисков
От: Alex Dav Россия  
Дата: 27.12.06 12:24
Оценка:
Расскажите, плиз, только попроще и по русски
Спасибо.
Re: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 27.12.06 12:35
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Расскажите, плиз, только попроще и по русски

AD>Спасибо.

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

FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT
Above is a paraphrase of the Liskov Substitution Principle (LSP). Barbara Liskov first
it as follows nearly 8 years ago. What is wanted here is something like the following substitution property: If
for each object o of type S there is an object o of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o is substituted for o then S is a subtype of T.


И пример кода нарушающего этот принцип:

void DrawShape(const Shape& s)
{
    if (typeid(s) == typeid(Square))
        DrawSquare(static_cast<Square&>(s));
    else if (typeid(s) == typeid(Circle))
        DrawCircle(static_cast<Circle&>(s));
}
ДЭ!
Re: Принцип подстановки Барбары Лисков
От: Sshur Россия http://shurygin-sergey.livejournal.com
Дата: 27.12.06 12:47
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Расскажите, плиз, только попроще и по русски

AD>Спасибо.


Введение в программу новых порожденных типов не должно изменять логику работы функционала, зависящего от базовых типов. Чаще всего нарущения допусткаются в коде, использующем инфоррмацию о типах в runtime.
Шурыгин Сергей

"Не следует преумножать сущности сверх необходимости" (с) Оккам
Re: Принцип подстановки Барбары Лисков
От: LaptevVV Россия  
Дата: 27.12.06 13:42
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Расскажите, плиз, только попроще и по русски

В ООП примерно так: Объект производного типа является также и объектом базового типа; на место объекта базового типа всегда может быть подставлен объект производного типа... То же касается и указателей и ссылок...
Обратное — неверно! Всякий будильник (производный тип) является часами (базовый тип), но не всякие часы — будильник.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Принцип подстановки Барбары Лисков
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 27.12.06 13:43
Оценка:
Здравствуйте, Sshur, Вы писали:

S> Чаще всего нарущения допусткаются в коде, использующем инфоррмацию о типах в runtime.


"Кто про что, а лысый про расческу." (с) Народная мудрость
http://www.smalltalk.ru | << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[2]: Принцип подстановки Барбары Лисков
От: Alxndr Германия http://www.google.com/profiles/alexander.poluektov#buzz
Дата: 27.12.06 17:04
Оценка:
Здравствуйте, VladGalkin, Вы писали:

VG>Здравствуйте, Alex Dav, Вы писали:


VG>

VG>FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT
VG>Above is a paraphrase of the Liskov Substitution Principle (LSP). Barbara Liskov first
VG>it as follows nearly 8 years ago. What is wanted here is something like the following substitution property: If
VG>for each object o of type S there is an object o of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o is substituted for o then S is a subtype of T.


VG>И пример кода нарушающего этот принцип:


VG>
VG>void DrawShape(const Shape& s)
VG>{
VG>    if (typeid(s) == typeid(Square))
VG>        DrawSquare(static_cast<Square&>(s));
VG>    else if (typeid(s) == typeid(Circle))
VG>        DrawCircle(static_cast<Circle&>(s));
VG>}
VG>


Вообще-то это иллюстрация нарушения Open-Closed Principle. Похоже, к LSP пример иммет мало отношения

Классический пример нарушения — пресловутый квадрат, (не) являющийся подтипом прямоугольника (или наоборот )
Re[3]: Принцип подстановки Барбары Лисков
От: dottedmag Мальта http://dottedmag.net/
Дата: 27.12.06 18:11
Оценка: +1
Здравствуйте, Alxndr, Вы писали:

A>Вообще-то это иллюстрация нарушения Open-Closed Principle. Похоже, к LSP пример иммет мало отношения


Одно другому не мешает. LSP — это всего лишь OCP, применённый к классам.
Re[2]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.12.06 00:51
Оценка: 6 (1)
Здравствуйте, VladGalkin, Вы писали:

VG>И пример кода нарушающего этот принцип:


VG>
VG>void DrawShape(const Shape& s)
VG>{
VG>    if (typeid(s) == typeid(Square))
VG>        DrawSquare(static_cast<Square&>(s));
VG>    else if (typeid(s) == typeid(Circle))
VG>        DrawCircle(static_cast<Circle&>(s));
VG>}
VG>


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

Забавно было бы осудить насколько этот принцип вообще состоятелен? Не вызван ли он скудностью выразительных средств языка?

Я согласен, что если думать в понятиях ООП, то все выглядит более менее нормально. Но ведь можно думать и по другому!

Возьмем тот же паттерн Посетитель. Вся его суть заключается в попытке ранушить этот принцип. Мы как бы пытаемся изменить направление нашего взгляда на проблему. Вывести метод за пределы класса. Причем в ООЯ это получается очень неуклюже. А на языке с паттерн-матчингом просто и элегантно:
DrawShape(shape : Shape) : void
{
  | square is Square => DrawSquare(square);
  | circle is Circle => DrawCircle(circle);
    | _                => DoDefaultAction(shape);
}

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

В общем, эти прицыпы рассчитаны на ООП. А ООП не всегда лучший выбор. Так что по-моему не все так однозначно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.12.06 00:51
Оценка:
Здравствуйте, Sshur, Вы писали:

S>Введение в программу новых порожденных типов не должно изменять логику работы функционала, зависящего от базовых типов. Чаще всего нарущения допусткаются в коде, использующем инфоррмацию о типах в runtime.


На самом деле это догма. А по жизни могут быть разные приоритеты. Например, иногда просто нет возможности ввести виртуальные члены или не хочется создавать наследников. При этом внешнее решение может оказаться очень выгодным. Кое как проблему позволяет решить паттерн Посетитель, но увы у него море своих проблем.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Принцип подстановки Барбары Лисков
От: Sshur Россия http://shurygin-sergey.livejournal.com
Дата: 28.12.06 06:02
Оценка: :)
Здравствуйте, VladD2, Вы писали:

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


S>>Введение в программу новых порожденных типов не должно изменять логику работы функционала, зависящего от базовых типов. Чаще всего нарущения допусткаются в коде, использующем инфоррмацию о типах в runtime.


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



Нет, на самом деле это классика кун-фу
Автор: Sinclair
Дата: 19.01.06
.
Шурыгин Сергей

"Не следует преумножать сущности сверх необходимости" (с) Оккам
Re[4]: Принцип подстановки Барбары Лисков
От: gbear Россия  
Дата: 28.12.06 08:08
Оценка: -1
Здравствуйте, dottedmag, Вы писали:

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


A>>Вообще-то это иллюстрация нарушения Open-Closed Principle. Похоже, к LSP пример иммет мало отношения


D>Одно другому не мешает. LSP — это всего лишь OCP, применённый к классам.


Ещё как мешает... LSP, вообще-то, имеет давольно опосредованное отношение к классам, как таковым, и к ООП — в частности. А Вы, скорее всего путаете, subtyping и subclassing.

---
С уважением, Сиваков Конастантин.
Re[3]: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 28.12.06 08:29
Оценка:
Здравствуйте, VladD2, Вы писали:

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

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

Чувство возникло и у меня (о pattern matching узнал угадайте сами при знакомстве с каким языком программирования ), однако я забил на него, поскольку надо четко осознавать что одним ООП и виртуальными методами все не исчерпывается, и профессионал должен хотя бы знать, хм, иные (я нарочно не написал "более мощные" ) концепции и средства (почему собственно сейчас и пытаюсь читать SICP )

VD>Забавно было бы осудить насколько этот принцип вообще состоятелен? Не вызван ли он скудностью выразительных средств языка?

VD>Я согласен, что если думать в понятиях ООП, то все выглядит более менее нормально. Но ведь можно думать и по другому!
Все зависит от точки зрения и концепции. В более простом, перефразированном виде концепция LSP звучит как

Subtypes must be substitutable for their base types

(С) Robert Martin. А при pattern matching такое определение, фактически, выкидывается. Но никто
и не говорит использовать LSP при pattern matching.

VD>Возьмем тот же паттерн Посетитель. Вся его суть заключается в попытке ранушить этот принцип. Мы как бы пытаемся изменить направление VD>нашего взгляда на проблему. Вывести метод за пределы класса. Причем в ООЯ это получается очень неуклюже. А на языке с VD>паттерн-матчингом просто и элегантно


Тут уже приводили цитату про паттерны GoF и динамические языки В данном случае она также справедлива на 99,9%.

VD>В общем, эти прицыпы рассчитаны на ООП. А ООП не всегда лучший выбор. Так что по-моему не все так однозначно.

VD>Тут уже пробегала цитата про паттерны GoF и динамические языки

Я, собственно, в контексте только ООП его и рассматривал, т.к. человек, видимо, хотел услышать ответ применительно к ООП , однако я рад таким развернутым замечаниям и дискуссии.
ДЭ!
Re: Принцип подстановки Барбары Лисков
От: gbear Россия  
Дата: 28.12.06 08:36
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Расскажите, плиз, только попроще и по русски

AD>Спасибо.

ЕМНИП, звучит он примерно так:


Если подстановка типа A, вместо типа B не приводит к изменению поведения программы P, то тип A, явялется подтипом B.


LSP, ЕМНИП, является [первой?] попыткой (не очень удачной, ИМХО) сформулировать положения т.н. behavioural subtyping.

В свое время имел неосторожность затронуть данный вопрос (см. Кто автор?
Автор: cranky
Дата: 30.07.05
)

---
С уважением, Сиваков Константин
Re[5]: Принцип подстановки Барбары Лисков
От: dottedmag Мальта http://dottedmag.net/
Дата: 28.12.06 08:44
Оценка:
Здравствуйте, gbear, Вы писали:

G> Ещё как мешает... LSP, вообще-то, имеет давольно опосредованное отношение к классам, как таковым, и к ООП — в частности. А Вы, скорее всего путаете, subtyping и subclassing.


Я прекрасно знаю разницу между subtyping и subclassing. А вам бы неплохо узнать, что в ОО-языках типы выражаются классами.
Re[3]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 28.12.06 09:37
Оценка: +3
Здравствуйте, VladD2, Вы писали:

VD>На самом деле это догма.

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

VD> А по жизни могут быть разные приоритеты.

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

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

Не зацикливайся на ООП, говоря проще — код, который пользуется некоторым функционалом по заранее оговоренному контракту, не должен зависеть от конкретной реализации этого контракта.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Мы уже победили, просто это еще не так заметно...
Re[2]: Принцип подстановки Барбары Лисков
От: Трурль  
Дата: 28.12.06 12:18
Оценка: +1
Здравствуйте, gbear, Вы писали:

G>LSP, ЕМНИП, является [первой?] попыткой (не очень удачной, ИМХО) сформулировать положения т.н. behavioural subtyping.


А именно поэтому говорить о нарушении этого принципа — примерно то же, что говорить о нарушении принципа наименьшего действия.
Re[2]: Принцип подстановки Барбары Лисков
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 28.12.06 15:06
Оценка: 5 (2)
Здравствуйте, LaptevVV, Вы писали:

LVV>Обратное — неверно! Всякий будильник (производный тип) является часами (базовый тип), но не всякие часы — будильник.


Я бы сказал несколько иначе. Существуют две функции:

1) Измерение времени.
2) Выдача сообщения (например, звонка) по сигналу.

Эти функции могут быть реализованы как в одном устройстве, так и в разных. Это я к тому, что далеко не всякий будильник является или может являться часами.
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[2]: Принцип подстановки Барбары Лисков
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 28.12.06 15:17
Оценка:
Здравствуйте, VladGalkin, Вы писали:

VG>И пример кода нарушающего этот принцип:

VG>
VG>void DrawShape(const Shape& s)
VG>{
VG>    if (typeid(s) == typeid(Square))
VG>        DrawSquare(static_cast<Square&>(s));
VG>    else if (typeid(s) == typeid(Circle))
VG>        DrawCircle(static_cast<Circle&>(s));
VG>}
VG>


Странно, следующий код:

TYPE Message = ABSTRACT RECORD END;

...

PROCEDURE (this: MyObject) HandleMessage (VAR msg: Message);
BEGIN
WITH msg: KeyDownMsg DO ... | msg: MouseMoveMsg DO ... ELSE ... END
END HandleMessage;

вроде аналогичный, а ничего не нарушает
Re[3]: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 28.12.06 15:42
Оценка: :))
Здравствуйте, Сергей Губанов, Вы писали:

СГ>Странно, следующий код:

СГ>TYPE Message = ABSTRACT RECORD END;
СГ>...
СГ>PROCEDURE (this: MyObject) HandleMessage (VAR msg: Message);
СГ>BEGIN
СГ> WITH msg: KeyDownMsg DO ... | msg: MouseMoveMsg DO ... ELSE ... END
СГ>END HandleMessage;

"И эти люди запрещают мне ковырятся в носу" (C) Это ж какой, пардон, "синтаксический оверхед", для всех этих msg: KeyDownMsg DO, вместо одного "msg.DoSomething()"

СГ>вроде аналогичный, а ничего не нарушает


Почему не нарушает? Потому что Вы так утверждаете? Я не знаю Oberon-2 (насколько я понял поддержка ООП появилась в нем). Вобщем почитал я про Oberon-2, и насколько понял, ООП там в понимании Вирта. Вот цитата:

Oberon-2 introduced limited reflection, methods ("type bound procedures"), and single inheritance ("type extension") without interfaces or mixins. Method calls were resolved at run-time, and limited polymorphism was possible by either overloading methods or by explicit typecase ("with" statement).


Дискутировать на тему Oberon, синтаксического оверхеда и Вирта я не намерен, говорю сразу.
ДЭ!
Re[4]: Принцип подстановки Барбары Лисков
От: Сергей Губанов Россия http://sergey-gubanov.livejournal.com/
Дата: 28.12.06 16:17
Оценка:
Здравствуйте, VladGalkin, Вы писали:

СГ>>TYPE Message = ABSTRACT RECORD END;

СГ>>...
СГ>>PROCEDURE (this: MyObject) HandleMessage (VAR msg: Message);
СГ>>BEGIN
СГ>> WITH msg: KeyDownMsg DO ... | msg: MouseMoveMsg DO ... ELSE ... END
СГ>>END HandleMessage;

VG>вместо одного "msg.DoSomething()"


У объекта сообщения Message не может быть метода DoSomething!!!
У него вообще ничего нету, это абстрактный тип-пустышка = ABSTRACT RECORD END.
Откуда сообщению знать как его будет обрабатывать какой-то конкретный получатель?
У сообщения не может быть метода его обработки — cообщение пришло, а уж как на него реагировать — это целиком в компетенции получателя.

Несколько примеров типов объектов сообщений:
  TYPE
    CursorMessage = ABSTRACT RECORD (RequestMessage)
      x, y: INTEGER
    END;

    DropMsg = RECORD (TransferMessage)
      view: Views.View;
      isSingle: BOOLEAN;
      w, h, rx, ry: INTEGER
    END;

    EditMsg = RECORD (RequestMessage)
      op: INTEGER;
      modifiers: SET;
      char: CHAR;
      view: Views.View;
      w, h: INTEGER;
      isSingle, clipboard: BOOLEAN
    END;

    MarkMsg = RECORD (Views.CtrlMessage)
      show, focus: BOOLEAN
    END;

    Message = Views.CtrlMessage;

    PageMsg = RECORD (Views.CtrlMessage)
      op, pageX, pageY: INTEGER;
      done, eox, eoy: BOOLEAN
    END;

    PollCursorMsg = RECORD (CursorMessage)
      cursor: INTEGER;
      modifiers: SET
    END;

    PollDropMsg = RECORD (TransferMessage)
      mark, show: BOOLEAN;
      type: Stores.TypeName;
      isSingle: BOOLEAN;
      w, h, rx, ry: INTEGER;
      dest: Views.Frame
    END;

    PollFocusMsg = EXTENSIBLE RECORD (Views.CtrlMessage)
      focus: Views.Frame
    END;

    PollOpsMsg = RECORD (Views.CtrlMessage)
      type, pasteType: Stores.TypeName;
      singleton: Views.View;
      selectable: BOOLEAN;
      valid: SET
    END;

    PollSectionMsg = RECORD (Views.CtrlMessage)
      focus, vertical: BOOLEAN;
      wholeSize, partSize, partPos: INTEGER;
      valid, done: BOOLEAN
    END;

    ReplaceViewMsg = RECORD (RequestMessage)
      old, new: Views.View
    END;

    RequestMessage = ABSTRACT RECORD (Views.CtrlMessage)
      requestFocus: BOOLEAN
    END;

    ScrollMsg = RECORD (Views.CtrlMessage)
      focus, vertical: BOOLEAN;
      op, pos: INTEGER;
      done: BOOLEAN
    END;

    SelectMsg = RECORD (Views.CtrlMessage)
      set: BOOLEAN
    END;

    TickMsg = RECORD (Views.CtrlMessage)
      tick: INTEGER
    END;

    TrackMsg = RECORD (CursorMessage)
      modifiers: SET
    END;

    TransferMessage = ABSTRACT RECORD (CursorMessage)
      source: Views.Frame;
      sourceX, sourceY: INTEGER
    END;

    WheelMsg = RECORD (CursorMessage)
      done: BOOLEAN;
      op, nofLines: INTEGER
    END;

Например, рассмотрим сообщение WheelMsg:

TYPE WheelMsg (CursorMessage)
Это сообщение посылается, когда колесо на мыши с колесом поворачивается.

done: BOOLEAN
Если отображение обрабатывает это сообщение, оно должно установить флаг done в TRUE.

op: INTEGER
Показывает, какой тип события колеса мыши произошел. Используются те же константы, что и для прокрутки, но допустимы только следующие из них: incPage, decPage, incLine and decLine.

nofLines: INTEGER nofLines >= 1
Если op или icnLine, или decLine, то nofLines показывает, сколько строк должно быть прокручено. Для incPage и decPage это значение не определено.



Кстати, это Component Pascal, а не Oberon-2, что видно по использованному ключевому слову ABSTRACT.
Re[5]: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 28.12.06 16:23
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>У объекта сообщения Message не может быть метода DoSomething!!!

СГ>У него вообще ничего нету, это абстрактный тип-пустышка = ABSTRACT RECORD END.
СГ>Откуда сообщению знать как его будет обрабатывать какой-то конкретный получатель?
СГ>У сообщения не может быть метода его обработки — cообщение пришло, а уж как на него реагировать — это целиком в компетенции получателя.

Хм, похоже на события в C#. Поскольку, если "абстрактный тип — пустышка", то важен сам факт получения сообщения. Только, пардон, объяснять надо, а то есть у меня такой недостаток, как незнание Oberon. А то что Вы привели, это скорее некий закос под "Visitor".
Выше уже писали про LSP в контексте данного паттерна. Все.
ДЭ!
Re[3]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 28.12.06 20:29
Оценка: +1
Здравствуйте, VladD2, Вы писали:

ИМХО, нет большой разицы между этим:

VG>>
VG>>void DrawShape(const Shape& s)
VG>>{
VG>>    if (typeid(s) == typeid(Square))
VG>>        DrawSquare(static_cast<Square&>(s));
VG>>    else if (typeid(s) == typeid(Circle))
VG>>        DrawCircle(static_cast<Circle&>(s));
VG>>}
VG>>


и этим:

VD>
VD>DrawShape(shape : Shape) : void
VD>{
VD>  | square is Square => DrawSquare(square);
VD>  | circle is Circle => DrawCircle(circle);
VD>    | _                => DoDefaultAction(shape);
VD>}
VD>


Не важно, есть pattern-matching в языке, или нет. Проблема всегда в том, сколько именно такого кода появится в программе. Если один фрагмент — не беда, если десяток, то...
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 29.12.06 01:10
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Не важно, есть pattern-matching в языке, или нет. Проблема всегда в том, сколько именно такого кода появится в программе. Если один фрагмент — не беда, если десяток, то...


И в чём именно проблема?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.12.06 02:06
Оценка:
Здравствуйте, VladGalkin, Вы писали:

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


Я не против ООП. Я просто хотел обратить внимание, что ООП — это тоже штампы. Осозновая это ты становишся умнее, так как будешь применять правила не как слепой верующий, а со знанием дела.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.12.06 02:06
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Не важно, есть pattern-matching в языке, или нет. Проблема всегда в том, сколько именно такого кода появится в программе. Если один фрагмент — не беда, если десяток, то...


Конечно! Разница только в удобстве! Вот только получая это удосбтво начинаешь задумываться на тем не являются ли догмами многие "незыблимые принципы ООП".

На самом деле есть два подхода. Подход от функции и подход от объекта. Иногда удобен одни. Иногда другой. Подход от функции позволяет расширять функциональность не меняя классов. Это бывает очень полезно. Как я уже говорил, паттерн Посетитель решает ту же задачу, только очень убого.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.12.06 02:06
Оценка:
Здравствуйте, IB, Вы писали:

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


VD>>На самом деле это догма.

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

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

VD>> А по жизни могут быть разные приоритеты.

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

С чего бы это? Если код спроектирован разумно, то его ничто не порушит.

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

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

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

IB>Не зацикливайся на ООП, говоря проще — код, который пользуется некоторым функционалом по заранее оговоренному контракту, не должен зависеть от конкретной реализации этого контракта.

Дык, как раз я то на ООП не зацикливаюсь.
Функции могут иметь высший приоритет, в некоторых стратегиях, а данные быть вторичными.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.12.06 02:06
Оценка:
Здравствуйте, dottedmag, Вы писали:

D>Я прекрасно знаю разницу между subtyping и subclassing. А вам бы неплохо узнать, что в ОО-языках типы выражаются классами.


Кое-кто считает Сэлф и Руби ООЯ.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.12.06 05:13
Оценка:
Здравствуйте, IT, Вы писали:

ГВ>>Не важно, есть pattern-matching в языке, или нет. Проблема всегда в том, сколько именно такого кода появится в программе. Если один фрагмент — не беда, если десяток, то...


IT>И в чём именно проблема?


Только в количестве.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[6]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 29.12.06 06:17
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>>>Не важно, есть pattern-matching в языке, или нет. Проблема всегда в том, сколько именно такого кода появится в программе. Если один фрагмент — не беда, если десяток, то...


IT>>И в чём именно проблема?


ГВ>Только в количестве.


Ну так функционал всё равно писать надо, много его или мало.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 29.12.06 08:21
Оценка:
Здравствуйте, Сергей Губанов, Вы писали:

СГ>У объекта сообщения Message не может быть метода DoSomething!!!

СГ>У него вообще ничего нету, это абстрактный тип-пустышка = ABSTRACT RECORD END.
СГ>Откуда сообщению знать как его будет обрабатывать какой-то конкретный получатель?
СГ>У сообщения не может быть метода его обработки — cообщение пришло, а уж как на него реагировать — это целиком в компетенции получателя.

Пардон, вчера сильно торопился домой, поэтому сейчас еще допишу, что данный код вообще кажется мне несколько странным, и непонятно
при чем тут LSP, если речь идет не о поведении соббщений, а о том, как они обрабатываются кем либо.
ДЭ!
Re[5]: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 29.12.06 08:47
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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


Ничто не следует расматривать как догму, ко всему стоит подходить с умом. Что еще тут сказать?

ЗЫ: У меня Janus падает при попытке отправить или сохранить сообщение, после того как я убрал использование tagline:

System.NullReferenceException: Object reference not set to an instance of an object.
at Rsdn.Janus.TagLineManager.FindAppropriateTagLine(TagLineInfos tagLineInfos, Int32 forumId)
at Rsdn.Janus.DatabaseManager.AddOutboxMessage(MessageInfo mi)
at Rsdn.Janus.MessageForm.SaveMessage(Boolean closeOnSave)
at Rsdn.Janus.MessageForm.WriteMessageHandler()
at Rsdn.Janus.Framework.StripEventDispatcher.DispatchEvent(String eventId)
at Rsdn.Janus.Framework.StripEventDispatcher.ClickHandler(Object sender, EventArgs e)
at System.Windows.Forms.ToolStripItem.RaiseEvent(Object key,



ЗЫЗЫ: Всех с наступающим Новым Годом, счастья, здоровья etc. и интересных дискуссий на RSDN.
ДЭ!
Re[6]: Принцип подстановки Барбары Лисков
От: VladGalkin Украина  
Дата: 29.12.06 09:00
Оценка:
Забыл написать, версия Janus: 1.2.0 alpha rev. 655
ДЭ!
Re[5]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 29.12.06 09:26
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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

Нет, я-то как раз смотрю на нее шире..

VD> Будучи же примененным с умом необычный подход может дать очень неожиданный результат.

Не спорю, но это имеет мало отношения к данной теме... )

VD>С чего бы это? Если код спроектирован разумно, то его ничто не порушит.

Об этом и речь. Если код завязан на конкретную реализацию не оговоренную в контракте, то код спроектирован не разумно.

VD>Вообще в ООП есть много догм. Одна из них обязательная инкапсуляция.

Это не догма, это способ выживания.. =)

VD>ООП почему-то не хочет воспринимать чистые данные.

Вот зверюга! )

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

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

VD>Дык, как раз я то на ООП не зацикливаюсь.

Да ладно.. )

VD>Функции могут иметь высший приоритет, в некоторых стратегиях, а данные быть вторичными.

И что? Данные-то тут причем...
... << RSDN@Home 1.2.0 alpha rev. 0>>
Мы уже победили, просто это еще не так заметно...
Re[7]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.12.06 14:50
Оценка:
Здравствуйте, IT, Вы писали:

ГВ>>>>[...]Если один фрагмент — не беда, если десяток, то...

IT>>>И в чём именно проблема?
ГВ>>Только в количестве.
IT>Ну так функционал всё равно писать надо, много его или мало.

А кто-то это отрицает?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[8]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 29.12.06 15:00
Оценка: +1 :)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>>>>>[...]Если один фрагмент — не беда, если десяток, то...

IT>>>>И в чём именно проблема?
ГВ>>>Только в количестве.
IT>>Ну так функционал всё равно писать надо, много его или мало.

ГВ>А кто-то это отрицает?


Так в чём тогда проблема?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.12.06 15:28
Оценка: 1 (1) +1
Здравствуйте, VladGalkin, Вы писали:

VG>

VG>FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT
VG>Above is a paraphrase of the Liskov Substitution Principle (LSP). Barbara Liskov first
VG>it as follows nearly 8 years ago. What is wanted here is something like the following substitution property: If
VG>for each object o of type S there is an object o of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o is substituted for o then S is a subtype of T.


На самом деле, это довольно забавная подмена. Если интерпретировать более точно, то LSP постулирует, что если объект, являющийся формальным подтипом S не может быть свободно подставлен вместо объекта супертипа T, то S не является подтипом T. Даже если формально S "наследует интерфейсы" T.

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

VG>И пример кода нарушающего этот принцип:


VG>
VG>void DrawShape(const Shape& s)
VG>{
VG>    if (typeid(s) == typeid(Square))
VG>        DrawSquare(static_cast<Square&>(s));
VG>    else if (typeid(s) == typeid(Circle))
VG>        DrawCircle(static_cast<Circle&>(s));
VG>}
VG>


В смысле иллюстрации здесь не хватает одного очень важного элемента:

void DrawShape(const Shape& s)
{
    if (typeid(s) == typeid(Square))
        DrawSquare(static_cast<Square&>(s));
    else if (typeid(s) == typeid(Circle))
        DrawCircle(static_cast<Circle&>(s));
    else s.Draw();
}


Если точнее, то не хватает ссылки на следование некоему контракту, предоставляемому базовым классом. Если этой строчки нет, то нарушение LSP не иллюстрируется, поскольку сам критерий Лисковой определён для ситуаций, когда программа строится на контрактах супертипов.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[6]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.06 03:53
Оценка:
Здравствуйте, IB, Вы писали:

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

IB>Нет, я-то как раз смотрю на нее шире..

Тебе кажется.

VD>> Будучи же примененным с умом необычный подход может дать очень неожиданный результат.

IB>Не спорю, но это имеет мало отношения к данной теме... )

Прямейшее. Просто ты не можешь это осознать.

VD>>С чего бы это? Если код спроектирован разумно, то его ничто не порушит.

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

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

VD>>Вообще в ООП есть много догм. Одна из них обязательная инкапсуляция.

IB>Это не догма, это способ выживания.. =)

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

VD>>ООП почему-то не хочет воспринимать чистые данные.

IB>Вот зверюга! )

Ага. И что забавно очень часто совершенно напрасно. Проектировать в ОО-стиле все подряд не эффективно. ООП не панацея.

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

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

Это прицип применим только при очень большом количестве "но". Он рассчитан на динамический полиморфизм в ООП. Меж тем бывает статический полиморфизм в функциональном стиле. Он не менее мощен и позволяет решать ряд задач существенно проще чем в ОО-стиле.

VD>>Функции могут иметь высший приоритет, в некоторых стратегиях, а данные быть вторичными.

IB>И что? Данные-то тут причем...

При том, что для фукнций данные не более чем то чеми они оперируют. Как int или double.

В общем, этот принцип применим к узкому подтипу полиморфизма. И при попытке тарктовать его более широко (без соотвествующих ограничений) становится бессмысленным и даже вредным.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Надобно подкорректировать
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 30.12.06 05:06
Оценка: 1 (1) +1
ГВ>...то LSP постулирует,

Неправильно выразился... LSP — это только критерий, которому должны удовлетворять подтипы, если мы хотим, чтобы название "подтип" было корректным. Но при этом возможна забавная коллизия, когда с точки зрения компилятора типы находятся в отношении "супертип-подтип", а с точки зрения LSP — нет.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[7]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 30.12.06 07:57
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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


VD>Контракты и интерефейсы тоже догмы той идиологии которую ты считашь единственно верной. Меж тем есть другие которые во многих случаях могут оказаться быолее эффективными.


Не могу не согласиться с данным утверждением. В качестве примера можно упомянуть излишнюю многословность контрактов и их, мягко говоря, негибкость при дальнейшем развитии системы.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: Принцип подстановки Барбары Лисков
От: IDL  
Дата: 30.12.06 10:57
Оценка:
Здравствуйте, IT, Вы писали:

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


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


VD>>Контракты и интерефейсы тоже догмы той идиологии которую ты считашь единственно верной. Меж тем есть другие которые во многих случаях могут оказаться быолее эффективными.


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


А можно по-подробнее о каких альтернативах идёт речь?
Re[7]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 30.12.06 14:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Тебе кажется.

Нет, это тебе кажется, что мне кажется..

VD>Контракты и интерефейсы тоже догмы той идиологии которую ты считашь единственно верной.

Контракты != Интерфейсы, вот интерфейсы это лишь один из способов явно оговорить контракты в ООП, понятие жэе контракта много шире и рамками ООП не ограничивается.
Поэтому вылезай из догмы о том, что я ограничен рамками ООП и ничего кроме этой идеологии не вижу. =)

VD> Если нет, то будет однобокое мышление.

Я тебя умоляю, мышление только мое не трожь..

VD>И что забавно очень часто совершенно напрасно.

Нет. Если мы решаем задачу через ООП, то совершенно не напрасно, если мы решаем ее как-то по другому, то причем здесь ООП?
Инкапсуляция один из фундаментальных принципов ООП, если он не нравится — решай задачу по другому, но ООП здесь не виновато..

VD> Проектировать в ОО-стиле все подряд не эффективно. ООП не панацея.

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

VD> Он рассчитан на динамический полиморфизм в ООП.

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

VD> Меж тем бывает статический полиморфизм в функциональном стиле. Он не менее мощен и позволяет решать ряд задач существенно проще чем в ОО-стиле.

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

VD>При том, что для фукнций данные не более чем то чеми они оперируют. Как int или double.

И что?

VD>В общем, этот принцип применим к узкому подтипу полиморфизма.

У меня такое чувство, что ты принцип ты для себя усвоил на основе примера, а не на основе того как он сформулирован.
... << RSDN@Home 1.2.0 alpha rev. 669>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 30.12.06 14:17
Оценка:
Здравствуйте, IT, Вы писали:

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

Могу только повторить, что контракты != интерфейсы, интерфейс — лишь способ явно описать контракт в ООП, со своими достоинствами и недостатками, можно пользоваться, можно не пользоваться — но сам контракт от этого никуда не денется...
... << RSDN@Home 1.2.0 alpha rev. 669>>
Мы уже победили, просто это еще не так заметно...
Re[9]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.06 16:56
Оценка: 177 (14)
Здравствуйте, IDL, Вы писали:

IDL>А можно по-подробнее о каких альтернативах идёт речь?


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

Так мы можем описывать задачу в объектах. Тогда разумно говорить о иерархии интерфесов и иерархии реализации. В этих рамках догмы ООП прекрасно работают. (ообектноориентированное программирование, ООП)

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

Так же можно описать решение задачи в виде трансформации некой модели в некий код. (мета-программирование, МП)

Еще мы можем рассматривать задачу как набор логических условий (логическое программироание).

В зависимости от задачи эффективным становится тот или иной подход.

Забавно, что в области то где ООП по идее должен быть очень силен — построении моделей — он может уступить ФП. Например, при создании компилятора надо построить модель кода (так называемое абстрактное синтаксическое дерево). Если описывать каждый элемент такой модели как отдельный класс то получается огромное количество кода. Причем 90% этого кода (а то и больше) получается написанным под копирку. Плюс появляется проблема добавления стандартных методов обрабтки этой модели. Ведь любой вид обработки приводит к необходимости добавления новых виртуальных методов к каждому классу модели! Альтернативный вариант — реализовать паттерн Посетитель. Но и этот вариант создает проблем не намного меньше чем их мешает. Учитывая то что моделей в компиляторе бывает несколько (список токенов, нетипизированное АСТ, типизированное АСТ, промежуточный код...) объем компилятора пухнет на глахах.

Что же может предложить ФП в такой ситуации?

Два решения:
1. Использовать алгеброические типы вместо классов.
2. Отказаться от ООП подхода в обработке АСТ и воспользоваться для этого отдельными полиморфными функциями.

На этом месте имеет смысл остановить чтение моего сообщения и пойти прочитать статью Nemerle
Автор(ы): Сергей Туленцев, Владислав Чистяков
Дата: 23.05.2006
Производительность труда программиста в основном зависит от самого программиста. Однако даже самый опытный и знающий программист мало что может без подходящего инструмента. Эта статья открывает цикл статей об одном из таких инструментов, еще мало известном среди программистов, но очень многообещающем. Язык Nemerle, о котором пойдет речь в этих статьях, на первый взгляд очень похож на слегка улучшенный C#, но привносит многое из передовых исследовательских языков. Данная статья рассказывает об отличиях Nemerle от C# (как наиболее близкого языка)и является неформальным введением в язык.
(особенно ее резделы про сопоставление с образцом и варианты).

Так вот алгеброические типы (variant-ы в терминах Немерле) позволяют описать замкнутый набор типов. Например, для простого АСТ (арифмитических выражений) он может выглядеть так:
public variant Expr
{
  | Literal { value : double; }
  | Call    { name : string; parms : list[Expr]; }
  | Plus    { expr1 : Expr; expr2 : Expr; }
  | Minus   { expr1 : Expr; expr2 : Expr; }
  | Mul     { expr1 : Expr; expr2 : Expr; }
  | Div     { expr1 : Expr; expr2 : Expr; }
}

Чтобы теперь написать преобразование выражения в строку мне достаточно объявить одну функцию в которой воспользоваться паттерн-матчингом:
public override ToString() : string
{
  match (this)
  {
    | Literal(value)    => value.ToString()
    | Call(name, parms) => $"$name($(parms.Map(_.ToString()).ToString(\", \")))"
    | Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
    | Mul(e1, e2)  with op = "*" | Div(e1, e2)   with op = "/" => $"$e1 $op $e2"
  }
}

Реализовать интерпретатор не намного сложнее:
public Eval() : double
{
  match (this)
  {
    | Literal(value)    => value
    | Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
    | Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval())
    | Call(_, _)                => throw InvalidOperationException(this.ToString());
    | Plus(e1,  e2)             => e1.Eval() + e2.Eval()
    | Minus(e1, e2)             => e1.Eval() - e2.Eval()
    | Mul(e1,   e2)             => e1.Eval() * e2.Eval()
    | Div(e1,   e2)             => e1.Eval() / e2.Eval()
  }
}


В общем, чтобы написать калькулятор на Немерле с использованием паттерн-матчинга и алгеброических типов у меня ушло 10 минут. Вот полный его код:
using System;
using System.Console;
using Nemerle.Utility;
using Expr;

public variant Expr
{
  | Literal { value : double; }
  | Call    { name : string; parms : list[Expr]; }
  | Plus    { expr1 : Expr; expr2 : Expr; }
  | Minus   { expr1 : Expr; expr2 : Expr; }
  | Mul     { expr1 : Expr; expr2 : Expr; }
  | Div     { expr1 : Expr; expr2 : Expr; }
  
  public override ToString() : string
  {
    match (this)
    {
      | Literal(value)    => value.ToString()
      | Call(name, parms) => $"$name($(parms.Map(_.ToString()).ToString(\", \")))"
      | Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
      | Mul(e1, e2)  with op = "*" | Div(e1, e2)   with op = "/" => $"$e1 $op $e2"
    }
  }

  public Eval() : double
  {
    match (this)
    {
      | Literal(value)    => value
      | Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
      | Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval())
      | Call(_, _)                => throw InvalidOperationException(this.ToString());
      | Plus(e1,  e2)             => e1.Eval() + e2.Eval()
      | Minus(e1, e2)             => e1.Eval() - e2.Eval()
      | Mul(e1,   e2)             => e1.Eval() * e2.Eval()
      | Div(e1,   e2)             => e1.Eval() / e2.Eval()
    }
  }
}

module Program
{
  Main() : void
  {
    def expr = Plus(Literal(1.23), Call("max", [Literal(1), Literal(2)]));
    WriteLine($"Expression '$expr' = $(expr.Eval())");
    //_ = ReadLine();
  }
}

Кстати, код был написан с использованием интеграции. Она малось глюкала, но таки сильно помогла.

Ради хохмы я реализовал аналогичный код на C#. Этот код написан в соотвествии с принципами проектирования на ООЯ (с использованием паттернов и наследования). Сравни объем, простоту и легкость расширения этого кода с кодом на Немерле.
using System;
using System.Collections.Generic;
using System.Text;

public interface IExprVisiter
{
    void Visit(Literal expr);
    void Visit(Call expr);
    void Visit(Plus expr);
    void Visit(Minus expr);
    void Visit(Mul expr);
    void Visit(Div expr);
}

public abstract class Expr
{
    public abstract void AceptVisiter(IExprVisiter visiter);

    public override string ToString()
    {
        ToStringExprVisiter visiter = new ToStringExprVisiter();
        AceptVisiter(visiter);
        return visiter.ToString();
    }
}

public class Literal : Expr
{
    public Literal(double value)
    {
        _value = value;
    }

    double _value;

    public double Value
    {
        get { return _value; }
    }

    public override void AceptVisiter(IExprVisiter visiter)
    {
        visiter.Visit(this);
    }
}

public class Call : Expr
{
    public Call(string name, params Expr[] parm)
    {
        _name = name;
        _parms = parm;
    }

    string _name;

    public string Name
    {
        get { return _name; }
    }

    Expr[] _parms;

    public Expr[] Parms
    {
        get { return _parms; }
    }

    public override void AceptVisiter(IExprVisiter visiter)
    {
        visiter.Visit(this);
    }
}

public abstract class Operator : Expr
{
    public Operator(Expr expr1, Expr expr2)
    {
        _expr1 = expr1;
        _expr2 = expr2;
    }

    Expr _expr1;

    public Expr Expr1
    {
        get { return _expr1; }
        set { _expr1 = value; }
    }

    Expr _expr2;

    public Expr Expr2
    {
        get { return _expr2; }
        set { _expr2 = value; }
    }
}

public class Plus : Operator
{
    public Plus(Expr expr1, Expr expr2) : base(expr1, expr2) { }

    public override void AceptVisiter(IExprVisiter visiter)
    {
        visiter.Visit(this);
    }
}

public class Minus : Operator
{
    public Minus(Expr expr1, Expr expr2) : base(expr1, expr2) { }

    public override void AceptVisiter(IExprVisiter visiter)
    {
        visiter.Visit(this);
    }
}

public class Mul : Operator
{
    public Mul(Expr expr1, Expr expr2) : base(expr1, expr2) { }

    public override void AceptVisiter(IExprVisiter visiter)
    {
        visiter.Visit(this);
    }
}

public class Div : Operator
{
    public Div(Expr expr1, Expr expr2) : base(expr1, expr2) { }

    public override void AceptVisiter(IExprVisiter visiter)
    {
        visiter.Visit(this);
    }
}

class ToStringExprVisiter : IExprVisiter
{
    StringBuilder _bilder = new StringBuilder();

    public override string ToString()
    {
        return _bilder.ToString();
    }

    void PrintList(IList<Expr> lst)
    {
        foreach (Expr var in lst)
        {
            var.AceptVisiter(this);
            _bilder.Append(", ");
        }

        if (lst.Count > 0)
            _bilder.Length -= ", ".Length;
    }

    public void Visit(Literal expr)
    {
        _bilder.Append(expr.Value);
    }

    public void Visit(Call expr)
    {
        _bilder.Append(expr.Name);
        _bilder.Append("(");
        PrintList(expr.Parms);
        _bilder.Append(")");
    }

    void VisitOperator(Operator expr, string kind)
    {
        expr.Expr1.AceptVisiter(this);
        _bilder.Append(kind);
        expr.Expr2.AceptVisiter(this);
    }

    public void Visit(Plus expr)
    {
        VisitOperator(expr, " + ");
    }

    public void Visit(Minus expr)
    {
        VisitOperator(expr, " - ");
    }

    public void Visit(Mul expr)
    {
        VisitOperator(expr, " * ");
    }

    public void Visit(Div expr)
    {
        VisitOperator(expr, " / ");
    }
}

class EvalExprVisiter : IExprVisiter
{
    public double Result;

    public double Eval(Expr expression)
    {
        expression.AceptVisiter(this);
        return Result;
    }

    public void Visit(Literal expr)
    {
        Result = expr.Value;
    }

    public void Visit(Call expr)
    {
        switch (expr.Name)
        {
            case "min":
                if (expr.Parms.Length != 2)
                    throw new InvalidOperationException(expr.ToString());
                Result = Math.Min(Eval(expr.Parms[0]), Eval(expr.Parms[1]));
                return;

            case "max":
                if (expr.Parms.Length != 2)
                    throw new InvalidOperationException(expr.ToString());
                Result = Math.Max(Eval(expr.Parms[0]), Eval(expr.Parms[1]));
                return;

            default: throw new InvalidOperationException(expr.ToString());
        }
    }

    public void Visit(Plus expr)
    {
        Result = Eval(expr.Expr1) + Eval(expr.Expr2);
    }

    public void Visit(Minus expr)
    {
        Result = Eval(expr.Expr1) - Eval(expr.Expr2);
    }

    public void Visit(Mul expr)
    {
        Result = Eval(expr.Expr1) * Eval(expr.Expr2);
    }

    public void Visit(Div expr)
    {
        Result = Eval(expr.Expr1) / Eval(expr.Expr2);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Expr expr = new Plus(new Literal(1.23), new Call("max", new Literal(1), new Literal(2)));
        Console.WriteLine("Expression '{0}' = {1}", expr, new EvalExprVisiter().Eval(expr));
    }
}


Мне кажется результат сам говорит за себя. Нарушение догм ООП, а точнее просто выбор другого подхода существенно (более чем в пять раз, 50 строк на Немерле против 265 строк на C#) упростил реализацию.

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

Например, если мы захотим добавить поддержку вычисления остатка от деления (аналогично оператору % в C), и добавим в вариант еще одно вхождение "Mod":
public variant Expr
{
  ...
  | Div     { expr1 : Expr; expr2 : Expr; }
  | Mod    { expr1 : Expr; expr2 : Expr; }
  ...

то при компиляции, компилятор честно предупредит нас о том, что новое вхождение варианта необработано:
Main.n(18,5,18,10): warning : matching is not exhaustive, example unmatched value: Mod
Main.n(29,5,29,10): warning : matching is not exhaustive, example unmatched value: Mod

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

На C# мы будем вынуждены:
1. Добавить новый класс.
2. Изменить интерфейс посетителя.
3. Изменить все реализации посетителя добавив к ним новый метод.

А теперь внимание вопрос. А нафига нужно следовать догмам если в конкретном случае они вредят делу?

Предвижу замечание сведующего народа. "Но ведь ты использовал более мощьный язык..." Да, это так. Но сути дела это не меняет. Догмы от этого догмами быть не перестают. И было бы очень полезно, чтобы программист даже ограниченный конкретным ЯП знал о "других путях". Это знание позволит ему более здраво смотреть на решаемые задачи. А возможно поможет упростить решаемую задачу заменой инструмента на более подходящих.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 30.12.06 18:38
Оценка:
Здравствуйте, IB, Вы писали:

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

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

Естественно контракты != интерфейсы. Контракты более широкое понятие. Скажем так, интерфейс — это контракт внутри одной платформы. В свою очередь контракт — это межплатформенный интерфейс. Но суть у них одна и та же. Проблемы тоже.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 30.12.06 19:07
Оценка: +1
Здравствуйте, IDL, Вы писали:

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


IDL>А можно по-подробнее о каких альтернативах идёт речь?


Влад уже показал некоторые альтернативы.

Конкретно по контрактам можно сказать, что они очень даже имеют смысл когда речь идёт о взаимодействии с внешними независимыми системами. Т.е. мы не знаем кто и когда нас будет пользовать, но мы очень хотим, чтобы это произошло. На практике таких задач, где контракты реально нужны, а не высосаны из пальца очень и очень не много. Писать внутренности системы с использованием контрактов, конечно, никто не запрещает, но это дорого и практически не имеет никого смысла, т.к. преимущества подхода становятся несущественны, а недостатками можно наслаждаться в полной мере.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 30.12.06 22:32
Оценка:
Здравствуйте, IT, Вы писали:

IT> Контракты более широкое понятие.

Угу..

IT>Скажем так, интерфейс — это контракт внутри одной платформы.

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

IT>В свою очередь контракт — это межплатформенный интерфейс.

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

IT>Но суть у них одна и та же. Проблемы тоже.

По поводу проблем, мы с тобой в марте за бутылочкой кетел вана поговорим, в уютном месте, все равно в сиэтл через NY лететь..
Вопрос явного описания контракта — это вопрос воздействия на вкусовые рецепторы на предмет сравнительного анализа на сладость хрена и редьки.. =))
... << RSDN@Home 1.2.0 alpha rev. 669>>
Мы уже победили, просто это еще не так заметно...
Re[8]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 30.12.06 22:47
Оценка:
Здравствуйте, IB, Вы писали:

VD>>Контракты и интерефейсы тоже догмы той идиологии которую ты считашь единственно верной.

IB>Контракты != Интерфейсы,

Да, бога ради. Я даже не собирался касаться отношений контракта и интерфейса. Ты что-то слишьно зациклился на этих контрактах. Вот тебя и тянет о них спорить.

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

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


Ваань. К чему ты все это говоришь? Ты не забыл о том, что обсуждалось?

IB>Поэтому вылезай из догмы о том, что я ограничен рамками ООП и ничего кроме этой идеологии не вижу. =)


Это реальность. То что ты этог даже не замечашь проблемы твои, а не мои.

VD>> Если нет, то будет однобокое мышление.

IB>Я тебя умоляю, мышление только мое не трожь..

Вань. Ты влез в спор чтобы сказать свое окончательное верное слово? Или чтобы перевести разговор в плоскость обсуждения контрактов? Я этим уже наигрался. Мне это сейчас не интересно. Поробуй понять то что тебе говорят.

VD>>И что забавно очень часто совершенно напрасно.

IB>Нет. Если мы решаем задачу через ООП, то совершенно не напрасно, если мы решаем ее как-то по другому, то причем здесь ООП?

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

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


Она доведена до догмы. А все что превращено в догму рано или поздно становится тормозом в развитии. Не все проблемы в программировании надо решать с помощью ООП. ООП не всегда эффективен. Пример тому я привел в соседней ветке
Автор: VladD2
Дата: 30.12.06
.

VD>> Проектировать в ОО-стиле все подряд не эффективно. ООП не панацея.

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

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

VD>> Он рассчитан на динамический полиморфизм в ООП.

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

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

VD>> Меж тем бывает статический полиморфизм в функциональном стиле. Он не менее мощен и позволяет решать ряд задач существенно проще чем в ОО-стиле.

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

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

VD>>При том, что для фукнций данные не более чем то чеми они оперируют. Как int или double.

IB>И что?

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

VD>>В общем, этот принцип применим к узкому подтипу полиморфизма.

IB>У меня такое чувство, что ты принцип ты для себя усвоил на основе примера, а не на основе того как он сформулирован.

А у тебя никогда не было чувства, что ты просто не понимаешь или не знаешь чего-то?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 31.12.06 00:06
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Да, бога ради. Я даже не собирался касаться отношений контракта и интерфейса.

Почему же ты тогда о них заговорил?

VD> А уж чем ты там будешь оперировать... контрактами, интерфейсами или фунциями и структурами мне по барабану.

Ну, в данном-то случае речь об оценке этой операции.. )

VD>Ваань. К чему ты все это говоришь?

К тому что ты упомянул интерфейсы..

VD> Ты не забыл о том, что обсуждалось?

Обсуждался LSP, в котором ты нашел некие "догмы" ООП... Ты сам-то помнишь о чем речь?

VD>Это реальность.

В каком-то измененном сознании..

VD>Поробуй понять то что тебе говорят.

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

VD>Мы осбуждали незыблемость приципа/догмы.

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

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

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

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

Нет. Принцип вообще ни как не завязан на типы.

VD> Не все проблемы в программировании надо решать с помощью ООП.

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

VD>Ты таки заблуждаешся.

Таки нет..

VD> Он не имеет смысла за пределами номинальной системы типов (иерархической с динамическим полиморфизмом).

Он вообще никак не завязан на типы. Ну взгляни ты на проблему шире..

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

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

VD>Вань. Перестань повторять базворды.

Я их повторяю?

VD> Забуть ты про контракты и реализации.

Это ты лучше про них вспомни..

VD> Важно только то насклько простое, расширяемое решение и поддерживаемое решение ты получишь в итоге.

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

VD> Еще точнее можут оказться так, что рассуждать других терминах окажется выгоднее. Понимаешь о чем я?

Понимаю, боюсь только ты не понимаешь о чем я..

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

Во-первых, никто не говорил, что принцип незыблем, хочешь — нарушай... ) Во-вторых, если решение оказалось более простым но менее расширяемым и поддерживаемым, то пошло нафиг такое решение, этот код еще сопровождать надо, причем с хорошей вероятностью совсем не тому кто его писал. Ну и, наконец, в третих — если решение оказалось простым, выгодным и расширяемым, то оно, как правило, таки удовлетворяет вышеприведенному принципу, как на проблему ни гляди..
... << RSDN@Home 1.2.0 alpha rev. 669>>
Мы уже победили, просто это еще не так заметно...
Re[10]: Принцип подстановки Барбары Лисков
От: Дм.Григорьев  
Дата: 31.12.06 02:12
Оценка:
Здравствуйте, IT, Вы писали:

IT>Конкретно по контрактам можно сказать, что они очень даже имеют смысл когда речь идёт о взаимодействии с внешними независимыми системами...


А как насчет взаимодействия с другими подсистемами в большом проекте? Особенно, если разные подсистемы пишут разные люди? Мне кажется, здесь без контрактов будет проблематично. Какие есть варианты?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
http://dimgel.ru/lib.web — thin, stateless, strictly typed Scala web framework.
Re[11]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 31.12.06 04:16
Оценка:
Здравствуйте, Дм.Григорьев, Вы писали:

IT>>Конкретно по контрактам можно сказать, что они очень даже имеют смысл когда речь идёт о взаимодействии с внешними независимыми системами...


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


Это зависит от конкретного большого проекта и его конкретных подсистем. Часто можно обойтись простыми лэйерами и модулями.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Надобно подкорректировать
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 31.12.06 09:15
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

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


Угу. Это потому, что наследование, как инструмент, может использоваться для разных целей. В результате "типы" для компилятора не соответсвуют один в один "типам" для программистов.
http://www.smalltalk.ru | << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[12]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 31.12.06 09:22
Оценка:
Здравствуйте, IT, Вы писали:

IT>Это зависит от конкретного большого проекта и его конкретных подсистем. Часто можно обойтись простыми лэйерами и модулями.

А между слоями и модулями контрактов нет?
... << RSDN@Home 1.2.0 alpha rev. 669>>
Мы уже победили, просто это еще не так заметно...
Re[13]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 31.12.06 17:20
Оценка: +1
Здравствуйте, IB, Вы писали:

IT>>Это зависит от конкретного большого проекта и его конкретных подсистем. Часто можно обойтись простыми лэйерами и модулями.

IB>А между слоями и модулями контрактов нет?

В том смысле в котором они понимаются теми, кто ввёл этот термин — нет. Если твоя интерпретация уже практически не отличается от, например, "контракт есть публичный интерфейс класса/модуля и т.п.", то можно сказать, что у модулей контракт есть. Только нафига тогда нужен такой термин, без которого до этого прекрасно обходились и не было никакой путаницы.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.12.06 19:03
Оценка:
Здравствуйте, IT, Вы писали:

IT>В том смысле в котором они понимаются теми, кто ввёл этот термин — нет. Если твоя интерпретация уже практически не отличается от, например, "контракт есть публичный интерфейс класса/модуля и т.п.", то можно сказать, что у модулей контракт есть. Только нафига тогда нужен такой термин, без которого до этого прекрасно обходились и не было никакой путаницы.


Как же? Бащврды шибко способствуют самовнушению.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Принцип подстановки Барбары Лисков
От: Дм.Григорьев  
Дата: 01.01.07 08:17
Оценка:
Здравствуйте, IT, Вы писали:

IB>>А между слоями и модулями контрактов нет?

IT>В том смысле в котором они понимаются теми, кто ввёл этот термин — нет.

Имеется в виду наличие дополнительной документации (UML, etc.) вне кода? Или что?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
http://dimgel.ru/lib.web — thin, stateless, strictly typed Scala web framework.
Re[10]: Принцип подстановки Барбары Лисков
От: remark Россия http://www.1024cores.net/
Дата: 01.01.07 11:14
Оценка: 31 (3)
Здравствуйте, VladD2, Вы писали:

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

VD>
VD>public variant Expr
VD>{
VD>  | Literal { value : double; }
VD>  | Call    { name : string; parms : list[Expr]; }
VD>  | Plus    { expr1 : Expr; expr2 : Expr; }
VD>  | Minus   { expr1 : Expr; expr2 : Expr; }
VD>  | Mul     { expr1 : Expr; expr2 : Expr; }
VD>  | Div     { expr1 : Expr; expr2 : Expr; }
  
VD>  public override ToString() : string
VD>  {
VD>    match (this)
VD>    {
VD>      | Literal(value)    => value.ToString()
VD>      | Call(name, parms) => $"$name($(parms.Map(_.ToString()).ToString(\", \")))"
VD>      | Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
VD>      | Mul(e1, e2)  with op = "*" | Div(e1, e2)   with op = "/" => $"$e1 $op $e2"
VD>    }
VD>  }
VD>


До боли что-то напоминает... А! Это же старый добрый С! Уж не так ли мы писали в течение 20 лет:

struct expr
{
    enum type {Literal, Call, Plus, Minus, Mul, Div} t;
    union
    {
        double value;
        struct {const char* name; expr* params[10]; int count;};
        struct {expr *expr1, *expr2;};
    } data;
};

void to_str(const expr* e)
{
    switch (e->t)
    {
    case expr::Literal: cout << e->data.value; break;
    case expr::Call: cout << e->data.name << "("; 
        for (int i = 0; i < e->data.count; ++i)
        {
            to_str(e->data.params[i]);
            cout << "," + !!i;
        }
        cout << ")"; break;
    case expr::Plus: to_str(e->data.expr1); cout << "+"; to_str(e->data.expr2); break;
    case expr::Minus: to_str(e->data.expr1); cout << "-"; to_str(e->data.expr2); break;
    case expr::Mul: to_str(e->data.expr1); cout << "*"; to_str(e->data.expr2); break;
    case expr::Div: to_str(e->data.expr1); cout << "/"; to_str(e->data.expr2); break;
    }
}


Имхо тождественно с точностью до синтаксиса. Практически так же лаконично.
И уж не от этого ли мы бежали? Уж не это ли у нас было плохо поддерживаемым, error-prone и т.д? И уж не глядя на это ли мы решили, что хорошо было бы иметь более структурированный код и более явно выделять сущности (пустай даже ценой менее лаконичного кода)?



Нет, я согласен, для этого конкретного примера код на C# выглядит как overkill. Но в начале поста пример-то у тебя был другой — несколько типов деревьев, куча типов нодов и т.д.
В С, кстати, "умные" компиляторы или тулзы тоже выдают варнинг на "неполные" switch'и. Но тем не менее такой подход мировым сообществом программистов был признан... не очень хорошим.


Твой "switch" выглядит красивым и лаконичным и читаемым пока он такой маленький и не распух. А представь у тебя будет на каждый case по 10-50 строк кода (разное поведение в зависимости от настроек, логирование и т.д. а в промышленном проекте так и будет). Что ты сделаешь? Правильно. Вынесешь код в функции. А вот тут уже станут сомнительны приемущества такого switch'а — уже сам этот switch будет пустой писаниной, т.к. vtable реализует его автоматически (0 строчек кода со стороны программиста). И уже пошли возможности для ошибок — а что если я и для Plus и для Minus вызову одну функцию?


Или вот ещё аналогичный пример. Допустим есть некая функция. Пока относительно небольшая, она выграет от того, что мы её не будем разделять на несколько — одна функция из 10 строк — просто, читаемо, можно охватить логику одним взглядом. Если же функцию из 10 строк разбить на 3, то во-первых, кол-во кода существенно вырастет, во-вторых станет менее читаемо, т.к. не так локально.
Когда же есть функция из 100 строк, то она уже будет проигрывать от того, что она реализована одной функцией на 7 экранов, т.к. она уже все равно не простая и не лаконичная и одним взглядом её не поймёшь. Тут она уже выграет от разбивания на несколько функций, т.к. код станет более структурированным, более чётко будут видны интерфейсы и зависимости, от некоторых частей можно будет абстрагироваться и т.д. При этом кол-во кода вырастет — но мы готовы с этим мириться, т.к. взамен получаем более важные вещи.

Так же и с ООП. Для небольших задач оно может показаться overkill, одна для больших и сложных задач лучше написать больше кода, но зато явно выделить все понятия, разложить всё по полочкам. Вобщем структурировать. Допустим есть базовый класс Expression c 5 виртуальными функциями и есть 147 производных классов. Что бы всё это понять достаточно изучить базовый класс и один наследник. Всё. далее, когда надо будет допустим изменить поведение "сложения" понятно, что надо найти некий ExpressionPlus и изменить его.


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

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



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[14]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 01.01.07 11:26
Оценка:
Здравствуйте, IT, Вы писали:

IT>В том смысле в котором они понимаются теми, кто ввёл этот термин — нет.

Разьве? Ну ладно, не суть...

IT> Только нафига тогда нужен такой термин, без которого до этого прекрасно обходились и не было никакой путаницы.

Ну хорошо, замени контракт на "публичный интерфейс модуля, ect.." суть-то от этого не изменится.
... << RSDN@Home 1.2.0 alpha rev. 669>>
Мы уже победили, просто это еще не так заметно...
Re[9]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 01.01.07 12:01
Оценка:
Здравствуйте, IT, Вы писали:

ГВ>>>>>>[...]Если один фрагмент — не беда, если десяток, то...

IT>>>>>И в чём именно проблема?
ГВ>>>>Только в количестве.
IT>>>Ну так функционал всё равно писать надо, много его или мало.
ГВ>>А кто-то это отрицает?
IT>Так в чём тогда проблема?

В расширяемости, разумеется.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[11]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.01.07 20:44
Оценка: 39 (6)
Здравствуйте, remark, Вы писали:

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

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

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

Ну, а теперь по пунктам...

R>До боли что-то напоминает... А! Это же старый добрый С!


Скорее Лисп или ОКамл, но тебе явно они незнакомы, вот ты узрел тут С. С тем же успхом бвышие дельфийцы прейды на дотнет постоянно узнают в C#-е Обеъектный Паскаль.

R> Уж не так ли мы писали в течение 20 лет:


R>
R>void to_str(const expr* e)
R>{
R>    switch (e->t)
R>    {
R>    case expr::Literal: cout << e->data.value; break;
R>    case expr::Call: cout << e->data.name << "("; 
R>        for (int i = 0; i < e->data.count; ++i)
R>        {
R>            to_str(e->data.params[i]);
R>            cout << "," + !!i;
R>        }
R>        cout << ")"; break;
R>    case expr::Plus: to_str(e->data.expr1); cout << "+"; to_str(e->data.expr2); break;
R>    case expr::Minus: to_str(e->data.expr1); cout << "-"; to_str(e->data.expr2); break;
R>    case expr::Mul: to_str(e->data.expr1); cout << "*"; to_str(e->data.expr2); break;
R>    case expr::Div: to_str(e->data.expr1); cout << "/"; to_str(e->data.expr2); break;
R>    }
R>}
R>


R>Имхо тождественно с точностью до синтаксиса. Практически так же лаконично.


Серьезно? Так же? Сравни сам:
public override ToString() : string
{
  match (this)
  {
    | Literal(value)    => value.ToString()
    | Call(name, parms) => $"$name($(parms.Map(_.ToString()).ToString(\", \")))"
    | Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
    | Mul(e1, e2)  with op = "*" | Div(e1, e2)   with op = "/" => $"$e1 $op $e2"
  }
}

И это самый простой случай. Чем более сложный будет код тем хуже он будет на С. Реализуй, плиз, весь пример на С и попробуем сравнить. Особенно интересует как ты повторишь вот эти строки:
match (this)
{
    ...
    | Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
    | Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval())
    | Call(_, _)                => throw InvalidOperationException(this.ToString());

Поясню, что в них особенного. Это как раз паттерн-матчинг во всей своей мощи. Мы очень короткими и хорошо читаемыми строками "Call("max", [arg1, arg2])" распознаем конкретные случае. Если такой возможности нет, то прийдется писать кучу занудных if-ов с кучей ручных проверок, каждая из которых черевата ошибками.

R>И уж не от этого ли мы бежали?


Вы? Может не надо обобщать?

R> Уж не это ли у нас было плохо поддерживаемым, error-prone и т.д?


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

R> И уж не глядя на это ли мы решили, что хорошо было бы иметь более структурированный код и более явно выделять сущности (пустай даже ценой менее лаконичного кода)?

R>

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

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

R>Нет, я согласен, для этого конкретного примера код на C# выглядит как overkill.


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

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


У меня? Пример был не мой. Он даже был не автора. Это стандартная калька из книг по ООЯ. Пример этот, кстати, в реальной жизни никогда не встречается, так как наследование для подобных задач тоже полнейший оврекил. Большинство библиотек 2D-графики обычно выводят геометрические примитивы отдельными функциями. О наследовнии там даже речи не идет. Ну, да это так отступление.

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

R>В С, кстати, "умные" компиляторы или тулзы тоже выдают варнинг на "неполные" switch'и.


Кстатати, можно хотя бы один пример таких компиляторов?
И кстати, ты точно понимашь суть паттерн-матчинга? Ты помнимашь, что компилятор отслеживает не только примитивные случаи, но более сложные:
| Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
| Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval())
| Call(_, _)                => throw InvalidOperationException(this.ToString());

Если мы уберем сточку:
| Call(_, _)                => throw InvalidOperationException(this.ToString());

то компилятор опять таки выдаст предупреждение. Ни один компилятор С на такое не способен.

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

R> Но тем не менее такой подход мировым сообществом программистов был признан... не очень хорошим.


Серьезно? А мировое сообщество то и не знало.
Оно вот взяло и породило Лисп, МЛ, ОКамл и в итоге Немерле. Так что не надо выдвать ограниченность своего кругозора за решение мирового сообщества. И не надо противопоставлять ООП всему остальному. Он хорош для многих задач, но не для всех. Просто нужно уметь применять его с умом, а так же уметь применять и не его. Ну, и опять же хочу заметить, что надо остерегаться догм.

R>Твой "switch"


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

R>выглядит красивым и лаконичным и читаемым пока он такой маленький и не распух. А представь у тебя будет на каждый case по 10-50 строк кода (разное поведение в зависимости от настроек, логирование и т.д. а в промышленном проекте так и будет).


Это огромное заблуждение. Если скажем увеличить количество сущьностей, например, расширить калькулятор до современного ЯП, то код выростет пропроционально. Так что если у нас исходно получилась разница в 5 раз, то она и останется. Так что если компилятор на Немерле занимает 1.5 мегабайта, то анологичный код на C# будет 7.5 мебагайт, а то и больше.

R> Что ты сделаешь? Правильно. Вынесешь код в функции.


Не факт. В функцию я буду выносить не всегда.

R> А вот тут уже станут сомнительны приемущества такого switch'а — уже сам этот switch будет пустой писаниной, т.к. vtable реализует его автоматически (0 строчек кода со стороны программиста). И уже пошли возможности для ошибок — а что если я и для Plus и для Minus вызову одну функцию?


Я не знаю как можно перепутать плюс и минус. Зато я знаю, что это не свитч. И знаю, что с помощью миртуальных методов реализовать функциональность паттерн-матчинга невозможно. Вот простой пример попавшийся под руку. Компилятор Немерле генерировал не очень красивый код для булевых выражений (правда опимизатор дотнета устраля проблему, но все же). Вот код птача исправляющего проблему:
Index: ncc/generation/ILEmitter.n
===================================================================
--- ncc/generation/ILEmitter.n    (revision 7181)
+++ ncc/generation/ILEmitter.n    (working copy)
@@ -574,6 +574,10 @@
           def emit_branch (expr : TExpr, else_label : Label) {
             Mark (expr.loc);
             match (expr) {
+              | Call (OpCode ("=="), [nested_cond,
+                 Parm where (expr = TExpr.TypeConversion(TExpr.Literal(Literal.Bool(true)), _, _))], _) =>
+                emit_branch(nested_cond.expr, else_label)
+
               | Call (OpCode (opcode), parms, _) =>
                 emit_parms (parms);

Добавленный код помечен плюсиками. Обратите внимание на паттерн. Я конечно понимаю, понять его не зная зяыка и остобенностей устройства компилятора сложно. Но это и не важно. Важно то, что этот паттерн находит выражение "x == (true :> bool)" (или в теминах С "x == (bool)true"), где "x" это любое выражение, и генерирует для него более простой код. В результате компилятор порождает более простой код. Вместо:
IL_000e: blt.s IL_0016
IL_0010: ldc.i4.0 
IL_0011: br IL_0017
IL_0016: ldc.i4.1 
IL_0017: ldc.i4.1 
IL_0018: bne.un IL_0026

он генерирует:
IL_000e: bge IL_001c


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




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

Это неверная теория. У меня есть сразу несклько аргументов против нее.

1. В сущьности нет разницы между классом содержащим много функций кайждая из которых обрабатывает (скажем) одну ветку и одной функцией содержащей много образцов обрабатвающих одну (а то и не оду) ветку. Это высосанное из пальца предубеждение. Наборот охватить галзами компактный список проще. Тут мне могут заметить, что пробему создают распухший код между образцами (код обработчиков), но эту проблему легко решает среда с поддержкой свортывания код (фолдингом).
Например, следующий код:
GetExpr(expression : TExpr) : object
{
| StaticRef(from, mem, _)          =>      // { from : MType.Class; mem : IMember; type_parms : list [TyVar]; }

    if (mem.MemberType != MemberTypes.Constructor && from.tycon.Name == PExprName)
        from
    else
        mem : object

| TypeConversion(_, tt, _)         =>      // { mutable expr : TExpr; target_type : TyVar; kind : ConversionKind; }

    if (tt.IsFixed)
    {
        match (tt.FixedValue)
        {
        | Class(tycon, _) =>

            def dt = tycon.DeclaringType;
            if (dt != null && dt.Name == PExprName) dt else tt : object

        | _ => tt
        }
    }
    else
        tt

| Literal(Enum(value, ty, null))   => 

    def members = ty.GetMembers();
    def field   = members.Find(f =>
    {
        match (f)
        {
        | f is IField when f.IsStatic && f.IsLiteral =>

            match (f.GetValue())
            {
            | Integer as val
            | Literal.Enum(val, _, _) => val.ToString() == value.ToString()
            | _ => false
            }

        | _ => false
        }
    });

    match (field)
    {
    | Some(f) => f
    | None    => expression : object
    }

| Literal(Enum(_, _, field))       => field

| ConstantObjectRef(_, o : object)         // { from : MType.Class; mem : IField; }
| StaticPropertyRef(_, o : object)         // { from : MType.Class; prop : IProperty; }
| StaticEventRef   (_, o : object)         // { from : MType.Class; ev : IEvent; }
| Base                (o : object)         // { base_ctor : IMethod; }
| LocalFunRef         (o : object, _)      // { decl : LocalValue; type_parms : list [TyVar]; }
| LocalRef            (o : object)         // { decl : LocalValue; }
| MethodRef        (_, o : object, _, _)   // { obj : TExpr; meth : IMethod; type_parms : list [TyVar]; notvirtual : bool; }
| EventMember      (_, o : object)         // { obj : TExpr; ev : IEvent; }
| FieldMember      (_, o : object)         // { obj : TExpr; fld : IField; }
| PropertyMember   (_, o : object)         // { obj : TExpr; prop : IProperty; }
| DefValIn            (o : object, _, _)   // { name : LocalValue; val : TExpr; mutable body : TExpr; }
| HasType          (_, o : object)         // { expr : TExpr; test_ty : MType; }
| TypeOf              (o : object) => o    // { target_type : TyVar; }
| _                                => expression
}

В IDE будет выглядеть вот так:


2. Реализация паттерн-матчинга в виде оператора — это одна из возможных реализаций. В Немерле в виду того, что язык имеет C-подобный (точнее C#-подобный) синтаксис проблематично реализовать другой варинт. Но есть ЯП в которых возможен паттерн-матчинг на базе отдельных фукнкций. Стало быть исчезает последний натянутый аргумент.

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

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

R>Или вот ещё аналогичный пример. Допустим есть некая функция. Пока относительно небольшая, она выграет от того, что мы её не будем разделять на несколько — одна функция из 10 строк — просто, читаемо, можно охватить логику одним взглядом. Если же функцию из 10 строк разбить на 3, то во-первых, кол-во кода существенно вырастет, во-вторых станет менее читаемо, т.к. не так локально.

R>Когда же есть функция из 100 строк, то она уже будет проигрывать от того, что она реализована одной функцией на 7 экранов, т.к. она уже все равно не простая и не лаконичная и одним взглядом её не поймёшь. Тут она уже выграет от разбивания на несколько функций, т.к. код станет более структурированным, более чётко будут видны интерфейсы и зависимости, от некоторых частей можно будет абстрагироваться и т.д. При этом кол-во кода вырастет — но мы готовы с этим мириться, т.к. взамен получаем более важные вещи.

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

R>Так же и с ООП. Для небольших задач оно может показаться overkill, одна для больших и сложных задач лучше написать больше кода, но зато явно выделить все понятия, разложить всё по полочкам.


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

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

R> Вобщем структурировать. Допустим есть базовый класс Expression c 5 виртуальными функциями и есть 147 производных классов. Что бы всё это понять достаточно изучить базовый класс и один наследник. Всё. далее, когда надо будет допустим изменить поведение "сложения" понятно, что надо найти некий ExpressionPlus и изменить его.


Твои предположения о простоте не более чем теоритические рассуждения. А факты упрямая вещь. Функциональные языки намного лучше подходят для написания компиляторов. Чтобы в этом убедиться достаточно сравнить код двух компиляторов написанны на ООЯ и на ФЯ. Наприер, код компилятора Немерле занимает 1.5 МБ, а во много раз более простого Питона несколько десятков.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.01.07 20:44
Оценка:
Здравствуйте, IB, Вы писали:

VD>>Да, бога ради. Я даже не собирался касаться отношений контракта и интерфейса.

IB>Почему же ты тогда о них заговорил?

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

VD>>Ваань. К чему ты все это говоришь?

IB>К тому что ты упомянул интерфейсы..

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

IB>Обсуждался LSP, в котором ты нашел некие "догмы" ООП... Ты сам-то помнишь о чем речь?


Я? Прекрасно. Проблема как раз с твоим пониманием. И знаешь что? К сожалению, чтобы тебе меня понять тебе нужно кроме ООП изучить и другие подходы. Иначе разговор не получится.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 01.01.07 22:43
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>[/c#]

VD>Реализовать интерпретатор не намного сложнее:
VD>
VD>public Eval() : double
VD>{
VD>  match (this)
VD>  {
VD>    | Literal(value)    => value
VD>    | Call("max", [arg1, arg2]) => Math.Max(arg1.Eval(), arg2.Eval())
VD>    | Call("min", [arg1, arg2]) => Math.Min(arg1.Eval(), arg2.Eval())
VD>    | Call(_, _)                => throw InvalidOperationException(this.ToString());
VD>    | Plus(e1,  e2)             => e1.Eval() + e2.Eval()
VD>    | Minus(e1, e2)             => e1.Eval() - e2.Eval()
VD>    | Mul(e1,   e2)             => e1.Eval() * e2.Eval()
VD>    | Div(e1,   e2)             => e1.Eval() / e2.Eval()
VD>  }
VD>}
VD>


Поскольку я с Немерле знаком слабо, то задам вопрос: можно ли добавить сюда описание новой операции (допустим — возведение в квадрат, Sqr) без перетрансляции исходного текста Expr?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[11]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.01.07 23:05
Оценка: 21 (2)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Поскольку я с Немерле знаком слабо, то задам вопрос: можно ли добавить сюда описание новой операции (допустим — возведение в квадрат, Sqr) без перетрансляции исходного текста Expr?


Вопрос на который трудно дать однозначный ответ.
С одной стороны ответ будет "нет и не надо". Варинты средство рассчитанное на статическую типизацию и поддержку компилятора. Весь его кайф в том, что динамическое расширение им противопаказано.
С другой стороны ответ будет "да", так как мы всегда можем создать динамическое решение другими средствами. Мы можем сделать так:
| Call(name, parms) as call => 
  def func = funcMap(call);
    if (func == null)throw SomeException();
    else             func(makeParams(parms));


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

Более того в Немерле квази-циритование конвертируется в список PExpr, а это как раз варинт отражающий нетипизированное АСТ. Это позволяет в качестве образца использовать просто код. То есть мы можем написать:
match (expr)
{
  | <[ if ($x) $y else $z ]> => // используем одвыражения if-а
}

а if, между прочем, это макрос.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 02.01.07 00:17
Оценка:
Здравствуйте, VladD2, Вы писали:

ГВ>>Поскольку я с Немерле знаком слабо, то задам вопрос: можно ли добавить сюда описание новой операции (допустим — возведение в квадрат, Sqr) без перетрансляции исходного текста Expr?


VD>Вопрос на который трудно дать однозначный ответ.

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

Ясно. В принципе, чего-то в таком духе я и ожидал. То есть для создания набора, расширяемого в runtime варианты, очевидно, не годятся. В отличие от иерархий типов и публичных контрактов, по отношению к которым, кстати, и сформулирован LSP. Во избежание терминологической путаницы замечу, что здесь под термином "контракт" я понимаю набор соглашений об использовании типа: протокол, инварианты и т.п. вне зависимости от того, описаны контракты формально средствами целевого языка или нет.

VD>С другой стороны ответ будет "да", [...]

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

Тут тоже понятно — обратиться к функции по имени.

VD>Более того в Немерле квази-циритование конвертируется в список PExpr, а это как раз варинт отражающий нетипизированное АСТ. [...]

VD>а if, между прочем, это макрос.

Здесь тоже ясно, но это уже из области DSL-ей, которые есть смежная область.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[10]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 02.01.07 01:10
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>>>>>>>[...]Если один фрагмент — не беда, если десяток, то...

IT>>>>>>И в чём именно проблема?
ГВ>>>>>Только в количестве.
IT>>>>Ну так функционал всё равно писать надо, много его или мало.
ГВ>>>А кто-то это отрицает?
IT>>Так в чём тогда проблема?
ГВ>В расширяемости, разумеется.

Наример? И как эта пробема решается другими средствами?
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[15]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 02.01.07 01:25
Оценка: 4 (1)
Здравствуйте, Дм.Григорьев, Вы писали:

IB>>>А между слоями и модулями контрактов нет?

IT>>В том смысле в котором они понимаются теми, кто ввёл этот термин — нет.

ДГ>Имеется в виду наличие дополнительной документации (UML, etc.) вне кода? Или что?


Имеется ввиду вариант определения контрактов введённый в SOA.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[15]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 02.01.07 01:35
Оценка:
Здравствуйте, IB, Вы писали:

IT>>В том смысле в котором они понимаются теми, кто ввёл этот термин — нет.

IB>Разьве? Ну ладно, не суть...

IT>> Только нафига тогда нужен такой термин, без которого до этого прекрасно обходились и не было никакой путаницы.

IB>Ну хорошо, замени контракт на "публичный интерфейс модуля, ect.." суть-то от этого не изменится.

Конечно же измениться. Как минимум я не буду это отражать на веб-сервисамы, SOA и WCF и мы сразу начнём говорить на одном языке
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 02.01.07 01:36
Оценка:
Здравствуйте, IT, Вы писали:

IT>>>Так в чём тогда проблема?

ГВ>>В расширяемости, разумеется.

IT>Наример?


А что тут не понятного? Когда конкретный вызов метода проводится на основании явного анализа типа объекта, то для добавления нового типа нужно модифицировать все места программы, где это перечисление имеется. Будут это switch/case, цепочки if или выражения для pattern-matching — не важно.

IT>И как эта пробема решается другими средствами?


Я тебе должен рассказывать про наследование и фабрики? Игорь, я точно не с твоим двойником общаюсь?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: Надобно подкорректировать
От: VladGalkin Украина  
Дата: 02.01.07 09:42
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Но при этом возможна забавная коллизия, когда с точки зрения компилятора типы находятся в отношении "супертип-подтип", а с точки ГВ>зрения LSP — нет.


Да, давно где то встречал (источник вспомнить не могу) пример иллюстрирующий LSP и его нарушение, с фразой:

B is a subclass of A, but not its subtype.

ДЭ!
Re[12]: Принцип подстановки Барбары Лисков
От: Blazkowicz Россия  
Дата: 02.01.07 11:07
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

IT>>И как эта пробема решается другими средствами?


ГВ>Я тебе должен рассказывать про наследование и фабрики? Игорь, я точно не с твоим двойником общаюсь?


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

Хотя одно время пришлось сотрудничать с человекам который в 3х классах написал многострочный if instanceof ... (порядка 30 типов — расширяемый набор виджетов). И при добавлении нового виджета приходилось модифицировать все три класса добавляя if instanceof.
Re[11]: Принцип подстановки Барбары Лисков
От: Андрей Хропов Россия  
Дата: 02.01.07 20:02
Оценка: +1
Здравствуйте, remark, Вы писали:

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


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

VD>>
VD>>public variant Expr
VD>>{
VD>>  | Literal { value : double; }
VD>>  | Call    { name : string; parms : list[Expr]; }
VD>>  | Plus    { expr1 : Expr; expr2 : Expr; }
VD>>  | Minus   { expr1 : Expr; expr2 : Expr; }
VD>>  | Mul     { expr1 : Expr; expr2 : Expr; }
VD>>  | Div     { expr1 : Expr; expr2 : Expr; }
  
VD>>  public override ToString() : string
VD>>  {
VD>>    match (this)
VD>>    {
VD>>      | Literal(value)    => value.ToString()
VD>>      | Call(name, parms) => $"$name($(parms.Map(_.ToString()).ToString(\", \")))"
VD>>      | Plus(e1, e2) with op = "+" | Minus(e1, e2) with op = "-" 
VD>>      | Mul(e1, e2)  with op = "*" | Div(e1, e2)   with op = "/" => $"$e1 $op $e2"
VD>>    }
VD>>  }
VD>>


R>До боли что-то напоминает... А! Это же старый добрый С! Уж не так ли мы писали в течение 20 лет:


R>
R>struct expr
R>{
R>    enum type {Literal, Call, Plus, Minus, Mul, Div} t;
R>    union
R>    {
R>        double value;
R>        struct {const char* name; expr* params[10]; int count;};
R>        struct {expr *expr1, *expr2;};
R>    } data;
R>};

R>void to_str(const expr* e)
R>{
R>    switch (e->t)
R>    {
R>    case expr::Literal: cout << e->data.value; break;
R>    case expr::Call: cout << e->data.name << "("; 
R>        for (int i = 0; i < e->data.count; ++i)
R>        {
R>            to_str(e->data.params[i]);
R>            cout << "," + !!i;
R>        }
R>        cout << ")"; break;
R>    case expr::Plus: to_str(e->data.expr1); cout << "+"; to_str(e->data.expr2); break;
R>    case expr::Minus: to_str(e->data.expr1); cout << "-"; to_str(e->data.expr2); break;
R>    case expr::Mul: to_str(e->data.expr1); cout << "*"; to_str(e->data.expr2); break;
R>    case expr::Div: to_str(e->data.expr1); cout << "/"; to_str(e->data.expr2); break;
R>    }
R>}
R>


R>Имхо тождественно с точностью до синтаксиса.

Неправильно, в вариантах каждый подтип имеет свои данные, тут у тебя type и data разделены (и вообще говоря для какого типа верны какие данные остается только догадываться) и ничто не мешает тебе для Literalа попробовать взять name, что есть UB.

R> Практически так же лаконично.

Ну не совсем, да и ошибки не контролируются как я уже сказал.

R>И уж не от этого ли мы бежали? Уж не это ли у нас было плохо поддерживаемым, error-prone и т.д? И уж не глядя на это ли мы решили, что хорошо было бы иметь более структурированный код и более явно выделять сущности (пустай даже ценой менее лаконичного кода)?

R>

R>Нет, я согласен, для этого конкретного примера код на C# выглядит как overkill. Но в начале поста пример-то у тебя был другой — несколько типов деревьев, куча типов нодов и т.д.

R>В С, кстати, "умные" компиляторы или тулзы тоже выдают варнинг на "неполные" switch'и. Но тем не менее такой подход мировым сообществом программистов был признан... не очень хорошим.
Он хорош для вот таких простых случаев. Каждой задаче — свой подход. Зачем городить зоопарк виртуальных функций для простейших операций?

R>Твой "switch" выглядит красивым и лаконичным и читаемым пока он такой маленький и не распух. А представь у тебя будет на каждый case по 10-50 строк кода (разное поведение в зависимости от настроек, логирование и т.д. а в промышленном проекте так и будет).


Правильно — для каждой задачи свой подход. К слову, в плане реализации вариантов в Немерле конкретные типы варианта — это как раз подклассы, более того, их можно отдельно создавать
def plus = Expr.Plus( expr1, expr2 )

и передавать в функции
public ProcessPlus( expr: Expr.Plus )


а сам вариант также может наследоваться от другого класса (правда от самого варианта наследовать нельзя).

R>И уже пошли возможности для ошибок — а что если я и для Plus и для Minus вызову одну функцию?

Ну а если ты для реализации виртуальной функции в подклассах Plus и Minus скопипастишь код ? Это даже труднее будет найти, поскольку код разнесен.

R>Или вот ещё аналогичный пример. Допустим есть некая функция. Пока относительно небольшая, она выграет от того, что мы её не будем разделять на несколько — одна функция из 10 строк — просто, читаемо, можно охватить логику одним взглядом. Если же функцию из 10 строк разбить на 3, то во-первых, кол-во кода существенно вырастет, во-вторых станет менее читаемо, т.к. не так локально.

Во-во.

R>Когда же есть функция из 100 строк, то она уже будет проигрывать от того, что она реализована одной функцией на 7 экранов, т.к. она уже все равно не простая и не лаконичная и одним взглядом её не поймёшь. Тут она уже выграет от разбивания на несколько функций, т.к. код станет более структурированным, более чётко будут видны интерфейсы и зависимости, от некоторых частей можно будет абстрагироваться и т.д. При этом кол-во кода вырастет — но мы готовы с этим мириться, т.к. взамен получаем более важные вещи.


R>Так же и с ООП. Для небольших задач оно может показаться overkill, одна для больших и сложных задач лучше написать больше кода, но зато явно выделить все понятия, разложить всё по полочкам. Вобщем структурировать. Допустим есть базовый класс Expression c 5 виртуальными функциями и есть 147 производных классов. Что бы всё это понять достаточно изучить базовый класс и один наследник. Всё. далее, когда надо будет допустим изменить поведение "сложения" понятно, что надо найти некий ExpressionPlus и изменить его.

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

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


Правильно. Авторы Немерле и не призывают от них отказываться (все что есть в C# есть и там). Но для некоторых случаев они припасли кое-что поудобнее .

R>Проблема, что кода много и он "по копирке" существует. Но есть приёмы, которыми практически всегда можно свести кол-во "повторяющегося" кода к минимуму.

Не всегда их удается изящно применить.

R>Если, конечно, захотеть это сделать.


R>

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Принцип подстановки Барбары Лисков
От: Андрей Хропов Россия  
Дата: 02.01.07 21:19
Оценка:
Здравствуйте, VladD2, Вы писали:

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

На самом деле чистые данные — это объект типа Tuple
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.01.07 23:17
Оценка:
Здравствуйте, Андрей Хропов, Вы писали:

АХ>На самом деле чистые данные — это объект типа Tuple


Под чистыми данными я имел в виду объекты без методов. Или даже так. Объекты с небольшим набором методов. Главное что они предназначены для обработки другими фукнциями. Такие объекты зачастую являются неизменяемыми (imutable).

Собственно это никак не противоречит ООП. Это всего лишь противоречит некоторым докамтическим приципам.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 03.01.07 00:29
Оценка: +1
Здравствуйте, Геннадий Васильев, Вы писали:

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


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

ГВ>Будут это switch/case, цепочки if или выражения для pattern-matching — не важно.


Только switch и if не надо, пожалуйста. Ценность подхода уменьшается пропорционально количеству порождаемого им мусора. К сожалению, в решениях со switch и if из-за деревьев становится леса не видно.

IT>>И как эта пробема решается другими средствами?


ГВ>Я тебе должен рассказывать про наследование и фабрики? Игорь, я точно не с твоим двойником общаюсь?


При чем тут фабрики и двойники? Твоя альтернатива — это наследование и инкапсуляция. Так и скажи.

Разница лишь в том, что в случае с объектами функционал скапливается вокруг объектов. В случае с match функционал помещается в одном месте, вокруг одной функциональной единицы приложения. У каждого подхода есть свои достоинства и недостатки, каждый может быть плох или хорош в каждом конкретном случае. Следовательно, не важно сколько таких мест в программе. Если разумнее выносить функционал в такие методы, то так и надо делать. Если его лучше оставить в объекте, то никто этого делать не запрещает.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 03.01.07 05:23
Оценка:
Здравствуйте, IT, Вы писали:

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


Так я подразумеваю как раз только те ситуации, когда предполагается расширение набора типов. Или проблема с расширением может возникнуть в условиях, когда набор типов зафиксирован? Это такой оксюморон, да? Так что не надо излишне обобщать. "В общем" понятно, что каждому инструменту своё место. Просто LSP, которой здесь онтопик, лучше всего применим именно тогда, когда мы предполагаем расширять набор типов. Отсюда уже формулируются "супертипы", "подтипы" и всё прочее подобное. И тогда решения, построенные на явном перечислении допустимых типов могут (я не говорю — непременно должны) оказаться неприемлемыми.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[5]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 03.01.07 05:35
Оценка:
Здравствуйте, VladD2, Вы писали:

ГВ>>Не важно, есть pattern-matching в языке, или нет. Проблема всегда в том, сколько именно такого кода появится в программе. Если один фрагмент — не беда, если десяток, то...


VD>Конечно! Разница только в удобстве! Вот только получая это удосбтво начинаешь задумываться на тем не являются ли догмами многие "незыблимые принципы ООП".


Да нет, принципы ООП догмами вовсе не являются, ну разве что в неокрепших умах, кои склонны к догматизму. И никто, вроде бы, на их догматичности не настаивает (прежде всего — сами авторы).

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

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


Ещё есть подход от данных и программ. Базовый, в общем-то. Остальное зависит уже от того, какой способ группировки мы выбираем в качестве строительного материала для абстракций.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[10]: Принцип подстановки Барбары Лисков
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.01.07 11:42
Оценка: 8 (1) +1 :)
Здравствуйте, IB, Вы писали:

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

IB>Я же сказал, что этот принцип совершенно не зависит от подхода, если забыть про ООП и расширить его на контракты и реализации.

Иван, забей. Ты, имхо, пытаешься уж слишком углубиться в дебри высоких абстракций. Эдак мы доберемся до двуединства Инь и Янь и их достаточности для описания всего сущего. К сожалению, из такой безусловно справедливой модели не удастся извлечь ничего, мало-мальски практически пригодного. Ну вот в принципе ничто не запрещает нам рассматривать вселенную как материальную точку с массой около 10^58 грамма, которая ни с чем не взаимодействует. Ну и что?

Так и с принципом Б.Л. Во-первых, изначально он был высказан именно в рамках ООП и именно по отношению к типам. Нет, я конечно в курсе, что в математике есть масса теорем, которые применяются значительно шире, чем мыслили их авторы. Но попытка интерпретировать принцип подстановки в общефилосовском смысле нас далеко не приведет. Да, можно считать, что если заменить утку на скотном дворе произвольным объектом, который жрет отруби, крякает, и несет яйца с потребной периодичностью, мы можем смело считать это чудо уткой. Даже если у него крыльев нету вовсе, а яйцекладов, к примеру, два. Контракт по отрубям, кряканью и яйцам выполнил — всё, свободен, иди окукливайся. Барбара разрешила.

Но вот, к примеру, в ФП уже не удастся найти что-то похожее на Контракт. Сигнатура функции служить таковым не может — если мы заменим Min на Max, то извините, последствия будут весьма и весьма заметны. А если определить контракт функции Min как возврат того аргумента, который не больше оставшегося, то заменить ее ничем вовсе не удастся.
Типы в ФП тоже вряд ли будут себя вести "правильным" с точки зрения Барбары образом. Потому, что, к примеру, целое число нельзя заменить комплексным — извлечение корня из целой -1 даст совсем другой результат, чем из комплексной. Да и в обратную сторону тоже нельзя. А если подойти с должной строгостью, то даже пытаться применить принцип подстановки к ним нельзя — в терминологии ФП экземпляры типов вовсе не имеют никакого поведения, стало быть и сравнивать нечего.
1.2.0 alpha rev. 655
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Принцип подстановки Барбары Лисков
От: Cyberax Марс  
Дата: 03.01.07 12:46
Оценка: +3
Sinclair wrote:
> Но вот, к примеру, в ФП уже не удастся найти что-то похожее на Контракт.
Ну почему же. Например, возьмем, к примеру, обычную высшую алгебру. У
нас есть полугруппа, моноид, группа, кольцо, тело, поле. При этом, все
теоремы для полугруппы будут выполняться, если вместо нее взять группу,
или, например, алгебраическую структуру с одной из операций поля.

То есть, контракты можно представить в виде набора аксиом. Для того же
sqrt у нас есть аксиома "sqrt(x)*sqrt(x)=x". Поэтому любой объект,
который выполняет эти аксиомы будет нам подходить. Например, мы можем
взять sqrt, использующий метод аппроксимаций Ньютона или fastsqrt из
сырцов Q3, а может даже sqrt, использующий статистические вычисления.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[12]: Принцип подстановки Барбары Лисков
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.01.07 13:07
Оценка: +1
Здравствуйте, Cyberax, Вы писали:
C>Ну почему же. Например, возьмем, к примеру, обычную высшую алгебру.

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

C>То есть, контракты можно представить в виде набора аксиом. Для того же

C>sqrt у нас есть аксиома "sqrt(x)*sqrt(x)=x". Поэтому любой объект,
О! Объект. Что есть объект? В ФП объектов нет. Есть функции, есть структуры. Объект в ООП является сущностью, обладающей идентичностью, поведением, и состоянием.
Поэтому для моделирования математики в ООП приходится идти на трюки. Вводить объекты типа "математика". Если требуется, к примеру, вычислять производную, то значит придется вводить объект "функция", и объект "дифференциатор", возвращающий для каждой функции другую функцию — ее производную. И весь полиморфизм сводится к тому, что можно заменять "дифференциатор" каким-то другим. С точки зрения математики, большого смысла это не имеет, т.к. существует ровно один способ получать из функции производную, который собственно зашит в ее определение. С точки зрения императивного программирования можно иметь разные "дифференциаторы", возвращающие различные, но эквивалентные производные функции.
Ну или можно отнаследовать от "дифференциатора" объект "функциональный анализ", который умеет в дополнение к дифференцированию выполнять еще и интегрирование. О да, вот этот объект будет потомком в смысле Лисков — ведь его можно отдавать всем клиентам, которым нужно дифференцирование.
Практического смысла это выпиливание по вазелину не имеет, поэтому во всех современных ОО-библиотеках есть банальный синглтон Math, который реализует чуть более сложные вычисления, чем арифметика.

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

C>взять sqrt, использующий метод аппроксимаций Ньютона или fastsqrt из
C>сырцов Q3, а может даже sqrt, использующий статистические вычисления.
А, пардон, зачем? И к чему это приведет? Напомню, что Барбара выдвигает требования к классам объектов. Что, мы сможем благодаря этому доказать, что одна из функций sqrt является в каком-то смысле наследником другой? Нет, не сможем. А уж если fastsqrt вернет неточный результат, то это вообще испортит нам всю малину — ведь мы сможем таки отличить в клиенте "настоящий" sqrt и переданный нам эрзац. Нарушаться будет соотношение sqrt(x)^2 == x.

Ок, ну, наверное, единственное что можно сделать в ФП в стиле Лисков — это доопределить функцию, которая ранее работала с неким множеством, на более широком множестве. Ну как там определяют Г(x), которая для натуральных x сводится к факториалу, но в отличие от факториала определена на всех комплексных числах. Наверное, так.
1.2.0 alpha rev. 655
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 03.01.07 13:14
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

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


ГВ>Так я подразумеваю как раз только те ситуации, когда предполагается расширение набора типов. Или проблема с расширением может возникнуть в условиях, когда набор типов зафиксирован? Это такой оксюморон, да? Так что не надо излишне обобщать. "В общем" понятно, что каждому инструменту своё место. Просто LSP, которой здесь онтопик, лучше всего применим именно тогда, когда мы предполагаем расширять набор типов. Отсюда уже формулируются "супертипы", "подтипы" и всё прочее подобное. И тогда решения, построенные на явном перечислении допустимых типов могут (я не говорю — непременно должны) оказаться неприемлемыми.


Это всё, Гена, надо было говорить в своём первом сообщении
Автор: Геннадий Васильев
Дата: 28.12.06
. Тогда и вопросов бы не было.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: Принцип подстановки Барбары Лисков
От: palm mute  
Дата: 03.01.07 13:25
Оценка: 1 (1) +3
Здравствуйте, Sinclair, Вы писали:

S>Но вот, к примеру, в ФП уже не удастся найти что-то похожее на Контракт. Сигнатура функции служить таковым не может — если мы заменим Min на Max, то извините, последствия будут весьма и весьма заметны. А если определить контракт функции Min как возврат того аргумента, который не больше оставшегося, то заменить ее ничем вовсе не удастся.

S>Типы в ФП тоже вряд ли будут себя вести "правильным" с точки зрения Барбары образом. Потому, что, к примеру, целое число нельзя заменить комплексным — извлечение корня из целой -1 даст совсем другой результат, чем из комплексной. Да и в обратную сторону тоже нельзя. А если подойти с должной строгостью, то даже пытаться применить принцип подстановки к ним нельзя — в терминологии ФП экземпляры типов вовсе не имеют никакого поведения, стало быть и сравнивать нечего.

Понятие контрактов вполне применимо в ФП. Смущает отсутствие классов/интерфейсов? Их можно заменить модулями ML или классами типов Haskell.
Контракт в ФП — это логическое утверждение об алгебраических свойствах функции или семейства функций. Например, применив функцию reverse дважды, мы должны получить исходный список. Функция сравнения, передаваемая в функцию сортировки, должна быть рефлексивной, транзитивной и антисимметричной. Известный пример контракта в функциональном мире — законы монад.
   1. (return x) >>= f == f x
   2. m >>= return == m
   3. (m >>= f) >>= g == m >>= (\x -> f x >>= g)


Что замечательно, для тестирования на соответствие контрактам есть автоматизированные средства — см. QuickCheck, реализованный для Haskell, Erlang, Python, etc.
Re[13]: Принцип подстановки Барбары Лисков
От: Cyberax Марс  
Дата: 03.01.07 13:31
Оценка:
Sinclair wrote:
> C>нас есть полугруппа, моноид, группа, кольцо, тело, поле. При этом, все
> C>теоремы для полугруппы будут выполняться, если вместо нее взять группу,
> C>или, например, алгебраическую структуру с одной из операций поля.
> Я себе совершенно не представляю, что означает "взять вместо полугруппы
> группу".
Если кратко, то полугруппа — это множество с определенной на нем
ассоциативной бинарной операцией. Группа — это множество с ассоциативной
бинарной операцией, причем в нем еще существует нейтральный элемент и
для каждого элемента (кроме нейтрального) существует обратный элемент.

> C>То есть, контракты можно представить в виде набора аксиом. Для того же

> C>sqrt у нас есть аксиома "sqrt(x)*sqrt(x)=x". Поэтому любой *объект*,
> О! Объект. Что есть объект? В ФП объектов нет. Есть /функции/, есть
> структуры. Объект в ООП является сущностью, обладающей идентичностью,
> поведением, и состоянием.
Я имел в виду "объект" в более широком смысле. Как синоним для слова
"фигня"

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

> C>взять sqrt, использующий метод аппроксимаций Ньютона или fastsqrt из
> C>сырцов Q3, а может даже sqrt, использующий статистические вычисления.
> А, пардон, /зачем/? И к чему это приведет? Напомню, что Барбара
> выдвигает требования к классам объектов. Что, мы сможем благодаря этому
> доказать, что /одна/ из функций sqrt является в каком-то смысле
> /наследником/ другой?
Не обязательно. Например, у нас может быть обычный арифметический sqrt и
sqrt, поддерживающий комплексные числа. Но для случая положительных
вещественных чисел комплексный sqrt будет вести себя как и арифметический.

> Нет, не сможем. А уж если fastsqrt вернет

> /неточный/ результат, то это вообще испортит нам всю малину — ведь мы
> сможем таки отличить в клиенте "настоящий" sqrt и переданный нам эрзац.
> Нарушаться будет соотношение sqrt(x)^2 == x.
В программировании "==" — это приблизительная операция

> Ок, ну, наверное, единственное что можно сделать в ФП в стиле Лисков —

> это /доопределить/ функцию, которая ранее работала с неким множеством,
> на более широком множестве. Ну как там определяют Г(x), которая для
> натуральных x сводится к факториалу, но в отличие от факториала
> определена на всех комплексных числах. Наверное, так.
Ну да, примерно так. Кстати, забыл сказать, что наследование контрактов
используется в системах с доказательством корректности кода.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[12]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 03.01.07 13:47
Оценка: +1
Здравствуйте, palm mute, Вы писали:

PM>Понятие контрактов вполне применимо в ФП.


Контракт как популярный термин был введён в SOA и обозначает формальное соглашение по взаимодействию между сервисами, независимое от платформ и языков программирования. Например, контракты для веб-сервисов описываются с помощью WSDL. В последнее время этот термин полюбился некоторым товарищам и они его пытаются применять с умным видом ко всему, что можно назвать публичным интерфейсом. Пока что кроме путаницы это ничего не даёт.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: Принцип подстановки Барбары Лисков
От: palm mute  
Дата: 03.01.07 13:56
Оценка:
Здравствуйте, IT, Вы писали:

PM>>Понятие контрактов вполне применимо в ФП.

IT>Контракт как популярный термин был введён в SOA и обозначает формальное соглашение по взаимодействию между сервисами, независимое от платформ и языков программирования.
Ок, примем такое определение. Тогда понятие контракта применимо к ООЯ не больше и не меньше, чем к ФЯ, т.к. по определению, контракты от языков не зависят. Мне все-таки кажется, что Sinclair не о тех контрактах говорил.
Re[12]: Принцип подстановки Барбары Лисков
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.01.07 13:56
Оценка: +1
Здравствуйте, palm mute, Вы писали:
PM>Понятие контрактов вполне применимо в ФП. Смущает отсутствие классов/интерфейсов? Их можно заменить модулями ML или классами типов Haskell.
PM>Контракт в ФП — это логическое утверждение об алгебраических свойствах функции или семейства функций. Например, применив функцию reverse дважды, мы должны получить исходный список.
Угу. Это все здорово, но не мог бы ты применить принцип подстановки Лисков к функции reverse и заменить ее чем-то другим?
PM> Функция сравнения, передаваемая в функцию сортировки, должна быть рефлексивной, транзитивной и антисимметричной.
Ну, при этом у нас нет такого понятия как "базовая рефлексивная функция", которое можно использовать как базу для наследования/субтипизации.
1.2.0 alpha rev. 655
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Принцип подстановки Барбары Лисков
От: palm mute  
Дата: 03.01.07 14:27
Оценка: -1 :)
Здравствуйте, Sinclair, Вы писали:

S>Угу. Это все здорово, но не мог бы ты применить принцип подстановки Лисков к функции reverse и заменить ее чем-то другим?

Я могу передать различные реализации функции reverse.
PM>> Функция сравнения, передаваемая в функцию сортировки, должна быть рефлексивной, транзитивной и антисимметричной.
S>Ну, при этом у нас нет такого понятия как "базовая рефлексивная функция", которое можно использовать как базу для наследования/субтипизации.
Зато мы может ввести понятие частично упорядоченного множества и требовать, чтобы функция сравнения задавала отношение частичного порядка. А затем ввести подтип — вполне упорядоченное множество. А затем наплодить реализаций этого интерфейса для чисел, строк, множеств и т.д.

В противном случае что получается?
class List<T> {
  public void Sort (
    IComparer<T> comparer
  )
}


module List = struct
  val sort : ('a -> 'a -> int) -> 'a list -> 'a list
end


К comparer, значит, LSP применим, а к первому аргументу List.sort — нет? В чем принципиальная разница?
Re[13]: Принцип подстановки Барбары Лисков
От: Cyberax Марс  
Дата: 03.01.07 14:35
Оценка:
IT wrote:
> Контракт как популярный термин был введён в SOA и обозначает формальное
> соглашение по взаимодействию между сервисами, независимое от платформ и
> языков программирования.
Hint: термин "контракты" в Eiffel появился, эдак, в начале 90-х.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[14]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 03.01.07 15:04
Оценка:
Здравствуйте, Cyberax, Вы писали:

>> Контракт как популярный термин был введён в SOA и обозначает формальное

>> соглашение по взаимодействию между сервисами, независимое от платформ и
>> языков программирования.
C>Hint: термин "контракты" в Eiffel появился, эдак, в начале 90-х.

В юриспруденции он появился ещё раньше. Тем не менее до знакомства с SOA его никто не использовал.
Если нам не помогут, то мы тоже никого не пощадим.
Re[15]: Принцип подстановки Барбары Лисков
От: Cyberax Марс  
Дата: 03.01.07 15:37
Оценка: +2 :))
IT wrote:
>> > Контракт как популярный термин был введён в SOA и обозначает формальное
>> > соглашение по взаимодействию между сервисами, независимое от платформ и
>> > языков программирования.
> C>Hint: термин "контракты" в Eiffel появился, эдак, в начале 90-х.
> В юриспруденции он появился ещё раньше. Тем не менее до знакомства с SOA
> его никто не использовал.
Это, минимум, большая натяжка. Я помню, что этот термин вполне нормально
употреблялся в ФИДОшных флеймах еще в прошлом тысячелетии, причем еще до
изобретения XML.

То что менеджеры узнали этот термин только недавно — это еще ничего не
значит.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[15]: Принцип подстановки Барбары Лисков
От: dottedmag Мальта http://dottedmag.net/
Дата: 03.01.07 15:44
Оценка:
Здравствуйте, IT, Вы писали:

>>> Контракт как популярный термин был введён в SOA и обозначает формальное

>>> соглашение по взаимодействию между сервисами, независимое от платформ и
>>> языков программирования.
C>>Hint: термин "контракты" в Eiffel появился, эдак, в начале 90-х.

IT>В юриспруденции он появился ещё раньше. Тем не менее до знакомства с SOA его никто не использовал.


<занудство on>ну я использовал до своего личного знакомства с SOA, именно как выше в квоте определено, заменяя "сервисы" на "сущности"</занудство off>
Re[16]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 03.01.07 16:13
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Это, минимум, большая натяжка. Я помню, что этот термин вполне нормально

C>употреблялся в ФИДОшных флеймах еще в прошлом тысячелетии, причем еще до
C>изобретения XML.

Может быть и использовался, но вот как-то не прижился.

C>То что менеджеры узнали этот термин только недавно — это еще ничего не значит.


Для тебя может и не значит, а я предпочитаю общаться с людьми на одном и том же языке и не устраивать терминологический трёп вроде этого по разным пустякам.
Если нам не помогут, то мы тоже никого не пощадим.
Re[16]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 03.01.07 16:21
Оценка:
Здравствуйте, dottedmag, Вы писали:

IT>>В юриспруденции он появился ещё раньше. Тем не менее до знакомства с SOA его никто не использовал.


D><занудство on>ну я использовал до своего личного знакомства с SOA, именно как выше в квоте определено, заменяя "сервисы" на "сущности"</занудство off>


Я не возражаю против использования этого термина в любой интерпретации. Только сегодня для многих он тестно связан с SOA. Хорошо это или плохо мне всё равно. Если этот термин нам всем так нравится как замена многословного "публичный интерфейс", то для того, чтобы его узурпировать нужно как минимум приучить понимать его других в этом контексте. У меня лично он чётко ассоциируется с SOA. Хочешь поменять мои рефлексы, используй какое-то время пояснения вроде — контракт (публичный интерфейс модуля) бла-бла-бла. А пока не удивляйся при упоминании контрактов вопросам из серии "А при чём тут вообще SOA ".
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 03.01.07 18:32
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Типы в ФП тоже вряд ли будут себя вести "правильным" с точки зрения Барбары образом. Потому, что, к примеру, целое число нельзя заменить комплексным — извлечение корня из целой -1 даст совсем другой результат, чем из комплексной. Да и в обратную сторону тоже нельзя.


А между целыми и комплексными определены отношения супертип-подтип?

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


LSP ничего не говорит о собственном поведении типов. Он связан только с подстановками.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[15]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 03.01.07 18:44
Оценка:
Здравствуйте, IT, Вы писали:

IT>Это всё, Гена, надо было говорить в своём первом сообщении
Автор: Геннадий Васильев
Дата: 28.12.06
. Тогда и вопросов бы не было.


Это сообщение было вообще на другую тему.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[13]: Принцип подстановки Барбары Лисков
От: Dr.Gigabit  
Дата: 03.01.07 22:03
Оценка: +1
Здравствуйте, Blazkowicz, Вы писали:

B>Здравствуйте, Геннадий Васильев, Вы писали:


IT>>>И как эта пробема решается другими средствами?


ГВ>>Я тебе должен рассказывать про наследование и фабрики? Игорь, я точно не с твоим двойником общаюсь?


B>Наверное имеется ввиду что во многих реальных и более примитивных случаев усложнение логики не окупается и бывает проще, выгоднее и нагляднее использовать switch или else if.


Как только дело доходит до множественной диспетчеризации (а собственно сама идеология паттерн-матчинга именно оттуда), ни ифы, ни фабрики с наследованием не спасают; ну или как минимум выразительность сильно страдает.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[12]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.01.07 17:20
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>То есть, контракты можно представить в виде набора аксиом. Для того же

C>sqrt у нас есть аксиома "sqrt(x)*sqrt(x)=x".

Согласись, что такой конктракт уже ничего общего с тем о чем говорил Ваня не имеет. В современных ЯП подобные контракты выражаются только ассертами. Кое что есть в Sepc#, Nemerle и совсем чуть-чуть в Эфиле (в том смысле, что проверки только в рантайме, а это почти те же ассерты). Причем такие контракты накладываются отнюдь не только на объекты. Они накладываются на функции/методы, циклы и т.п.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.01.07 17:20
Оценка:
Здравствуйте, IT, Вы писали:


IT>В юриспруденции он появился ещё раньше. Тем не менее до знакомства с SOA его никто не использовал.


Я бы сказал, что со статистической точки зрения Eiffel вообще никто не использовал и не использует.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Принцип подстановки Барбары Лисков
От: Cyberax Марс  
Дата: 04.01.07 20:38
Оценка:
VladD2 wrote:
> C>То есть, контракты можно представить в виде набора аксиом. Для того же
> C>sqrt у нас есть аксиома "sqrt(x)*sqrt(x)=x".
> Согласись, что такой конктракт уже ничего общего с тем о чем говорил
> Ваня не имеет.
Да, согласен.

> В современных ЯП подобные контракты выражаются только

> ассертами. Кое что есть в Sepc#, Nemerle и совсем чуть-чуть в Эфиле (в
> том смысле, что проверки только в рантайме, а это почти те же ассерты).
> Причем такие контракты накладываются отнюдь не только на объекты. Они
> накладываются на функции/методы, циклы и т.п.
Именно. Хотя исследования в этом направлении идут — GNU Hurd будет
использовать bitC для создания доказанного микроядра.
Posted via RSDN NNTP Server 2.0
Sapienti sat!
Re[11]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 04.01.07 21:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Иван, забей.

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

S> Эдак мы доберемся до двуединства Инь и Янь и их достаточности для описания всего сущего.

Заманчиво..

S> К сожалению, из такой безусловно справедливой модели не удастся извлечь ничего, мало-мальски практически пригодного.

Это уже другой вопрос.. )
Мы уже победили, просто это еще не так заметно...
Re[16]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 04.01.07 21:39
Оценка:
Здравствуйте, IT, Вы писали:

IT> Как минимум я не буду это отражать на веб-сервисамы, SOA и WCF и мы сразу начнём говорить на одном языке

Так проблема была в том, что я назвал это "контракт"? Ок, слово "спецификация" тебя устроит? )
Мы уже победили, просто это еще не так заметно...
Re[11]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 04.01.07 21:44
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ты почитай внимательно обсуждение.

Контракты и интерефейсы тоже догмы той идиологии

Это кто-то другой за тебя писал?

VD> Я говорил о том, что применение данного принципа становится бессмысленным как только ты отходишь от приципов ООП

А я говорил, что нет, по пятому кругу пойдем?

VD> Иначе разговор не получится.

Да он и так не очень-то.
Мы уже победили, просто это еще не так заметно...
Re[17]: Принцип подстановки Барбары Лисков
От: IT Россия linq2db.com
Дата: 04.01.07 21:56
Оценка:
Здравствуйте, IB, Вы писали:

IB>Так проблема была в том, что я назвал это "контракт"? Ок, слово "спецификация" тебя устроит? )


Теплее
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.01.07 22:32
Оценка: 27 (1) :)
Здравствуйте, Cyberax, Вы писали:

>> C>То есть, контракты можно представить в виде набора аксиом. Для того же

>> C>sqrt у нас есть аксиома "sqrt(x)*sqrt(x)=x".
>> Согласись, что такой конктракт уже ничего общего с тем о чем говорил
>> Ваня не имеет.
C>Да, согласен.

Ну, так мы с Синклером как раз и говорим, о том, что нельзя с мерилом из ООП, где понятие контракта очень специфично, подходить к программированию в целом. Так же надо понимать, что правла вроде обсуждаемого здесь имеют смысл только если твое видение мира ограничено ООП-ом. И его опять же нельзя применять на программирование в целом. Так что если нарушение подобных правил делается не по глупости, а просто потому что люди выбрали другой концептуальный подход, то это нормально и в сущьности никаких нарушенпй нет, так как само правило уже не применимо.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: Принцип подстановки Барбары Лисков
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.01.07 22:32
Оценка:
Здравствуйте, IB, Вы писали:

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


VD>>Ты почитай внимательно обсуждение.

IB>

IB>Контракты и интерефейсы тоже догмы той идиологии

IB>Это кто-то другой за тебя писал?

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

VD>> Я говорил о том, что применение данного принципа становится бессмысленным как только ты отходишь от приципов ООП

IB>А я говорил, что нет, по пятому кругу пойдем?

Ты говоришь совершенно бездоказательно и твои суждения рушатся на совершенно банальных вещах. К сожалению объяснить тебе ничего не удастся так как ты видел только одну сторону медали (ООП).

VD>> Иначе разговор не получится.

IB>Да он и так не очень-то.

Остльные вроде бы потихоничку пришли к консенсусу.
Автор: Cyberax
Дата: 04.01.07
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Принцип подстановки Барбары Лисков
От: IB Австрия http://rsdn.ru
Дата: 04.01.07 22:58
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это было сказано в ответ на твою попытку перевести разговор на обсуждение контрактов.

Я не пытался перевести разговор, я с самого начала о них говорил.

VD>Тут как раз очень хорошо было показано, что твое понимание контракта очень узко.

=)
Я формулировочку контракта специально упростил, чтобы тебе понятнее было. И в ее ширину вполне влезает все что было показано.

VD> И что в том же ФП контракты тоже есть, но они другие и их нелзя выразить средствами ООП.

Где я говорил, что контракт надо выражать средствами ООП? Я говорил совершенно обратное.

VD>К сожалению объяснить тебе ничего не удастся так как ты видел только одну сторону медали (ООП).

Влад, я устал. Давай сойдемся на том что я и ООП-то не очень знаю и покончим с этим.
Мы уже победили, просто это еще не так заметно...
Re[15]: Принцип подстановки Барбары Лисков
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 05.01.07 10:23
Оценка: 1 (1) +2
Здравствуйте, VladD2, Вы писали:

VD>Ну, так мы с Синклером как раз и говорим, о том, что нельзя с мерилом из ООП, где понятие контракта очень специфично, подходить к программированию в целом.


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

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


LSP прекрасно работает начиная с того момента, когда мы определяем некие "слоты" для дальнейшего расширения системы. Совершенно не важно, как именно мы будем определим сами "слоты": как соглашения для функций (сигнатуры и требования к функциям), или для классов (интерфейсы в смысле "interface"). Когда соглашения слота будут определены, следующим шагом с большой вероятностью этот набор будет объявлен "типом", ибо так проще ссылаться на него в дальнейшем. А те внешние "штуки", которые должны будут подключаться к этому слоту — будут называться реализациями типа, или же — подтипами. Вуаля! Здравствуй, критерий допустимости подстановки Лисковой.

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


Естественно, нет необходимости блюсти LSP, если не возникает тех самых "слотов" расширения.

PS.: Ты это, бросай уже на "догмомировзгляды" ссылаться. Это всё забавно, конечно, но ощущение возникает, что читателю мозги промыть пытаются.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[13]: Принцип подстановки Барбары Лисков
От: deniok Россия  
Дата: 05.01.07 15:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

PM>>Понятие контрактов вполне применимо в ФП. Смущает отсутствие классов/интерфейсов? Их можно заменить модулями ML или классами типов Haskell.
PM>>Контракт в ФП — это логическое утверждение об алгебраических свойствах функции или семейства функций. Например, применив функцию reverse дважды, мы должны получить исходный список.
S>Угу. Это все здорово, но не мог бы ты применить принцип подстановки Лисков к функции reverse и заменить ее чем-то другим?
PM>> Функция сравнения, передаваемая в функцию сортировки, должна быть рефлексивной, транзитивной и антисимметричной.
S>Ну, при этом у нас нет такого понятия как "базовая рефлексивная функция", которое можно использовать как базу для наследования/субтипизации.

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

1. (return x) >>= f == f x
2. m >>= return == m
3. (m >>= f) >>= g == m >>= (\x -> f x >>= g)

то таки да, в Хаскелле любой тип, являющийся экземпляром класса Monad должен им удовлетворять. Правда это не проверяется на языковом уровне, но palm mute давал ссылки на внешние системы проверки.
Re[3]: Принцип подстановки Барбары Лисков
От: dr.Chaos Россия Украшения HandMade
Дата: 05.01.07 17:11
Оценка:
Здравствуйте, Кирилл Лебедев, Вы писали:

КЛ>Здравствуйте, LaptevVV, Вы писали:


LVV>>Обратное — неверно! Всякий будильник (производный тип) является часами (базовый тип), но не всякие часы — будильник.


КЛ>Я бы сказал несколько иначе. Существуют две функции:


КЛ>1) Измерение времени.

КЛ>2) Выдача сообщения (например, звонка) по сигналу.

КЛ>Эти функции могут быть реализованы как в одном устройстве, так и в разных. Это я к тому, что далеко не всякий будильник является или может являться часами.


Любой будильник измеряет время, он его может не показывать, это как раз комбинация тех двух устройств : измерителя и сигнала
Побеждающий других — силен,
Побеждающий себя — Могущественен.
Лао Цзы
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.