Object Pascal
Из Википедии, бесплатной энциклопедии
Object Pascal | |
---|---|
Класс языка | объектно-ориентированный, мультипарадигмальный, императивный, структурный язык программирования[вд] и язык программирования |
Тип исполнения | компилируемый |
Появился в | 1986 |
Разработчик | Ларри Теслер и Никлаус Вирт |
Расширение файлов | .p , .pp или .pas |
Система типов | статическая, динамическая (array of const, RTTI, Variant), строгая |
Основные реализации | Delphi (x86 and CLI), Oxygene (CLI), Free Pascal (x86, x86-64, PowerPC, ppc64, SPARC and ARM), Virtual Pascal (x86), TMT Pascal (x86), Turbo51 (Intel 8051) |
Диалекты | Apple, Turbo Pascal, objfpc, Delphi, Delphi.NET, Oxygene |
Испытал влияние | Паскаль и Smalltalk |
Повлиял на | C#, Java, Nim |
![]() |
Object Pascal (с англ. — «Объектный Паскаль») — язык программирования, разработанный в фирме Apple Computer в 1986 году группой Ларри Теслера, который консультировался с Никлаусом Виртом[1]. Произошёл от более ранней объектно-ориентированной версии Паскаль[2], называвшейся Clascal, который был доступен на компьютере Apple Lisa.
Изменения в Object Pascal от Borland в сравнении с Turbo Pascal
[править | править код]Изменения коснулись групп целых, символьных и строковых типов, которые стали разделяться на две категории:
- Фундаментальные (fundamental) типы. Их представление в памяти (число битов и наличие знака) строго фиксируется и выдерживается неизменным во всех последующих реализациях Object Pascal для любых операционных систем и компьютерных платформ.
- Родовые (generic) типы. Их представление в памяти не фиксируется и будет реализовано оптимальным способом, в зависимости от реализации для конкретной операционной системы и компьютерной платформы.
Интерфейсы
[править | править код]Перегрузка процедур и функций (не ООП)
[править | править код]Введена перегрузка процедур и функций, не являющихся членами объекта или класса. Перегружаются (с помощью ключевого слова overload) отличающиеся типами и числом параметров процедуры и функции:
procedure Calc(I: Integer); overload; // ... procedure Calc(S: String; J: Integer); overload;
Динамический массив
[править | править код]Введён для устранения рутинных операций выделения и возвращения памяти в heap-область (кучу), и для того, чтобы избежать случайных ошибок и утечки памяти. Элементы массива должны быть одинаковыми по типу. Нумерация элементов начинается с нуля.
Пример объявления:
var MyFlexibleArray: array of Real;
Использование:
var A, B: array of Integer; begin SetLength(A, 1); //Выделяем память под один элемент A[0] := 1; B := A; B[0] := 2; end;
Начиная с Delphi XE7 стали возможны следующие действия с динамическими массивами:
var M: array of integer; begin M := [1, 2, 3, 4, 5]; end; M := M + [5, 6, 7]; Insert([6, 7, 8], M, 5); // вставка массива [6, 7, 8], в M, начиная с индекса 5 Delete(M, 1, 3); // удаляем 3 элемента, начиная с индекса 1 Concat([1, 2, 3, 4], [5, 6, 7])
То есть с динамическими массивами можно работать так же, как со строками.
В динамическом массиве также возможно задание открытого массива параметров, но тип их должен быть объявлен ранее, например:
type TDynamicCharArray = array of Char; function Find(A: TDynamicCharArray): Integer;
Динамическая типизация
[править | править код]Операторы динамической проверки и приведения типов
[править | править код]В языке Object Pascal фирмы Borland появилась динамическая типизация, а также оператор динамического приведения типов as и оператор is для динамической проверки типов. Также в открытом массиве параметров стала возможна передача параметров различного типа (variant open array parameters).
Вариантный тип
[править | править код]В языке Object Pascal был введён вариантный тип данных (Variant), тип которых не известен на этапе компиляции и может изменяться на этапе выполнения программы. Однако этот тип данных поглощает больше памяти по сравнению с соответствующими переменными и операции над данными типа Variant выполняются медленнее. Более того, недопустимые операции над данными этого типа чаще приводят к ошибкам на этапе выполнения программы, в то время как подобные ошибки над данными другого типа были бы выявлены ещё на этапе компиляции.
Вариантные переменные могут принимать различные значения (целые, строковые, булевские, Currency, OLE-строки), быть массивами элементов этих же типов и массивом значений вариантного типа, а также содержать COM и CORBA объекты, чьи методы и свойства могут быть доступны посредством этого типа. Однако Variant не может содержать:
- данные структурных типов;
- указатели;
- Int64 (начиная с Delphi 6 — может).
Variant можно смешивать (в выражениях и операторах) с другими вариантами, числовыми, строковыми и булевскими данными. При этом компилятор автоматически выполняет преобразование типа. Варианты, содержащие строки, не могут, однако, индексироваться (V[i] не допустимо).
var V1, V2, V3, V4, V5: Variant; I: Integer; D: Double; S: String; begin V1 := 1; //значение типа integer V2 := 359.768; //значение типа real V3 := 'Hello world!'; //значение типа string end;
Параметры типа вариантного открытого массива
[править | править код]Стала возможна передача параметров различного типа. В оригинале он назван как «variant open array parameters». Тип данных определяется динамически в процессе выполнения программы. Так же как и в обычном открытом массиве функция High вызывается для определения числа элементов массива. Для объявления используются ключевые слова array of const. Пример:
function Output(const Args: array of const): string; var I: Integer; begin Result := ''; for I := 0 to High(Args) do with Args[I] do case VType of vtString: Result := Result + VString^; vtPChar: Result := Result + VPChar; vtInteger: Result := Result + IntToStr(VInteger); vtBoolean: Result := Result + BoolToStr(VBoolean); vtChar: Result := Result + VChar; vtExtended: Result := Result + FloatToStr(VExtended^); vtObject: Result := Result + VObject.ClassName; vtClass: Result := Result + VClass.ClassName; vtVariant: Result := Result + string(VVariant^); vtInt64: Result := Result + IntToStr(VInt64^); vtAnsiString: Result := Result + string(VAnsiString); vtCurrency: Result := Result + CurrToStr(VCurrency^); end; Result := Result + ' '; end; //... Output(['test', 777, '@', True, 3.14159, TForm]); //передача открытого массива параметров
Будет возвращена строка: «test 777 @ T 3.14159 TForm».
Как видно, имеет свою внутреннюю структуру, обращение к которой даёт возможность определить тип данных. В строке вызова функции создаётся массив, с помощью конструктора открытого массива, который использует квадратные скобки.
Различия в объектных моделях
[править | править код]Для введения новой объектной модели введено ключевое слово class (в Turbo Pascal ключевое слово object).
Введены операторы для проверки и приведения классов is и as динамически в ходе выполнения программы. Появились указатели на методы, для чего введено новое использование ключевого слова object:
type TMyMethod = procedure (Sender : Object) of object;
Изменения синтаксиса, из-за изменения размещения объектов
[править | править код]В Turbo Pascal можно было работать как с динамическими, так и со статическими экземплярами объектов.
В объектной модели Object Pascal программист работает только с динамическими экземплярами классов, выделяемых в heap-области (куче). В связи с этим изменён синтаксис обращения к полям и методам объектов.
Ранее для работы с динамическими экземплярами объектов, инициализированными с использованием обращения к конструктору в сочетании с функцией New, необходимо было использовать обращение по указателю (^). Теперь тип класса стал являться по умолчанию также указателем.
Пример для сравнения:
Объектная модель в Turbo Pascal:
type PMyObject = ^TMyObject; TMyObject = object (TObject) MyField : PMyType; constructor Init; end; //... var MyObject : PMyObject; begin MyObject := New(PMyObject,Init); MyObject^.MyField := //... end;
Новая объектная модель в Object Pascal:
type TMyObject = class (TObject) MyField : TMyType; constructor Create; end; //... var MyObject : TMyObject; begin MyObject := TMyObject.Create; MyObject.MyField := //... end;
Было изменено соглашение об именовании конструкторов и деструкторов. В старой объектной модели вызов New отвечал за распределение памяти, а обращение к конструктору инициализировало выделенную область памяти. В новой модели эти действия выполняет конструктор Create. Начиная с версии Delphi XE появились статические методы класса.[3]
Появилась возможность ограничивать видимость членов класса (методы, свойства), которые предназначены для использования только в реализации производных классов. Это даёт возможность защищать исходный код от модификации пользователями класса. Такие методы содержатся в секции protected (защищённые) в объявлении класса.
Визуальное объектно-ориентированное программирование
[править | править код]Появились понятия свойства (property) и связанные со свойствами ключевые слова read, write, stored, default (nodefault), index. Свойства визуальных объектов, видимых в интегрированной среде разработки, объявляются с помощью нового слова published в качестве секции в объявлении класса, являющегося визуальным объектом.
type {объявление} generic TList<T> = class Items: array of T; procedure Add(Value: T); end; implementation {реализация} procedure TList.Add(Value: T); begin SetLength(Items, Length(Items) + 1); Items[Length(Items) - 1] := Value; end;
Общий класс может быть просто специализирован для конкретного типа с использованием ключевого слова specialize:
type TIntegerList = specialize TList<Integer>; TPointerList = specialize TList<Pointer>; TStringList = specialize TList<string>;
Разработчики TMT Pascal (модификация Object Pascal) первыми ввели полноценную перегрузку операторов, что впоследствии было перенято разработчиками других диалектов языка: Delphi (с Delphi 2005), Free Pascal и др.
Пример:
{объявление} type TVector = packed record A, B, C: Double; procedure From(const A, B, C: Double); class operator Add(const Left, Right: TVector): TVector; class operator Implicit(const v: TVector): TPoint; end; {реализация} implementation //... class operator TVector.Add(const Left, Right: TVector): TVector; begin Result.A := Left.A + Right.A; Result.B := Left.B + Right.B; Result.C := Left.C + Right.C; end; class operator TVector.Implicit(const v: TVector): TPoint; begin Result.A := round(v.A); Result.B := round(v.B); end; //... {использование} var v1, v2: TVector; begin v1.From(20, 70, 0); v2.From(15, 40, 4); Canvas.Polygon([v1, v2, v1 + v2]); end;
Поддержка различными разработчиками
[править | править код]Начиная с версии среды Delphi 7, фирма Borland стала официально называть язык Object Pascal как Delphi[4].
Язык Object Pascal поддерживается и развивается другими разработчиками. Наиболее серьёзные реализации Object Pascal (помимо Delphi) — это кроссплатформенный TopSpeed Pascal (версия языка Turbo Pascal[5]) мультиязыковой среды TopSpeed, TMT Pascal, Virtual Pascal, PascalABC.NET, Free Pascal, GNU Pascal. Язык программирования Oxygene является диалектом Object Pascal для платформы .NET и дальнейшим его развитием, а новыми возможностями языка является оператор ":", асинхронный и отложенный вызовы методов, асинхронное выполнение блока кода, параллельные циклы, анонимные конструкторы, элементы контрактного и аспектно-ориентированного программирования и др.[6] (компилятор распространяется без ограничений).
Примеры «Hello, world!» в различных объектных расширениях языка
[править | править код]program ObjectPascalExample; type THelloWorld = object procedure Put; end; var HelloWorld: THelloWorld; procedure THelloWorld.Put; begin WriteLn('Hello, World!'); end; begin New(HelloWorld); HelloWorld.Put; Dispose(HelloWorld); end.
Delphi (для обеспечения обратной совместимости) и Free Pascal также поддерживают этот вариант синтаксиса.
program ObjectPascalExample; type PHelloWorld = ^THelloWorld; THelloWorld = object procedure Put; end; var HelloWorld: PHelloWorld; { это указатель на THelloWorld } procedure THelloWorld.Put; begin WriteLn('Hello, World!'); end; begin New(HelloWorld); HelloWorld^.Put; Dispose(HelloWorld); end.
В Free Pascal этот вариант синтаксиса доступен в режимах ObjFpc и Delphi.[7]
program ObjectPascalExample; type THelloWorld = class { определение класса } procedure Put; end; procedure THelloWorld.Put; { описание процедуры метода Put класса THelloWorld } begin Writeln('Hello, World!'); end; var HelloWorld: THelloWorld; { определение переменной-указателя на экземпляр класса } begin HelloWorld := THelloWorld.Create; { конструктор возвращает значение указателя на экземпляр класса } HelloWorld.Put; HelloWorld.Free; { деструктор уничтожает экземпляр класса и освобождает область памяти } end.
Примечания
[править | править код]- ↑ Tesler, Larry (1985). Object Pascal Report. Structured Language World. 9 (3): 10–7.
- ↑ Буч Г. Объектно-ориентированное проектирование с примерами применения К.: Диалектика; М.: Конкорд, 1992. — 519 с.
- ↑ Преимущества перехода на Delphi XE Что нового по сравнению с Delphi 7 Андреано Лануш (Andreano Lanusse) Архивная копия от 15 июня 2016 на Wayback Machine,Ноябрь 2010 г. Embarcadero Technologies Россия, СНГ
- ↑ Delphi Language Overview (недоступная ссылка)
- ↑ TopSpeed-компиляторы: не дожили до триумфа Архивировано 11 января 2012 года.
- ↑ Remobjects Oxygene . Дата обращения: 16 ноября 2015. Архивировано из оригинала 17 ноября 2015 года.
- ↑ Michaël Van Canneyt. Chapter 6: Classes (англ.). Free Pascal : Reference guide. (декабрь 2011). Дата обращения: 16 января 2012. Архивировано из оригинала 2 февраля 2012 года.