LINUX.ORG.RU

ооп, иерархии, подмножества


2

2

если стандартное отношение наследования в точности не совпадает с идеей иерархии/подмножеств (для чего их обычно и пытаются использовать, и потом рождаются псевдопроблемы про квадарт и параллелипипед, эквивалентность итп)... Почему бы не ввести для этого интуитивно ожидаемого отношения специальные ключевые слова и строить все на них? (вместо классического наследования с подразумевающимися принципами [Single responsibility, Open/closed, Liskov substitution, Interface segregation, Dependency inversion], его можно дропнуть вообще) Включая другие интуитивно-нужные вещи типа пересечения. Где-то из ооп-мейнстрима такое уже есть?

★★★★☆

Ответ на: комментарий от monk

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

а тут учебник по теории чисел, и пишем ее from ground up )) Сначала у нас есть палочки, палочки можно сгребать в кучки... ну итп до когда не надоест ))

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

перечисли все числа с 0 до 100 вручную

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

anonimous
()
Ответ на: комментарий от anonimous

Я тоже не знаком, но знаю, что <в определенных кругах> он прославился тем, что скопипиздил, один в один теорию нашего Шейфенкеля, благодаря чему и прославился.

anonymous
()
Ответ на: комментарий от anonymous

Да, сам термин «каррирование», а оно открыто Шойфенкелем, какбэ намекает.

anonimous
()
Ответ на: комментарий от anonimous

ну-ка напиши на Яве тип «процент»

class Percent {
  private int value = 0;
  public Percent(int number) {
   if (number<0 || number>100) throw new Exception("wtf") 
   else value = number;
  }
}

дооо, очень красиво и отражает суть вещей

stevejobs ★★★★☆
() автор топика
Ответ на: комментарий от stevejobs

ну-ка напиши на Яве тип «процент»

Я где-то сказал, что ява - годный ЯП?

anonimous
()
Ответ на: комментарий от anonimous

А если серьезно, какой язык нормальный? Со статической типизацией, естественно. Типы в динамике - это не типы, а «проверки».

anonymous
()
Ответ на: комментарий от anonimous

Зато полное перечисление можно проверить статически в compile time, а вот этот иф с экзепшеном в конструкторе даже IDE типа Идеи не распарсит (нужно городить язык, в котором в сигнатуру нужно будет добавлять тесты/guards, которые IDE будет гонять в compile time для проверки параметров, а в рантайме в начало каждого метода с этими гардами впихать проверку теста и если не проходит - RuntimeException).

типа

class Percent {
  private int value = 0;
  @Guard("should be between 0 and 100", number>=0, number<100)
  public Percent(int number) {
    value = number;
  }
}

stevejobs ★★★★☆
() автор топика
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

Зато полное перечисление можно проверить статически в compile time

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

anonimous
()
Ответ на: комментарий от anonimous

типы - это такие синтаксические(!) штуки для проверки отсутствия определенного вида ошибок в программах. Хочешь поспорить - спорь с таплом.

anonymous
()
Ответ на: комментарий от anonimous

можно сделать вывод, что вам подойдет только динамика.

Можно подробнее?

anonymous
()
Ответ на: комментарий от stevejobs

их модели равны тогда, когда есть взаимооднозначное преобразование, превращающее одну модель в другую

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

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

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

Я не уверен, что написание горы canEqual, hasEqual, shouldEqual, approxEqual итп есть правильная «таблица умножения»,

Конечно неправильная.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Зачем вообще делать квадрат наследником прямоугольника, если он в общем случае не отвечает принципу подстановки лисков? В чью светлую голову пришла эта мысль? А если он будет отвечать в каком-то конкретном случае, то и с наследованием проблемы не будет.

anonymous
()
Ответ на: комментарий от anonymous

Мне нравится ATS

Например, упомянутый percent:

sortdef percent = {a: int | 0 <= a && a <= 100}

Статические проверки. Зависимые типы. Высокая скорость. Замыкания, лямбды, вывод типов, сборка мусора, многопоточность. Близкий к Си синтаксис (не скобки и не хаскелевский a b c d = c b d).

monk ★★★★★
()
Ответ на: комментарий от anonymous

типы - это такие синтаксические(!) штуки для проверки отсутствия определенного вида ошибок в программах.

Хм... пытаюсь представить себе C++ (особенно его шаблоны) без типов (предположим мне не надо ничего проверять)... как-то даже не представляется.

И даже в CL (динамическом!) есть стандартная конструкция typecase. Так что не для проверки на ошибки, а для выбора алгоритма в зависимости от _типа_ полученных данных.

monk ★★★★★
()
Ответ на: комментарий от anonymous

Зачем вообще делать квадрат наследником прямоугольника

Вопрос не по адресу. Я так не делаю.

не отвечает принципу подстановки лисков?

Этот принцип по факту требует, чтобы наследник был в одной категории с родителем. Т.о. наследование не создает новой категории объектов, оно создает иную реализацию.

если он будет отвечать в каком-то конкретном случае

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

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Этот принцип по факту требует, чтобы наследник был в одной категории с родителем.

Интересно, есть ли хоть одна объектная модель, где этот принцип соблюдается?

Ведь даже в POSIX: наследование файл->каталог, файл->сокет хотя к сокету или каталогу применимы не все операции с файлом.

Про графические системы типа Motif/Gtk/KDE я уж молчу: там сплошные переходы типа прямоугольник->квадрат.

И что взамен? Union и typecase в качестве основного инструмента?

monk ★★★★★
()
Ответ на: комментарий от no-such-file

Что, и предикат-ограничение таки проверяется статически

Везде, где может. Если параметр константа или ограничен. По крайней мере автор так заявляет...

monk ★★★★★
()
Ответ на: комментарий от monk

И что взамен?

Тред не читай, сразу отвечай.

Ведь даже в POSIX: наследование файл->каталог, файл->сокет

Где вы там наследование нашли? Эта иерархия есть только в голове, в коде её нет.

Про графические системы типа Motif/Gtk/KDE я уж молчу: там сплошные переходы типа прямоугольник->квадрат.

Про Motif и Gtk не скажу, глубоко не копал, а вот в Qt проблема решается тем, что категории виджетов там строятся не на классах, а на совершенно сбоку приделанной метаобъектной системе со своей отдельной иерархией, свойствами (properties) слотами и сигналами. Да и прибавьте к этому неповторимый костыль qobject_cast призванный заставить крутиться всю эту динамику быстрее чем на голом dynamic_cast.

no-such-file ★★★★★
()
Ответ на: комментарий от monk

Везде, где может

Пусть задан диапазон p 0..100, диапазон q 0..10, дано выражение p=p*q/2. При определенных условиях (достаточно малые p и q) результат корректен и попадает в заданный диапазон для p, но не всегда. Является ли данное выражение корректным для статического проверяльщика. Если нет, то как мне вывернуться, чтобы задать корректный диапазон для q, если он зависит от значения p?

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от anonymous

спорь с таплом

Он для меня ничего не значит

синтаксические(!)

Ну и что? Что это прпинципиально меняет? Ты и в динамике можешь проверять синтаксически.

anonimous
()
Ответ на: комментарий от anonymous

синтаксические(!)

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

anonimous
()
Ответ на: комментарий от no-such-file

Является ли данное выражение корректным для статического проверяльщика.

Сам же пишешь «не всегда». Соответственно, скажет что-то вроде «доказать нельзя». А если q: 0..2, тогда корректно всегда.

Такое даже Typed Racket умеет проверять. Правда, в отличие от ATS, на «не всгда корректные» куски ругается и требует менять типы. То есть в упомянутом выше случае тип p придётся ставить «целое неотрицательное». Ну или опять же q: 0..2.

Про ATS и доказательства вот подробно: http://www.ats-lang.org/EXAMPLE/#FIBONACCIexample

monk ★★★★★
()
Ответ на: комментарий от monk

скажет что-то вроде «доказать нельзя».

И нафига тогда это надо.

А если q: 0..2, тогда корректно всегда.

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

Ну ладно, посмотрю что за зверь по-подробнее.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

И нафига тогда это надо.

1. Замена Си/С++ (скорость та же, синтаксис близок, но нормальные замыкания, ФВП, сборщик мусора, нормальные модули).

2. Если где-то нужна гарантия при любых входных данных, то можно указать инварианты, а ATS скажет, действительно ли это так (как на Agda).

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

monk ★★★★★
()

http://www.cs.uwm.edu/~boyland/fool2012/papers/fool2012_submission_3.pdf — как раз на основе подмножеств, пересечений, объединений и т.п., так что просто обязательно к ознакомлению :)

http://www.reddit.com/r/haskell/comments/1pjjy5/odersky_the_trouble_with_type...

А вот если смешивать агрегацию полей и наследование интерфейсов, как в C++, то действительно иногда возникают весёлые ситуации (например, делаем MaybeA : A и обеспечиваем хорошую (но не тривиальную) агрегацию и правильные публичные конструкторы, но забываем удалить или переопределить метод(ы) из AIface, так что MaybeAIface в итоге может ломать объекты — он же содержит методы которые для A предполагались).

Ещё вариант — простая агрегация и простые интерфейсы отдельно, как в Haskell (data A агрегируется в data MaybeA, при этом отдельный интерфейс в виде class Iface никак неявно ничего не ломает, так как требуется явного расписывания для A и MaybeA).

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)

Почему бы не ввести для этого интуитивно ожидаемого отношения специальные ключевые слова и строить все на них? (

аспекты ?

anonymous
()
Ответ на: комментарий от AIv

Что такое A и B?

миксины, например, или аспекты

Как вообще из этого самого подмножества получить в итоге что то работающее? Как подмножество устроено?

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

anonymous
()
Ответ на: комментарий от no-such-file

Методы считаем за свойства?

нет, свойства за методы — геттер и сеттер

anonymous
()
Ответ на: комментарий от arturpub

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

попробую сформулировать: суть ООП не состоит в «наследовании, инкапсуляции, полиморфизме».

суть ООП состоит в реализации некоторой «объектной модели», показывающей как объекты работают в рантайме.

эта модель может быть построена на этих трёх концепциях «наследование, инкапсуляция, полиморфизм» (назовём ее оо-модель-С++), а может быть на других «посылка сообщений, позднее связывание» (назовём её оо-модель-смоллток, она же в objective c), а может быть основана на других принципах «методы вне классов, мультиметоды, метаобъектный протокол, динамическое расширение» (назовём её оо-модель-CLOS), или на каких-то других вообще принципах (так, автор C object system Laurent Deniau приводит мультидиспетчирезацию сообщений и мультифорвардинг сообщений, как основные способы построения «динамической объектной модели»).

вполне логично, что ООП можно построить и на каких-то других ортогональных принципах.

например, в Oberon-2, Компонентно-Ориентированном Программировании приводились другие принципы на уровне модулей.

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

например, возьмём такие штуки как traits, mixins, aspects.

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

метаобъектный протокол,протоколы и категории в Objective C и интерфейсы — это тоже в некотором роде одно и то же, по-разному выраженное.

anonymous
()
Ответ на: комментарий от anonymous

да, а Бертран Мейер в тёплом ламповом Эйфеле тоже придумывает свою терминологию: специализацию и универсализацию.

anonymous
()
Ответ на: комментарий от arturpub

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

озвучь ещё раз

anonymous
()
Ответ на: комментарий от stevejobs

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

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

они применяются к объектам, которые задаются в наиболее общем виде (это Understand FOO as BAR now. или «kind of things»)

логично далее придумывать правила правил, метаправила и прочие.

а для моделей — модели и метамодели. и преобразовывать по таким метаправилам такие метамодели.

где «наличие свойства» - часто встречающийся пример правила, и в силу частоты употребления имеющий для себя специальный синтаксис

предикат или действие ?

anonymous
()
Ответ на: комментарий от no-such-file

Давайте пример на квадрате и параллелепипеде, что бы вы хотели от ключевого слова model. Давайте иерархию на model, примеры с пересечением и т.п.

пример: если на квадрате и параллепипеде нарушается принцип подстановки Лисков (LSP), то значит мы получили сущность не класс (для которой он не должен нарушаться), а что-то другое.

модель — хорошо, только уточняйте модель чего, в каком смысле модель.

anonymous
()
Ответ на: комментарий от anonymous

Анончик, охота обсудить, но времени прям щас нет. Блин.

arturpub ★★
()
Ответ на: комментарий от anonimous

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

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

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

anonymous
()
Ответ на: комментарий от anonimous

К примеру, в простейшем случае, ты можешь написать функцию, которая возвращает множество с заданными свойствами, какие ты сам считаешь нужным для того чтобы квадрат был квадратом. Присваиваешь результат переменной, Штампуй эти переменные - они будут «Экземплярами твоего класса»

что-то похожее на predicate dispatch

anonymous
()
Ответ на: комментарий от AIv

Я половину слов в посте не понял

Это норма, он сам свой понос, только понимает.

windofchange
()
Ответ на: комментарий от no-such-file

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

праально, а почему? потому что наследование это слишком статическая онтология, а хочется какой-то параллельной онтологии в динамике.

комбинаторы

ага. а потом будут комбинаторы комбинаторов, классы комбинаторов, комбинаторы классов, классы классов и т.п.

плюс какие-то индексы на tree dispatch.

собственно C++-ный VTABLE это есть пример, когда эти индексы по отношению наследования МОЖНО построить во время компиляции ПРИ УСЛОВИЯХ (ограничения, виртуальные методы и т.п.)

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

anonymous
()
Ответ на: комментарий от no-such-file

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

детали, из чего он конкретно там состоит не нужны (инкапсуляция же — может же там гвоздей нет?).

нужны абстрактные классы стол, стул, интерфейс с методом сидеть, отличительное свойство «без спинки».

anonymous
()
Ответ на: комментарий от no-such-file

кстати, а почему на ноль делить нельзя?

ведь если выражать деление через вычитание, то вычитать 0 раз ведь можно ;-^)

anonymous
()
Ответ на: комментарий от anonimous

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

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.