Это вопрос языковой независимости c, хотя он мотивируется библиотекой built_value в Dart, в частности в этом обсуждении о том, как избежать повторного использования существующих созданных неизменяемых объектов с шаблоном Builder .
Короткая версия вопроса: есть ли хороший шаблон heuristi c, позволяющий избежать создания новых объектов, которые логически равны существующим объектам?
Равенство и совместное использование объектов с шаблоном построителя
Строитель - это изменяемый объект, который можно использовать для создания неизменяемого объекта, который я назову «построенным» объектом. Неизменяемые встроенные объекты могут безопасно использоваться в качестве подобъектов других объектов. Это позволяет быстро сравнивать на равенство, поскольку проверка ссылочного равенства (т. Е. Указывают ли две ссылки на один и тот же объект?) В начале всех сравнений на равенство немедленно вернет true.
Проблема в том, что , если создается новый построенный объект, равный существующему, для сравнения на равенство его необходимо глубоко сравнить, что может быть намного дороже.
Цель состоит в том, чтобы найти значение heuristi c, которое автоматически избегает создания новых построенных объектов во многих распространенных случаях.
Оптимизация при восстановлении
Распространенным случаем является то, что построенный объект «перестраивается», то есть каждый делает что-то вроде этого:
builder = built.toBuilder();
builder.field = "abc";
built = builder.build();
Иногда создатель из созданного объекта не меняет свои поля. Например,
builder = built.toBuilder();
v = builder.field;
built = builder.build();
Объект строителя, созданный из построенного объекта (как в первом живом примере выше), поддерживает ссылку на построенный объект, из которого он получен. Если ни одно из полей не доступно, то для вызова builder.build()
в третьей строке безопасно просто вернуть исходный построенный объект.
Теперь вот подвох: можно подумать, что это безопасно делайте это, даже если к полям конструктора обращаются, если только читает (т. е. получатели, а не установщики). Таким образом, второй блок кода выглядит так, как будто сборщик должен иметь возможность оптимизировать и вернуть исходный построенный объект, поскольку доступ к builder.field
был доступен только для чтения.
Проблема с оптимизацией, даже если доступ к полю доступен только для чтения
Но вот почему это небезопасно: строители могут быть вложенными . Другими словами, я могу сделать это:
builder = built.toBuilder();
nested = builder.nestedBuilder;
nested.field = "abc";
built = builder.build();
Это проблема. Объект компоновщика не может «видеть», что доступ получателя к его полю nested
привел к доступу установщика к nested.field
. Таким образом, последняя строка на самом деле должна вызвать nested.build()
на своем поле и создать новый построенный объект.
В любом случае я пытался придумать способ добиться этой оптимизации, хотя разрешил вложенные компоновщики, но я не могу найти способ сделать это, не требующий глубокого тестирования вложенных компоновщиков на равенство, чтобы увидеть, нужен ли новый построенный объект. В этом случае это не обязательно сэкономит время, просто pu sh проверка глубокого равенства должна произойти раньше.
Мне интересно, есть ли какой-нибудь язык программирования или какая-то библиотека на языке , это решило эту проблему.
Мотивация
Если кому-то интересно, я использую библиотеки React / Redux в Dart, а Redux поддерживает состояние всего приложение в одном большом неизменяемом объектном дереве. Обновления приложения выражаются как «Действия», которые возвращают новое дерево состояний. Большинство действий изменяют только небольшую часть дерева. Однако любой доступ для чтения к полям дерева приведет к созданию нового поддерева объекта, которое логически равно старому.
Реакция работает путем сравнения на равенство, чтобы увидеть, когда какая-то часть дерева состояний изменилась, нужно ли перерисовывать. Эти сравнения молниеносны, если новое дерево состояний в основном является тем же объектом, что и старое, потому что начальная проверка на равенство ссылок быстрая. Если дерево нужно глубоко сравнить, оно гораздо медленнее.