Skip to content

Don't rely on S4 initialize dispatch to build tinytable objects - #688

Merged
vincentarelbundock merged 1 commit into
mainfrom
issue687-initialize-dispatch
Aug 22, 2026
Merged

vincentarelbundock merged 1 commit into
mainfrom
issue687-initialize-dispatch

Conversation

@vincentarelbundock

Copy link
Copy Markdown
Owner

Fixes #687.

Problem

tt() built its object with methods::new("tinytable", ..., colnames = colnames). colnames is not a slot — it is an argument of the custom initialize method.

Methods defined for generics owned by the methods package are merged into the live dispatch table by cacheMetaData() at load time, and that merge is skipped when methods is not attached as the namespace loads. In such a session new() falls back to the default initialize(), which treats every named argument as a slot and errors:

Error in initialize(value, ...) :
  invalid name for slot of class “tinytable”: colnames

The installed metadata is fine — the namespace does contain .__T__initialize:methods. Only the merge into the live table is missing:

methods NOT attached: initialize methods for: ANY, array, ..., ts
methods attached:     initialize methods for: ANY, array, ..., tinytable, traceable, ts

Attaching methods afterwards does not repair it; the merge only happens at load. The package's own generics (build_eval, style_eval, …) are unaffected — their tables live in the namespace.

Reproducer, both examples from the issue:

$ Rscript --default-packages=utils,stats,grDevices,graphics,datasets,base \
    -e 'tinytable::tt(pairwise_df, digits = 3) |> tinytable::style_tt(j = 2:3, align = "c")'
Error in initialize(value, ...) : invalid name for slot of class “tinytable”: colnames

This was latent before colnames was added: every argument used to be a real slot, so the fallback ran without error but silently skipped the dynamic setup (@id, @nrow, @ncol, @nhead, @names).

Fix

Move the slot-filling logic out of the initialize method into an ordinary function, tinytable_init(), and call it directly from tt(). The initialize method stays as a thin delegate, so new("tinytable", ...) keeps working where dispatch is available.

Testing

  • Both reprexes from the issue now render correctly with methods unattached.
  • New regression test in inst/tinytest/test-bugfix.R runs tt() + style_tt() + save_tt() in a subprocess started without methods in the default packages. It is skipped unless tinytable resolves to an installed package, so pkgload::load_all() workflows are unaffected. Verified that the old new("tinytable", colnames = TRUE) path still fails in that subprocess, so the test genuinely guards the regression.
  • tinytest::run_test_dir(): all ok, 642 results.
  • R CMD check: Status OK, 643 results (the new test runs there).

Note on the CRAN report

I could not determine what dropped methods on win-builder. R's own vignette-rebuild step does not set R_DEFAULT_PACKAGES (only static-analysis subprocesses do, via R_runR2), and I reproduced the reporter's full chain locally — R CMD check → quarto::html engine → quarto CLI → R — where methods is attached and the render succeeds. Whatever causes it appears specific to that machine's environment. This fix removes the failure mode regardless of the cause.

https://claude.ai/code/session_01KXi6DkijKg5gMLajPJiWbP

`tt()` created its object with `new("tinytable", ..., colnames = colnames)`,
where `colnames` is an argument of the custom `initialize` method rather than
a slot. Methods defined for generics owned by the `methods` package are merged
into the live dispatch table by `cacheMetaData()` at load time, and that merge
is skipped when `methods` is not attached as the namespace loads. In such a
session `new()` falls back to the default `initialize()`, which treats every
argument as a slot name and quits with "invalid name for slot of class
tinytable: colnames".

Move the slot-filling logic into an ordinary function, `tinytable_init()`, and
call it directly from `tt()`. The `initialize` method is kept as a thin
delegate so `new("tinytable", ...)` keeps working where dispatch is available.

Fixes #687

Claude-Session: https://claude.ai/code/session_01KXi6DkijKg5gMLajPJiWbP
@vincentarelbundock
vincentarelbundock merged commit 4b39e8d into main Aug 22, 2026
3 checks passed
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.

Windows CRAN vignette rebuild: invalid S4 slot colnames with tt() |> style_tt()

1 participant