Та же тенденция, хотя и выраженная не так ярко, наблюдается за пределами мира Unix, например, в продолжающемся переходе от С++ к Visual BASIC, который заметно проявляется в разработке приложений для Microsoft Windows и NT, а также в движении к Java в мире мэйнфреймов.
Аргументы против С и С++ в равной степени применимы к другим традиционным компилируемым языкам, таким как Pascal, Algol, PL/I, FORTRAN и компилируемые диалекты BASIC. Несмотря на отдельные "героические усилия", такие как Ada, отличия между традиционными языками остаются внешними при сопоставлении их основных конструктивных решений, оставляющих управление памятью программисту. В Unix большинство из когда-либо созданных языков доступны в виде высококачественных реализаций с открытым исходным кодом. Несмотря на это, в широком использовании в Unix или Windows не осталось других традиционных языков. Разработчики отказались от них в пользу С или С++. Соответственно, в данной главе они не рассматриваются.
14.3. Интерпретируемые языки и смешанные стратегии
Языки с автоматическим управлением памятью осуществляют его с помощью диспетчера памяти, встроенного в их динамически исполняемые модули. Как правило, среды выполнения в таких языках разделены на программную часть (собственно выполняющийся сценарий) и часть интерпретатора с управляемой им динамической памятью. В Unix-системах (а также в других современных операционных системах) память интерпретатора может совместно использоваться несколькими программными частями, что сокращает фактические издержки для каждой из них.
Использование сценариев — нисколько не новая идея в мире Unix. В 1970-х годах, в эпоху гораздо меньших машин, Unix shell (интерпретатор для команд, вводимых в Unix-консоль) был спроектирован как полностью интерпретируемый язык программирования. Даже тогда было распространено написание программ полностью на shell или использование shell для написания связующей логики, объединяющей встроенные утилиты и нестандартные программы на С в целостные системы, эффективность которых была больше, чем сумма эффективности составляющих частей. В классических вводных книгах по Unix-среде (таких как
В современном shell-программировании языки свободно смешиваются, для решения подзадач задействуются как бинарные, так и интерпретируемые элементы из почти десятка других языков. Каждый язык решает ту задачу, к которой он приспособлен лучше остальных, каждый компонент является модулем с узкими интерфейсами для связи с другими модулями, а глобальная сложность системы в целом гораздо ниже, чем в случае ее реализации в виде одного массивного монолита на универсальном языке программирования.
14.4. Сравнение языков программирования
Сочетание языков представляет собой стиль программирования, который требует скорее более интенсивного использования знаний, чем программного кода. Для успешной работы разработчику необходимо владеть достаточным количеством языков программирования, а также знать преимущества каждого из них и иметь опыт их совместного использования. В этом разделе содержатся ссылки, которые помогут в этом. Для каждого рассмотренного языка приводятся учебные примеры, иллюстрирующие его достоинства.
14.4.1. С
Несмотря на проблему управления памятью, существуют прикладные области, в которых С остается наилучшим языком. С является оптимальным языком для программ, в которых нужна максимальная скорость, актуальны требования реального времени или необходима тесная связь с ядром операционной системы.
Язык С также является оптимальным для программ, переносимых на многие операционной системы. Однако рассмотренные ниже альтернативы С все больше используются в основных операционных системах, отличных от Unix; в ближайшем будущем значение переносимости как основного преимущества С может уменьшаться.
Иногда преимущество, которое достигается с помощью таких существующих программ, как генераторы синтаксических анализаторов или GUI-построители, которые генерируют код С, так велико, что оправдывает программирование на С остальной части небольшого приложения.
И конечно, С доказал свою незаменимость для разработчиков всех его альтернатив. При достаточно глубоком изучении реализации каждого из рассматриваемых здесь языков обнаруживается ядро, выполненное на простом, переносимом С. Эти языки унаследовали многие из преимуществ С.
В современных условиях, возможно, лучше было бы рассматривать С как ассемблер высокого уровня для виртуальной машины Unix (учебный пример в главе 4). В другие операционные системы C-стандарты внесли такие возможности этой виртуальной машины, как стандартная библиотека ввода-вывода. Язык С незаменим, когда требуется тесная связь с аппаратной составляющей при сохранении переносимости.