Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, artelk, Вы писали:
A>>Но представь такой случай: ты используешь рекорд Foo, определенный в некоторой библиотеке. Чтобы узнать, изменяемы ли его поля или нет, тебе нужно лезть в сорцы этой библиотеки, т.к. по public contract этого не видно. Даже если в текущей версии библиотеки он неизменяем, ничто не мешает в следующей ее версии сделать некоторые поля рекорда изменяемыми.
НС>И при чем тут рекорды? Ровно то же ты можешь получить и с классами.
Вот именно, рекорды это просто классы с автогенерированным кодом. Для пользователя рекорда неважно, сгенерирован ли его код или написан вручную. А хотелось бы, чтоб у рекордов была еще какая-то семантика относительно пользователя рекорда.
A>> А все потому, что (не)изменяемость рекорда это деталь его реализации,
НС>Нет. Это деталь его публичного контракта.
A>> никак не выраженная в его контракте.
НС>Здрасте, приехали. Наличие set вместо init это контракт и есть.
Ок, отчасти убедил, изменяемость можно выразить
С неизменяемостью недоработка.
Хотелось бы, например, вот чего: после того как автор рекорда поменял init на set, при компиляции моего кода компилятор бы сказал "эй, мы тут закладывались на неизменяемость, но теперь она не гарантируется".
А лучше бы вообще запретили set.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, AlexRK, Вы писали: ARK>>А какой профит от того, что мутабельность оставили? НС>В том что сахар будет доступен и там, где дизайн изначально мутабельный. К примеру, не все десериализаторы умеют десериализовать в конструктор, к примеру тот же ConfigurationBinder.
На сколько понимаю, init — это compiletime сущность, для рантайма он работает как обычный set, нет?
Десериализаторы используют рефлексию, они и не заметят, что там init вместо set.
Здравствуйте, artelk, Вы писали:
НС>>И при чем тут рекорды? Ровно то же ты можешь получить и с классами. A>Вот именно, рекорды это просто классы с автогенерированным кодом.
Конечно. Разве кто то обещал больше?
A> А хотелось бы, чтоб у рекордов была еще какая-то семантика относительно пользователя рекорда.
Хотелки подкреплены реальными кейсами?
A>Хотелось бы, например, вот чего: после того как автор рекорда поменял init на set, при компиляции моего кода компилятор бы сказал "эй, мы тут закладывались на неизменяемость, но теперь она не гарантируется".
Это отдельный большой вопрос, не имеющий никакого отношения к рекордам.
A>А лучше бы вообще запретили set.
Здравствуйте, AlexRK, Вы писали:
ARK>Индус Вася добавил set в общий рекорд для того, чтобы ему в своем кусочке кода было удобнее. ARK>Смотрит — вроде все работает. ARK>Да, да, я знаю, что такого быть не может, и что вся функциональность, внешняя и внутренняя, всегда на 100% покрыта всеми возможными тестами.
Индус Вася заменил рекорд на класс, потому что AlexRK запретил set в рекордах.
Да, да, я знаю, такого быть не может, потому что Вася такой специальный хитрый индус, который set воткнуть в чужом коде и пройти с таким патчем ревью может, а заменить record на class уже нет.
P.S. Если в твоем проекте куча индусов, плохое покрытие тестами и нет никакого codereview, то ты можешь буквально за пару часиков написать свой простенький анализатор, который таки запретит set в рекордах.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, Serginio1, Вы писали:
НС>>>В мутабельность нет нужды по другой причине. S>>По какой?
НС>По той что анонимные типы были придуманы для конкретной задачи ad-hoc типов в запросах, и там мутабельность ен нужна.
Ну анонимные типы используются не только в запросах.
Например для для сериализации в Json и прочего.
И очень похожи на рекорды
var user = new { Name = "Tom", Age = 34 };
В общем то согласен, что и для рекордов не нужно делать мутабельные поля.
Для большинства задач эта мутабельность и не нужна.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, artelk, Вы писали:
A>>На сколько понимаю, init — это compiletime сущность, для рантайма он работает как обычный set, нет? НС>Нет. init добавляет модификатор readonly на backing field
А мог бы и не добавлять, например.
A>>Десериализаторы используют рефлексию, они и не заметят, что там init вместо set. НС>Нормальные десериализаторы используют кодогенерацию и она совершенно точно обломается на readonly полях.
Т.е. когда в язык вводили init-only свойства вопрос "а как же десериализаторы" отметался, а когда вводили рекорды он вдруг стал актуальным, так что-ли?
Напомню: обе фичи добавляются в язык одновременно.
Если уж начали делать кодогенерацию, то проблему десериализаторов (и более общую) могли бы, например, решить классическим образом: сгенерировать вложенный класс Builder, в котором все свойства имеют сеттер. Десериализацию будет нужно делать в него и потом из него получать инстанс рекорда. Популярные десериализаторы уже в следующих версиях позволят пропускать этот шаг.
Другой вариант: не ставить readonly на backing field.
П.С. Кстати, на сколько помню SRE игнорирует readonly на полях (не проверял на новых версиях .Net.)
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, artelk, Вы писали:
НС>>>И при чем тут рекорды? Ровно то же ты можешь получить и с классами. A>>Вот именно, рекорды это просто классы с автогенерированным кодом. НС>Конечно. Разве кто то обещал больше?
Хотелось бы, раз уж вводят новую сущность в язык.
A>> А хотелось бы, чтоб у рекордов была еще какая-то семантика относительно пользователя рекорда. НС>Хотелки подкреплены реальными кейсами?
Да, и ты их знаешь.
A>>Хотелось бы, например, вот чего: после того как автор рекорда поменял init на set, при компиляции моего кода компилятор бы сказал "эй, мы тут закладывались на неизменяемость, но теперь она не гарантируется". НС>Это отдельный большой вопрос, не имеющий никакого отношения к рекордам.
Этот большой вопрос можно было бы элементарно решить. При этом у рекордов появился бы своя семантика и вопрос "нафига вводить новое понятие в язык" имел бы ответ.
A>>А лучше бы вообще запретили set. НС>Лыко-мочало ...
Foo bar...
Здравствуйте, AlexRK, Вы писали:
ARK>>>Было бы четкое разделение НС>>В чем профит?
ARK>Снижение когнитивной нагрузки. Видишь рекорд — все, ты сразу знаешь, что наломать с ним дров нельзя. Индус Вася не сможет туда завтра добавить мутабельное поле и у тебя где-то в глубине не сломается хеш-таблица, как в примере выше. Меньше обращаешь внимания на это.
В этом плане, еще более скользкая конструкция — "in" параметры. В этом примере, если написали "in", чтобы сэкономить на одном клонировании структуры(а больше и незачем его использовать), то вместо этого получаем 1 млрд клонирований.
Достаточно не заметить readonly. Или кто-то удалит readonly, то потом уже этот баг никогда не найдут.
Назвали это "защитная копия"... Тут должна быть строго ошибка компилятора(ну хотя бы warning), т.к. если создаются "защитные копии", то in вообще уже не нужен — без него хоть будет только одно клонирование.
А лучше бы — компилятор создавал только одну защитную копию, оно будет работать как — неявно убрали "in", если есть доступ к не readonly property.
Из-за этого хочется вообще никогда не использовать "in". Лучше "ref" — он не накосячит с защитными копиями.
struct S
{
public S(int i) { Prop = i; }
public/*readonly*/int Prop { get; }
}
static int Func(in S p)
{
int sum = 0;
for (int i = 0; i < 1000_000_000; i++)
sum = p.Prop;
return sum;
}
S_S>struct S
S_S>{
S_S> public S(int i) { Prop = i; }
S_S> public/*readonly*/int Prop { get; }
S_S>}
S_S>static int Func(in S p)
S_S>{
S_S> int sum = 0;
S_S> for (int i = 0; i < 1000_000_000; i++)
S_S> sum = p.Prop;
S_S> return sum;
S_S>}
S_S>
На заметку, в твоем примере, что с readonly что без, не будет никакого клонирования, так как автосвойство и так получает такой модификатор
Здравствуйте, Qbit86, Вы писали:
S>>Копец, как это вслух-то читать? S>>Не произносить же кажный раз "null-coalescing assignment operator"...
Q>Я бы читал: «Элвис-присваивание».
Здравствуйте, AlexRK, Вы писали:
ARK>Индус Вася добавил set в общий рекорд для того, чтобы ему в своем кусочке кода было удобнее. ARK>Смотрит — вроде все работает. ARK>Да, да, я знаю, что такого быть не может, и что вся функциональность, внешняя и внутренняя, всегда на 100% покрыта всеми возможными тестами.
Как уже было справедливо замечено, этот ваш Вася наломает дров в проекте безо всяких рекордов. Что ему помешает заменить record на class?
Более того — с таким подходом к решению проблем он у вас запросто поменяет значение строки через reflection, и взорвётся вообще нахрен всё.
Задача языка, по большому счёту, это проектировать pit of success — чтобы написание хорошего кода было комфортным.
Сделать нормальную иммутабельность на классах — это закат солнца вручную, и большое количество boilerplate, в котором не очень легко отловить ошибку.
Сделать нормальную иммутабельность на рекордах — очень легко. Делать рекорды mutable требует прямо таки сознательного усилия и дополнительного кода — то есть хороший код писать проще, чем плохой.
Пока что всё, что я бы улучшил (если это ещё не сделано) — это добавил compiler warning для свойств с сеттерами.
ARK>В тех полутора местах, где такое нужно, можно просто использовать обычный класс.
Это как раз бы означало, что мелкое изменение сразу требует от меня написать в разы больше кода. Кривая инвестиций должна быть пологой, а не так, что "вот у вас автоматика в одну строку, а если не нравится один байт — переписывайте в 1500 строк".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S_S>>struct S
S_S>>{
S_S>> public S(int i) { Prop = i; }
S_S>> public/*readonly*/int Prop { get; }
S_S>>}
S_S>>static int Func(in S p)
S_S>>{
S_S>> int sum = 0;
S_S>> for (int i = 0; i < 1000_000_000; i++)
S_S>> sum = p.Prop;
S_S>> return sum;
S_S>>}
S_S>>
R>На заметку, в твоем примере, что с readonly что без, не будет никакого клонирования, так как автосвойство и так получает такой модификатор
вот это и есть ужос:
1) Почему тогда у меня одинаково тормозят для "in" варианты и с автосвойствами и ручными.
2) Если у тебя C# 8, и по другому работает. А у меня C# 7.3, так работает (readonly только на struct можно ставить). В любом случае так не должно быть — ненадежная фича.
3) Понятно, что ничего не упадет. Но "in" ввели для экономии на клонированиях. Если вместо этого в 1 млрд больше клонирований, то это уже можно считать багом.
Здравствуйте, artelk, Вы писали:
A>>>На сколько понимаю, init — это compiletime сущность, для рантайма он работает как обычный set, нет? НС>>Нет. init добавляет модификатор readonly на backing field A>А мог бы и не добавлять, например.
Но он добавляет. К чему ты это написал?
A>>>Десериализаторы используют рефлексию, они и не заметят, что там init вместо set. НС>>Нормальные десериализаторы используют кодогенерацию и она совершенно точно обломается на readonly полях. A>Т.е. когда в язык вводили init-only свойства вопрос "а как же десериализаторы" отметался, а когда вводили рекорды он вдруг стал актуальным, так что-ли?
Ничего не понял. Какое отношение к добавлению этой механики имеет наличие возможности делать set поля в рекордах?
A>Напомню: обе фичи добавляются в язык одновременно.
И?
A>Если уж начали делать кодогенерацию, то проблему десериализаторов (и более общую) могли бы, например, решить классическим образом: сгенерировать вложенный класс Builder, в котором все свойства имеют сеттер. Десериализацию будет нужно делать в него и потом из него получать инстанс рекорда.
И все ради того что кому то не понравилась возможность сделать мутабельным рекорды?
A>Другой вариант: не ставить readonly на backing field.
Ну пипец просто. Ради того чтобы не дать сделать мутабельность надо добавить возможность мутабельности любым свойствам безусловно. Абсурд на марше.
Здравствуйте, artelk, Вы писали:
A>>>Вот именно, рекорды это просто классы с автогенерированным кодом. НС>>Конечно. Разве кто то обещал больше? A>Хотелось бы, раз уж вводят новую сущность в язык.
Это отдельный вопрос. Зачем его к рекордам цеплять и делать тем самым убогим — непонятно.
A>>> А хотелось бы, чтоб у рекордов была еще какая-то семантика относительно пользователя рекорда. НС>>Хотелки подкреплены реальными кейсами? A>Да, и ты их знаешь.
Пока что ничего убедительного в этом топике я не увидел.
A>>>Хотелось бы, например, вот чего: после того как автор рекорда поменял init на set, при компиляции моего кода компилятор бы сказал "эй, мы тут закладывались на неизменяемость, но теперь она не гарантируется". НС>>Это отдельный большой вопрос, не имеющий никакого отношения к рекордам. A>Этот большой вопрос можно было бы элементарно решить.
Разве что языком.
A> При этом у рекордов появился бы своя семантика и вопрос "нафига вводить новое понятие в язык" имел бы ответ.
Если просто запретить set — полученное ничего не стоит и проблему не решает.