Практичный язык для практичных программистов

27 сентябрь, 2004 - 23:00Андрій Кухар

Каузальность

Глупцы бывают двух родов. Из уст первых мы слышим:
"Эта вещь старая, следовательно, качественная".
Вторые утверждают: "Эта вещь новая,
следовательно, лучшая".
Дж. Бруннер

Известно, что не бывает чего-либо из ничего, и реакция возникает только на акцию. Реакция У. Брайта (W. Bright) -- проект сверхвысокоуровневого языка программирования D -- является своеобразным ответом на фактическую неудовлетворенность пресловутым дуэтом C/C++. За плечами у трансляционных дел мастера Брайта -- непосредственное участие в разработке таких программных продуктов, как: Northwest Software C, Data-light C, Zorland C, Zortech C++ (между прочим, один из первых "родных" компиляторов с C++), Symantec C++ и Digital Mars C++; компилятор с ABEL (Ad-vanced Boolean Expression Language, предназначенный, как и более известный VHDL, для формального описания логических схем при проектировании электронных систем); компилятор/интерпретатор DMDScript (реализация стандарта ECMA 262, на основе которого также созданы JavaScript и JScript); Java-компилятор Visual Cafe. Поэтому, уж если такого ранга специалист чем-то недоволен, значит, действительно что-то не так. Впрочем, недостатки языков C и C++ давно уже стали притчей во языцех, поэтому мы остановимся на них совсем кратко.

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

Практичный язык для практичных программистов
Интегрированная среда разработки DIDE выглядит вполне современно и профессионально
С++, естественно, унаследовал большинство недостатков C. Имманентная совместимость с "родителем" привела к сохранению немалой доли ненадежных составляющих. Ситуация дополнительно усугубляется из-за традиционно отмечаемой избыточности и сложности. Чтобы окончательно понять, о чем идет речь, рекомендуем приобрести какое-либо серьезное современное руководство по C++ плюс к нему -- стандарт на C++ (порядка 750 страниц) и, наконец, попытаться выбрать из множества доступных компиляторов тот, который наиболее полно отвечает этому стандарту.

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

Здесь у неискушенного читателя наверняка возникнет резонный вопрос: раз эти проблемы известны не первый год, то, скорее всего, их уже пытались решить? Зачем в очередной раз изобретать велосипед, если существуют, скажем, Java и C#? А ответ состоит в различных предназначениях этих языков и D. Так, если целью Sun Microsystems было создание единого языка для разных прикладных областей (в том числе и для программирования бытовых электронных устройств от микроволновых печей до мобильных телефонов), то D был задуман как средство не только прикладного, но и системного (низкоуровневого) программирования. В связи с этим у данных языков больше отличий, чем сходств. Вот некоторые из них: Java абсолютно ориентирован на объекты, D лишь поддерживает парадигму ОО; Java не блещет низкоуровневыми возможностями, у D их предостаточно; Java присуща чрезмерная сложность -- бич современных средств программирования, D обладает умеренной сложностью.

Что касается C#, то одна из основных целей корпорации Microsoft заключалась в создании собственной альтернативы Java, необходимость в чем возникла после ряда разбирательств с Sun Microsystems. Если Java по Б. Гейтсу -- "просто еще один язык программирования", то C# противопоставляется именно этому "еще одному языку", но никак не C/C++.

Таким образом, ни Java, ни C# по своей сути не могут претендовать на лавры преемника C/C++. Посему предмет нашего обсуждения -- отнюдь не очередной велосипед, а, так сказать, иное средство передвижения, в котором сегодня ощущается насущная потребность и который не только заслуживает внимания, но и вполне может оказаться тем самым преемником.


Сущность D

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

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

Упрощенный, компактный и выразительный синтаксис. Чтобы облегчить изучение языка и перенос кода на С/С++, в D сохранена большая часть синтаксических конструкций предшественников. Невооруженным глазом заметны как неизменная нотация объявлений функций и блоков инструкций, так и схожесть форм выражений и операторов.

Бинарная совместимость с языком С. В частности, обеспечиваются использование всех типов данных C как собственных (кстати сказать, не всякий компилятор с C имеет поддержку всех типов стандарта C99); передача/прием значений любого типа; вызов любых функций, в том числе из библиотек C (благодаря чему программы на D могут непосредственно обращаться к API операционных систем). И все это без каких бы то ни было промежуточных слоев совместимости или раздельно компилируемых DLL. Соответственно, унаследованный код на C не требует конвертации, а попросту компонуется с новыми модулями, реализованными на D. Поскольку интерфейс с C++ не предусмотрен, C также играет роль своеобразного шлюза между D и C++.

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

Качественно новый уровень низкоуровневого программирования. В D имеются указатели, структуры, средства преобразования типов и, конечно, inline-ассемблер (х86). Последний также стандартизирован, что сразу выделяет его на фоне несовместимых реализаций, предоставляемых различными создателями компиляторов с C/C++.

"Чистая" модульная структурная программная организация как противопоставление пространствам имен и заголовочным файлам C++. Каждый исходный файл D представляет собой "импортабельный" модуль с собственным пространством имен и возможностью прекомпиляции. Соответственно, отпадает необходимость в препроцессоре.

Два метода управления динамической памятью. Первый -- на основе старых добрых функций malloc/alloc и free либо перегруженных операторов new и delete, второй -- более совершенный с так называемой сборкой мусора.

Современное управление "дорогими" ресурсами. В D реализована поддержка RAII (Resource Acquisition Is Initiali-zation), технологии, призванной помочь в написании надежного ПО. RAII чем-то напоминает работу деструкторов в C++, исполняющихся, когда переменная покидает область видимости, и может применяться как ко всем экземплярам конкретного класса, так и к конкретному экземпляру.

Обработка "исключительных ситуаций". Для этой цели вместо модели try-catch принята try-catch-finally. Исполь-зование finally позволяет отказаться от создания специальных классов, лишь реализующих необходимые деструкторы. Данный механизм имеет много общего с аналогом из C++, но с одним отличием: catch-операторы "ловят" сугубо ссылки на классы, а не на произвольные типы.

Идентификация типов во время исполнения. Частично реализованная в C++, в D эта возможность доступна в полной мере. В результате -- лучшие сборка мусора и отладка, а значит -- более высокая живучесть (persistence) приложений.

Многопоточность. Для организации многопоточных программ применяются: класс Thread -- для манипулирования потоками, и модификатор syn-chronized -- для создания синхронизированных методов, классов и критических секций (использовать которые в каждый момент времени может только один поток).

Шаблоны. Поддерживаются шаблоны классов и функций, частичная (partial) и явная (explicit) специализации, частичное упорядочение (partial ordering). Параметрами шаблонов могут выступать типы данных, значения, а также другие шаблоны. Однако эти средства реализованы несколько иначе, чем в C++. К основным отличиям относятся: однозначная форма записи (без угловых скобок), отсутствие объявлений (только определения), видимость всех предварительных ссылок, определение членов в одном месте, перегружаемость шаблонов классов и др.

Интерфейсы. Модель наследования в D подобна таковой в Java (и C#). Она одноклассовая, расширенная интерфейсами, под которыми понимают специальные классы, содержащие как члены только абстрактные виртуальные методы.

Сквозная поддержка Unicode. А именно, UTF-8, UTF-16 и UTF-32. Оперирование другими схемами кодирования осуществляется с помощью фильтрации ввода/вывода.

Проектирование "по контракту" (design by contract). Краеугольный камень методик повышения надежности ПО, концепция DBC (успешно применяющаяся в языке Eiffel) предполагает создание специальных утверждений-контрактов, которые в указанных местах программы должны принимать истинные значения. Контракты варьируются от элементарных утверждений (asserts) до инвариантов классов (class invariants), предусловий (function entry pre-conditions) и постусловий (function exit postconditions) для функций.

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


На финишной прямой

Я не знаю другого способа судить о
будущем, кроме как по прошлому.
Г. Патрик

Все это реализовано Брайтом в легально-бесплатном компиляторе Digital Mars D. На момент написания статьи для загрузки была доступна версия 0.97 (для платформ Windows и Linux), правда, без исходных текстов для генераторов кода и объектных файлов, а также для оптимизатора по причине неполной их завершенности. Имеются отдельные лексический, синтаксический и семантический анализаторы D, "встраиваемые" в GCC, их релиз 1f доступен для следующих платформ: Linux (Red Hat 8), Mac OS X (10.3.2), FreeBSD (5.2.1) и Cygwin. Для того чтобы начать программировать на D, остается добавить поддержку синтаксиса этого языка в предпочитаемый вами текстовый редактор либо воспользоваться легковесным редактором, специально предназначенным для D, -- leds. Имеется и полновесная интегрированная среда разработки DIDE.

Впрочем, ситуация выглядит благополучной только на первый взгляд. Ведь с начала проекта прошло более пяти лет, а большая часть инструментов даже не достигла отметки 1.0. Если он и дальше будет развиваться теми же темпами, то вряд ли D, несмотря на все предпосылки к тому, станет реально востребованным языком программирования и сможет потеснить тандем C/C++. В таком случае он просто примкнет к многочисленной когорте хоть и интересных, но по разным причинам не выдержавших естественного отбора разработок. Дело в том, что смена приоритетов происходит сегодня не только в целевом предназначении языков, но и в методах их продвижения. Чтобы программирующие массы смогли сделать осознанный выбор в пользу нового языка, мало обеспечить их информацией о его потенциале, необходимо также создать целую инфраструктуру, позволяющую этот потенциал раскрыть, -- хотя бы один полный комплект инструментальных средств, библиотеки решений и ресурсов, учебные пособия и много чего другого.