Здравствуйте, Sinix, Вы писали:
S>Угу. И "[In] char x" для интеропа ещё. Чтобы не скучно было. S>С вариантами особо не разгуляешься, т.к. нас походу ждут ещё и immutable types/variables (через два релиза, не раньше). S>Но могут и поменять, если получше in-а вариант предложат.
Ключевое слово const, как я понимаю, пало жертвой NIH-синдрома?
Since all regular instance methods of a struct can potentially mutate the instance or ref-expose this, an intermediate copy must be created, as already a case when receiver is a readonly field.
То есть сначала сделаем readonly ref потому что не хотим копировать большие структуры, а потом делаем копию структуры на каждый вызов метода. Ну если уж взяли из плюсов константные ссылки, то и константные методы тоже берите.
S>Не понимаю, зачем джиту создавать ссылку на массив, если ему предписано вернуть ссылку на элемент массива или поле. S>В том и смысл, что через ссылку можно принять/вернуть либо то, либо другое единым образом прямо в одном методе.
Всё равно не понимаю в чём проблема. Можно всё-таки пример когда пользователь будет получать что-то неожиданное?
Моя идея в том чтобы в C# вместо readonly ref появилась конструкция "readonly T x", которая для структур (и только для них), отдавала на откуп jit'у — делать вызов через ref (если структура большая), или как обычно — через копию на стеке. Допустим на примере операции Collection<T>.IndexOf(readonly T x) where T : struct
Для структур размером с регистр — jit будет создавать копию — совсем как сейчас. А для структур весом в килобайт — сам ставить на вызов ref, так как параметр readonly для пользователя ничего не поменяется, а перфоманс выиграет.
А так как сейчас сделала ms — у коллекции надо иметь два разных метода IndexOf(T x) и IndexOf(readonly ref T x), и добавляя в структуру пару полей — надо садиться и думать, подросла ли структура достаточно чтобы бежать по проекту и менять все потенциально узкие места на readonly ref вручную.
J>То есть сначала сделаем readonly ref потому что не хотим копировать большие структуры, а потом делаем копию структуры на каждый вызов метода. Ну если уж взяли из плюсов константные ссылки, то и константные методы тоже берите.
Чем больше они делают разных readonly тем сильнее впечатление что ни у кого из авторов нет бэкграунда в C++, зато есть в JavaScript, VB и прочих питонах Лучше бы начали с const методов, пусть даже самым тупым способом — поддержав аттрибут типа решарперовского [Pure]
Здравствуйте, koandrew, Вы писали:
K>Ключевое слово const, как я понимаю, пало жертвой NIH-синдрома?
const для compile-time expressions вроде надеются заюзать. Плюс, было бы странно одно и то же понятие (неизменяемое поле / переменную) двумя кейвордами называть.
Впрочем, если есть обоснование и примеры, можно попробовать им на гитхаб написать, могут и отреагировать.
Здравствуйте, hi_octane, Вы писали:
_>Моя идея в том чтобы в C# вместо readonly ref появилась конструкция "readonly T x", которая для структур (и только для них), отдавала на откуп jit'у — делать вызов через ref (если структура большая), или как обычно — через копию на стеке. Допустим на примере операции Collection<T>.IndexOf(readonly T x) where T : struct
Без потери совместимости с текущим fw, поломки интеропа и отказа от верификации il не выйдет.
_>>Моя идея в том чтобы в C# вместо readonly ref появилась конструкция "readonly T x", которая для структур (и только для них), отдавала на откуп jit'у — делать вызов через ref (если структура большая), или как обычно — через копию на стеке. Допустим на примере операции Collection<T>.IndexOf(readonly T x) where T : struct
S>Без потери совместимости с текущим fw, поломки интеропа и отказа от верификации il не выйдет.
откуда такие страсти? даже самая топорно-хачная реализация, которую (теоретически) можно наваять пользуясь исходниками рослина — компилятору достаточно для каждого вызова IndexOf(readonly T x) генерировать ещё одну функцию с именем типа "<rref>IndexOf(readonly ref T x)", для верификатора останется щасте чистого il где все вызываются без ref если программист прямо не сказал что хочет именно с ref, и останется только подхачить jit чтобы увидев что у функции есть второй вариант вызова и он актуален — вызывать именно его. Интеропа никто ничем не касается.
Здравствуйте, hi_octane, Вы писали:
S>>Не понимаю, зачем джиту создавать ссылку на массив, если ему предписано вернуть ссылку на элемент массива или поле. S>>В том и смысл, что через ссылку можно принять/вернуть либо то, либо другое единым образом прямо в одном методе.
_>Всё равно не понимаю в чём проблема. Можно всё-таки пример когда пользователь будет получать что-то неожиданное?
Неожиданно — это потерять контроль над возможностью явного указания передачи по ссылке. Если компилятор будет внезапно генерить передачу копии, то через readonly ref char не получится передать null terminated string.
_>Моя идея в том чтобы в C# вместо readonly ref появилась конструкция "readonly T x", которая для структур (и только для них), отдавала на откуп jit'у — делать вызов через ref (если структура большая), или как обычно — через копию на стеке. Допустим на примере операции Collection<T>.IndexOf(readonly T x) where T : struct _>Для структур размером с регистр — jit будет создавать копию — совсем как сейчас. А для структур весом в килобайт — сам ставить на вызов ref, так как параметр readonly для пользователя ничего не поменяется, а перфоманс выиграет. _>А так как сейчас сделала ms — у коллекции надо иметь два разных метода IndexOf(T x) и IndexOf(readonly ref T x), и добавляя в структуру пару полей — надо садиться и думать, подросла ли структура достаточно чтобы бежать по проекту и менять все потенциально узкие места на readonly ref вручную.
Да, я вроде понял. Так вот, когда мы не знаем, скопирована ли структура, переданная в параметре, мы не можем возвращать эту структуру по ссылке.
readonly ref int Min(readonly ref int a, readonly ref int b)
{
if (a < b) return ref a;
return ref b;
}
аналогичный метод с readonly T будет просто обязан всегда возвращать копию.
Здравствуйте, hi_octane, Вы писали:
S>>Без потери совместимости с текущим fw, поломки интеропа и отказа от верификации il не выйдет. _>откуда такие страсти?
Dynamic dispatch в любой форме — делегаты, интерфейсы, DLR и т.д. Тонна ограничений типа запрета на ref return вместе с async-методами. Implicit cast из ref T в ref readonly T и тыды.
Если сильно хочется — будут ref-like structs. Со всеми ограничениями ref T, угу.
S>аналогичный метод с readonly T будет просто обязан всегда возвращать копию.
Мне что-то кажется что копирований в любом случае будет <= чем их есть сейчас. Допустим у гипотетического компилятора есть функция на одних readonly:
readonly T Min(readonly T a, readonly T b)
{
if(a.CompareTo(b) <= 0)
return a;
else
return b;
}
Проверит компилятор что от входа до выхода аттрибут "ref" сохраняется, сделает и простую версию функции, и ещё одну с входными ref и с возвращаемым значением ref. А если что-то мешает (например return default(T)) — сделает версию у которой только один аргумент с ref, или только входные с ref а возвращаемое значение без ref. И там где надо функцию вызвать — остаётся просто выбрать самую быструю из доступных сигнатур.
S>Dynamic dispatch в любой форме — делегаты, интерфейсы, DLR и т.д. Тонна ограничений типа запрета на ref return вместе с async-методами. Implicit cast из ref T в ref readonly T и тыды. S>Если сильно хочется — будут ref-like structs. Со всеми ограничениями ref T, угу.
Это всё можно поддержать, но увы, тогда придётся иметь 3 способа записи — три как сейчас с T x/ref T x/readonly ref T x, четвёртый мой — readonly T x с компилятором способным генерить 3 оставшихся. Спасибо убедил, расхотелось реально сдаюсь, причём сползаю под стол от смеха представляя как этому будут учить будущих программистов в альтернативной вселенной с "ref C#"
С одной стороны все новые возможности C# относительно структур мне нравятся — часто работаю с кодом из которого надо скорость выжать, и лучше когда варианты есть, чем когда их нет. С другой, что-то есть ощущение что лет 15 назад, когда .NET появился, я считал что идея разделить типы на reference и value гениальна, особенно после Java. А сейчас после non-nullable references, возможного интереса к stackalloc operator for reference types, и всех этих ref return, кажется что авторы языка отчаянно превозмогают косяк 15-летней давности
Здравствуйте, hi_octane, Вы писали:
S>>Dynamic dispatch в любой форме — делегаты, интерфейсы, DLR и т.д. Тонна ограничений типа запрета на ref return вместе с async-методами. Implicit cast из ref T в ref readonly T и тыды. S>>Если сильно хочется — будут ref-like structs. Со всеми ограничениями ref T, угу. _>Это всё можно поддержать, но увы, тогда придётся иметь 3 способа записи — три как сейчас с T x/ref T x/readonly ref T x, четвёртый мой — readonly T x с компилятором способным генерить 3 оставшихся. Спасибо убедил, расхотелось реально сдаюсь, причём сползаю под стол от смеха представляя как этому будут учить будущих программистов в альтернативной вселенной с "ref C#"
Всё проще. Для тех структур, которые реально требуют передачи по ref, будет модификатор ref struct и обязательный in T в параметрах методов. ref T совместимы с readonly ref T, т.е. больше ничего не требуется.
_>С одной стороны все новые возможности C# относительно структур мне нравятся — часто работаю с кодом из которого надо скорость выжать, и лучше когда варианты есть, чем когда их нет.
Ты путаешь/смешиваешь возможность оптимизации со стороны рантайма (включая инлайн, девиртуализацию, stackalloc, auto ref etc) и поддержку со стороны языка фич, которые были заложены ещё в первом CLR.
Сейчас идёт планомерная работа по второму направлению, перфоманс — по остаточному принципу. Для полноценных оптимизаций надо нарушить очень много контрактов, предлагаемых штатной CLI — раз, перейти на AOT-компиляцию — два. Ну и иметь крупного потребителя внутри MS, который протолкнёт бюджет под все доработки — три. Последнего нет, так что пока имеем net native + зачаточный AOT в net core 2.
Здравствуйте, hi_octane, Вы писали:
_>Мне что-то кажется что копирований в любом случае будет <= чем их есть сейчас. Допустим у гипотетического компилятора есть функция на одних readonly:
для мелких методов типа Min() ref не нужен. Их JIT инлайнит.
Здравствуйте, hi_octane, Вы писали:
_>Мне что-то кажется что копирований в любом случае будет <= чем их есть сейчас. Допустим у гипотетического компилятора есть функция на одних readonly: _>
_>readonly T Min(readonly T a, readonly T b)
_>{
_> if(a.CompareTo(b) <= 0)
_> return a;
_> else
_> return b;
_>}
_>
_>Проверит компилятор что от входа до выхода аттрибут "ref" сохраняется, сделает и простую версию функции, и ещё одну с входными ref и с возвращаемым значением ref. А если что-то мешает (например return default(T)) — сделает версию у которой только один аргумент с ref, или только входные с ref а возвращаемое значение без ref. И там где надо функцию вызвать — остаётся просто выбрать самую быструю из доступных сигнатур.
Хорошо, давайте рассмотрим спецификацию гипотетического языка, чей гипотетический компилятор у нас есть. И вот такой вызывающий код
var array = new []{1, 2};
ref int min = Min(ref array[0], ref array[1]); // не уверен за синтаксис
array[0] = 100;
Console.WriteLine(min);
Каким что будет на выводе согласно спецификации в случае, когда компилятор будет использовать копии и когда он будет использовать ссылки??? Будет ли результат отличаться?
И если у нас T будет не int, а что-то реально тяжелое... Т.е. int — тут на самом деле X.
S>Хорошо, давайте рассмотрим спецификацию гипотетического языка, чей гипотетический компилятор у нас есть. И вот такой вызывающий код S>
S>var array = new []{1, 2};
S>ref int min = Min(ref array[0], ref array[1]); // не уверен за синтаксис
S>array[0] = 100;
S>Console.WriteLine(min);
S>
S>Каким что будет на выводе согласно спецификации в случае, когда компилятор будет использовать копии и когда он будет использовать ссылки??? Будет ли результат отличаться?
Так array тут типа T а не "readonly T". Получается компилятор встретив Min(array[0], array[1]) сможет только копирующий вызов сделать. Впрочем я уже сдался
Здравствуйте, hi_octane, Вы писали:
S>>Каким что будет на выводе согласно спецификации в случае, когда компилятор будет использовать копии и когда он будет использовать ссылки??? Будет ли результат отличаться?
_>Так array тут типа T а не "readonly T". Получается компилятор встретив Min(array[0], array[1]) сможет только копирующий вызов сделать. Впрочем
нене, readonly T — это гарантия о том, что вызываемый код не сможет изменить значение, переданное по ссылке. Т.е. если мы будем передавать по ссылке элементы массива, то Min не сможет их изменить, даже получив ссылку. Но смогла бы, если бы получила ref int.
_>я уже сдался
, уже лучше иметь три способа дать структуру на вход, чем гадать какой из них будет использован когда ты пишешь "более простой код"
Да, чем меньше неявных манипуляций с неоднозначным результатом, тем лучше.
Здравствуйте, hi_octane, Вы писали:
_>Чем больше они делают разных readonly тем сильнее впечатление что ни у кого из авторов нет бэкграунда в C++
А чем больше я смотрю на то как они пытаются сделать из C# непонятного утконоса типа С++, тем больше мне нравится Scala.
Здравствуйте, Sinix, Вы писали:
S>Сейчас идёт планомерная работа по второму направлению, перфоманс — по остаточному принципу.
Печально, что по остаточному. Ява с ее убогой архитектурой ушла далеко вперед. МС сдает позиции.
S>Для полноценных оптимизаций надо нарушить очень много контрактов,
Не очень много. И это сделать ключиком компиляции. Такие вещи как ковариантность для массивов или множественные делегаты на практике почти не используются. Я бы с удовольствием поправил бы места где они есть (если такие вообще есть) и получил бы более высокую производительность.
S>предлагаемых штатной CLI — раз, перейти на AOT-компиляцию — два.
Что значит перейти? А куда она девалась? NGEN никто не отменял. И вообще не ясно чем тут JIT мешает. У JIT-а даже больше возможностей для оптимизации. Разве что времени мало.
S>Ну и иметь крупного потребителя внутри MS, который протолкнёт бюджет под все доработки — три. Последнего нет, так что пока имеем net native + зачаточный AOT в net core 2.
Вот как надо МС нагнуть, чтобы он начал работать на внешнего потребителя?
Людей им туда нужно новых и креативных. То что надо было делать было известно еще 10 лет назад. Когда я все это говорил надо мной тут многие потешались. Сейчас это стало даже для МС очевидно. Но можно подождать еще 10 лет и просрать все в хлам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VD>Людей им туда нужно новых и креативных. То что надо было делать было известно еще 10 лет назад. Когда я все это говорил надо мной тут многие потешались. Сейчас это стало даже для МС очевидно. Но можно подождать еще 10 лет и просрать все в хлам.
Всё остальное комментировать не буду, только про "новых и креативных". Не работает оно так. Или старые спецы, которые думают, затем делают, или непрекращающиеся фейлы, которые не чинятся.
Если хочется поспорить — просто поработай пару недель с net core / связанными библиотеками. Вроде всё отлично, но вечно есть один нюанс...
Типа такого (релиз библиотеки ломает авторизацию в азуре прочих библиотек от ms), такого (dotnet command не умеет в target platform), такого(ef core второй год не может работать с default values — в базу заносится мусор. И да, это не баг) или такого (с мая поломан multitargeting в студии). Это только за неделю, и то не всё. За пару месяцев стабильно три-четыре десятка багов набегает.
Что характерно, в full fw подобных ляпов как не было, так и нет (три раза по дереву). Мистика