Основные отличия PascalABC.NET
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.
Пишите современный код!