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

type
  T = class
  end;
  
function operator+(var x, y: T); extensionmethod := default(T);
procedure operator+=(var x, y: T); extensionmethod := exit;

function operator-(var x, y: T); extensionmethod := default(T);
procedure operator-=(var x, y: T); extensionmethod := exit;

function operator*(var x, y: T); extensionmethod := default(T);
procedure operator*=(var x, y: T); extensionmethod := exit;

function operator/(var x, y: T); extensionmethod := default(T);
procedure operator/=(var x, y: T); extensionmethod := exit;

function operator mod(var x, y: T); extensionmethod := default(T);

function operator div(var x, y: T); extensionmethod := default(T);

function operator=(var x, y: T); extensionmethod := false;
function operator<>(var x, y: T); extensionmethod := false;

function operator<(var x, y: T); extensionmethod := false;
function operator<=(var x, y: T); extensionmethod := false;

function operator>(var x, y: T); extensionmethod := false;
function operator>=(var x, y: T); extensionmethod := false;

// Недопустимо использование var в первом параметре extension-метода
//function ExtensionA(var self, y: T); extensionmethod := default(T);
//procedure ExtensionB(var self, y: T); extensionmethod := exit;

begin
end.

Хотелось бы выяснить причину данного запрета (для себя). Код выше доказывает то, что в операторах расширения var параметры разрешены, в отличии от процедур и функций расширения.

У операторов это разрешено для += и т.п. А у extensionmethod - было бы видно, если бы вы правильно их написали:

//function ExtensionA(var self: T; y: T); extensionmethod := default(T);
//procedure ExtensionB(var self: T; y: T); extensionmethod := exit;

self := противоречит ООП. Хотя звучит это и для меня немного сомнительно…

Нет. Такое использование и не предполагалось. Предполагался, следующий код:

type
  T = record
    public X: integer;
  end;
  
procedure Change(var self: T); extensionmethod := self.X := 2;

begin
end.

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

1 лайк

self.X := 2;

Это оператор, а их присваивать можно только коротким процедурам

Но вот здесь всё-таки должно выводиться 2, а потому нужен var:

type
  T = record
    public X: integer;
  end;
  
procedure Change({var} self: T); extensionmethod := self.X := 2;

begin
  var v := new T;
  v.Change;
  v.X.Print;//0
end.

@Admin может неявно делать self - var-параметром, если у него размерный тип? Тогда extensionmethod-ы будут работать так же как просто методы в случае записей.

@MrFresnel как это в C# работает, кстати?

В C#:

  • параметры операторов могут иметь только модификатор: in.
  • параметр this методов расширения не может иметь модификаторов: ref, in и out. На остальные параметры, разумеется, ограничений не накладывается.

Вопрос был про реакцию метода расширения на структуру

Ы, кстати, я закомментировал тот запрет в SyntaxTreeVisitor и всё работает)))

Так что могу лишь повторить знаменитую фразу серёги: “В C# полно тупых запретов”))))

Мы можем продолжить тот, как Вы выразились, срач, если хотите. Но надо ли это Вам и мне? Нет, не думаю, да и форум засорять…

Я кинул эту цитату не для того, чтобы Вы намекали на продолжение срача.

И да, кстати, я так и не понял (мы так и не поняли), почему ты тогда так загорелся? Я всё лето думал и понять не мог…

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

Да, протестил сам короч, пока вы флудили.

using System;

namespace Test1
{
	struct t1
	{
		public int X;
	}
	
	static class Program
	{
		public static void p1(this t1 a)
		{
			a.X = 5;
		}
		
		public static void Main(string[] args)
		{
			t1 a;
			a.X = 3;
			a.p1();
			Console.WriteLine( a.X );
			Console.ReadLine();
		}
	}
}

Выводит 3.
При этом this не может быть использован с ref и out.

Повторю вопрос, @Admin:

Но, если пользователю не требуется var параметр? Предполагаю, что лучшим решением (с моей точки зрения, мнение разработчиков может быть отличным от моего) будет дать пользователю самому выбирать - ставить ли var или нет.

Все тесты были пройдены успешно, так что я сделал пулл:

Ну, я написал своё мнение. Можно разрешить многое. Но не стоит.

В вашем случае есть к счастью простая замена - внешний метод, принимающий ссылку.

В этой ситуации никто не вводит второе решение с кучей неочевидных ограничений, неочевидностей и потенциальных багов.

Попытка номер 2:

Теперь ссылочные типы нельзя использовать в var self методах расширения.

begin
  var hs: HashSet<string>;
  var s: string;
  writeln(hs = s);
end.

Вместо человеко-читаемой ошибки
Операция '=' не применима к типам HashSet<string> и string
Выдаёт:
Нет перегруженной подпрограммы с такими типами параметров

Почему? Это ошибка компилятора?

Нет. Это перегруженная подпрограмма. Компилятор не различает операции и методы. Для него это всё подпрограммы. Перегруженные для разных типов. Когда вы определяете =, вы перегружаете эту операцию

Может, тогда подправить текст предупреждения на следующий: Нет перегруженной подпрограммы или операции с такими типами параметров? Ваше мнение?

Да, может. @Sun_Serega - бросьте в Issue - сейчас совсем нет времени смотреть