Основные отличия PascalABC.NET

3dea2ae67fb2212840e823f2d38e6df2

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.

Пишите современный код!

© Habrahabr.ru