During Weeks 4 and 5, my primary focus was to close out previously opened PRs by refining implementations, responding to reviewer feedback, and ensuring each patch met quality and performance expectations. Alongside these cleanups, I also took the initiative to open and address new issues that were either high-impact or naturally aligned with ongoing improvements. This balance between wrapping up and branching out helped ensure steady project momentum while maintaining code quality.
Making tables()
Smarter: Recognizing Nested data.table
s (PR #7141, Closes #2606)
Historically, tables()
could only detect top-level data.table
objects in the environment. However, many users store data.table
s inside lists — especially after using functions like split()
.
To improve usability:
- I extended
tables()
to optionally recursively traverse plain lists in the environment. - This makes en-listed or split-generated
data.table
s visible intables(recursive = TRUE)
. - Nested structures within
data.frame
ordata.table
columns are intentionally excluded, to avoid false positives or excessive recursion. - The implementation was carefully designed to minimize performance overhead.
This addition improves discoverability and debugging workflows for complex environments and nested data.
Further discussion is ongoing around refining the recursive behavior, including how deep to traverse and whether to support additional structures (e.g., environments or language objects), to ensure the functionality aligns well with user expectations and real-world use cases.
Safer :=
Assignments: Guarding Against Function RHS (PR #7161, Closes #5829)
A subtle but dangerous misuse arises when users mistakenly assign a function or closure on the right-hand side (RHS) of :=
. This led to malformed tables or cryptic error messages.
To prevent this:
- I added a check: if
jval
is a function, a clear error is raised before proceeding. - The logic is scoped to cases where new columns are being created, ensuring no interference with valid operations.
- This check improves error diagnostics and guards against accidental misuse.
While a version of this check had been attempted previously, it required refinement. The new implementation builds on past work and follows up on feedback from earlier discussions, aiming for better placement, specificity, and clarity in error handling.
This patch currently covers only closures/functions, but it lays the groundwork for addressing other exotic RHS types (e.g., environments, external pointers) in future iterations.
Fixing Vignette Drift: Updating Reshape Examples to Match fread()
Behavior (PR #7150, Closes #6524)
The reshape
vignette contained an outdated example where fread()
used to read dob_child
columns as character
. Now, thanks to improved auto-type detection, they’re read as IDate
— which broke the original teaching point around type coercion.
To address this:
- I replaced
dob_child
columns withname_child
columns (strings like “Anna”, “Ben”). - This restored the original coercion conflict between character and integer types.
- Surrounding text was updated to reflect the new example and maintain pedagogical clarity.
This fix ensures the vignette remains relevant and educational for new users learning reshaping.
Improved Print Formatting: Dynamic Column Widths when col.names = "none"
(PR #7130, Closes #6882)
When printing data.table
s with col.names = "none"
, the column widths were previously influenced by the actual (but hidden) column names. This often caused columns to appear wider than necessary or misaligned — especially when long names were present.
To address this:
-
I added logic to explicitly replace column names with empty strings when
col.names == "none"
is specified:if (col.names == "none") colnames(toprint) <- rep.int("", ncol(toprint))
- This step is performed immediately after toprint is constructed, but before any formatting or width calculations.
- As a result, all width computations are now solely based on data content, not column names — resolving the issue completely.
- The patch includes a test to ensure consistent and predictable output behavior.
This change improves the legibility of output when column headers are suppressed and makes print.data.table
more intuitive in custom display workflows.
Silencing Spurious Warnings in cube()
Eval (PR #7110, Closes #6964)
Using cube()
triggered confusing warnings from min()
or max()
like:
These warnings originated during internal evaluation steps that inferred output structure — not from user code — and often caused unnecessary concern.
To resolve this:
- I wrapped the relevant call in a simple
suppressWarnings()
to silence these spurious min/max warnings. - The suppression is targeted only at the structure-seeding evaluation (
x[0L, eval(jj), by]
), where no real user data is involved. - This avoids cluttering output while still surfacing legitimate user-generated warnings elsewhere.
Although not a fine-grained suppression, this solution is sufficient and safe for this internal case — and significantly improves the UX when using cube()
on clean data.
Weeks 4 and 5 Summary
These two weeks focused on strengthening data.table
’s user experience and internal reliability. From guarding against subtle mistakes to modernizing documentation and squashing misleading warnings, each change helps create a more stable and intuitive tool.
With the foundation solidified, the next phase will explore performance enhancements, deeper type system integrations, and expanded functionality in joins and evaluation strategies.
Stay tuned — more improvements are on the way!