Skip to content

Add other_mort() and other_encounter() accessors (#579) - #585

Merged
gustavdelius merged 3 commits into
masterfrom
other-mort-accessors
Aug 27, 2026
Merged

Add other_mort() and other_encounter() accessors (#579)#585
gustavdelius merged 3 commits into
masterfrom
other-mort-accessors

Conversation

@gustavdelius

Copy link
Copy Markdown
Member

Fixes #579.

The reported bug

The guide to creating an extension package described mizerStarvation as adding starvation mortality "via the other_mort argument in setComponent()". There is no such argument (the mortality argument is mort_fun), and mizerStarvation does not call setComponent() at all — it assigns params@other_mort[["starvation"]] <- "starvMort" directly. A reader following the guide's simplest worked example hit Error: argument "dynamics_fun" is missing, with no default.

The gap behind it

@other_mort and @other_encounter are named lists of function names that getMort() and getEncounter() iterate over and add to their results, and they had no exported accessor. other_params() deliberately reaches only params@other_params$other, and setComponent() was the only exported writer of the two slots — but it requires dynamics_fun and initial_value, which a term carrying no state of its own has nothing to supply. mizer already half-filled the table:

fixed array state-dependent function
mortality ext_mort() / ext_mort<-() @other_mortnothing
encounter ext_encounter() / ext_encounter<-() @other_encounternothing

The route mizerStarvation actually takes is also a one-way door: getComponent() and removeComponent() are keyed on names(params@other_dynamics), so a bare @other_mort entry can neither be inspected nor removed through the API.

Changes

New accessors (R/extension.R) — other_mort() / other_encounter() and their replacement forms, as plain functions alongside other_params():

other_mort(params)[["starvation"]] <- "starvMort"
  • They filter out component-owned entries, as other_params() does and for the same reason. An entry created by setComponent(mort_fun = ) stays the property of its component — getComponent() reports it, removeComponent() removes it — so assigning a whole list through the accessor can no longer wipe it out. Getter and setter have the same scope, so other_mort(params) <- other_mort(params) is an exact identity.
  • Validation rejects a value that is not a function name, an unnamed entry, and a name that collides with a component (the error names setComponent()). Assigning NULL removes an entry; other_mort(params) <- NULL clears the free-standing ones only.
  • other_dynamics deliberately gets no accessor: it is coupled to @initial_n_other (MizerSim validity checks the two agree), so it stays behind setComponent(). other_mort and other_encounter are independent registries with nothing to keep in sync.
  • All four share one internal setRateContributions().

One behaviour changesetComponent() now refuses a component name that a free-standing contribution is already registered under, instead of silently taking it over and hiding it from the accessors. Recorded in inst/skills/upgrade-mizer-code/references/mizer-3.4.md with a row in the symptom index.

Documentation — the wrong sentence in inst/skills/create-extension-package/SKILL.md is rewritten to describe the supported route, with the two neighbouring mechanisms (ext_mort() for a fixed array, setComponent(mort_fun = ) for a component with state) spelled out so they cannot be confused again; a bullet added to the package-author checklist; a row and a paragraph added to inst/skills/extend-mizer/SKILL.md. The articles were regenerated with build_guides() — no generated vignette was edited by hand.

Verification

  • Full test suite: [ FAIL 0 | WARN 0 | SKIP 49 | PASS 4947 ]
  • 8 new tests in tests/testthat/test-extension.R: round trip, filtering, preservation across a whole-list assignment, the four validation errors, removal via NULL, both rates actually rising, projection of a model with a free-standing contribution and no components at all, the setComponent() collision guard, and time_modified for both setters.
  • pkgdown::check_pkgdown() clean; the new page is picked up by has_concept("extension tools") with no _pkgdown.yml edit.
  • lintr::lint() clean on the new lines.
  • build_guides() reports "All links resolve" — which is also what checks that the new symptom-index row resolves to its heading and that its quoted error text is still a literal in R/.

inst/llms.txt / docs/llms.txt do not yet list the new exports; they are regenerated from a full pkgdown site build.

🤖 Generated with Claude Code

The guide to creating an extension package described mizerStarvation as
adding starvation mortality "via the `other_mort` argument in
`setComponent()`". There is no such argument, and mizerStarvation does not
call `setComponent()` at all -- it assigns into `params@other_mort`
directly. A reader following the sentence hit

    Error: argument "dynamics_fun" is missing, with no default

Behind the wrong sentence was a real gap. `@other_mort` and
`@other_encounter` had no exported accessor, so `setComponent()` -- which
requires a `dynamics_fun` and an `initial_value` -- was the only supported
writer, and a term that carries no state of its own had nothing to supply
for either. mizer already had the parallel pair for the fixed-array case,
`ext_mort()` and `ext_encounter()`.

Fill in the two missing cells:

    other_mort(params)[["starvation"]] <- "starvMort"

Like `other_params()`, the accessors hide the entries belonging to a
component: those stay the property of `setComponent()`, `getComponent()`
and `removeComponent()`, so assigning a whole list cannot wipe them out.
Getter and setter therefore have the same scope. Validation rejects a name
that is not a function, an unnamed entry, and a name that collides with a
component; assigning NULL removes an entry.

`setComponent()` now also refuses a component name that a free-standing
contribution already holds, instead of silently taking it over and hiding
it from the accessors. That is the one behaviour change, and it is recorded
in the upgrading guide with a row in the symptom index.

Rewrite the guide sentence to describe the supported route, add the
mechanism to the extend-mizer skill and a bullet to the package-author
checklist, and regenerate the articles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gustavdelius
gustavdelius merged commit 7ec8623 into master Aug 27, 2026
@gustavdelius
gustavdelius deleted the other-mort-accessors branch August 27, 2026 11:53
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.

guide-create-extension-package: setComponent() has no other_mort argument and cannot express the mizerStarvation example

1 participant