Компилятор Object Pascal компании RemObjects Software
Особенности языка программирования
Платформа Microsoft .NET становится сегодня все более популярной среди создателей Windows-приложений благодаря своей универсальности, защищенности и удобству применения. Косвенным свидетельством эффективности принципов, положенных в основу ее проектирования, является тот факт, что многие компании сейчас активно занимаются проектами по переносу части этой платформы в операционные системы, отличные от Windows, такими как поддерживаемый рядом поставщиков Linux проект Mono по переносу Common Language Runtime в операционные системы Linux, Solaris, FreeBSD и Mac OS X (см. http://www.mono-project.com). В настоящее время все больше сторонников среди программистов и руководителей проектов находят средства разработки корпорации Microsoft — за последние пять лет заметно возросло их качество, удобство применения, а нынешняя оснащенность примерами приложений и кода, пожалуй, превосходит все, что когда-либо могли предложить поставщики подобных инструментов.
Естественно, производители компонентов, утилит, дополнений к средам разработки, компиляторов, отладчиков также обратили свои взоры к Visual Studio .NET как к перспективной среде разработки, сулящей выгодное партнерство и стабильный рынок для их продукции. К настоящему моменту представленные на рынке ПО дополнения к Visual Studio .NET охватывают весьма широкий спектр задач. О некоторых интересных разработках в этой области (например, о Borland Together for Visual Studio .NET) мы уже рассказывали в нашем журнале и планируем продолжать эту традицию в дальнейшем.
Сегодня мы поговорим о любопытном продукте — компиляторе языка Pascal для Microsoft .NET Framework 1.1 и 2.0 и Mono от компании RemObjects Software, носящем название Chrome. Он обладает некоторыми особенностями, представляющими немалый интерес для разработчиков, планирующих переход на Microsoft .NET и уже использующих Visual Studio .NET, но предпочитающих языки Pascal или Delphi всем остальным языкам программирования (как известно, таких разработчиков в нашей стране чрезвычайно много), а также для авторов Linux- и UNIX-приложений, желающих применять при их создании классы Microsoft .NET.
Особенности языка программирования
Chrome был создан командой специалистов, хорошо известных пользователям Delphi в качестве докладчиков на конференциях, авторов статей и книг. Естественно, создавая этот продукт, они предусмотрели в нем как те особенности языка, к которым привыкли пользователи Delphi, так и не реализованные в Delphi особенности, которые многие пользователи Delphi хотели бы видеть в новых версиях продукта. Поговорим немного о последних.
Групповые типы и методы (Generics)
Групповые типы предназначены для создания кода, исключающего ошибки, связанные с преобразованием типов. Характерные примеры применения таких типов — контейнерные классы, коллекции объектов строго определенного типа. Ниже приведен пример создания такого класса, реализующего связанный список:
type
List<T> = public class
public
constructor(aData: T);
constructor(aData: T; aNext: List<T>);
property Next: List<T>;
property Data: T;
method ToString: string; override;
end;
«T» обычно называют групповым параметром, и он должен быть заменен конкретным типом данных при создании экземпляра объявленного класса. Отметим, что на групповые параметры можно налагать ограничения, например:
type
List<T> = public class
where T has constructor, T is IComparable;
public
//...
end;
Отметим, что данная возможность поддерживается только при совместном применении Chrome с .NET Framework 2.0 или с Mono 2.0.
Контракты для классов (Class Contracts)
Проектируя класс или метод, разработчики нередко предполагают, что существуют определенные ограничения на данные, которыми он манипулирует. Однако в большинстве случаев эти ограничения остаются в голове разработчика и лишь изредка попадают в проектную документацию или в комментарии. Потом они забываются — и тогда начинаются проблемы с сопровождением и обновлением продукта.
Chrome включает расширения языка, позволяющие вводить подобные ограничения непосредственно в код на этапе отладки и, при необходимости, отключать их на этапе создания окончательной версии, предназначенной для внедрения. Так, с помощью блока require можно определить требования, которым должны удовлетворять данные перед началом выполнения метода, например:
method CalculateSquareRoot(aValue: Double):Double;
require
aValue >= 0;
begin
// ...
// вычисляем квадратный корень
// ...
end;
При невыполнении условия в блоке require метод просто будет проигнорирован без генерации исключения.
Помимо этого можно определить условия, которые должны быть соблюдены по окончании работы метода:
method QuadrupleLinkedList.Add(aItem: Object);
begin
// ...
// добавляем элемент в список
// ...
ensure
Count = old Count+1;
Contains(aItem);
end;
В данном примере блок ensure указывает, что при выполнении метода должно быть гарантировано, что в списке станет на один элемент больше, чем было перед выполнением метода, и что в список будет добавлен именно тот элемент, который являлся параметром метода. Если условие в этом блоке не выполнено, возникшее исключение позволит разработчику понять, что, модифицируя код метода, он нарушил требования к нему.
Помимо пре- и постусловий для методов, возможно создание ограничений, налагаемых на класс в целом (такие ограничения называются инвариантами). Пример реализации инварианта приведен ниже:
type
LightStatus = (Red, Green);
TrafficLight = public class
public
method Switch;
// ...
property Cars: LightStatus ...;
property Pedestrians: LightStatus ...;
// ...
public invariants
not ((Cars = Green) and (Pedestrians = Green));
end;
В блоке public invariants указано условие, которое всегда должно выполняться, что бы ни происходило с данным классом и его экземлярами. Если какой-либо код в приложении приведет к невыполнению данного условия, будет сгенерировано исключение, сигнализирующее о том, что экземпляр класса находится в недопустимом состоянии.
Поддержка пространств имен
Пространства имен, являющиеся одной из основных концепций .NET Framework, позволяют сгруппировать классы в иерархической структуре согласно задачам, для решения которых они предназначены, и тем самым упростить их поиск. Естественно, в Chrome реализована поддержка пространств имен:
namespace RemObjects.Chrome.TestApp;
interface
type
MyClass = public class
// ...
end;
implementation
// ...
end.
Ссылки на пространства имен могут быть осуществлены следующими способами:
uses
System.IO,
System.Text,
System.Windows.Forms;
или:
uses
System.Xml.*;
Асинхронные методы и работа с потоками
Многие пользователи Delphi неоднократно сталкивались с написанием многопоточных приложений и, наверное, согласятся со мной, что это не самая простая задача. Написание многопоточных приложений с помощью C# или Visual Basic .NET также предполагает как минимум создание наследников классов пространства имен System.Threading.
Компилятор Chrome значительно упрощает работу с потоками, позволяя просто описать метод как выполняющийся в отдельном потоке с помощью ключевого слова async, например:
MyWinForm = public class
method Fetch(aURL: string); async; empty;
end;
//Асинхронный метод можно вызвать в любом классе
Fetch(‘www.remobjects.com’);
Из других средств упрощения работы с потоками отметим блок locking, позволяющий выполнять любой фрагмент кода как потокозащищенный, окружив его уникальной критической секцией.
locking self do begin
...
// выполняем код, не являющийся потокозащищенным
...
end;
Другие полезные мелочи
Chrome позволяет определить виртуальные свойства, не создавая при этом виртуальных методов для их считывания и записи:
type
TMyClass = class
...
property Width: integer read write; virtual; abstract;
end;
При создании свойства класса-наследника можно описывать как само свойство, так и методы для его чтения и записи. Аналогичные принципы применяются также к интерфейсам и событиям — последние могут быть виртуальными.
При необходимости, программируя с помощью Chrome, можно определять переменные непосредственно внутри блока кода:
method MainForm.OnClick(Sender: Object; ea: EventArgs);
begin
for i: integer := 0 to 1 do
MessageBox.Show(i.ToString);
end;
Создание и уничтожение объектов внутри блоков кода может быть осуществлено с помощью блока using:
using f := new FileStream(...) do begin
...
f.Write(...);
...
end;
В данном примере внутри блока кода создается переменная f, и по окончании его выполнения метод Dispose класса FileStream вызывается автоматически.
Отметим также наличие некоторых новшеств в конструкции сase, таких как использование в качестве параметра нецелых типов (например, строк):
case aClassID.ToUpper of
‘XYZ’: result := TMyXYZClass;
‘ABC’: result := TMyOtherClass;
else raise new Exception(‘Invalid Class ID’);
или выполнение разных фрагментов кода в зависимости от типа объекта, являющегося параметром:
case aClass type of
TMyXYZClass: TMyXYZClass(aClass).DoSomething;
TMyOtherClass: TMyOtherClass(aClass).DoSomethingElse;
else raise Exception.Create(‘Invalid Class Reference’);
end;
Из иных полезных мелочей отметим поддержку частичных классов .NET (partial classes), определение которых может находиться в нескольких файлах; наличие конструкции try…except…finally…end, позволяющей одновременно и обрабатывать исключения, и освобождать выделенные в блоке try ресурсы; возможность использования указателей внутри управляемого кода; средства сравнения типа 0 <= x < Count; единожды инициализируемые и в дальнейшем не изменяемые поля классов; операторы is not и not in; конструкцию loop.
Особенности компилятора
Поддержка создания Web-приложений
Компилятор Chrome позволяет создавать приложения ASP .NET 1.1, ASP .NET 2.0 и Mono XSP, в том числе использовать фрагменты кода Object Pascal непосредственно на Web-страницах, например:
<%@ Page language=”Chrome” %>
<% var x: DateTime := DateTime.Now; %>
Today is <%=x%>.
Поддержка различных версий CLR
Chrome поддерживает различные версии CLR, в частности .NET Framework 1.1 и 2.0, .NET Compact Framework, 64-разрядную версию .NET Framework, Mono Framework для Linux. На данный момент это единственный коммерческий компилятор Object Pascal для платформы Mono.
Редакции Chrome
Сhrome существует в виде нескольких редакций: бесплатный компилятор командной строки, Chrome for Visual Studio и Chrome for Mono. Отметим, что версия Chrome for Visual Studio поддерживает создание проектов для Mono непосредственно в среде Visual Studio .NET, позволяя создавать в коде ссылки на сборки Mono (рис. 1).
Рис. 1. Типы проектов, поддерживаемые Chrome
Среди других особенностей Chrome for Visual Studio — полная поддержка средств отладки, предоставляемых Visual Studio (рис. 2), использование таких средств редактирования и рефакторинга, как синхронное переименование классов и методов, наличие средств автоматического завершения кода и автоматического объявления переменных, полей и методов (рис. 3).
Рис. 2. Средства отладки в проектах Chrome
Рис. 3. Средства отладки в проектах Chrome
Отметим, что стоимость Crome for Visual Studio весьма демократична — 199 долл. за полную лицензию, 149 — за лицензию для пользователей Delphi, 49 — за академическую лицензию для школьников и студентов. При таких ценах приобретение этого продукта, с одной стороны, не представляет почти никакого финансового риска, а с другой — легко может окупиться буквально за несколько дней.
Вместо заключения
Итак, сегодня мы ознакомились с компилятором Chrome, обладающим рядом довольно интересных и полезных особенностей, облегчающих написание кода. В каких же случаях следует его применять?
Данный продукт может быть интересен компаниям — разработчикам ПО и отделам разработки, много лет имевшим дело с языками Object Pascal или Delphi и планирующим активное использование Visual Studio для создания новых проектов, не включающих унаследованный VCL-код, — в этом случае Chrome позволит применять имеющиеся знания и опыт написания кода на этом языке и не вкладывать средства в переобучение бывших пользователей Delphi другим языкам программирования. Помимо этого Chrome представляет немалый интерес для разработчиков многоплатформенных приложений, например приложений, предназначенных одновременно для выполнения на платформе Windows с применением .NET Framework и для выполнения на платформах Linux или Mac OS X с применением Mono.
Отметим, однако, что для переноса на платформу .NET унаследованных приложений, созданных с помощью Delphi или Kylix и использовавших библиотеку классов VCL, Chrome не слишком полезен — в его состав не входят библиотеки классов, совместимые с VCL. Решение подобных задач требует применения одной из последних версий Delphi, например Delphi 2006, обзор которой мы надеемся опубликовать в ближайшее время.