СРЕДСТВА РАЗРАБОТКИ

Недавно корпорация Microsoft выпустила бета-версию среды разработки Visual Studio.NET (см. PC Week/RE, № 2/2001, с. 19), в которой реализована идея общего языкового окружения (Common Language Runtime, CLR; см. PC Week/RE, № 39/2000, с. 40). Тексты программ на различных языках программирования будут транслироваться не в команды процессора, а в промежуточный байт-код на языке MSIL. Это дает разработчикам ряд несомненных удобств, например доступ к общей библиотеке стандартных классов. На уровне CLR реализованы поддержка объектной технологии, сборка мусора, проверка безопасности, многопотоковость, вызов удаленных процедур и т. д.

Одно из важнейших достоинств CLR - возможность создания программ, написанных на разных языках программирования, а также разработки и отладки приложений в единой оболочке Visual Studio.NET. В стандартный комплект поставки Microsoft войдут скорее всего языки C#, Си++, Visual Basic.NET и JScript. Кроме того, Microsoft предложила ряду компаний реализовать их собственные расширения Visual Studio.NET для других языков программирования. Это будут и достаточно известные языки - такие, как Smalltalk, Component Pascal, Oberon, Perl, Fujitsu COBOL (его рекомендовал к переносу на .NET сам Билл Гейтс), и целый ряд менее известных, но во многих случаях гораздо более полезных. Хочется надеяться, что выпуск их .NET-версий принесет им заслуженную популярность.

Среди готовящихся к .NET-реализации немало языков функционального программирования. Они отличаются от обычных, процедурных (императивных) тем, что написанная на них программа - не линейная последовательность операторов, а выражение, которое не просто механически выполняется, а вычисляется, активно используя рекурсию, методы сопоставления с образцом и т. д. При этом обычно требуется достаточно мощное исполнительное ядро, реализующее подчас весьма сложные алгоритмы поддержки вычислений. Классический пример такого языка - Лисп.

Функциональная программа чаще всего представляет собой одно выражение. Программисту в процессе его составления удается сосредоточиться на логике решения задачи (что надо вычислить), а не на более мелкой проблеме - как что-то вычислить. К функциональным можно отнести, в частности, язык SQL. Операторы SQL определяют, что надо получить от БД (программист просто пишет команду “дайте мне данные, связанные таким-то образом”), но не уточняет, как их получить - эта задача возлагается на сервер БД).

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

Haskell (www.haskell.org)

Функциональный язык со строгой типизацией, базирующийся на лямбда-исчислениях (как Лисп). Обладает прозрачной для программиста семантикой, создавался для повышения производительности работы программистов в процессе создания больших систем. Как показал опыт таких компаний, как Ericsson, использовавшей Haskell при разработке телекоммуникационных приложений, и Software AG (экспертная система Natural Expert написана на Haskell), скорость создания ПО возрастала в 9-25 раз по сравнению с аналогичными проектами, где использовались Си/Си++.

Отличительная особенность Haskell - возможность использования собственного синтаксиса для формального описания требований к проекту, что позволяет безболезненно переходить от проектирования к программированию.

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

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

К недостаткам Haskell следует отнести повышенные требования к памяти (из-за рекурсии) и не очень высокое быстродействие.

Готовится к переносу на .NET облегченная версия Haskell под названием Mondrian (www.mondrian-script.org). По синтаксису этот язык напоминает Си и Java.

Scheme (http://rover.cs.nwu.edu/~scheme)

Диалект Лиспа с упрощенной семантикой и расширенными способами формирования и вычисления выражений, синтаксического разбора и сопоставления с образцом.

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

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

Интересно, что Scheme-приложение работает в статическом объеме памяти. Объекты явно уничтожить невозможно, это забота внутреннего механизма сборки мусора. В целях повышения эффективности выполнения Scheme-программ в ограниченном пространстве ОЗУ в интерпретаторе реализованы экономные алгоритмы поддержки рекурсивных вычислений.

Eiffel (www.eiffel.com)

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

В Eiffel сделана попытка совместить процессы проектирования и разработки ПО. С теоретической точки зрения он продуман так, что позволяет на этапе компиляции выявлять в исходных текстах все неточности, способные привести к ошибкам времени выполнения.

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

Встроенная система сборки мусора освобождает программиста от необходимости явного удаления объектов из памяти.

К недостаткам Eiffel можно отнести сложность реализации теоретической модели языка - на этапе компиляции обычно выявляются не все ошибки. В основном это связано со сложностью отслеживания корректности преобразования типов при множественном наследовании.

Mercury (www.cs.mu.oz.au/research/mercury/)

Логический функционально-декларативный язык со строгой типизацией. Создавался для реализации крупных программных проектов на основе декларативных технологий.

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

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

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

Тексты Mercury-программ более наглядны, чем программы на Прологе, а готовые Mercury-приложения работают в два раза быстрее самой эффективной на сегодня Пролог-реализации Aquarius Prolog и в десятки раз быстрее других реализаций. При этом с ростом объема Пролог-программы (базы знаний) скорость ее выполнения (логического вывода) снижается нелинейно: чем больше программа, тем медленнее она работает. Для Mercury эта зависимость линейна.

Python (www.python.org)

Объектный язык с очень простым синтаксисом. Позволяет динамически создавать сложные типы данных и выполнять динамическое приведение типов. Содержит развитую систему прерываний (с ее помощью иногда симулируется работа не включенного в язык оператора goto) и большое число стандартных библиотек. Python обеспечивает интерфейсы ко многим внешним системам и Си-библиотекам.

Python часто применяется в качестве скрипт-языка для написания Интернет-приложений, так как включает множество средств, поддерживающих сокеты, Интернет-протоколы - HTTP, почтовые и т. п. Сценарии на Python без изменений работают на платформах MS-DOS, Windows 9x/NT, Unix, Mac, OS/2. Python хорошо подходит для обработки текстов, организации и синхронизации параллельных процессов, интеграции приложений в гетерогенных сетях. Python-программы либо интерпретируются, либо компилируются в промежуточный байт-код, который в свою очередь можно конвертировать в Си-код или поставлять в виде законченного приложения вместе с интерпретатором. Без интерпретатора Python-приложение распространять довольно сложно - надо поддерживать гибкие возможности языка по работе с динамическими типами и функцию исполнения Python-выражений, заданных в виде внешней строки (такую строку можно конструировать на лету). Поэтому в комплект поставки Python обычно входит библиотека времени выполнения, позволяющая вызывать Python-программы из внешних приложений, вычислять выражения Python и обращаться к методам Python-объектов.

Поклонникам функциональных языков Python предлагает возможность записи программы в лямбда-форме.

Standard ML (http://research.microsoft.com/Projects/SML.NET/index.htm)

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

Oz (www.mozart-oz.org)

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

В Oz объединены практически все основные программные концепции - от обычной императивной (командной) и объектной до функциональной и логической. Может показаться, что в этом языке в одну кучу свалены такие технологии, как интеллектуальный поиск в базе знаний, сопоставление с образцом и возможность распределенной работы по виртуальным асинхронным каналам, но на самом деле после практического изучения можно достаточно быстро оценить стройность, элегантность и продуманность этого языка.

Программисту недоступны детали реализации на уровне исполнительной системы Mozart, и это обеспечивает высокую безопасность работы Oz-программам - любые потенциально опасные для ОС действия блокируются средой исполнения.

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

Java

Из принципиальных (одна из целей .NET - противовес Java) и юридических (судебные разбирательства с Sun) соображений Microsoft не собирается своими силами поддерживать современные версии Java на .NET, но можно не сомневаться, что этим займутся другие компании. Пока подобную работу собирается проделать Rational Software (www.rational.com).

* * *

Для большинства описанных в статье языков на указанных сайтах доступны свободно распространяемые (несовместимые с .NET) компиляторы и интерпретаторы для разных платформ, в том числе и Windows.