Информация об изменениях

Сообщение Re[13]: Догонит ли net java? от 05.12.2022 18:53

Изменено 05.12.2022 19:01 Sinclair

Re[13]: Догонит ли net java?
Здравствуйте, ·, Вы писали:

S>>А что там внутри этих updateBBB()?

·>Там ещё могут быть простыни кода, ведь у нас 40 полей которые надо по всякому вычислять и проставлять. Если модификация p происходит очень сложно, то хочется это всё разрезать на мелкие кусочки по разным методам или даже классам, иногда даже реюзабельным из разных мест.
Ну, и в чём проблема? Любое поле — это всего лишь значение. Для его вычисления есть формула.
В иммутабельном мире есть одна проблема — если, к примеру, целиковое "изменение" объекта тривиально расписывается в стиле
var date = DateTime.Now;
date += TimeSpan.FromMinutes(42); // == date = date + TimeSpan.FromMinutes(42);

несмотря на его иммутабельность, сигнатуру "мутабельного" метода можно поменять
var l = new ImmutableList<int> {4, 8, 15, 16, 23};
l.Add(42);     // ah-ah! 
l = l.Add(42); // good boy!

и всё будет работать, то с отдельными свойствами композитных объектов так сделать не получится. Если у меня immutable record Point(int x, int y), то запись вроде p.x += 5 запрещена.
Нельзя и сигнатуру у сеттера поменять, чтобы он перестал быть void, а стал возвращать Point.
p1.x = p1.y = 0; // intuitievely clean, but doesn't work in immutable case
(p1.y = 0).x = 0; // in case p1.y = 0 yields Point, not int.


И вот для обхода этой проблемы предлагается конструкция with.
Она позволяет легко и очевидно перейти от мутабельного кода к иммутабельному:
var mp = new MutablePoint(0, 0);
var ip = new Point(0,0);

mp.X += 10;
ip = ip with X = 10;

if (42 mod 17 != 1)
{
mp.X = mp.Y = 13;
ip = ip with {
}

S>>Почему нельзя просто сделать тот же With? Ведь при присванивании "в себя же" ескейп-анализ уберёт всю лишнюю нагрузку на GC, в итоге имеем тот же перформанс, лаконичный синтаксис, и отсутствие необходимости для каждого DTO еще и цельный билдер расписывать.

·>Как я понял, ты предлагаешь что-то вроде
·>
·>public Person modify(Person p) {
·>  p = updateAAA(p);
·>  ...
·>  if(...) p = updateBBB(p);
·>  else p = updateCCC(p);
·>  ...
·>  p = updateDDD(p);
·>  return p;
·>}
·>

·>но это тоже частный случай, да и выглядит коряво, имхо. Захочется манипулировать одновременно двумя билдерами, то опять что-то новое придумывать:
·>
·>public Result enrich(Person p, Order o) {
·>  var iBuilder = Info.newBuilder();
·>  var pBuilder = p.builder();
·>  var oBuilder = o.builder();
·>  updateAAA(pBuilder, iBuilder);
·>  updateBBB(oBuilder, iBuilder);
·>  updateCCC(oBuilder, pBuilder);
·>  return new Result(pBuilder.build(), pBuilder.build(), iBuilder.build());
·>}
·>

·>как тут можнро сделать красивее?

·>Лично мне пока самым удобным показалось то, что генерирует Avro, как тут. (генерацию setters для самих dto можно запретить, оставить только у билдеров).


S>>·>Ты прав. Можно только новый тип создавать оказывается.

S>>Переходите на сторону CLR. У нас всё это есть Включая "annotation processors"
·>Нее... мы мееедленно спускаемся.
Re[13]: Догонит ли net java?
Здравствуйте, ·, Вы писали:

S>>А что там внутри этих updateBBB()?

·>Там ещё могут быть простыни кода, ведь у нас 40 полей которые надо по всякому вычислять и проставлять. Если модификация p происходит очень сложно, то хочется это всё разрезать на мелкие кусочки по разным методам или даже классам, иногда даже реюзабельным из разных мест.
Ну, и в чём проблема? Любое поле — это всего лишь значение. Для его вычисления есть формула.
В иммутабельном мире есть одна проблема — если, к примеру, целиковое "изменение" объекта тривиально расписывается в стиле
var date = DateTime.Now;
date += TimeSpan.FromMinutes(42); // == date = date + TimeSpan.FromMinutes(42);

несмотря на его иммутабельность, сигнатуру "мутабельного" метода можно поменять
var l = new ImmutableList<int> {4, 8, 15, 16, 23};
l.Add(42);     // ah-ah! 
l = l.Add(42); // good boy!

и всё будет работать, то с отдельными свойствами композитных объектов так сделать не получится. Если у меня immutable record Point(int x, int y), то запись вроде p.x += 5 запрещена.
Нельзя и сигнатуру у сеттера поменять, чтобы он перестал быть void, а стал возвращать Point.
p1.x = p1.y = 0; // intuitievely clean, but doesn't work in immutable case
(p1.y = 0).x = 0; // in case p1.y = 0 yields Point, not int.


И вот для обхода этой проблемы предлагается конструкция with.
Она позволяет легко и очевидно перейти от мутабельного кода к иммутабельному:
var mp = new MutablePoint(0, 0);
var ip = new Point(0,0);

mp.X += 10;
ip = ip with X = 10;

if (42 mod 17 != 1)
{
   mp.X = mp.Y = 13; 
   ip = ip with { X = 13; Y = 13; }
}

S>>Почему нельзя просто сделать тот же With? Ведь при присванивании "в себя же" ескейп-анализ уберёт всю лишнюю нагрузку на GC, в итоге имеем тот же перформанс, лаконичный синтаксис, и отсутствие необходимости для каждого DTO еще и цельный билдер расписывать.
·>Как я понял, ты предлагаешь что-то вроде
·>
·>public Person modify(Person p) {
·>  p = updateAAA(p);
·>  ...
·>  if(...) p = updateBBB(p);
·>  else p = updateCCC(p);
·>  ...
·>  p = updateDDD(p);
·>  return p;
·>}
·>

Да, а почему нет?

·>но это тоже частный случай, да и выглядит коряво, имхо. Захочется манипулировать одновременно двумя билдерами, то опять что-то новое придумывать:

·>
·>public Result enrich(Person p, Order o) {
·>  var iBuilder = Info.newBuilder();
·>  var pBuilder = p.builder();
·>  var oBuilder = o.builder();
·>  updateAAA(pBuilder, iBuilder);
·>  updateBBB(oBuilder, iBuilder);
·>  updateCCC(oBuilder, pBuilder);
·>  return new Result(pBuilder.build(), pBuilder.build(), iBuilder.build());
·>}
·>

·>как тут можнро сделать красивее?
Эмм, да всё что угодно тут будет красивее.
Хотя бы так — если уж очень хочется.
public Result enrich(Person p, Order o) {
  var i = new Info();
  (p, i) = updateAAA(p, i);
  (o, i) = updateBBB(o, i);
  (o, p) = updateCCC(o, p);
  return new Result(p, o, i);
}


·>Лично мне пока самым удобным показалось то, что генерирует Avro, как тут. (генерацию setters для самих dto можно запретить, оставить только у билдеров).

Ну, это тот самый способ со сменой сигнатуры у сеттера на возврат self. Так себе решение, по сравнению с with operator, кмк. Лучше, чем ничего, конечно.

·>Нее... мы мееедленно спускаемся.

А стадо тем временем всё дальше и дальше.