Litvek - онлайн библиотека >> Крис Касперски >> Другие языки и системы программирования и др. >> Языки, которые мы потеряли >> страница 2
программирования для платформы. Net со встроенной поддержкой метапрограммирования) — вообще младенцы, но на самом деле концепция метапрограммирования возникла еще во времена палеолита. Lisp, появившийся в далеком 1958 г., — хороший пример языка, естественным образом поддерживающий метапрограммирование, одной из задач которого является создание программы, выводящей точную копию своего собственного исходного текста — так называемый куин (англ, quine). На Lisp'e он записывается так:


(funcall (lambda (x)

(append x (list (list 'quote x))))

'(funcall (lambda (x)

(append x (list (list 'quote x))))))


На Си так:


#include<stdio.h>

char*i="\\tinclude<stdio.h>",n='\ n',q="",*p=

«%s%cchar*i=%c%c%s%c,n='%cn',q='%c',*p= %c%c%s%c,*m=%c%c%s%c%c;%s%c",*m=

«int main () {returnIprintf (p,i+l,n,q,*i,i,q,*i,q,n,q,p,q,n,q,m,q,n,m,n);}"

;int main(){return!printf(p,i+l,n,q,*i,i,q,*i,q,n,q,p,q,n,q,m,q,n,m,n);}


А теперь попробуйте реализовать тоже самое на Си++ с использованием шаблонов и посмотрите, насколько сильно они вам «помогут». Парадигма метапрограммирования, красиво реализованная в Lisp'e, была заброшена на полвека именно из-за потери управляемости языком, но затем восстала из пепла в ужасной реинкарнации, уходящей своими корнями в директивы препроцессора языка Си… Но это уже совсем другая история.

Язык Си++ оказал огромное влияние как на мышление программистов, так и на развитие всех последующих языков, став стандартом де-факто. Никто, естественно, не говорит, что ООП- и метапрограммирование— это плохо. Почему обязательно плохо?! Очень даже хорошо! Местами. Но вот мысль о том, что ООП — единственно правильный подход — ужасна. Самолеты и космические корабли мирно сосуществуют с велосипедами и автомобилями. Никому ведь и в голову не придет летать за сигаретами на ракете, особенно если сигареты продаются в киоске на соседнем углу.

Но ведь это же неправильно! Появление ракет должно перевернуть наше мышление! Поэтому — строим киоск за орбитой Плутона и каждому даем по ракете, чтобы туда летать, а горючее покупаем за деньги, вырученные от строительства космодромов и продаж ракет. Кто не может строить ракеты — пусть учит других, как на них летать. Сколько создается новых рабочих мест и главное, что все в бизнесе. Вот тут уж действительно, возврата в прошлое нет… Сигареты стоят миллиарды долларов, и деньги в индустрию вращаются просто огромные. Кто же захочет от них отказываться?! Напротив, ракеты будут стремительно «совершенствоваться», чтобы за сигаретами можно было летать даже на Альфу Центавра. Говорите, что это нелогично и невозможно? Но ведь именно такая ситуация сложилась с Си++. Судите сами — реализация компиляторов языка Си++ очень сложная и дорогостоящая задача, а сам язык настолько обширен и объемен, что его изучение требует невероятных усилий. Чтобы окупить средства, вложенные в разработку компиляторов, фирмы вынуждены «подсаживать» на него миллионы программистов, которые, пройдя длительный (и ужасно мучительный) путь обучения Си++, просто не могут признаться себе в том, что напрасно убили десять лет своей жизни (данной человеку лишь однажды!) и что стоящие передними задачи с ничуть не меньшей эффективностью реализуются на чистом Си и других процедурных языках, легко осваиваемых на ходу без отрыва от производства. Вот они и начинают убеждать остальных, что процедурные языки давно мертвы. Сложность ради сложности.

Впрочем, среди этого мрака есть и светлые пятна. При приеме в нормальную фирму за попытку решить задачу с применением шаблонов, там, где они не требуются, по головке не погладят и программу скорее всего не зачтут. Один из известных «подколов» — написать программу, выводящую сумму первых 100 натуральных чисел на экран, int а, Ь=0; for(a=1;a<101;a++) b+=a; printf(«%d\n», b);— незачет, printf(«5050\n») — зачет. Ключевое слово здесь — «выводящую», а не «вычисляющую». Чуть более жестокий вариант— вывод первой сотни простых чисел. Разумеется, сумму членов арифметической прогрессии можно вычислить и в уме, а найти простые числа без компьютера не то, чтобы нереально, просто… зачем мучаться, когда компьютер под рукой? Однако, программист — это прежде всего инженер, а инженер должен не только внимательно читать ТЗ, но и выбирать адекватные средства для решения задачи. В данном случае — написать программу, генерирующую программу, выводящую простые числа на экран, т. е. что-то вроде: рг::: 1,5,7…\n»), после чего первую программу можно смело стереть. Действительно, какой смысл обсчитывать одни и те же данные при каждом запуске программы, когда это достаточно сделать всего один раз?! Важно понять, что язык — это всего лишь средство выражения мыслей. Не стоит фетишизировать его. Умные мысли можно выразить и в машинном коде (там, где это оправданно), если же мыслей нет — не поможет никакой язык. Проблема, однако, в том, что программирование машины (т. е. задание последовательности операций, которая она должна выполнять) все больше превращается в диалог с ней. Программисты перестали обдумывать решения поставленных задач вдали от машины. Компьютер превратился в калькулятор, а программы — в «записки охотника». Именно поэтому, когда современный программист слышит «сумма ряда», он рефлекторно представляет себе цикл и машинально тянется к клавиатуре… Он утратил понимание того, что язык (машинный) тут и рядом не валялся. Это чисто математическая задача, а от машины требуются лишь средства ввода/ вывода для печати результата.

ООП в ретроспективе

Многие языки, возникшие задолго до появления термина ООП (например, уже упомянутый Лисп), вполне отвечают его критериям, возможно, даже в большей степени, чем «чистокровные» представители ООП, такие как Си++ или его прямые предшественники Симула (Simula) и Смолток (Smalltalk), созданные в 1967 и 1980 году соответственно. Кстати, о предшественниках. Язык Си++ часто критикуют за то, что обращение к методу класса в нем реализовано как вызов функции, в то время как Симула и Смолток позволяли объектам обмениваться сообщениями. Сторонники Си++ утверждают, что конкретный способ вызова метода класса — внутренняя кухня языка, скрытая от программиста и что посылка сообщения является частным случаем вызова функции, только прямой вызов намного более эффективен в плане накладных расходов и машинных затрат на такты и оперативную память.

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