Ошибки компилятора PascalABC.Net

Нет, конечно, зачем мне хлам?))) FPC можете попробовать сами: выберите Pascal FPC (3.0.0)

Но по-моему там все же иной синтаксис.

Добрый день. Наткнулся под ALT Linux на ошибку, идентичную описанной в исходной ветке обсуждения. Что до mono-full vs mono-complete: в Альте последнего нет, как нет и libmono-system-numerics. Кто-нибудь побеждал подобное? Поделитесь, пожалуйста, рецептом.

Use the source, Luke!

begin
  var s: Set of Integer;
  Include(s, ReadInteger);
end.

Ошибка времени выполнения: System.InvalidProgramException: Среда выполнения Common Language Runtime обнаружила недопустимую программу.
Стек:
   в Program4.Program.$Main()
   в Program4.Program.Main()

Да, исправим.

Пока пишите

begin
  var s: Set of Integer;
  Include(s, ReadInteger());
end.

Спасибо

begin
  var s := 1.2-[2,3];//Ошибка: Операция 'dunmin' не применима к типам real и set of integer
end.

Что за dunmin? Так и должно писать?

Напишите в Issue

“Невозможно вывести типы-параметры generic-подпрограммы ReadElements (укажите типы-параметры явно)” Или может быть я неправильно пишу эту функцию?

begin
  var f1: file of integer;
  Rewrite(f1, 'a.dat');
  Write(f1, 1, 2, 3, 4, 5);
  f1.Close;
  ReadElements('a.dat').Println;//ошибка
end.

Ну, вам правильно пишет, надо указывать параметры шаблона явно:

function f1<T>: T := default(T);

begin
  var a := f1<byte>;
end.

Тут уже выдаёт другую ошибку. Проблема в том что компилятор думает что вы сравниваете указатель на функцию f1 и типа byte оператором <. А затем сравниваете результат с ничем. Поэтому пишет что ожидалось выражение вместо ; то есть то с чем можно сравнить.

В этом случае нужно экранировать первый <, то есть поставить перед ним & (этот знак под семёркой в англ раскладке). Тогда компилятор не сможет считать < оператором сравнения, и всё скомпилируется правильно.

1 лайк

Да, так работает ReadElements&<integer>('a.dat').Println;

begin
  loop 10 do
  begin
    var i: integer;
    writeln(i);
    i += 1;
  end;
end.

i обнуляется только в первой итерации цикла. @Admin, это ошибка?

В1 лекции повышение квалификации преподавателей об этом что-то есть https://youtu.be/U65-SebSaj4?t=5430

Там переменной присваивается сразу новое значение, поэтому обнуление и не нужно.

А почему должно обнуляться если память выделяется один раз, потом то что туда записалось то и остается. Наверное так.

Это внутренности реализации компилятора. Знание их не должно быть обязательным для программирования.

Рассмотрим попытку написать следующий код:

begin
  var i:=1;
  i.Println;
  begin
    var i:=2; // компилятор выдает ошибку
    i.Print;
    Inc(i);
    i.Println
  end;
  i.Println
end.

Ошибка следующая: Внутриблочные переменные не могут иметь те же имена, что и переменные из блока верхнего уровня

А почему, собственно? Создавая Паскаль, Н.Вирт оглядывался на языки Algol-60/68, в разработке которых он принимал участие. В языке Algol любой блок begin ... end наделялся правом управлять памятью описанных в нем объектов программы. Описали переменную - можете пользоваться. Из блока вышли - все, переменная исчезла. Не то, чтобы ее скушал какой-то сборщик мусора - она отдавалась на нужды программы и могла быть отдана под какой-то иной объект в следующем блоке. Другими словами, локализация переменных в блоке была действительно локализацией. Коллизии имен не возникало, потому что вне блока его переменные не были видны, а внутри блока локальное объявление имело приоритет. И вот это программистское счастье Н.Вирт порушил “одной левой”, потребовав все объекты программы описывать в специальном разделе. В Паскале Н.Вирта вся требуемая память выделялась компилятором разово и статически. Зато эффективно. но… неудобно. В Turbo Pascal попытались поизвращаться и создали кошмарный механизм работы с управляемой памятью. В Delphi это дело подправили и появились нормальные динамические массивы.

Я не знаю, чем руководствовались разработчики PascalАВС.NET реализовав возможность описывать переменные посредством var в любом месте программы, и не обеспечив локализацию описанных переменных в блоке. Может быть, эффективностью программы? В самом деле, если использовать механизм динамической памяти, строгая локализация потребует при каждом входе в блок выделять память, а при выходе - освобождать. Представим себе переменную, описанную внутри составного оператора во вложенном цикле… Конечно, это все так, фантазия. Разработчики, если сочтут нужным, расскажут как оно на самом деле было. Но факт остается фактом: в PascalАВС.NET память в программной единице выделяется один раз, невзирая на местонахождение var. И, если переменная не инициализирована, компилятор не делает никаких “телодвижений”. Сама среда .NET при выделении памяти всегда производит инициализацию. С этой позиции, я думаю, понятно поведение кода, который привел @Bronislav

Нет ну “почему?” - понятно. В IL коде нету внутри-блочных переменных, они всегда описываются в начале подпрограммы как в старых паскалях. Другое дело - надо всё же чётко решить:

@Admin это нормально или всё же должно быть исправлено? Возможно надо больше настаивать на том что переменные надо всегда инициализировать, потому что так:

begin
  loop 10 do
  begin
    var i: integer := 0;
    writeln(i);
    i += 1;
  end;
end.

Всё уже работает как ожидалось.

Зачем на этом настаивать специально? Любая переменная должна быть инициализирована перед первым обращением к ней - это основа какого угодно алгоритма. Если человеку вольно нарушать этот канон - ну, как говорится, “флаг ему в руки и трамвай навстречу” (не правда ли, я добрый?). Если он делает инициализацию явно - это уже стреляный воробей, а если полагается на особенности среды программирования, то это воробей желтоклювый, имеющий шанс после первого же выстрела стать воробьем дохлым.

В C# аналогично:

static void Main(string[] args)
        {
            int i;
            {
                int i;
            }
        }

Локальная переменная или параметр с именем “i” нельзя объявить в данной области, так как это имя используется во включающей локальной области для определения локальной переменной или параметра