Pull to refresh

Comments 99

спасибо за пост! вы открыли мне глаза на мои заблуждения относительно Lisp'а. Радует наличие поддержки OpenGL под LISP, и главное большое количество кроссплатформенности)
учитывая развитый FFI, обертки для C-библиотек делаются относительно просто. Кстати, для OpenGL есть еще и другие варианты: www.cliki.net/OpenGL%20Bindings
Кстати, opengl я изучал именно в лиспе по cl-opengl. Очень удобно менять код отрисовки или значения переменных без перезапуска программы. Ошибки также удобно исправлять (поймал ошибку, исправил и перекомпилировал функцию, продолжил выполнение программы).
Здорово, правда мне до гуи еще как до китая… Но заметочку поставил.
Я чего-то не понял, или вы еще раз подтвердили это миф? Разберемся по полкам:

> Базовой библиотекой для графики из Common Lisp под Unix является CLX. Это аналог xlib, т.е. низкоуровневый клиент, напрямую общающийся по X-протоколу.

Тут даже говорить не о чем.

> есть обертки для основных графических фреймворков разной степени зрелости: LTK, CL-GTK2, CommonQt, CL-CAIRO2

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

> Лично мне доводилось иметь дело с LTK

Предлагать писать гуй на Тк в 2010 году, когда в линуксе, наконец, с горем пополам, появилась какая-никакая унификация гуи и внешнего вида приложений (по крайней мере в гноме)… скажите честно, вы диверсант и саботажник?

> McCLIM

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

Поняли действительно неправильно. Про cl-gtk2 я могу сказать, что и о поддержке, и новых версиях речь идет.
есть обертки для основных графических фреймворков разной степени зрелости: LTK, CL-GTK2, CommonQt, CL-CAIRO2

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

В общем-то, обертки (GTK и иже с ними) делаются не раз в 2 года на колене, а нормальным считается написать и поддерживать скрипт, который из любой версии этого GTK сделает обертку. Между минорными релизами тулкитов этот скрипт даже не приходится и менять. Поэтому ваш самый страшный аргумент недействителен.
А где скриншоты этих Гуевых Лисп приложений?
Их я тут тоже ожидал увидеть.
Пару скриншотов то есть для примера. Если зайдете на сайты соотв. библиотек то увидите тестовые приложения. Как правило, они вас ничем не удивят — обычные скриншоты приложений на GTK или Cocoa :)

Вот еще для примера скриншотик LTK GUI, которое я «держал» в руках:
LTK screenshot
(в центре экрана)
Работать с ним было довольно просто.

Понятно, что это не навороченный вариант, а самый простенький. Но для разных целей нужны разные подходы. Для очень многих программ наиболее ценна возможность быстро и сразу посмотреть что-то на экране и интерактивно этим управлять.
А ведь есть жизнь на Марсе, в смысле гуй на лиспе :). Спасибо за статью, все таки Lisp — язык мощный и может использоваться в том числе и для GUI-приложений, может кому-то будет полезна статья
Помнится была попытка перевести McCLIM на GTK, но видимо не взлетело. Я даже пробовал его тогда запускать — ацки тормозило. McCLIM очень сложный и перегруженный кодом внутри — в этом его проблема.
Там использовалось не Gtk, а движки тем от Gtk.
Проблема McCLIM не в перегруженности, а в том, что им не занимаются. Еще у него интерфейс слишком общий.
Возможно. Когда я 4 года назад в него смотрел, его код создавал впечатление именно хитроперекрученности какой-то и избыточности. Однако CLIM imho лучший подход к описанию GUI для лиспа.
Я бы не согласился. В CLIM есть хорошие идеи, но его API очень устарело.
Да, именно избыточность и хитроперекрученность. А еще слабоспецифицированность.
Я бы посоветовал cl-gtk2. В ней пока не всё реализовано из GTK+, но постепенно она обрастает функционалом (одна let-ui чего стоит!). 99% того, что мне было нужно — уже реализовано. Остальное легко доделывается. Автор — наш соотечественник и открыт к сотрудничеству.
Ну, мне кажется что в топике вопрос поставлен вверх тормашками. У LISP-а нет проблем из-за того что нет фреймворков вокруг, а фреймоврков нету потому что у LISP-a проблемы =)

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

Кста, думаю LISP реально упустил свой шанс в области запросов и был побежден SQL. Просто SQL поставляется как часть СУБД ( читай «реально существующего и очень полезного решения») а LISP готовым решением никогда не был.
Особых проблем по сравнению с другими ЯП в чтении кода нет, я могу это уверенно сказать. Их даже меньше за счет того, что средства лиспа позволяют делать более «правильные» API библиотек.
А почему вы считаете, что лисп и sql как-то могут конкурировать между собой? Это совершенно разные языки с разными областями применения. Если лисп и где-то используется в качестве языка запросов, то это не common lisp и не scheme, а какой-нибудь очень ограниченный диалект (вероятно, там от лиспа только скобочный синтаксис взят). А лисп в качестве процедурного языка внутри, например, PostgreSQL использовать можно наравне с другими языками.
Под другими ЯП вы наверное имели ввиду BrainFuck-o подобные языки?)
Нет. Могу сравнить с C#, Javascript, Python, C, C++. Читаемо.
Что делает это кусок кода тогда (моя программа):

(require (lib "list.ss" "srfi" "1"))
(define (get-raising lst)

(define new_lst (fold (lambda (el iter)
(if (> el (car (cdr (car (cdr iter)))))
(cons (car iter)
(cons
(cons (car (car (cdr iter))) (cons el (cons (+ 1 (car (cdr (cdr (car (cdr iter)))))) '())))
'()))
(if (> (- (car (cdr (cdr (car (cdr iter))))) (car (car (cdr iter)))) (car (cdr (car iter))) )
(cons
(cons (car (car (cdr iter)))
(cons (- (car (cdr (cdr (car (cdr iter))))) (car (car (cdr iter)))) '()))
(cons
(cons (car (cdr (cdr (car (cdr iter)))))
(cons el (cons (+ 1 (car (cdr (cdr (car (cdr iter)))))) '())))
'()))
(cons
(car iter)
(cons
(cons (car (cdr (cdr (car (cdr iter)))))
(cons el (cons (+ 1 (car (cdr (cdr (car (cdr iter)))))) '())))
'()))

)))


'((0 0)(1 0 1))
lst ))
(if (> (- (car (cdr (cdr (car (cdr new_lst))))) (car (car (cdr new_lst)))) (car (cdr (car new_lst))))
(display (cons (car (car (cdr new_lst))) (cons (- (car (cdr (cdr (car (cdr new_lst))))) (car (car (cdr new_lst)))) '() )))
(display (car new_lst))))


(get-raising (read))
Вы привели пример очень плохого кода. Пожалуйста, не пишите так больше. И не используйте списки для эмуляции подходящих структур данных.
Если хотите ответить на челлендж — скажите, как работает code.jquery.com/jquery-1.4.2.min.js и прочитайте статью в википедии про обфускацию.
Я вас огорчу, хорошего кода на Лиспе не бывает…
(Я могу прислать прожку с «хорошим кодом», но она строк на 700 (Елиза (типа психолог)) и ее вы уж точно не поймете)

По поводу что делать всеми нами любыми jquery я имею представления.
(Только зачем вот вы посылаете за архивированный код на js (оптимизированный под браузеры и медленный инет))

Я вас обрадую, хороший код на лиспе бывает и часто встречается (например, много хорошего кода можно найти на github.com/languages/Common%20Lisp). Давайте, присылайте, разберемся с элизой.
А вы зачем мне присылаете обфусцированный исходник? Тот код на js нечитаем, из этого сделаем вывод о том, что программы на js нечитаемы?
К сожалению, этот исходник в таком виде был написан.

jquery — есть в нормально виде и там все ясно.

Вот элиза: stream.ifolder.ru/17012788. Все же я думаю, быстрее будет вам ее занова написать =)
Ссылку кинуть на условие?)

А вообще меня дико интересует, как на лиспе написать писать много поточные приложение (сложнее helloworld-a).

Жаль того несчастного, кому пришлось это писать. Но причем здесь Lisp? Можно с таким подходом и в Jave нагородить что-то подобное (только займет это, наверно, 10 экранов: представляете 10 вызовов Java-функций в одной строке?)

А не могли бы выложить Элизу на какой-то нормальный ресурс (paste.lisp.org)? А то не грузиться. Тем временем можете посмотреть на нормальную ее реализацию: norvig.com/paip/eliza.lisp

stream.ifolder.ru/17012788 я там точку поставил извиняюсь =)

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

Единственная ремарка: ваше приложение занимает 700 строк кода, а у Норвига — 200.
У меня коментариев много=)

А я не хочу ничего от вас.

Просто вы пытаесь меня убедить, что лисп является таким же понятным как Си++…

Мне кажется это не правильным… (Исходя из горького опыта).
Да нет, я заявляю, что Lisp намного понятнее (но не пытаюсь вас в этом убеждать: переубеждать кого-то — глупое занятие). Если вы хотите сделать это предметным спором, а не просто высказыванием своих убеждений, нужно сначала определить критерии «понятности», «хорошести» и т.д., о чем я вас попросил ниже. Разумеется, по некоторым критериям Lisp не будет понятным (например, по критерию наличия фигурных скобок ;)
Мне лень вводить определение понятности… Да и если вы этого не понимаете, то оно вам не поможет.
Мне не нужна статья (Это теория).

Мне нужно сложное (из хотя бы нескольких сот тысяч строк) приложение на лиспе, которое является многопоточным и лучше его конкурентов на других языках (Или по крайней мере конкурентоспособно).
Несколько сот тысяч строк — это должно быть что-то очень серьезное — эквивалент нескольким миллионам строк на C/Java/… За всю историю таких только несколько было, например известная система для компьютерной алгебры Macsyma (многие ученые прекрасно работают с ней и сейчас). Ну, все что было написано для Lisp-машины — это, явно, миллионы строк кода, но о них сейчас говорить не принято, потому как никто попробовать не может и сравнить (тем не менее Lisp-машины работали около 10 лет в очень многих научных учреждениях, проектных бюро и т.д., что доказывает, что на то время эта технология была вполне конкурентноспособна). Из современных примеров — QPX (http://itasoftware.com/solutions/qpx.html). Эта самая лучшая в мире система расчета цен на авиабилеты и стыковки маршрутов.
100 000 лисп = 1 000 000 Java

Элиза на Jave (примитивная такая) пишется в 100-150 строк (быдлокодом конечно)

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

Есть где-то даже исследования на этот счет. (Вот есть какая-то: chayden.net/eliza/Eliza/ Как-то не вериться, что там только 150 строк кода...)

Ну а на Lisp'е не до фига (не считая названных мною Lisp-машин, которые были 20 лет назад). А вы знаете, кстати, какое-то приложение на миллион строк на Javascript, или на Ruby, или даже на Python? Тем не менее, очень полезные языки, не находите?
Я не знаю, что это за прожка.

НО ту что я написал, и реализует минимум (скорее всего как и та на 200строк). Пишется на Jave-e (быдлокодом в функции мейн) в 100-150строк.

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

Быдло код на Java понятнее софт-кода на Lisp-e (опять таки опыт)

З.Ы. Я сомневаюсь, что вы софт-кодите больше меня… Иначе вам бы был противен Лисп (ввиду того, что он этого не позволяет..)
Знаете, на Lisp'е пишу почти каждый день. В то же время не скзал бы, что есть языки, которые мне противны.

Ну а почему вам софт-код на Lisp'е не понятен — вы же сами дали объяснение (опыт). И еще: быдлокод — он для маленьких задач (которые можно уместить в один файл) часто понятен, поскольку сразу видно ход мысли. Но вы же так не будете писать хоть что-то серьезное (я надеюсь :) И опять мы приходим к критериям хорошего кода. Для серьезных задач — это будет не возможность написать в лоб что-то, а возможность четко разделить интерфейс и реализацию, механизм и политику, возможность абстракции, отсутствие boilerplate, отсутствие нерегулярной ad hoc базы и т.д. По этим критериям Lisp даст фору любому языку.
Хорошего кода на Lisp не бывает — это типа как «На английском красивых стихов не пишут». А какие у вас, кстати, критерии «хорошести» кода? ;)
Да мне просто подсветка синтаксиса не нравится!
Вот с этого сразу и надо было начинать, а не ходить вокруг да около :)
Да да это основная характеристика языка!
Вы специально так нечитаемо написали? как минимум, последовательности каров/кудров можно сократить. Ну и консы на квазицитирование заменить.
вы имеет ввиду
caar
caaar
caaaar
...?)

Делу это не поможет (Пример реализует чрезвычайно простую вещь)
Второе моё замечание (про квазицитирование) вы, конечно же, проигнорировали.
Это я решил промолчать, но если вы настаиваете, то мой ответный вопрос: «Вы предлагает мне написать сперва себе язык? А потом тока кодить?) Увольте..».
Какой ещё язык? Квазицитирование есть в любом лиспе. Вы привели плохой код и вместо того, чтобы его исправить, увиливаете.
Скажите, что это за простая вещь, и я приведу код, который реализует эту простую вещь более ясным образом (конечно, мой код будет на лиспе, а не на схеме; схема — это довольно примитивный язык).
А почему у вас операции head и tail называются car и cdr? Нечитаемо же.
Нифига. Человеческий мозг очень любит инкапсуляцию и терпеть не может рекурсию (наверно потому что нейроная сеть). Уже программа строк 200-300 практический нечитаемая.

Что касается SQL, то у него идея такая же. Просто SQL более специализирован. Разница примерна такая же как между xml и html. Тем не мене, даже на SQL  сложные запросы далеко не самая легкая вещь для восприятия.


SQL и Lisp — это совсем разные языки. Разница примерно как между html и java.
А рекурсию лисперы тоже не ставят во главу угла (но не забываем, что многие алгоритмы в принципе являются рекурсивными, поэтому от рекурсии не избавиться). В лиспе основной упор делается на ООП (CLOS — мощнейшая объектная система), на построение абстракций различного уровня, на мощном базовом языке. (Сразу замечу, что лисп — не функциональный ЯП)
Как можно сравнивать html и java? Говорить что LISP не ФЯП?

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


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


ru.wikipedia.org/wiki/Лисп

Мне стыдно за нашу профессию -)

А как можно сравнить Lisp и SQL? Точно так же можно сравнивать Java и HTML.
А википедия — довольно слабый авторитет в этом вопрос. Современный лисп (Common Lisp) — это совсем не тот LISP, который придумал МакКарти полвека назад.
А Common Lisp — язык императивный с элементами функционального программирования и ряда других парадигм.
HTML и Java очень просто сравнить. Точнее, можно сравнить XML и Java. В XML закодированна логика работы Java-программы Ant, которую он интерпретирует. Таким образом XML — это декларативный язык предметной области, а Java может оказаться его интерпретатором. Так же само и SQL — это декларативный язык предметной области. Если мы напишем на Common Lisp реляционную СУБД, то Lisp будет для SQL играть ту же роль, что и Java для XML.

Common Lisp — это не ФЯП, не ООЯП, не императивный ЯП и т.д. Common Lisp — это мультипарадигменный динамический программируемый язык программирования с особым синтаксисом (префиксная нотация).
Я всегда думал, что XML используется для данных, вам бы книжки писать=)
а код — это данные*, вы не знали? ;)
Пока что ограничиваюсь статьями

* берем для примера первую же Ant Task из мануала (http://ant.apache.org/manual/CoreTasks/unpack.html):
/>
Обрабатываемая информация — это данные!

Код — это набор команд! которые выполняются на данных.

Вы говорите, как человек, далекий от программирования.
А программа — это не обрабатываемая компилятором информация?

А что по вашему приведенный пример? Если это чистые данные, то где же закодированна логика работы Ant'а? Как он решает, что ему нужно сделать: заархивировать или разархивировать?
Повторюсь вы говорите, как человек, далекий от программирования.

Вы не понимает базовых вещей, а пытаетесь говорить о сложных…

Данные — просто какая то информация которая ничего не делает!

Код — набор команд (Он что-то делает над определенными данными)

В свою очередь, код — набор команд для интерпретатора (или компилятора, или исполнителя).

Ваш пример не доказывает вообще ничего.
Разберитесь с базовым понятиями сперва.

вы почему-то не ответили ни на один из моих вопросов…
Теорию относительности слышали?

Если вы разрабатывает интерпретатор то для вас будут данными как программа так и данные к этой программе…

Но если опустится на землю и вернутся, к написанию программ отличных от этой области, (чем я думаю вы и занимаетесь) то мы получим четко разделение:

Код — что делать
Данные — то над чем делают.

Ваш пример неуместен, пояснение:

То что вы написали это код для ант. Это не данные. И ант такой код понимает и может выполнить, а данные в вашем примере будут example.org/archive.tar.gz вот этот файл.

Надеюсь теперь я доходчиво объяснил?

Но у меня вопрос встал: «Зачем так извращаться? Приведи пример когда это действительно нужно… „
Этот пример показан в ответ на то, что вы сказали, что XML — это для данных. Однако в данном случае то XML используется для того, чтобы написать, что делать Ant'у (т.е. это код). (А что Ant — это не пример из практики, где это действительно нужно?)

Поэтому вы правы: всё относительно и иногда данные становятся кодом и наоброт. Это, собственно, то, о чем я говорил изначально.
просто если вы используете монитор для убийства мух, то это же не означает, что это его главное назначение…
Рекурсия — это одна из стратегий вычисления. Вы что, никогда рекурсию в С не использовали? Причем здесь Lisp? Так же само, как инкапсуляция — это абстрактная концепция, которую можна реализовать множеством способов. Когда мы говорит о языке программирования общего назначения, то такой язык должен позволять задействовать любые стратегии вычисления, реализовать любые не взаимопротиворечивые концепции. Common Lisp это позволяет сделать.

Ну а читаемость программы не должна в общем-то зависить от количества строк в ней: вы же читаете ее потоково, по нескольку строк, а не сразу 300, которые на экране не умещаются ;) Читаемость зависит от порядка в голове у того, кто программу написал.
>и терпеть не может рекурсию (наверно потому что нейроная сеть)
Пожалуйста ссылку на авторитетный источник or GTFO.
Прикинь в голове реализацию рекурсий в нейроной сети. Если не можешь — поверь мне на слово.
Прикинь в голове реализацию на транзисторах.
Да нет никакой нереальной сложности — наоброт, гораздо проще держатьв голове правила разбора, потому что их на порядок меньше, чем у Algol-семейства языков. Дело привычки просто.

Что до Lisp'а как языка запросов, то Вы, возможно, спутали его тут с Prolog'ом. Lisp никогда для таких целей особо не использовался (хотя некоторые люди, возможно это делают).
Нереальная сложность появляется когда нужно что нить полезное написать =)

Ничего я не путал, так как не говорил что его использовали как язык запросов (хотя бы я о таком не слышал). Я говорил что это был его шанс на хоть какое-то применения в этом реальном мире (Ну, я тут Столлмана не беру в расчет, он же инопланетянин и у него эНЛОмакс =).
Не появляется нереальной сложности. Почему вы так решили?
Ну, опять же, елси вернуться в реальный мир в котором я хотел бы и остаться, то Лисп врядли чем поможет, ну хотя бы потому что у него нормального SDK нет =)

Ну если серьезно, я представляю какие плюсы у Лиспа, и эти плюсы могут быть востребованы и очень удобный в некоторых ситуациях. Работая как разработчик корпоративных информационных систем, постоянно сталкиваешь с обработкой коллекции (те, набора данных — читай списки-Lists (какая первая буква у названия LISP?)) которые создаются на выгрузках из БД. Конечно, данные из БД нужно маппит в объекты и структуры. Вот одно из мест где данных подход может быть очень полезен.
Ну чего скрывать, SQL уже давно этому служит, да и LINQ от майкрософт, мягко говоря про то же.
Вывод какой — идею Лиспа, но с хорошей реализацией под конкретный класс задач можно очень успешно использовать. Lisp как основа — ну почты бесполезен.
Вас, наверно, удивит, но самая распространенная SDK в мире — это Emacs (если сомневаетесь, то посчитайте, сколько людей пользуется им из книги Coders at Work. Около 10ка. Или вы скажете, что те люди, которые написали Unix, BitBlt и Firefox — это не реальный мир?)

Далее, если говорить о применимости Lisp'а в корпоративной среде (да и в целом в типичных задачах, с которыми сталкиваются большинство программистов), то вы зря делаете такой акцент на списках. Списки — это очень базовая вещь. Все нормальные современные языки прекрасно их поддерживают (взять тот же Python). Возможность Lisp, которые позволяют бороться со сложностью крупных систем (против которых, как уже показала практика, ООП-подход бессилен) — это возможность создания многослойных слабосвязанных систем за счет проблемно-ориентированного программирования (прежде всего на основе макросов) и не привязанного к необходимости городить иерархии классов полиморфизма.
«как уже показала практика, ООП-подход бессилен» — чья практика?

По поводу терминологии:
«Слабосязанные системы» — это из области веб сервисов с каталогами типа «желтых» и «белых» страниц. По сей день — научная фантастика, даже Стругацких наверно по круче будет. До лиспа — как до Пекина раком.
«Иерархии классов полиморфизма» — wtf?
полиморфизм, классов полиморфизма и тем боле иерархии классов полиморфизма нет.
Полиморфизм бывает у интерфейса. Банально — если розетка одинаковая, то можно воткнуть что угодно -) и никакого тут наследования нет.
Я привел ссылку на Yegge. Поищите в интернете по чему-то типа «big project fail oop» :)

Слабосвязные системы — это не научная фантастика. На этом принципе построен Unix (в некоторой мере).

Простите, если не понятно написал. «Не привязанному к иерархиям классов полиморфизму». Это о том, что полиморфизм в ОО-языках (читай C++, Java) не существует отдельно от наследования (будь то через механизм интерфейсов как в Java, или абстрактных классов (это в хорошем случае), или же простого наследования, которое повсеместно для это используется (в не очень хорошем случае)). Если ОО-язык отказывается от концепции наследования, то он теряет и полиморфизм. Не согласны? Как на счет примера Javascript?
Unix написан на ассемблере и Си пардон что вмешался. И он совсем не на этом построен…

И чем вам ненравится наследование и ООП модель?
(Прекрасный способ для управления сложность приложения… )

Понятно, что Unix написан на С. А о его принципах можете почитать здесь: www.faqs.org/docs/artu/ch01s06.html Это я к тому, что слабая связность — это не фантастика.
Да нету там никакой «слабой связности» вы путаетесь в определениях.

Я программировал под Юникс на С писал свой командный интерпретатор… Ботал ее изнутри.

Юникс хорош только тем, что устроен он чрезвычайно просто и понятно, что позволяет четко его настраивать и управлять… Вы явно не понимает, что такое «слобая связанность»…
Ну а я программирую на юниксе постоянно. И что дальше — кто из нас круче? ;)

Объясните мне тогда, что же такое эта слобая связанность, будьте добры…
Связность на лбах, очевидно.
Тогда я не знаю что вы имеете ввиду под Слабосвязаными системами. У вас есть определение?

Вы пишете слишком много, очень сложно уловить мысль…

Вы сказали
Простите, если не понятно написал. «Не привязанному к иерархиям классов полиморфизму». Это о том, что полиморфизм в ОО-языках (читай C++, Java) не существует отдельно от наследования (будь то через механизм интерфейсов как в Java, или абстрактных классов (это в хорошем случае), или же простого наследования, которое повсеместно для это используется (в не очень хорошем случае)). Если ОО-язык отказывается от концепции наследования, то он теряет и полиморфизм. Не согласны? Как на счет примера Javascript?


В двух словах: если не наследовать классы, не будет полиморфизма.

Это утверждение не верно. Я по яве совсем не спец, но в c# можно реализовать сколько угодно интерфейсов в любом классе. Да чего один IEnumerable стоит.

В двух словах, что я хотел сказать: если не создавать иерархий, то не будет полиморфизма в ООП.

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

Далее, чтобы получить всего-лишь 1 полиморфную функцию, нужно создать:
1. интерфейс
2. класс, который этот интерфейс реализует
3. инстанциировать этот класс
В целом, конечно, интерфейсы — это гораздо лучше класс-методов, но в чистом виде то никто так не делает: комбинируют и то, и то, правда же? (И интерфейсы, кстати, тоже наследуются, так что и тут иерархии создаются). А ведь полиморфизм в чистом виде — это разное поведение функции в зависимости от типов входных параметров (или каких-то еще критериев). Причем здесь интерфейсы/классы?
Ну, я опять же говорю про то, что знаю.
В c# наследование только од одного класса. Всегда.
Интерфейсы с иерархиех классов ничего общего не имеют. Дам жизненный пример.

Допустим у меня есть iPod. Когда дома, подключаю его к домашней системе, когда в машине к магнитоле, а когда на улице никуда не подключаю а слушаю в наушниках. Все потому что Apple определила интерфейс и дала возможность реализовать его другим компаниям. Так вопрос — это какая иерархия существует между магнитолой, домашней системой и айподом? Тоже самое в программировании — хочу сортировать свои коллекции — реализую IEnumerable в классе и все ок. И тут ни о какой иерархии речь не идет.
Прошу прощение, ошибся — для сортировки icomparable, для foreach ienumerable
Хорошо, в этом примере всё выглядит ОК.
А как быть в таком случае: у нас есть программа, которая использует Хабр, как источник данных о людях. Она получает N видов данных (например, список записей в блог, список друзей, профиль, ...) и может сделать это несколькими путями (через REST API, прямо через HTTP — scraping, а также из собственного кеша), и к тому же запрос может делать по id пользователя (число) или его имени (строка). Как видите, концептуально имеет полиморфную функцию get_data(kind, source, user), которая может менять поведение в зависимости от каждого из своих параметров. Как бы вы это выразили с помощью интерфейсов (да и, вообще, классического ООП), например, в том же C#?
Вы не поняли суть этого дела.

Отвечу на вопрос — пишется один (1!) метод get_data одного класса контролера без всяких интерфейсов.

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

Просто не понимаю, при чем тут лисп? ))
А можно по-подробнее: что это за класс контроллера такой? И каким образом реализуется полиморфизм? Я имею в виду: вот у нас есть 2 конкретных варианта вызова:
1. получить через API данные о постах пользователя «lookat»
2. получить из кеша профиль пользователя 123
Методами каких классов они будут, каким образом будет происходит специализация? Если бы накидали пару строчек кода, было бы вообще супер… (А я взамен могу показать, как это будет выглядеть в Common Lisp)
Ну что-то типа этого
заметите, тут нет ни наследования ни интерфейсов, а функция GetUser полиморфная

class User
{
public User()
{
name = "lookat";
id = 123;
}

public string name;
public int id;
};

class Chache
{
public bool UserExists(int id)
{
bool result = true;
//Chache search
return result;
}
public User GetUserByID(int id)
{
User result = new User();
//
return result;
}

}
class HttpAPI
{
public User GetUserByName(string name)
{
User result = new User();
//Search
return result;
}
}

class DataIntegrator
{
Chache chache;
HttpAPI httpAPI;
public DataIntegrator(Chache _chache, HttpAPI _httpAPI)
{
chache = _chache;
httpAPI = _httpAPI;
}

public User GetUser(int id)
{
if(chache.UserExists(id))
return chache.GetUserByID(id);
else return null;
}
public User GetUser(string UserName)
{
return httpAPI.GetUserByName(UserName);
}
}

class Program
{
static void Main(string[] args)
{
HttpAPI h = new HttpAPI();
Chache c = new Chache();
DataIntegrator di = new DataIntegrator(c, h);

User u1 = di.GetUser(123);
User u2 = di.GetUser("lookat");
}
}

В принципе, это то, что я и ожидал (потому что по другому не получится в ООП).
Есть несколько замечаний:
1. вы не учли, что мы можем получать разную информацию о пользователе, а не только его ID и name. Я хочу получить список постов пользователя. Принадлежит ли он к классу пользователя? В вашем варианте по другому не получится: прийдется возвращать объект User, в котором, кроме ID и username будет еще и PostsList, Profile, FriendsList,… А что, если нам захочется добавить еще какое-то свойство, например, Carma? Выхода 2: лезть внутрь User'а или же наследовать от него UserWithCarma. Вот и наследование появляется, так же?
2. Классы HttpApi, Cache и т.д. не имеют никакого состояния — это просто наборы методов. Однако вам приходится их инстанциировать. Да еще и нужен класс-обертка Integrator, который тоже состояния не имеет, он у вас только организовывает полиморфизм. Кстати, политика интегратора захардкожена в GetUser: т.е. сначала делается запрос к кешу, потом к API. А что если у нас добавляется новый метод доступа (какой-нибуть ThriftAPI) или же для некоторых случаев мы хотим сначала информацию смотреть в API, а потом в кеше (если API не отвечает из-за того, что Хабр лежит), а для некоторых сначала в кеше? Правильно, приходится писать новый интегратор.

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

Альтернатива на Common Lisp:

<code>(defgeneric get-data (source attribute user))

(defmethod get-data ((source (eql :api))
                     (attribute (eql :posts))
                     (id integer))
  ;; собственно код
  )

(defmethod get-data ((source (eql :fast)) attribute user)
  ;; сначала полезем в кеш, потом в API
  (or (get-data :cache attribute user)
      (get-data :api attribute user)))
</code>


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

То что вы написали в C# выглядит примерно так

cass Integratior()
{
public User GetUser(object method, object id);
}

и вызов в коде
Integrator i = new Integrator();

i.GetUser(_method, _id)

В свою очередь я дал полностью работающее решение (ну конечно есть дописать код который работает с кэш и http, но этого кода у вас тоже нет)

Ну и, вы уверены, что функция GetUser в этом варианте полиморфна?
Sign up to leave a comment.

Articles