LINUX.ORG.RU

ООП. Как представляете себе идеальную реализацию?

 , ,


2

3

Я знаю как минимум 4 слабо совместимых друг с другом понятия ООП:

  • С++: класс = неймспейc, вызов метода через точку,
  • CLOS: класс = идентификатор + наследование, тело метода определяется по классу всех параметров (а не только первого), методы доопределяются модификаторами :after :before :around.
  • Racket: класс = first-class object, как и функция, соответственно, может доопределяться по месту и не иметь имени.
  • Haskell: классы типов как наборы операций над типам (которые можно считать эквивалентными классам других языков)

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

★★★★★

Self: классов нет, есть объекты, клонирование и делегация. У вас это, вероятно, Racket.

класс = first-class object

Вот тебе, бабушка, и XXI-ый век, есть «ООП», где класс — не first-class entity.

идентификатор + наследование, тело метода определяется по классу всех параметров (а не только первого), методы доопределяются модификаторами :after :before :around.

Как сложно вы описали множественную диспетчеризацию.

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

Кстати, да. Пятая категория: javascript, self = у разных объектов одного класса могут быть разный набор полей и разные методы.

В Racket хитрее: там объект создаётся через что-то типа

(define super-window
  (class (decorated (gradiented (always-on-top window%)))
    (super-new)))

где decorated, gradiented и т.д. — функции с одним аргументом типа «класс» и возвращающие класс.

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

есть «ООП», где класс — не first-class entity.

С++, Java, Haskell, ... --- много их. В CLOS вроде как first-class, но безымянный существовать не может, так как методы привязываются не к классу, а к его имени.

monk ★★★★★ ()

Это все ООП на классах, а где на прототипах?

слабо совместимых друг с другом понятия ООП:

Чем же они слабо совместимы? Везде есть тип(ы) + набор операций (функций, методов).

Из всего списка мне больше нравится CLOS как наиболее развитый вариант.

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

Или сразу делаем экземпляр безымянного класса

(define super-window
  (new (class (decorated (gradiented (always-on-top window%)))
         (super-new)))
     [title "Super window]))

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

Вот тебе, бабушка, и XXI-ый век, есть «ООП», где класс — не first-class entity.

Вам несложно будет назвать десяток языков, где класс (а не объект класса) - first-class entity?

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

Чем же они слабо совместимы? Везде есть тип(ы) + набор операций (функций, методов).

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

С++ -> CLOS — не хватает имён

CLOS -> C++ — половина действий невозможно (начиная от метода для двух классов, заканчивая тривиальным :before).

ну и так далее...

Соответственно «идеальным ООП» в рамках данного треда можем считать такой ООП, на который можно перенести любое API, описанное в вышеприведённых стилях.

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

десяток языков, где класс (а не объект класса) - first-class entity

Common Lisp, Racket, Scheme, Java (через Reflection), Closure, Scala, Ruby, Python, Perl, Vala

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

Тогда в Racket класс = словарь

Ну не совсем. Добавить или изменить в этом «словаре» ничего нельзя. Только в момент создания. Поэтому скорее тоже «неймспейс»

У C++ перед Racket есть плюс: возможность полиморфизма методов.

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

С++ -> CLOS — не хватает имён

Чего, простите?

CLOS -> C++ — половина действий невозможно (начиная от метода для двух классов, заканчивая тривиальным :before).

Я бы сказал 3/4 действий невозможно.

такой ООП, на который можно перенести любое API, описанное в вышеприведённых стилях

Не думаю, что такая ООП система есть, но сделать можно всё. А зачем?

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

Интроспекция != first-class entity.

first-class entity для класса - это когда можно сохранить определение класса в переменную. Соответственно языки с декларативным описание классов не подходят.

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

Чего, простите?

Есть C++ библиотека

class A
{
    A();
    A(string x);
    int foo();
    int foo(int a);
    int foo(string s);
    ~A();
}

class B
{
    B();
    B(string x);
    int foo();
    int foo(string file);
    int foo(int a);
    int foo(int a, int b);
    ~B();
}

Тебе надо сделать идентичную реализацию на CLOS. Какие сигнатуры будут у методов (7 функций foo)?

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

когда можно сохранить определение класса в переменную

Ну тогда все языки с ООП и eval :-)

Из списка выкинь Java, добавь Tcl.

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

Не думаю, что такая ООП система есть, но сделать можно всё. А зачем?

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

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

Какие сигнатуры будут у методов (7 функций foo)?

Перегрузку придётся делать руками - передавать пары key=value и делать матчинг по ним, либо матчить параметры по типу/количеству.

В итоге имеем то же самое, т.к. C++ не диспетчит методы по параметрам.

Альтернативный вариант - заворачивать параметры в специальный класс параметров и диспетчить методы по двум классам - рабочему и параметров. В итоге имеем «перегрузку», почти как в крестах.

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

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

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

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

заворачивать параметры в специальный класс параметров

А пользоваться как?

(foo my-b (make-instance 'parameters-int-int 1 2)) ?

Или я что-то не так понял?

передавать пары key=value и делать матчинг по ним

В этом случае имеем а) параметры по имени кроме первого b) в реализации один огромный cond/case/typecase на реально 3-4 функции.

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

Интересно послушать, что скажет yoghurt.

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

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

И разве eval исполняется в текущем окружении (захватывает переменные из окружения)?

Обычно ему их можно как-нибудь передать. По крайней мере у всех перечисленных подобные костыли имеются. (у Lisp'а будет defmacro, у tcl мощный eval, у Python функция type и т.д.)

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

пятый подход к ООП — «не нужно».

Тогда какие блоки декомпозиции посоветуешь? структуры и модули? Так это тоже «ООП», только упрощённое.

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

А после выбора переделывать архитектуру под возможности языка?

По-моему, лучше сначала сделать архитектуру под задачу, потом попытаться подобрать язык под архитектуру, а уже потом что в выбранный язык не помещается, либо переделывать либо дописывать язык (как сделали, например, Trolltech со своим Qt).

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

(foo my-b (make-instance 'parameters-int-int 1 2)) ?

Вроде этого, только я обычно даю осмысленные имена и make-instance заворачиваю в функцию/макрос. Тогда:

(foo my-b (number-pair 1 2))

или

(foo my-b (file-name «test.me»))

Пойдет?

а) параметры по имени кроме первого

Как будто это что-то плохое.

b) в реализации один огромный cond/case/typecase на реально 3-4 функции.

Это да. Но для красоты можно спрятать в макрос.

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

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

По моему, это слишком идеалистический подход. Кадры решают всё - и в наше время тоже, так что дешевле нанять 10 индусов и наколбасить по-быстрому на крестах/яве/шарпе по имеющимся шаблонам, чем что-то изобретать и выискивать.

Хотя, конечно, всё зависит от того, что значит «лучше».

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

Пойдет?

На безрыбье, конечно пойдёт...

Но я с трудом представляю себе в API например, для GTK-CFFI описание типа

(text text-buffer parameters) => текст 

примеры:

(text buf (start-end--include-hidden 0 5 t))

В принципе, я костыль придумал: https://github.com/Kalimehtar/message-oo , но при этом приходится отказываться от принципа «метод = функция».

для красоты можно спрятать в макрос

Всё равно это всё сломается как только встретится class C : public B { int foo(int a, int b, int c); }.

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

у Python функция type

Это тип, а не функция. Для удобства и для совместимости с предыдущими версиями языка, в которых type действительно был функцией, умеет имитировать такое поведение, благо синтаксис инстанцирования классов/типов и вызов функции выглядит одинаково.

И в пайтоновский eval тоже можно передавать произвольный неймспейс.

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

Кадры решают всё

Индусов можно найти для разных языков. А вот слишком ранний выбор языка иногда делает рассматриваемую задачу трудно решаемой или не решаемой вовсе. Например, стоит задача «сделать серверный движок, позволяющий пользователю писать скрипты отображающиеся в GUI и HTML/JS, серверный код скриптов должен быть единым». Если сразу выбрать Яву/C++, то решение будет прогнутым под HTML с явным разделением серверного/клиентского кода в скриптах, а если рассматривать все языки, то можно и типа Seaside/Weblocks что-то придумать.

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

я с трудом представляю себе в API например, для GTK-CFFI

А зачем, gtk не использует кресты, значит там нет перегрузки. Поэтому просто передаём один параметр для диспетчинга (gobject) и произвольный набор параметров, по которым диспетчинга нет.

Собственно, все как в крестах, только объект передаётся явно как пареметр. Диспетчинг по двум параметрам нужен только для реализации «перегрузки».

Всё равно это всё сломается как только встретится class C : public B { int foo(int a, int b, int c); }.

Если так писать, то и в крестах сломается - foo из C закрывает все определения из B.

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

сделать серверный движок, позволяющий пользователю писать скрипты отображающиеся в GUI и HTML/JS, серверный код скриптов должен быть единым

Так бы и сказали - сервер приложений. Кстати на java - вагон и маленькая тележка вариантов, гораздо более проработанных чем seaside (не говоря уж о weblocks). Парочка явистов есть в любой деревне, а вот где искать людей с опытом на weblocks в количестве более 1.5 человек я не знаю.

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

передаём один параметр для диспетчинга (gobject) и произвольный набор параметров, по которым диспетчинга нет

Приходится или этот «произвольный набор» всегда писать после &key, что иногда неудобно, или наткнувшись на другое количество параметров переписывать оба метода (пока в gtk-cffi так и делаю).

Вторая проблема: в cl уже используются over 900 имён, включая такие часто используемые как length, remove, position, delete, ...

foo из C закрывает все определения из B

Точно. Забыл. Тогда про перегрузку внутри класса согласен.

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

гораздо более проработанных чем seaside

Можно ссылку хотя бы на один движок на Java для Web, в котором можно писать наподобие

void loadForm()
{
   for(int i=0; i<=countObjects; i++) {
      showProgress(i*1.0/countObjects);
      if(i>100 && !askUser("100 Loaded. Continue?"))
         break;
      loadData(i);
   }
}

?

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

В CLOS вроде как first-class, но безымянный существовать не может, так как методы привязываются не к классу, а к его имени.

К классу, а не к имени; так что может. См. например раздел 7.4 Mapping Between Names and Objects у Sonja Keene.

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

А зачем, gtk не использует кресты, значит там нет перегрузки.

Тогда можно CommonQt например взять. Там по факту сделали своё пространство имён с доступом через #_.

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

к безымянному классу добавить метод

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

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

в cl уже используются over 900 имён, включая такие часто используемые как length, remove, position, delete, ...

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

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

Вообще-то на smalltalk'е энтерпрайз писали и пишут (что будут писать утверждать не берусь). И побольше чем на лиспах и даже хаскелях (который разработчики из Microsoft Research считают production-ready).

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

в cl уже используются over 900 имён, включая такие часто используемые как length...

Это ещё ничего. В некоторых языках length (или size) - это ключевое слово.

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

Вообще-то на smalltalk'е энтерпрайз писали и пишут

Где?

И побольше чем на лиспах

Даже на ЛОРе есть энтерпрайзописатели на лиспе (с их слов). А где смолтолкеры, которые хотя бы говорят, что пишут ынтерпрайз?

no-such-file ★★★★★ ()

С++: класс = неймспейc, вызов метода через точку
класс = неймспейc
класс = неймспейc

Дальше не читал.

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

Из списка выкинь Java

Почему? Только потому, что твой собеседник некомпетентен в Java и перепутал интроспекцию с рефлексией?

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

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

Но ведь уже существует инструмент для «описания архитектуры программы до начала программирования». Называется UML. Зачем изобретать велосипед?

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