PascalABC.NET имеет базовую совместимость с Turbo Pascal, что должно было позволить портировать старые программы с меньшим трудом. Однако, благодаря этому, сложилась тенденция, использовать PascalABC.NET только в стиле Turbo Pascal и игнорировать современные конструкции. Тут я хочу коротко изложить основные отличия и показать правильное использование этого диалекта.
Стандартные функции для ввода и вывода
Не самое важное отличие, однако это пригодится нам для дальнейшего сравнения.
В Turbo Pascal для ввода и вывода используются процедуры read[ln] и write[ln] соответственно.
var a, b: integer; begin write('a='); readln(a); write('b='); readln(b); writeln('сумма ', a, ' и ', b, ' равна ', a+b); end.
PascalABC.NET предлагает использовать для ввода функции с явным указанием типа данных. Они не просто меняют значение указанной переменной, а возвращают считаное значение.
write('a='); a:= ReadlnInteger;
Аналогичные функции есть для остальных типов (real, string, etc). Более того, эти функции могут выводить приглашение для ввода самостоятельно.
a:= ReadReal('a =');
Для вывода используется подпрограмма Print[ln], которая автоматически разделяет переданные параметры пробелами. Таким образом, можно убрать из команды вывода лишние пробелы.
В результате программа приобретает такой вид:
var a, b: integer; begin a:= ReadlnInteger('a ='); b:= ReadlnInteger('b ='); Println('сумма', a, 'и', b, 'равна', a+b); end.
Локальные переменные
В Turbo Pascal переменные объявляются перед основной программой или перед телом подпрограммы. Например для решения квадратного уравнения может потребоваться такой набор переменных
var a, b, c, d, x1, x2: real; // коэффициенты, дискриминант, корни count: integer; // кол-во найденных корней
В результате образуется нагромождение переменных с избыточной областью видимости. По коду сложно понять в какой момент начинает использоваться та или иная переменная. Сложно определить используется ли переменная только в основной программе или к ней обращаются и подпрограммы. Сложнее определить назначение этой переменной.
В PascalABC.NET переменные могут объявляться прямо в коде. Делать это нужно как можно ближе к месту первого использования переменной.
Посмотрим на примере программы, складывающей числа.
begin var a: integer; // объявляем a:= ReadlnInteger('a ='); // инициализируем var b: integer; b:= ReadlnInteger('b ='); Println('сумма', a, 'и', b, 'равна', a+b); end.
Объявление переменной можно совместить с инициализацией.
begin var a: integer:= ReadlnInteger('a ='); var b: integer:= ReadlnInteger('b ='); Println('сумма', a, 'и', b, 'равна', a+b); end.
Более того, компилятор понимает, что мы инициализируем переменную значением типа integer и тип можно не указывать явно. Работает автовыведение типов.
begin var a:= ReadlnInteger; // a: integer var b:= 24.5; // b: real Println('сумма', a, 'и', b, 'равна', a+b); end.
Всё это применимо и к циклу for
for var i:= 0 to 10 do ;
Динамические массивы
В Turbo Pascal используются статические массивы, основная проблема которых -- необходимость указывать размер массива ещё на этапе создания программы. В результате массивы зачастую создаются "с запасом". Вместо этого PascalABC.NET предлагает использовать динамические массивы.
begin var n:= ReadLnInteger('Введите размер массива:'); var arr: array of integer; arr:= new integer[n]; var arr2:= new integer[n]; // автовывод типа end.
Такие массивы индексируются с ноля.
Помимо стандартного заполнения массива по индексам существует ряд других методов.
begin var x:= 1; // заполнение известными значениями var arr:= |1, 10, 43, x|; // чтение 10 значений из консоли var arr2:= ReadArrInteger(10); end.
Свойства и расширения типов
Каждый стандартный тип данных имеет достаточно большое количество свойств и методов расширения. Это элементы, доступные по точечной нотации.
Пример для integer
begin var x:= 2; var f:= x.IsEven; // чётное ли число var f2:= x.Divs(4); // делится ли на 4 x.Print; // вывод в консоль end.
Пример для динамических массивов:
begin var arr:= |1, 31, 40, 4, 1|; arr.Sort; // сортировка var len:= arr.Length; // получение размера var max:= arr.Max; // получение максимального var count:= arr.CountOf(1); // кол-во указанного элемента end.
Многие из этих расширений для массивов относятся к LINQ, но это достаточно обширная тема.
Благодаря этому код на PascalABC.NET может выглядеть как цепочка методов. Например эта программа находит количество двоек в записи считанного числа
begin ReadlnInteger.ToString.CountOf('2').Print; end.
Кстати .Print[ln] можно использовать для всех базовых типов. Это особенно удобно в длинных выражениях.
Кортежи
Кортежи используются для хранение нескольких значений в одной переменной. Это может быть полезно, когда значения тесно связанны друг с другом. Например координаты точки.
begin var point: (integer, integer); point:= (1, 2); Print(point.Item1, point.Item2); end.
В стандартной библиотеке есть функции, считывающие из консоли несколько значений сразу и возвращающих кортеж
begin var point1:= ReadInteger2; print(point1.Item1, point1.Item2); var point2:= ReadReal2; Print(point2.Item1, point2.Item2); end.
Кортеж можно распаковать в отдельные переменные
begin var point:= (1, 4, 2); var x, y, z: integer; (x, y, z):= point; Print(y); // 4 end.
И наконец, объявление переменных можно совместить с распаковкой
begin var point:= (1, 4, 2); var (x, y, z):= point; Print(y); // 4 end.
Заключение
Актуальность статьи вызвана скорее недостатком проработанной информации по данному языку, чем сложностью материала.
Конечно я затронул лишь малую часть отличий языка. Однако я постарался передать основные идеологические моменты программирования на PascalABC.NET.
Пишите современный код!
