Skip to content

Commit

Permalink
Remove {UN,}SET_S4_OBJECT usage (#6183)
Browse files Browse the repository at this point in the history
* Remove {UN,}SET_S4_OBJECT usage

* handle asS4 from R side

* tweak NES

* switch to C API

* restore dogroups code using public API

* new test

* adjust NEWS

* IS_S4_OBJECT --> isS4
  • Loading branch information
MichaelChirico authored Jul 11, 2024
1 parent 643f514 commit cd89ceb
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 2 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@
20. Removed a warning about the now totally-obsolete option `datatable.CJ.names`, as discussed in previous releases.
21. Refactored some non-API calls to R macros for S4 objects (#6180)[https://github.com/Rdatatable/data.table/issues/6180]. There should be no user-visible change. Thanks to various R users & R core for pushing to have a clearer definition of "API" for R, and thanks @MichaelChirico for implementing here.
## TRANSLATIONS
1. Fix a typo in a Mandarin translation of an error message that was hiding the actual error message, [#6172](https://github.com/Rdatatable/data.table/issues/6172). Thanks @trafficfan for the report and @MichaelChirico for the fix.
Expand Down
7 changes: 7 additions & 0 deletions inst/tests/S4.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,10 @@ if (TZnotUTC) {
fread("a,b,c\n2015-01-01,2015-01-02,2015-01-03 01:02:03", colClasses=c("Date",NA,NA)),
ans, output=ans_print)
}

# S4 object in grouping output requiring growVector
# coverage test towards refactoring for #6180
DT = data.table(a = rep(1:2, c(1, 100)))
# Set the S4 bit on a simple object
DT[, b := asS4(seq_len(.N))]
test(6, DT[, b, by=a, verbose=TRUE][, isS4(b)], output="dogroups: growing")
2 changes: 1 addition & 1 deletion src/assign.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ static SEXP shallow(SEXP dt, SEXP cols, R_len_t n)
SEXP newdt = PROTECT(allocVector(VECSXP, n)); protecti++; // to do, use growVector here?
SET_ATTRIB(newdt, shallow_duplicate(ATTRIB(dt)));
SET_OBJECT(newdt, OBJECT(dt));
IS_S4_OBJECT(dt) ? SET_S4_OBJECT(newdt) : UNSET_S4_OBJECT(newdt); // To support S4 objects that include data.table
if (isS4(dt)) newdt = asS4(newdt, TRUE, 1); // To support S4 objects that include data.table

This comment has been minimized.

Copy link
@MichaelChirico

MichaelChirico Jul 14, 2024

Author Member

@ben-schwen I think #6257 is suggesting we need to PROTECT() the asS4() output here, WDYT? I'm confused why we'd need to given we PROTECT() the newdt for the first time a few lines prior...

This comment has been minimized.

Copy link
@ben-schwen

ben-schwen Jul 14, 2024

Member

AFAIU rchk sees the assignment of newdt as change and therefore demands the PROTECT because of caller protection

Sometimes an object is changed (for example duplicated, coerced or grown) yet the current value needs to be protected.

This comment has been minimized.

Copy link
@MichaelChirico

MichaelChirico Jul 14, 2024

Author Member

WDYT is the best thing to do

  1. Just PROTECT() here and run another UNPROTECT() later
  2. Do a PROTECT_WITH_INDEX() thing to potentially just re-use the protection stack space.
  3. Just ignore the rchk output here

I lean towards (1) since using S4 is pretty peripheral use case & it least clutters up the non-S4 code.

This comment has been minimized.

Copy link
@ben-schwen

ben-schwen Jul 14, 2024

Member

PROTECT here and proteci++ seems the right option now.

Overall we might want to inspect all uses of PROTECT regardless of whether rchk detects them or not.

This comment has been minimized.

Copy link
@MichaelChirico

MichaelChirico Jul 15, 2024

Author Member

I agree even more after trying to re-read R-exts again for the nth time:

It is a common mistake to believe that if you invoked PROTECT(p) at some point then p is protected from then on, but that is not true once a new object is assigned to p.

I believe that's just what's happened here.

//SHALLOW_DUPLICATE_ATTRIB(newdt, dt); // SHALLOW_DUPLICATE_ATTRIB would be a bit neater but is only available from R 3.3.0

// TO DO: keepattr() would be faster, but can't because shallow isn't merely a shallow copy. It
Expand Down
2 changes: 1 addition & 1 deletion src/dogroups.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ SEXP keepattr(SEXP to, SEXP from)
// Same as R_copyDFattr in src/main/attrib.c, but that seems not exposed in R's api
// Only difference is that we reverse from and to in the prototype, for easier calling above
SET_ATTRIB(to, ATTRIB(from));
IS_S4_OBJECT(from) ? SET_S4_OBJECT(to) : UNSET_S4_OBJECT(to);
if (isS4(from)) to = asS4(to, TRUE, 1);
SET_OBJECT(to, OBJECT(from));
return to;
}
Expand Down

0 comments on commit cd89ceb

Please sign in to comment.