Skip to content

Answer a question that depends on several members - #249

Draft
VPDPersonal wants to merge 1 commit into
fix/size-delta-vector2-and-mask-paddingfrom
feat/aggregator-binders
Draft

Answer a question that depends on several members#249
VPDPersonal wants to merge 1 commit into
fix/size-delta-vector2-and-mask-paddingfrom
feat/aggregator-binders

Conversation

@VPDPersonal

Copy link
Copy Markdown
Owner

📚 Stacked on #248#247 → … → #137.

Summary

A binder binds one member. That is the right shape for a value and the wrong one for "is the button available", whose answer depends on three of them. Composition existed only for collection filters, so the workaround adds a fourth field to the ViewModel that exists to hold the answer — view logic one layer down.

The shape, and why this one

The framework's rule stays intact: each input is an ordinary binder bound to its own member (BoolAggregatorInputMonoBinder, StringAggregatorInputMonoBinder), writing into a shared aggregator under its own index. The aggregator is not a binder — it is the point the inputs meet at.

[Bind] _hasAmmo   → BoolAggregatorInputMonoBinder (index 0) ┐
[Bind] _isAlive   → BoolAggregatorInputMonoBinder (index 1) ├→ AndBoolMonoBinder → UnityEvent<bool>
[Bind] _isReady   → BoolAggregatorInputMonoBinder (index 2) ┘

AndBoolMonoBinder, OrBoolMonoBinder, FormatStringMonoBinder.

Decisions

  • Nothing is forwarded until every input has reported once. With an And over three conditions, two arriving first would enable a button the third immediately disables — a partial answer is worse than a late one.
  • A mismatched format string is reported, not thrown. An exception inside a binding loop takes the rest of the View's bindings with it.
  • A null part composes as an empty string, not the word null — a missing name should leave a gap.
  • An index the aggregator was not configured for is reported: it means an input and the aggregator disagree about the shape, and the missing value would keep the result from ever being forwarded.

Also here

ConditionalFloat, ConditionalString, ConditionalColorMonoBinder — a bound boolean becomes one of two values configured in the Inspector. The two-state case that is neither a colour block nor a sprite swap, and that otherwise puts the view's wording into the ViewModel.

Verification

Eight tests. Recompile clean, EditMode 767.

🇷🇺 Описание на русском

📚 Стек: поверх #248#247 → … → #137.

Кратко

Биндер привязывает один член. Для значения это верная форма, для вопроса «доступна ли кнопка», ответ на который зависит от трёх, — неверная. Композиция была только у фильтров коллекций, поэтому обходной путь добавляет во ViewModel четвёртое поле ради ответа — логику view на слой ниже.

Форма и почему именно она

Правило фреймворка остаётся нетронутым: каждый вход — обычный биндер, привязанный к своему члену (BoolAggregatorInputMonoBinder, StringAggregatorInputMonoBinder), который пишет в общий агрегатор под своим индексом. Агрегатор — не биндер, а точка, где входы сходятся.

[Bind] _hasAmmo   → BoolAggregatorInputMonoBinder (индекс 0) ┐
[Bind] _isAlive   → BoolAggregatorInputMonoBinder (индекс 1) ├→ AndBoolMonoBinder → UnityEvent<bool>
[Bind] _isReady   → BoolAggregatorInputMonoBinder (индекс 2) ┘

AndBoolMonoBinder, OrBoolMonoBinder, FormatStringMonoBinder.

Решения

  • Ничего не отдаётся, пока не отчитались все входы. При And по трём условиям два пришедших первыми включили бы кнопку, которую третье тут же выключит: частичный ответ хуже позднего.
  • Несовпадающий формат сообщается, а не бросается. Исключение внутри цикла привязки утащит за собой остальные привязки View.
  • null-часть попадает в строку пустой, а не словом null: пропущенное имя должно оставить пробел.
  • Индекс вне настроенного количества сообщается: значит, вход и агрегатор расходятся в форме, и без этого значения результат не уйдёт никогда.

Ещё здесь

ConditionalFloat, ConditionalString, ConditionalColorMonoBinder — привязанный булев превращается в одно из двух значений, заданных в инспекторе. Тот двухсостоянийный случай, который не является ни ColorBlock, ни подменой спрайта и который иначе заносит формулировки view во ViewModel.

Проверка

Восемь тестов. Компиляция чистая, EditMode 767.

A binder binds one member. That is the right shape for a value and the
wrong one for "is the button available", whose answer depends on three of
them - and composition existed only for collection filters, so the
workaround adds a fourth field to the ViewModel that exists to hold the
answer.

The shape here keeps the framework's rule intact rather than bending it.
Each input is an ordinary binder bound to its own member -
BoolAggregatorInputMonoBinder, StringAggregatorInputMonoBinder - and writes
into a shared aggregator under its own index. The aggregator is not a
binder at all; it is the point they meet at.

AndBoolMonoBinder, OrBoolMonoBinder, FormatStringMonoBinder.

Nothing is forwarded until every input has reported once. With an And over
three conditions, two arriving first would enable a button the third
immediately disables - a partial answer is worse than a late one.

A format string that does not match its inputs is reported rather than
thrown: it is a configuration mistake, and an exception inside a binding
loop takes the rest of the View's bindings with it. A null part composes as
an empty string, not the word null.

An index the aggregator was not configured for is reported too: it means an
input and the aggregator disagree about the shape, and the missing value
would keep the result from ever being forwarded.

Alongside them, ConditionalFloat, ConditionalString and
ConditionalColorMonoBinder turn a bound boolean into one of two values
configured in the Inspector - the two-state case that is neither a colour
block nor a sprite swap, and that otherwise puts the view's wording into the
ViewModel.

Tests: eight.

Verification: recompile clean, EditMode 767.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant