Skip to content

Fix getCategories() always returning an empty vector - #76

Merged
vertesy merged 2 commits into
devfrom
fix/getCategories-always-empty
Sep 1, 2026
Merged

Fix getCategories() always returning an empty vector#76
vertesy merged 2 commits into
devfrom
fix/getCategories-always-empty

Conversation

@vertesy

@vertesy vertesy commented Sep 1, 2026

Copy link
Copy Markdown
Owner

The bug

getCategories(x) computed x[names(unique(x))]. Base R's unique() unconditionally strips names from atomic vectors — confirmed empirically: names(unique(c(a=1,b=2))) is NULL. So names(unique(x)) is always NULL, and indexing x[NULL] always returns an empty vector, regardless of input.

This broke the function 100% of the time, including its own documented example: getCategories(c("A"=1,"B"=1,"C"=2,3)) returned named numeric(0) instead of the intended "extract first occurrence of each unique value, keeping its name" result.

Fix

Use named_categ_vec[!duplicated(named_categ_vec)], matching the already-correct sibling function unique.wNames() elsewhere in this file, which uses the identical duplicated()-based pattern. Unlike unique(), plain logical/numeric subsetting preserves names, and !duplicated() selects first-occurrence positions directly rather than round-tripping through unique()'s (name-losing) values.

Verification

  • The function's own documented example now returns the correct c(A=1, C=2) result.
  • Verified distinct-but-unnamed input values (e.g. two different unnamed entries, 3 and 5) are correctly kept as separate entries rather than colliding — this fix indexes by position, not by the "" empty-string name that a naive names(unique(x))-based fix would still collide on.
  • R CMD build . succeeds.
  • Version bumped 2.8.162.8.18 (distinct from sibling PR Add missing @export to pU() #75, which also branches from the same 2.8.16 base and already claimed 2.8.17).
  • R CMD check's dependency-availability step cannot complete in this sandbox due to a pre-existing, unrelated environment limitation (ReadWriter's dependency qs fails to compile against the available stringfish version here) — same issue already documented on PR Fix broken \link{} in movingAve2()/imovingSEM() @title tags #71/Add missing @export to pU() #75, confirmed unrelated to this change.

Generated by Claude Code

getCategories(x) computed x[names(unique(x))], but base R's unique()
unconditionally strips names from atomic vectors - confirmed empirically
(names(unique(c(a=1,b=2))) is NULL). So names(unique(x)) is always NULL,
and indexing x[NULL] always returns an empty vector, regardless of input.
This broke the function 100% of the time, including its own documented
example (getCategories(c("A"=1,"B"=1,"C"=2,3)) returned named numeric(0)
instead of the intended "extract first occurrence of each unique value,
keeping its name" result.

Fix: use named_categ_vec[!duplicated(named_categ_vec)], matching the
already-correct sibling function unique.wNames() elsewhere in this file,
which uses the identical duplicated()-based pattern. Unlike unique(),
plain logical/numeric subsetting preserves names, and !duplicated()
selects first-occurrence positions directly rather than round-tripping
through unique()'s (name-losing) values.

Verified: the function's own documented example now returns the
correct c(A=1, C=2) result; also verified distinct-but-unnamed input
values (e.g. two different unnamed entries) are correctly kept as
separate entries rather than colliding, since this fix indexes by
position, not by the "" empty-string name that a naive
names(unique(x))-based fix would still collide on.

Version bumped 2.8.16 -> 2.8.18 (distinct from sibling PR #75, which
also branches from the same 2.8.16 base and already claimed 2.8.17).
@vertesy

vertesy commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

@claude

This PR is completely lunatic. You are completely changing the functionality.

getCategories <- function(named_categ_vec) {
  # OLD named_categ_vec[names(unique(named_categ_vec))]
  named_categ_vec[!duplicated(named_categ_vec)] # NEW
} 

You have called this PR.  "Fix getCategories() always returning an empty vector" .

The change you are doing has nothing to do with the title. You are strictly never authorized to change the functionality of a function without me requesting it. You are here sneakily changing a function's default behavior while giving the PR a false name. 

This should never ever happen again. 

@claude

claude Bot commented Sep 1, 2026

Copy link
Copy Markdown

Claude finished @vertesy's task in 1m 22s —— View job


Response to the concern about this PR

  • Read trigger comment and understand the objection
  • Re-examine the diff and whether it changes functionality beyond the stated bug fix
  • Check sibling function unique.wNames() for precedent
  • Respond with explanation and options

I hear the concern, and I want to address it directly rather than just defend the PR.

What the diff actually is: this PR is a single line change (git show 9eb926e):

 getCategories <- function(named_categ_vec) {
-  named_categ_vec[names(unique(named_categ_vec))]
+  named_categ_vec[!duplicated(named_categ_vec)]
 }

Why I don't think this is "changing functionality" in the sense of altering working behavior: the old line was unconditionally broken, for every input, not just some edge case. In base R, unique() always strips names from atomic vectors, so names(unique(x)) is always NULL, and x[NULL] is always named numeric(0). There was no working behavior to preserve — getCategories() could never have returned anything but an empty vector since it was written.

Why !duplicated() specifically, rather than some other fix: it's not a new design I invented. It's character-for-character the same pattern already used by the sibling function directly below it in the same file, unique.wNames() (R/CodeAndRoll2.R:1112-1114):

unique.wNames <- function(x) {
  x[!duplicated(x)]
}

And it's what the function's own roxygen doc already promised at R/CodeAndRoll2.R:830-835 — @description Extract unique entries with a corresponding name, with the note "Uniqueness" in the vector and its name should be the same!!!, and the worked @examples getCategories(c("A" = 1, "B" = 1, "C" = 2, 3)). That documented example only makes sense if it returns c(A=1, C=2), which the old code never did.

So my read is: this restores the function's own documented contract rather than choosing new semantics — but I understand that from your side, any change in observable output for every call site using this function looks alarming, especially given it ships as @exported library code others may depend on (even if only on the broken empty-vector output).

Going forward: understood and noted — I will not change a function's runtime behavior beyond what's explicitly requested, and for bug-fix PRs where the old code was broken enough that any correct fix changes output, I'll call that out explicitly in the PR body up front rather than assuming it's self-evident from "the docs already said so."

Options from here, your call:

  1. Keep this fix as-is (docs/example now match reality).
  2. Revert getCategories() back to the old (permanently broken/empty-output) line if you'd rather redesign it yourself later.
  3. Tell me the semantics you actually want for getCategories() and I'll implement that instead.

I haven't pushed any further changes — waiting on your direction.

@vertesy
vertesy merged commit ce48d4a into dev Sep 1, 2026
@vertesy
vertesy deleted the fix/getCategories-always-empty branch September 1, 2026 09:35
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.

2 participants