Замечания и предложения

Это не мешает особо, если компилировать в уме. :slight_smile:

В современном C# есть кортежи с именованными полями. Посмотрите, как у них сделано. Очень хорошая штука - просто руки не доходят.

3 лайка
            (int x, string s) t;
            t = (x: 0, s: "abc");

В паскале это выглядело бы как то так:

var t: (x: integer; s: string);
t := (x := 0, s := 'abc');

Однако создание экземпляра через список имён и значений уже есть с анонимными классами. Поэтому если дополнять их вместо создания новой фичи - должно быть на много проще реализовать. Если через них - как то так:

var t: class(x: integer; s: string);
t := new class(x := 0, s := 'abc');

Относительно предыдущего кода - в первой строчке добавилось только class, а во второй new class перед скобками.
При этом функционал второй строчки уже полностью реализован.

1 лайк

Вот только уживутся ли они с лямбдами, LINQ и автоприведением типа?

Полагаю, что возможно следующее использование этих фич:

  1. Кортежи - для примитивной группировки значений, скорее, для внутренних нужд.
  2. Анонимные классы (как показано выше) - для использования в интерфейсах модулей, библиотек, классов и записей, поскольку они позволят задавать имена свойств, несущих смысловую нагрузку.

Вы не передадите анонимные классы между dll.

1 лайк

А это и не надо. Анонимные классы, если добавить возможность описывать их тип - получат примерно ту же область применения что лямбды (то есть анонимные подпрограммы). А анонимность лямбд как раз заключается в том, что их видно и можно использовать только там, где они описаны. И нигде больше их существование не показывается.

Это позволяет реализовывать всякие мелкие кишки. Как в случае лямбд - делегаты, как те что передаются в методы Linq. Если заменить лямбду глобальной подпрограммой - добавится лишнее и неудобное имя.

Если надо класс который будет видно всюду - надо делать НЕ_анонимный, то есть обычный класс.
Ну а для класса с авто генерацией конструктора и прочих, муторных в реализации, удобств - есть автоклассы.

Ну то есть как это не надо?

Вот, пример приводили в этом топике.

Это не будет работать в dll при попытке определения через анонимный класс

2 лайка
  1. Почему не будет? Читать и записывать значения каждого элемента можно будет.

  2. Да совместимый тип нельзя будет сделать. Но я говорил что логически не правильно использовать анонимность публично. То есть можно и лямбду присвоить публичной переменной/полю, видимой вне библиотеки, но обычно это не более чем выстрел себе в ногу.

    Но - это правило общего случая, у него могут быть редкие исключения. К примеру лямбда может быть дефолтным значением какого то поля с типом делегата, которое можно изменять извне библиотеки.

  3. Вообще то можно между паскалевской библиотекой и паскалевской программой - сделать совместимость. Анонимные классы разворачиваются в типы с недопустимыми знаками в названии, поэтому их легко найти при чтении библиотеки.

  4. Пример который привёл @MrFresnel - это явно что то из паскалевского модуля который он сделал как прокладку между своей библиотекой и паскалем. Это понятно потому что оно написано на паскале. А значит тут это проблемы не будет.

Проблемы не будет если сделать это на базе кортежей.

Надо только выяснить, как обеспечивается совместимость кортежей с именованными полями в C# и есть ли она вообще.

1 лайк

Посредством применения специального атрибута, который задаёт их имена. Источник

1 лайк

Нет. Вы ошиблись. Это был просто абстрактный пример. В модуле моём такого нет. Это есть в библиотеке, но пока без применения именованных кортежей (пока в той части библиотеки рефакторинг не проводил). Реализация на анонимных классах - она проста. Но с точки зрения совместимости библиотеки и PascalABC.NET лучше реализация на кортежах. Однако, моя библиотека, поскольку она не стандартная и вряд ли ей когда нибудь станет (потому что в случае включения её как стандартную придётся тянуть ещё и модуль, точнее с этой точки зрения она не легковесная, а также потому что имеется пересекающийся функционал), не может быть сильным аргументом для того, чтобы разработчики только из-за неё делали подобную функциональность на кортежах.

type
   T = class
end;

function operator implicit(self: T): integer; extensionmethod := 0; // error here

begin
end.

При компиляции выдаёт:

Program1.pas(5) : extension-операторы преобразования типов допустимы только для классов из других сборок .NET

Данное ограничение запрещает определять extension операторы преобразования для массивов.

PABCSystem строчка 9413:

/// Возвращает индекс последнего минимального элемента
function LastIndexMin<T>(Self: array of T): integer; extensionmethod; where T: System.IComparable<T>;
begin
  Result := Self.LastIndexMin(Self.Count - 1);
end;  

.Count плохо применять к массивам. .Count воспринимает массив как yield последовательность и проходит по всем элементам перед тем как дать результат, в то время как .Length только читает внутреннее поле.

1 лайк

Приоритет оператора возведения в степень не указан в справке:

Исправили. Спасибо.

1 лайк

При сохранении нового документа перестало автоматически вставляться ProgramXXX в имя файла:

Как насчёт того, чтобы в стандартную библиотеку добавить метод расширения IsPrime для целых, который будет возвращать true, если число простое?

function IsPrime(self: integer): boolean; extensionmethod;
begin
  if self <= 1 then exit;
  var i := 2;
  while i * i <= self do
  begin
    if self mod i = 0 then exit;
    i += 1;
  end;
  Result := true;
end;

Добавлять нужно 2. Все простые числа кроме 2 нечётные. Работать будет медленно. Лучше использовать небольшую таблицу с уже вычисленными простыми числами. Более того все следующие делители должны быть простыми.

1 лайк

Это можно, но я не уверен стоит ли. Ну, сейчас сделаю.