Гарантированно (то бишь, из коробки) нет проблем совместимости с бинарниками, созданными в Паскале под нынешнюю целевую версию .NET 4.0, только у тех, кто работает под Win8 и старше – у всех остальных из коробки – .NET 3.5 или еще старее, что уже требует сознательного апгрейда со стороны пользователя не только для компиляции, но и просто для запуска скомпилированных программ из этой среды.
Значит, большинство наших пользователей как-то справлялись с этой задачей, почему же сейчас выдвигается тезис о каких-то трудноразрешимых и непонятных простому смертному “ужасных ошибках”, если мы предложим им сначала проагрейдиться автоматом в процессе установки Паскаля (хотя бы первоначальной), а потом, со временем, переключимся на .NET 4.7 (когда по собранной нами же объективной статистике кол-во XP-шек упадет ниже какого-то предела, напр. < 5…10%).
Большинство пользователей справлялись с задачей, поскольку с 2010 года прошло 8 лет.
А с момента появления ValueTuple прошло меньше года - до такой степени, что текущая версия VS не видит кортежи.
И в первые Windows 10 как следует из таблицы автоматом 4.7 не ставилась.
Проблема Паскаля - именно в том, что он стандартную библиотеку подключает автоматом.
В C# такой проблемы нет. И всё равно пользователи мучаются. Вон, у нас студенты - дома есть кортежи, а в дисплейных классах нет.
Присваивать 1 переменную другой - по умолчанию не правильно. Нет реальных случаев где это надо. А вот если надо сделать такое возвращаемое значение - надо через var-параметр. И передавать в функции тоже, как var-параметры.
Странно, у меня наоборот этот код в релиз-варианте (и без IDE) показывает выигрыш по скорости только для ValueTuple – где-то в районе 20%, хотя из-под IDE получается почти поровну – всего 1-4%.
Tuples = 0.334
ValueTuples = 0.034
Ratio = 9.61
Имя ОС - Microsoft Windows 7 Максимальная
Версия - 6.1.7601 Service Pack 1 Сборка 7601
Тип - x64-based PC
Процессор - Intel(R) Core(TM)2 Duo CPU E8400 @ 3.00GHz, ядер: 2
Установленная оперативная память (RAM) - 8.00 ГБ
Ну сравнение туплов медленнее (оно реализовано с помощью Equals). ValueTuple сравниваются IL-командой ceq. А если написать без сравнений. то разницы нет никакой
uses
System.Diagnostics;
const
Cycles = 10000000;
type
MyTuple1 = System.Tuple<integer, real, char>;
MyTuple2 = System.ValueTuple<integer, real, char>;
function MyRandomTuple1: MyTuple1;
begin
Result := (Random(123), Random(123.45), ChrAnsi(Random(256)));
end;
function MyRandomTuple2: MyTuple2;
begin
Result := new MyTuple2(Random(123), Random(123.45), ChrAnsi(Random(256)));
end;
begin
Randomize;
var a1, b1: MyTuple1;
var sw1 := new Stopwatch;
sw1.Start;
loop Cycles do
begin
a1 := MyRandomTuple1;
b1 := a1;
//if a1 = b1 then;
end;
sw1.Stop;
Println('Tuples =', sw1.ElapsedMilliseconds / 1000);
var a2, b2: MyTuple2;
var sw2 := new Stopwatch;
sw2.Start;
loop Cycles do
begin
a2 := MyRandomTuple2;
b2 := a2;
//if a2 = b2 then;
end;
sw2.Stop;
Println('ValueTuples =', sw2.ElapsedMilliseconds / 1000);
Println($'Ratio = {sw1.ElapsedTicks/sw2.ElapsedTicks :f2}');
end
Я думаю, что как в любом деле, желающий аргументировать всегда найдет вымороченный пример или контрпример. Интерес представляет некое синтетическое понимание вопроса, а не частности, демонстрирующие как явное преимущество, так и полное отсутствие оного. Конечно, мое мнение ничего не решает, но пока я не пришел к выводу, полезное это дело или нет. Точнее не так: опционально иметь козыря в рукаве всегда полезно, но если тебе за это могут “накидать по щам”, нужно подумать, что перевесит.
Эта “размерщина”, как минимум, позволяет писать простые вещи просто и одновременно эффективно, не изобретая громоздких велосипедов на ровном месте. Разве это не преимущество?
Кроме того, в вырожденных случаях она дает возможность JIT-компилятору и/или процессору радикально оптимизировать процесс исполнения, сокращая его уже в десятки, а то и сотни раз.
Единственный серьезный аргумент против ValueTuple сейчас – отсутствие его поддержки в старых, но еще широко используемых версиях .NET и на XP.
P.S. Еще один недостаток текущей реализации ссылочных Tuples – их неизменность после создания (immutability), хотя, конечно, это зависит от контекста применения. Но если, напр., хранить в кортежах какие-то координаты, то может быть очень удобно изменять отдельные их элементы без пересоздания всего кортежа.
Думаю, моя реализация сравнения кортежей на равенство неэффективна.
function InternalEqual<T1, T2> (x: (T1,T2); y: (T1,T2)): boolean;
begin
var xn := Object.ReferenceEquals(x,nil);
var yn := Object.ReferenceEquals(y,nil);
if xn then
Result := yn
else if yn then
Result := xn
else Result := x.Equals(y);
end;