Некоторые считают, что современный мир почти не знает Никлауса Вирта и даже не догадывается о его огромном вкладе в мировую компьютерную науку. Кто-то полагает его «отцом Паскаля». Вирта вспоминают не только педагоги в ВУЗах, когда преподают студентам Turbo Pascal, но и коммерческие разработчики, пишущие на Delphi.
На самом деле, Никлаус Вирт является инженером с большой буквы, его вклад в развитие языков программирования не ограничивается Паскалем, а только начинается с него. Кроме того, Вирт — педагог, общественный деятель и, можно сказать, философ. Попробуем оценить реальный масштаб его личности и вклад в ИТ-индустрию.
Детство, образование, увлечения
Никлаус Вирт родился 15 февраля 1934 года в небольшом городке Винтертуре, в предместье Цюриха. Его родители — Уолтер и Хедвиг Вирт. Отец Никлауса был школьным учителем. Он жил неподалеку от школы, где преподавал его отец. В их доме была хорошая библиотека, где Вирт находил немало интересных книг про железные дороги, турбины и телеграф.
Винтертур имеет многовековую историю и славится своими машиностроением: там выпускаются локомотивы и дизельные двигатели. С детских лет Вирт увлекался техникой, особенно авиамоделированием. Для запуска ракет нужно было получать топливо, и потому он занялся химией. Юный Вирт оборудовал в подвале школы «секретную» лабораторию. Ничто не могло его остановить: однажды сделанная им модель отклонилась от заданной траектории и угодила под ноги директору школы. Однако Вирт все равно продолжал упорно идти к намеченной цели.
Хобби оказалось настолько серьезным, что Вирт даже построил более десятка моделей по собственным чертежам. Между прочим, позднее он занялся настоящими полетами и пронес это увлечение через всю свою жизнь. Даже в весьма почтенном возрасте создатель популярного языка программирования не отказывал себе в удовольствии полетать на реактивном истребителе.
Когда ему исполнилось 18 лет, то он с еще двумя цюрихскими авиамоделистами выписали из Англии желанную радиоаппаратуру. Это предопределило его дальнейшую судьбу – в 1954 году Вирт поступил на факультет электроники в цюрихский ETH (Eidgenoessische Technische Hochschule – Швейцарский федеральный технологический институт). После четырех лет обучения Вирт получил степень бакалавра в области электротехники. А затем начинается славное десятилетнее заокеанское научное «турне» будущего «отца Паскаля» и «короля компиляторов» по маршруту Швейцария – Канада – США – Швейцария.
Свое обучение Вирт продолжил в Лавальском университете города Квебек (Канада), где в 1960 году получил степень магистра. Затем его пригласили в университет Калифорнии в Беркли (США) – будущую жемчужину Кремниевой долины. Там под руководством профессора Хаски в 1963 году Никлаус Вирт защитил диссертацию, посвященную развитию Алгола средствами Лиспа (Euler).
Путевка в жизнь
Эта работа в буквальном смысле дала ему путевку в жизнь: Вирта приметили мэтры программирования и пригласили в Комитет IFIP по стандартизации Алгола.
Вместе с Чарльзом Хоаром Вирт отстаивал в комитете линию на разработку умеренно модифицированной версии Алгола, свободной от недостатков исходного языка и дополненной минимумом действительно необходимых средств. Вирт и Хоар представили комитету язык Алгол-W (W — от Wirth), представлявший собой именно такую переработку Алгола, но поддержки не встретили. По завершении работы комитета в 1968 году Вирт вошёл в число тех, кто критиковал Алгол-68, говоря о его недостаточной надёжности и чрезвычайной избыточности.
Та школа не прошла даром: на всю жизнь Вирт запомнил, что доказывать свою правоту нужно делом, особенно когда тебя не хотят слышать. В разработке языков он навсегда отказался от абстрактно-научного подхода в пользу математически инженерного. По его словам, лучше сначала реализовать язык и лишь потом следует о нем писать.
Великие единомышленники
Романтические 1960-е годы положили начало дружбе трех патриархов структурного программирования – голландца Эдсгера Дейкстры, англичанина Чарьза Энтони Хоара и швейцарца Никлауса Вирта.
Слева направо: Никлаус Вирт, Эдсгер Дейкстра, Чарльз Хоар
Этих «нобелевских» лауреатов (премия Тьюринга, присуждаемая ассоциацией ACM, вручается раз в жизни и приравнивается в компьютерных науках к Нобелевской) сблизили не столько абстракции компьютерных наук, сколько четкая профессиональная позиция.
Паскаль
Самым известным достижением профессора Вирта считается язык Паскаль (1970). Паскаль сыграл огромную роль в области формирования мировоззрения нескольких поколений программистов. Главное его достоинство в простоте и элегантности: он построен на четких принципах структурного программирования, сформулированных Эдсгером Дейкстрой, на красивой математической базе, заложенной Энтони Хоаром, и на блестящем архитектурном воплощении идей Algol-W, реализованных Никлаусом Виртом.
С технологической точки зрения, Паскаль был интересен не только тем, что его компилятор, созданный в ETH, стал одной из первых реализаций языков высокого уровня на самом себе, примерно на два года опередив компилятор Си. В ходе работ над ним в 1973 году была придумана абстрактная Pascal-машина (P-машина), исполняющая специальный P-код. Чтобы решить проблему переноса компилятора Паскаля на разные платформы, Вирт решил воспользоваться испытанными временем методами интерпретации.
Язык Паскаль многими воспринимался, прежде всего, как язык для преподавания компьютерных наук. Но сам Вирт не согласен с таким заведомым сужением его потенциала (1984): «Паскаль был разработан в качестве языка для обучения. Хотя это утверждение справедливо, но его использование при обучении не являлось единственной целью. На самом деле я не верю в успешность применения во время обучения таких инструментов и методик, которые нельзя использовать при решении каких-то практических задач. По сегодняшним меркам Паскаль обладал явными недостатками при программировании больших систем, но 15 лет назад он представлял собой разумный компромисс между тем, что было желательно, и тем, что было эффективно».
«Пятый элемент»
В период с 1978 по 1980 год в Швейцарском федеральном технологическом институте, куда Вирт вернулся еще в конце 60-х, он разработал одну из первых компьютерных станций с графическим дисплеем 768 x 592 пикселя и мышью. Для своего компьютера он выбрал несколько странное название — «Лилит».
Лилит в иудейской традиции — злой демон в женском обличии. Она овладевает мужчинами против их воли. Кстати, согласно одной из апокрифических легенд, Лилит под именем Лилу (как в фильме «Пятый элемент») была женой Адама до сотворения Евы. Наверное, Вирт имел в виду то, что его компьютер будет чрезвычайно привлекателен для мужчин и вызовет жгучую привязанность.
Компьютер «Лилит» имел 64 кбайт оперативной памяти и процессор с частотой 7 МГц. Для 1980 года это было неплохо. Все программное обеспечение для данной машины, включая оригинальную операционную систему, Вирт — при поддержке коллег — написал на языке «Модула-2», который сам и разработал незадолго до этого.
Modula-2
В свое время Брайан Керниган, известный популяризатор языка Си, соавтор классического руководства по Си (K&R), написал критическую статью «Почему Паскаль не является моим любимым языком программирования». Если с ней внимательно ознакомиться, то можно решить, что Никлаус Вирт сделал из нее правильные выводы и в языке Modula-2 (1980) под воздействием статьи устранил многие изъяны канонического Паскаля.
Однако следует иметь в виду одно немаловажное обстоятельство. Наделавшая шума работа Кернигана была написана 2 апреля 1981 года, т.е. через два года после реализации группой Вирта в ETH первого компилятора Modula-2 и через год после выпуска аппаратной реализации Modula-2 – персонального компьютера Lilith. В апреле 1993 года на Конференции ACM по истории языков программирования Вирт в ответ на вопрос одного из своих коллег поставил языку Modula-2 оценку «6 баллов» (наивысшая оценка в школах Швейцарии).
Язык Modula-2 был не только компактной и эффективной альтернативой языку Ada, он намного опережал те реализации идей модульного программирования, которые лишь спустя годы и в гораздо менее продуманном виде нашли свое отражение в Turbo Pascal и Delphi. Знаменитая операционная система OS/400 для IBM AS/400 была реализована на Modula-2. Центр системных исследований корпорации Digital (DEC Systems Research Center) взял этот язык в качестве основы реализации своих внутренних проектов, создав впоследствии язык Modula-3.
Компьютерная индустрия отставала от работ Вирта как минимум на 5–7 лет. В том же 1979 году (когда появился первый компилятор Modula-2 на компьютере PDP-11 в среде RT-11) намного уступавший Lilith легендарный компьютер Apple II только-только обрел компилятор Apple Pascal, ориентированный на UCSD-реализацию Паскаля. До появления первого скромного Turbo Pascal Андерса Хейльсберга оставалось целых четыре года. Что касается компьютера Lilith, то он стал первым компьютером в Европе, который полноценно использовал возможности лазерной печати. Впоследствии Вирт с грустью говорил о том, что с проектом Lilith швейцарская промышленность упустила свой уникальный шанс.
«Школа Вирта»
Алексей Недоря – кандидат физико-математических наук (1994) считает себя последователем Никлауса Вирта:
«Школа Вирта» дарила нам новые горизонты. Читая препринты Вирта, мы открывали мир и открывались миру. Что гораздо важнее, у Вирта мы учились простоте и искусству борьбы со сложностью. Простой пример. Первые компиляторы с языка Модула-2 были двухпроходными, того требовал язык. Так и наш первый кросс-компилятор, сделанный Дмитрием Кузнецовым (Leo) на Burroughs 6700 под руководством И.В.Поттосина, был двухпроходным. Потом была история “Кроноса”. Когда у нас заработал первый “Кронос”, мы в срочном порядке сделали компилятор с урезанной Модулы-2, чтобы можно было вести разработку на самом “Кроносе”.
Алексей Недоря, Никлаус Вирт и Владимир Филиппов (слева направо). Москва, Политехнический музей, 2005 год
Мы называли этот язык и компилятор Модула-0. Компилятор был однопроходным, для чего пришлось внести изменение в язык. А потом пришла пора делать полный компилятор Модулы-2, и мы в соответствии с описанием языка начали делать его двухпроходным. Но тут пришло известие, что Вирт подкорректировал язык (добавил forward-описания процедур), и теперь можно делать однопроходный компилятор.
В итоге мы упростили себе жизнь и ускорили разработку. Главное было в том, что язык программирования, который до того был «священной коровой», принесенной откуда-то свыше, стал всего лишь рабочим инструментом, который можно подточить и подправить. Мы получили урок: разрешение творчества и понимание важности и полезности упрощений.
Ada
Во второй половине 1970-х Вирт участвовал в конкурсе министерства обороны США на разработку нового языка для программирования встроенных систем, в результате которого был создан язык Ada.
Министерство поставило задачу разработать единый язык программирования для систем управления автоматизированными комплексами, функционирующими в реальном времени. Имелись в виду, прежде всего, бортовые системы управления военными объектами. Язык назван в честь математика Ады Лавлейс.
Повторилась история с Алголом-68 — проект группы, в которой работали Вирт и Хоар, не был одобрен комитетом по языку. Чарльз Хоар и Никлаус Вирт выбыли из конкурса после первого этапа. В конкурсе победил проект, основанный на Паскале, но гораздо более сложный и объёмный.
Хоар выразил своё сожаление тем, что «погремушки и побрякушки возобладали над фундаментальными требованиями надёжности и безопасности» и предостерёг от «армады ракет, летящих не туда из-за не обнаруженной вовремя ошибки в компиляторе Ada».
Никлаус Вирт высказался более сдержанно, но тоже негативно. Он сказал: «Слишком много всего вываливается на программиста. Я не думаю, что, изучив треть Ada, можно нормально работать. Если вы не освоите всех деталей языка, то в дальнейшем можете споткнуться на них, и это приведёт к неприятным последствиям».
Жан Ишбиа, руководитель группы разработчиков Ada, выразив своё «уважение и восхищение» Виртом, не согласился с ним, сказав: «Вирт верит в простые решения сложных проблем. Я не верю в такие чудеса. Сложные проблемы требуют сложных решений».
Оберон
В 1988 году в содружестве с Юргом Гуткнехтом Вирт разработал язык программирования Оберон. Целью разработки было создание языка для реализации системного ПО проектируемой новой рабочей станции. Основой для Оберона стала Модула-2, которую существенно упростили, но при этом дополнили новыми возможностями.
Юрг Гуткнехт
Никлаус Вирт с коллегами разработали первую версию системы «Оберон», машину, компилятор языка Оберон и операционную систему System Oberon, которая обладала графическим интерфейсом пользователя, расширенными концепциями использования текста в интерфейсе и в целом являла собой материальное доказательство применимости концепций Вирта.
Как уже писали на «Хабре», в Обероне модуль — это не только средство структурирования алгоритмов и структур данных, но и единица компиляции, загрузки и распространения. То есть модуль является минимальной сущностью, которую может скомпилировать компилятор. Зависимости одного модуля от других модулей вычисляются автоматически, но не приводят к включению кода из одного модуля в другой. Включаются только идентификаторы импортируемых сущностей и хэшкод зависимости, для контроля версии кода.
Модуль является единицей загрузки, то есть, кроме особых случаев код модуля представляет собой законченную программу, в которой есть точка входа, и который может выполняться неограниченно долго. То есть, полноценная программа. Даже ядро ОС это всего лишь первый загруженный в память модуль. Так же модуль предполагает, что его будут распространять не только в виде исходника, но и в виде бинарника, а так же в виде интерфейсной части, и для его запуска потребуется только определенная платформа или несколько платформ. В целом, эти понятия входят в концепцию модульности в Обероне и составляют собой модульно-ориентированное программирование.
В 1992 году Вирт и Мёссенбёк выпустили сообщение о новом языке программирования — Оберон-2, — минимально расширенной версии Оберона. В этом же году была образована дочерняя компания ETH — Oberon microsystems, которая занялась разработкой систем Оберон. Вирт стал одним из членов её совета директоров. В 1999 году эта компания выпустила следующую версию Оберона — Компонентный Паскаль, более приспособленную для компонентного программирования.
Оберон послужил прямым предком для языка параллельного программирования (Active Oberon), различных модификаций языка Оберон под другие среды исполнения (Component Pascal, Zonnon), был реализован на нескольких платформах (JVM, CLR, JS), послужил прообразом языка Java. Сама система Оберон послужила прообразом для проекта Microsoft Singularity.
Как известно, появление виртуальной (абстрактной) машины Java преподносилось ее разработчиками из Sun Labs едва ли как не фундаментальное открытие в практике языков программирования.
Один из учеников Вирта, Михаэль Франц, заметил по этому поводу следующее: «Переносимость Java основана на наличии виртуальной машины, позволяющей легко имитировать большое число архитектур. Идея виртуальной машины была очень популярна уже более двадцати лет назад, хотя впоследствии о ней забыли. Тогда речь шла о Pascal-P – созданной в ETH реализации Паскаля, которая сыграла решающую роль в распространении этого языка. Интересно, что виртуальные машины для Паскаля и Java весьма схожи по архитектурe».
На пороге 2000-х
«А теперь обсудим характеристики «самого современного, самого объектно-ориентированного и очень простого» языка Java», писал Сергей Свердлов.
Java не только не может считаться простым, но является одним из самых сложных языков, более сложным, чем Си++, и вдвое более сложным, чем Оберон.
Но может быть, сопоставление с тем же Обероном некорректно? Ведь, наверное, Java все же более богатый язык, чем этот ваш Оберон? Ничего подобного! В Java есть всего две существенные вещи, которых нет в Обероне: встроенная многопоточность и обработка исключений. Целесообразность включения средств параллельного программирования непосредственно в язык подвергается сомнению многими специалистами. Это могло бы решаться на уровне библиотек. К тому же тот механизм, который реализован в Java, — решение отнюдь не самое удачное.
Сравнение объема синтаксиса языков
Общее число лексем в описании синтаксиса языка может служить обобщенной характеристикой размера этого описания.
Зато в маленьком Обероне есть и полноценные записи (объекты), и нормальные многомерные массивы, а не только указатели на них. Имеются в Обероне и привычные строки с нулем на конце, которые являются просто массивами символов, а никакими не объектами, а значит, не требуют специальных средств для манипуляций.
Вопреки пропаганде Java содержит мало чего-либо действительно нового. Та же концепция виртуальной машины — первое, что приходит в голову, если задуматься о многоплатформности. Лет двадцать пять назад это было удачным и свежим решением.
Такое мнение было высказано более 15 лет назад, когда подобные споры были актуальны. Вопрос о том, насколько теперь Java стал лучше или хуже в этом плане, оставим открытым.
Педагогическая и общественная деятельность
С 1963 по 1967 годах Вирт работал доцентом (assistant professor) в Стэнфордском университете и в 1967 вернулся в этом звании в университет Цюриха. А в 1968 году он получил в ETH звание профессора компьютерных наук и начал возводить на родине свой «швейцарский» Стэнфорд.
Двадцатилетие с 1969 по 1989 год было, пожалуй, самым плодотворным периодом в жизни Вирта. Он продолжал строить свою школу, уделяя немало времени организационной деятельности.
Источник: oberon2005.oberoncore.ru
C 1982 по 1984 год (а потом и с 1988 по 1990 год) Вирт возглавлял в ETH факультет компьютерных наук, а с 1990 года руководил Институтом компьютерных систем (Institute of Computer Systems) при ETH.
На пенсию профессор Вирт ушел 1 апреля 1999 года по достижении 65-летнего возраста.
Источник: oberon2005.oberoncore.ru
В 2001 году Никлаус Вирт написал приветствие российским студентам и преподавателям в связи с введением курсов по изучению «Оберона» в МГУ: «Искренне надеюсь, что «Оберон» поможет в обучении высококлассных программистов и ученых в России и что его оценят в стране, где всегда придавали большое значение основательному образованию».
Жизненное кредо
Жизненное кредо Никлауса Вирта, пишет Руслан Богатырев, лучше всего передают слова великого Блеза Паскаля: «Все наше достоинство заключено в мысли. Не пространство и не время, которых мы не можем заполнить, возвышают нас, а именно она, наша мысль. Будем же учиться хорошо мыслить».
P.S. А теперь читателям предлагается оценить масштаб личности по списку основных проектов Никлауса Вирта:
Источник: oberon2005.oberoncore.ru
Комментарии (54)
white_pony
15.06.2016 22:39На первой фотке Винт Серф.
tyomitch
16.06.2016 02:41На правах сделавшего этот снимок заявляю, что на нём Вирт собственной персоной.
Londoner
15.06.2016 23:33+1А почему, кстати, Оберон совсем не прижился в коммерческой разработке?
ditu
16.06.2016 07:33-2Потому что Оберон это студенческая поделка, там всё КАПСом, и ещё он только для обучения, и нет корпорации-овнера и ещё рынок не выбрал, а в продукшон нужны фичи, а не академичность, а Вирт вообще теоретик. А ещё в России никому не нужен ещё один язык программирования.
Vjatcheslav3345
16.06.2016 08:44+2А фичи в библиотеки нельзя вынести? И поделкой является реализация языка а не сам язык (как абстракция) — т. е. этот недостаток устраним.
akastargazer
16.06.2016 09:52+3Потому что инвестиции в другие языки уже были сделаны (с оглядкой на разработки Вирта, естественно — сам профессор вспоминал, как компания Sun, ныне почившая в бозе, изучала исходники его оберон-системы) и инфраструктурная поляна оказалась занятой.
Другими словами, точка бифуркации была пройдена без Оберона. Хотя на Оберонах делались (и делаются) промышленные разработки.
potan
16.06.2016 16:06Сложность низкоуровневого программирования, отсутствие поддержки обобщенного программирования (в C это делалось через void *, но делалось).
j3fe
17.06.2016 11:55Расскажите об этом дедушке Вирту и парням из ETHZ, которые на Обероне сделали не одну ОС.
potan
17.06.2016 12:35Вирт далеко не студент и способен разработать ОС почти на чем угодно.
j3fe
17.06.2016 14:55Он показал, что Оберон пригоден — и другие проверили его опыт на себе, у всех всё получилось. Если вы изучите матчасть, то и у Вас получится. В этом суть, Вирт показывает всем, что ничего сложного для человека или невозможного для простого ЯП в этом всём нет.
Saffron
16.06.2016 02:42+1> Целесообразность включения средств параллельного программирования непосредственно в язык подвергается сомнению многими специалистами. Это могло бы решаться на уровне библиотек.
Все библиотеки выполняются внутри виртуальной машины. Если эта виртуальная машина не поддерживает многопоточность, то никакая библиотека не поможет. От этого очевидного ограничения сильно страдают ruby, python, javascript, php. И никакие библиотеки не помогают.vsb
16.06.2016 08:38Речь идёт о synchronized-блоках. Они и вправду бесполезны и легко заменяются на использование мютекса. А виртуальная машина, не поддерживающая многопоточность, это просто плохая реализация (обычно в силу исторических причин).
hdfan2
16.06.2016 07:59Картинка «Сравнение объема синтаксиса языков» заставила меня страдать. Но за статью спасибо. Сам начинал с ТрубоПаскаля.
Shamov
16.06.2016 10:29+2То, что Java отстой, — это святая правда. Целый год на ней программировал. Это был худший год в моей жизни. Как будто добровольно сделал себе временную лоботомию. Ничего толком нельзя сделать нормально. Для всего уже есть готовые библиотеки, которые более-менее подходят к случаю, и потому приходится их использовать, хотя интегрируются друг с другом они отнюдь не бесшовно. Все время такое ощущение, что закручиваешь крестовые шурупы плоской отверткой.
PsyHaSTe
19.06.2016 21:37А в сравнении с до-диезом как? Просто я долгое время считал, что джава это тот же шарп, только появился раньше и в нем отсутствует много полезных фич (вроде полноценной рефлексии), но в целом языки достаточно похожие. Основные идеи совпадают. Например для меня «массив как объект» намного предпочтительнее, чем просто указатель на память и длина секции. Зачастую над массивами нужно производить многие вещи, расширять и т.п., все это решается типичными ООП средствами — интерфейсами, которые однозначно используются полиморфно. Поэтому я так и не понял предъявы по поводу «плохой джавы». Может объясните, что в ней не так? Я близко не общался с ней, только переносил пару классов одно время, немного неприятно, но все же лучше, чем паскаль или делфи.
Shamov
19.06.2016 22:32Да, всё с ней не так. Какой-то бесконечно убогий язык. Крайне ограниченный. Множественного наследования нет. Дженерики, которые претендуют на роль шаблонов, нельзя назвать даже бледной тенью настоящих шаблонов… какая-то пародия. Ленин в своё время очень точно описал шаблоны в Джаве: «Формально правильно, а по сути издевательство». Прямого доступа к памяти нет. Общее ощущение такое, как будто ты ещё недостаточно взрослый, чтобы программировать по-настоящему, и тебя просто запустили в некую песочницу для маленьких программистов с напутствием типа: «Ну, давай, пока здесь поиграй. Попробуй хотя бы сам себе не навредить. Вот тебе совочек, который мы специально затупили так, что он почти не копает, но зато выглядит как настоящий. Главное, не ешь песок, всегда обрабатывай исключения, а любое взаимодействие делай через интерфейсы.»
PsyHaSTe
20.06.2016 10:32Ну, от того что в шарпах есть указатели сильно они не распространились, ибо это достаточно серьезный удар по GC, который не может перемещать куски памяти, в которых мы шаримся по абсолютным адресам. Множественное наследование поддерживается интерфейсами, насколько я знаю. Множественное наследование же классов очевидно несет в себе кучу проблем с нулевой пользой. Да, были бы трейты или миксины, было бы лучше, но они во-первых позже распространились, а во-вторых это не множественное наследование.
Лично я указатели в продакшн-коде вообще ни разу не использовал, потому что если они где-то и используются, то либо где-то очень глубоко в библиотеках для всяких некрасивых хаков, либо в интеропе с С/С++, хотя и там оберток Managed-кода вроде ref/out/IntPtr достаточно, чтобы снизить написание unsafe до 0.Shamov
20.06.2016 11:00В языке D есть и GC и прямой доступ к памяти. Так что теоретически одно другому не мешает. Надо просто явно определить, что адресная арифметика не порождает сильных указателей, которые мешают уборке мусора. Т.е. ты можешь ходить по куску памяти как угодно, порождая сколько угодно указателей в его середину, но все эти указатели будут жить ровно до тех пор, пока жива главная ссылка на этот кусок памяти в целом.
Польза от множественного наследования будет нулевой только в том случае, если ты не умеешь им правильно пользоваться. Тогда да… будут только одни проблемы. Я в принципе согласен с тем, что использование множественного наследования требует более глубокого понимания ООП, чем обычно есть у тех, кто считает, что понимает эту парадигму. Но тем не менее отсутствие этой фичи уж точно не несёт никакой пользы, кроме защиты от дурака, который стремится пользоваться тем, чем не умеет.
В наши дни голые указатели и в С++ нечасто используются. Люди предпочитают оборачивать их в shared/unique_ptr. Хотя лично я считаю, что при программировании на безопасных указателях ощущения не те.PsyHaSTe
20.06.2016 11:26В наши дни голые указатели и в С++ нечасто используются. Люди предпочитают оборачивать их в shared/unique_ptr. Хотя лично я считаю, что при программировании на безопасных указателях ощущения не те.
Если только так.
Польза от множественного наследования будет нулевой только в том случае, если ты не умеешь им правильно пользоваться. Тогда да… будут только одни проблемы. Я в принципе согласен с тем, что использование множественного наследования требует более глубокого понимания ООП, чем обычно есть у тех, кто считает, что понимает эту парадигму. Но тем не менее отсутствие этой фичи уж точно не несёт никакой пользы, кроме защиты от дурака, который стремится пользоваться тем, чем не умеет.
Зачем сначала позволять множественное наследование реализации, а потом ломать себе голову, как ничего не отстрелить? Это детский подход, что шрамы украшают мужчину, а чем сложнее ЯП, тем элитнее на нем писать. Вон, можно посмотреть хаб PVS, там статистика подсказывает, что люди совершают элементарные ошибки в простейших местах, зачем расставлять грабли дополнительно? Какую выразительную силу это несет?
Вот покажите пример, что вот так вот с множественным наследованием реализации сделать изи, а вот с интерфейсным ничего хорошего не выходит.Shamov
20.06.2016 11:48Когда у тебя множественно наследуются только интерфейсы, тебе приходится делать реализацию руками непосредственно в классе-потомке. Это более безопасно, когда у тебя кривые ручки. Но это менее ООПшно.
PsyHaSTe
20.06.2016 12:20Обычно реализацию делают с помощью экстеншн-метода, причем тогда она появляется сразу у всех реализующих интерфейс классов, а не только у «наследованных». И тот же LINQ показывает, что это крайне полезный вариант.
Ну и ты так и не ответил на опрос, зачем наследовать МНОЖЕСТВЕННУЮ реализацию? Ведь можно наследовать как кучу интерфейсов, так и базовый класс. Зачем наследовать разную реализацию? Как раз с ООП множественное наследование плохо сочетается, как правило это все от хреново продуманной иерархии.Shamov
20.06.2016 12:47Всмысле зачем? Я не понимаю вопрос. Никто же не говорит о том, что надо одновременно наследовать разные виды одного и того же поведения. Типа, когда объект одновременно наследует реализацию «квадрат» и реализацию «круг». Это дебилизм. Одновременно надо наследовать разные виды поведения и реализацию разных аспектов функционала. Например, объект может от одного базового класса унаследовать реализацию своей квадратности, а от другого — реализацию возможности сохраняться в БД. Использование в данном случае наследования интерфейсов вместо естественного наследования непосредственно реализаций неизбежно приводит к необходимости использовать всякие фабрики только для того, чтобы банально создавать объекты.
PsyHaSTe
20.06.2016 13:47Зачем делать класс сохранения в БД, если можно сделать интерфейс `IDbEntity`, и затем написать сколько угодно экстеншнов для сохранения в БД этих `IDbEntity`? По факту это то же множественное наследование, за маленьким исключением: мы всегда можем указать своё поведение этой `IDbEntity`, а не зависеть от базового класса. Можем написать свою реализацию, можем использовать экстеншн с поведением по-умолчанию.
Множественное наследование же заставляет нас использовать реализацию, которую придумали разработчики языка.
Ну и да, если у вас одновременно объект — круг, и он еще и умеет в БД сохраняться, то это очевидное нарушение SRP.Shamov
20.06.2016 14:19Против экстеншен-методов я ничего не имею. Это очень неплохая замена мн. наследованию. И даже маленького исключения нет. При наследовании мы тоже всегда можем переопределить любой метод по-своему.
Нарушения SRP нет в том случае, когда объект компонуется из двух базовых классов. Каждый класс отвечает за свой функционал. Ну, точнее, формально можно придраться к тому, что существует интегрирующий класс, но в жопу такие придирки. Лучше уж пусть такой класс будет. В нём можно реализовать что-то специфическое для данного конкретного сочетания базовых классов. Всё равно при необходимости это сделать в реальной задаче придётся сделать класс, который содержит в себе все те же базовые объекты в качестве членов. Но только ещё придётся нафигачить бесконечное число делегирующих методов, которые будут тупо пробрасывать вызов во внутренний объект.
sshikov
20.06.2016 12:09Прямого доступа к памяти нет.
Его нет практически нигде в современных языках высокого уровня. Все почему-то пишут разные FFI. И они теперь все убогие?
Множественного наследования нет
Знаете, во многих языках вообще наследования нет. Например в Lisp-ах, и вообще в большинстве функциональных. Они убогие тоже?
Вам бы стоило понять, что есть языки, которые просто нужны для другого.Совсем для другого.Shamov
20.06.2016 12:26Lisp — не ООП язык. К нему претензий нет. И вообще, если бы вместо Java столь широко использовался Lisp, то мир был бы другим. Все крутые фичи Lisp'а можно просто добавить в тот список, который я начал с отсутствия прямого доступа к памяти и отсутствия мн. наследования. Сам Lisp не становится убогим из-за отсутствия мн.наследования, а вот Java из-за отсутствия макропрограммирования становится ещё более убогой, чем просто из-за отсутствия мн. наследования. Хотя всегда можно утешиться тем, что «зато на Java могут программировать даже олигофрены». Для многих это считается веским достоинством языка.
sshikov
20.06.2016 12:34А намек на кучу других языков вы проигнорировали, или не уловили? Еще раз — прямого доступа к памяти нет в Haskell, например. И в Python. И в javascript. И что? И ничего. Это смешная придирка при наличии JNI/FFI.
Что до наследования — то оно прекрасно заменяется делегированием. И это всем известно, и никаких проблем не вызывает. Т.е. вообще никаких. А вот само множественное наследование их еще как вызывает.
Можно я спрошу просто — вы много языков-то знаете? Ну, таких на которых работали и работаете?
Shamov
20.06.2016 12:56Ну, Python и Javascript знаю, поскольку регулярно использую. Perl уже почти забыл. Даже Java владею на достаточном уровне, чтобы осознанно ненавидеть. Молодыми языками типа Go не владею вообще и не имею к ним интереса. Функциональными тоже не владею, но лишь потому, что нет возможности их реально где-то применять, а в целом они мне нравятся.
sshikov
20.06.2016 13:18Ну вот при всем при этом, ваши претензии выглядят странно. Про те же библиотеки, скажем… Я не знаю других распространенных систем, где бы подключение сторонних библиотек было настолько же просто, как в языках на базе JVM. Фактически — добавить в проект ссылку на репозиторий — и уже можно работать. В Perl это сложнее. В Python — тоже сложнее, хотя и не сильно. Примерно на таком же уровне это в javascript. Поддержка сторонних компонент в IDE на порядки лучше — во многом благодаря той самой "неполноценной" рефлексии, которая позволяет видеть метаданные по классам без исходников.
А то что библиотеки друг с другом не стыкуются — так какая же это претензия к языку?
Опять же — Java это язык для другого. Скажем, сделать отчет на основе данных из базы, в формате Excel — это плюс одна-три зависимости, и 5 строк кода + шаблон в виде xls файла.
Shamov
20.06.2016 14:03То, что библиотеки подключать просто, — это вообще ни при чём. От этого зависит только то, сколько библиотек разработчик засунет в свой проект ради одной-двух функций, и насколько болезненным будет его геморрой с разруливанием зависимостей прямых и косвенных. Это я даже по себе знаю. Когда мне нужно было преобразовывать геокоординаты в меркатор и обратно, я вместо того, чтобы написать функцию в пару строк, подключил через JNI нативную библиотеку PROJ.4. А почему бы и нет? Это же так просто…
Библиотеки плохо стыкуются друг с другом ровно потому, что само ядро языка слишком ограничено. Почти для всего нужны библиотеки. В итоге авторов библиотек слишком много. Есть очень много библиотек, тупо повторяющих функционал других библиотек, но с немного другим интерфейсом. И практически никогда не получается выбрать такой набор, в котором бы библиотеки идеально подходили друг к другу. Кто-то возвращает списки объектов как ArrayList, кто-то другой — как SomeObject[], кто-то третий — как IList. Сплошной разброд и шатание. В результате, пользовательский код часто более, чем наполовину, состоит из циклов по перекладыванию из одного контейнера в другой.
Кстати, я согласен с тем, что Java — это новый Visual Basic. Только почему-то эта концепция не соблюдается. Очень часто можно увидеть её на серверах.sshikov
20.06.2016 17:31То, что библиотеки подключать просто, — это вообще ни при чём.
Да ладно ) То-то я видел тут (небольшую правда) кучку постов, о том что не надо тащить в проект лишние зависимости, потому что это трудно. В том-то и дело, что это реальная польза. У меня в текущем открытом проекте — 83 зависимости, и меня это совершенно не волнует. Не будет никакого геморроя — просто не надо тащить все в один проект, надо разбивать на сравнительно мелкие модули.
Почти для всего нужны библиотеки.
Вы не поверите — но это прекрасно! Главное что они не просто нужны — а они есть.
Что до остального — то опять же, с моей точки зрения это мелкие придирки. Да, можно List, можно массив, сейчас стало можно еще и Stream вернуть. Ну так извините, можно ведь и иначе взглянуть — можно вернуть имя файла (это String), можно Path (это уже немного другое, потому тут уже и структура папок в файловой системе, родитель, дети и.т п), а можно и просто File. И в чем же тут недостаток? Это разные вещи, для разных целей.
В результате, пользовательский код часто более, чем наполовину, состоит из циклов по перекладыванию
Ну это вы загнули… Arrays.asList(массив) — у вас этого половина? )))
Но в каком-то смысле — это правда. Потому что большая часть бизнес-кода — она реально из этого и состоит. Из базы в форму, из формы — обратно в базу.Shamov
20.06.2016 18:26Так просто редко удаётся сделать. Обычно возвращается список не того типа, объекты которого реально в нём хранятся, а список из базовых интерфейсов. И из-за type-erasure приходится вручную циклом бежать по списку, тупо приводя каждый элемент к нужному типу и добавляя в целевой контейнер. Необходимость постоянно делать такое тупое и бесполезное действие меня просто убивает.
sshikov
20.06.2016 12:00вроде полноценной рефлексии
Что, простите? Это куда же она делась-то?PsyHaSTe
20.06.2016 12:19А что, type erasure уже заменили человеческой реализацией?
sshikov
20.06.2016 12:49Видите ли, если вы с точки зрения скажем .Net смотрите, то да, где-то вы правы. Если с точки зрения других языков, где рефлексии вообще нет — то претензия непонятна. Более полноценная? А где вы ее видели?
И потом — это претензия слегка не по адресу. Она к erasure, а не к рефлексии. Глупо требовать давать доступ к тому, чего нет.
И еще — а можно спросить, зачем это вам? И почему вам не хватает скажем вот этого: https://github.com/google/guava/wiki/ReflectionExplained?
PsyHaSTe
20.06.2016 13:58Видите ли, если вы с точки зрения скажем .Net смотрите, то да, где-то вы правы. Если с точки зрения других языков, где рефлексии вообще нет — то претензия непонятна. Более полноценная? А где вы ее видели?
Вы же сами сказали — в .Net-е. Да, мне с этой ТЗ странно смотреть на то, что считается рефлексией в джаве. Да, лучше, чем вообще без нее, но это и без моего высказывания очевидно.
И потом — это претензия слегка не по адресу. Она к erasure, а не к рефлексии. Глупо требовать давать доступ к тому, чего нет.
Ну так, собственно тезис можно свести к «без real-time дженериков полноценной рефлексии не получится». Хотя бы потому, что List<int> и List<string> это разные типы.
И еще — а можно спросить, зачем это вам? И почему вам не хватает скажем вот этого: https://github.com/google/guava/wiki/ReflectionExplained?
«А почему ви собственно спrашиваете?». Так диалог строить нехорошо :)
Тут налицо парадокс блаба. Зачем — ну тут много вещей, зачем. Например я использовал рефлексию для динамическоо построения наследника IComparer<T>, чтобы вручную постоянно не писать. Когда нужно сравнить 4-5 полей приходится писать кучу бойлерплейт-кода для этого. А так — просто перечислил поля для сравнения, вызвал метод GetComparer(), он динамически чик-чик, все типы проинспектировал, проверил что у них есть нужные методы (всё в рантайме, естественно), после этого сгенерировал код нужного класса, проистанцировал его и вернул в качестве результата. Т.к. класс после всего этого дела кэшируется то не считая первого вызова разницы в скорости никакой нет, а вот удобство использования повышается на порядок.
Вот тут немного тестов (и если интересна реализация — исходников), это пока что моя домашняя библиотечка, но возможно я когда её допилю сделаю на эту тему статью.Shamov
20.06.2016 14:32Такую штуку (или почти такую) в наши дни можно даже в С++ сделать, где вообще никакой рефлексии нет. Правда с использованием костыля в виде LLVM. Ну, и без автоматической проверки типов, разумеется, поскольку рефлексии нет. Но самописную валидацию типов, если она нужна, всегда можно вставить туда, где по списку полей динамически генерируется код самого Comparer'а.
То, что такого нет в Java — это просто позор. При наличии интерпретирующей JVM сам бог велел предусмотреть хоть что-то для генерации байт-кода в рантайме.
sshikov
20.06.2016 17:35Не, ну я же вполне конкретно спросил — почему вам не хватает TypeToken? У меня это основной язык, и я в редчайших случаях сталкиваюсь с тем, что рефлексии мне почему-то не хватило.
для динамическоо построения наследника IComparer,
Ну это да, имеете право, хороший пример. Просто я обычно такие вещи пытаюсь решить на этапе компиляции, именно там где дженерики имеются в наличии (а еще есть аннотации).PsyHaSTe
20.06.2016 18:38Я не использовал TypeToken и не могу сказать, что меня в нем не устраивает :)
Но вообще минус библиотек именно в том, что пользователь должен знать, как они работают. ну и иметь их. В данном случае это такой «костыль», который позволяет немного обойти эти ограничения, о которых я говорил.
Ну это да, имеете право, хороший пример. Просто я обычно такие вещи пытаюсь решить на этапе компиляции, именно там где дженерики имеются в наличии (а еще есть аннотации).
Я был бы рад, если бы подобные вещи можно было бы решить на этапе компиляции (я несколько завидую тем же constexpr из плюсов, в шарпах все рантаймово делается, даже если по идее компилятор может все это сам провернуть), но я лично не представляю, как именно. В данном случае пользователь может просто взять мою dll и использовать, для него лично ничего не поменяется — не надо использовать сторонние либы, (создавать токен на свои типы и передавать), не надо на этапе компиляции ничем заниматься — он может вообще, получить описание типа по сети (WCF), сгенерировать новый тип в рантайме, затем создать коллекцию этих типов и типобезопасно туда их складывать. И если внезапно придет объект другого типа на тот же эндпойнт, при попытке запихнуть его в коллекцию возникнет typemismatch. Это очень очень полезная фишка.
У меня это основной язык, и я в редчайших случаях сталкиваюсь с тем, что рефлексии мне почему-то не хватило.
В этом и суть :) Вы не сталкивались, потому что у вас это основной язык, мне даже ничего добавлять не надо — это типичная зона комфорта. Мое личное мнение, что это плохо, т.к. развитие останавливается — экстенсивно оно идет, новые фреймворки/классы и т.п., но интенсив пропадает. В этом весь парадокс блаба:
Программисты старше определенного возраста редко меняют язык по своей воле. Они будут считать достаточно хорошим тот язык, к которому привыкли.
Программисты очень привязываются к своим любимым языкам, а я не хочу оскорбить ничьи чувства, поэтому я объясню свою позицию, используя гипотетический язык с названием Блаб.
Блаб попадает в середину континуума абстрактности. Это не самый мощный язык, но он мощнее, чем Cobol или машинный язык.
И на самом деле, наш гипотетический программист на Блабе не будет использовать ни Cobol, ни машинный код. Для машинных кодов есть компиляторы. Что же касается Cobol'а, наш программист не знает, как на этом языке вообще что-то можно сделать. В Cobol'е даже нет некой возможности X, присутствующей в Блабе.
Когда наш гипотетический Блаб-программист смотрит вниз на континуум мощности языков, он знает, что смотрит вниз. Менее мощные, чем Блаб, языки явно менее мощны, так как в них нет некой особенности, к которой привык программист. Но когда он смотрит в другом направлении, вверх, он не осознает, что смотрит вверх. То, что он видит, — это просто «странные» языки. Возможно, он считает их одинаковыми с Блабом по мощности, но со всяческими сложными штучками. Блаба для нашего программиста вполне достаточно, так как он думает на Блабе.
Когда мы поменяем точку обзора программиста, используя любой язык программирования выше по континууму мощности, мы обнаружим, что теперь программист смотрит на Блаб сверху вниз. «Как же можно что-то сделать, используя Блаб? В нем отсутствует даже конструкция Y!»
Используя метод индукции, приходишь к выводу, что только те программисты, которые понимают самый мощный язык, в состоянии осознать полную картину разницы в мощности между различными языками (видимо, именно это имел ввиду Эрик Реймонд, когда говорил о том, что Lisp сделает вас лучше как программиста). Следуя парадоксу Блаба, нельзя доверять мнению других: другие программисты довольны тем языком, который используют, потому что этот язык определяет способ их программистского мышления.sshikov
20.06.2016 19:20Ну вы же его (TypeToken) только что просили? :)
Называется, угадайте с трех раз, для чего вот это нужно:
TypeToken<List> stringListTok = new TypeToken<List>() {};
Что до генерации на этапе компиляции, то можно просто погуглить проект lombok, и поглядеть на живых примерах. Это конечно не сам компилятор генерирует, а annotation processors, но в данном случае это пофиг.
Что до остального, то я сказал основной язык, а не единственный ))) Мне например вполне комфортно на лиспе, без всяких преувеличений. И на Python тоже. И на многих других.
PsyHaSTe
20.06.2016 21:06Да, вроде бы TypeToken то, что нужно. Правда чуть беднее и синтаксис убивает, но зато работает.
TypeToken<List> stringListTok = new TypeToken<List>() {};
даже не знаю, что бы это могло быть. Если судить по примеру, тут должно быть TypeToken<List<?>>.
Лисп кстати тоже бывает разный. Common например так себе, а вот диалекты вроде схемы уже съедобное. Хотя в любом случае сознание расширяет неплохо и классика :)
babbubava
16.06.2016 11:21Давайте и в этом году устроим неделю Оберона habrahabr.ru/post/302076/#comment_9657336
vlsinitsyn
16.06.2016 12:44+1Утверждение, что «Знаменитая операционная система OS/400 для IBM AS/400 была реализована на Modula-2» не совсем правда.
Вот что по этому поводу пишет Франк Солтис, создатель AS/400:
"… Язык программирования VLIC, называвшийся PL/MP и использовавшийся со времен разработки оригинальной System/38, был основан на языке PL/I. MP в его названии расшифровывается как Machine Product — имя, которое часто использовалось для обозначения аппаратных средств и обоих слоев микрокода. Компилятор PL/MP, как и ассемблер IMPI, генерировал двоичные машинные команды IMPI.
… В течение ряда лет мы пытались использовать другие языки при разработке компонентов VLIC. Например, один из наших новейших трансляторов был написан на Modula-2, применялся также язык С. Однако, мы чувствовали, что ни один из них не подходит для проекта, основанного на объектно-ориентированной технологии. Выбор напрашивался сам собой — язык C++. Нам нужно было разрабатывать код ОС очень низкого уровня. Иногда, для достижения оптимальной производительности приходилось прибегать к ассемблеру, и С+ + легче позволял это. Ведь, фактически, язык С++ и есть современный вариант ассемблера…
Технология ООП не подвела: производительность программистов при разработке SLIC повысилась почти в четыре раза по сравнению с традиционной методикой. В период с июля 1992 года, было создано более миллиона строк кода на С+ + и более 7 000 классов.… "
Ф. Солтис, «Основы AS/400».
alexeiz
18.06.2016 08:23-2О, чувствуется стиль оберонкорщиков (oberoncore.ru)! «Вирт был в основе всех современных языков и технологий. Неблагодарные плагиаторы его даже вскользь не упоминают!» Херня всё это. Вирт остался на задворках технического прогресса, благодаря своему узкому мышлению и тяге к примитивизму. До сих пор его лучшие достижения — это Паскаль и книга «Алгоритмы + структуры данных». По сути, с 1970 года он ничего более существенного не добился. Ему можно было на пенсию уходить ещё 40 лет назад.
kemiisto
18.06.2016 11:56Ну Ваш то стиль ничем не лучше, если не хуже. Даже если Вам Оберон не нравится, то Модула — однозначно «более лучшее» достижение, чем Паскаль. А это уже конец 70-х. Модульность в большинстве императивных языков есть пошла именно от Модулы, что таки очень даже существенно. А книги… Ну мне вот АиСД вообще не по душе, но вообще Вирт — это в первую очередь разработчик языка Оберон, одноимённого компилятора и ОС, а уже только потом я бы стал обсуждать его книги. Не очень люблю аргумент «сперва добейся», но, ей богу, Вы много знаете людей, которые спроектировали ЯП, реализовали для него компилятор и написали с его использованием ОС? Вот с конца 70-х Вирт этим и занимался. Как-как Вы там сказали: «ничего существенного не добился»?! Ну-ну.
evocatus
Я вот недавно купил вторую книгу по Go. Один из авторов — Брайан Керниган.
И в этой книге есть схема языков, которые повлияли на Go:
ALGOL60->C-Go,
ALGOL60->Pascal->Newsqueak->Alef->Go,
Pascal->Modula-2->Oberon-Oberon-2->Go
Так что идеи Вирта живут и здравствуют. Вместе с идеями Кернигана.
kemiisto
Керниган взял некоторые идеи из Оберона, да, но Go не имеет ровным счётом никакого отношения к тем ценностям, который пропагандирует Вирт. Опять этот жуткий С-подобный синтаксис (пускай и с Обероновской структурой программ) с кучей колокольчиков и сюрпризов на ровном месте. Эдак можно и кивая в сторону Java сказать, что идеи Вирта живут и здравствуют. Идеи Вирта (максимально простой, жёсткий и в то же время достаточный язык программирования) последовательно воплощались лишь в его же линейке (Pascal -> Modula -> Oberon) и, пожалуй, нигде более. Ну разве что Modula-3 сюда же можно отнести с небольшой натяжкой: исключения и обобщённое программирование не делают этот язык максимально простым, но в то же время Oberon, в котором эти средства отсутствуют, не является всегда достаточным. Имеем своего рода компромисс, который, правда, можно оспорить.