diff --git a/NEWS.md b/NEWS.md index 303a049a2..c1482c927 100644 --- a/NEWS.md +++ b/NEWS.md @@ -197,6 +197,8 @@ 19. Ellipsis elements like `..1` are correctly excluded when searching for variables in "up-a-level" syntax inside `[`, [#5460](https://github.com/Rdatatable/data.table/issues/5460). Thanks @ggrothendieck for the report and @MichaelChirico for the fix. +20. `rowwiseDT()` now provides a helpful error message when a complex object that is not a list (e.g., a function) is provided as a cell value, instructing the user to wrap it in `list()`. [#7219](https://github.com/Rdatatable/data.table/issues/7219). Thanks @kylebutts for the report and @venom1204 for the fix. + ### NOTES 1. The following in-progress deprecations have proceeded: diff --git a/R/rowwiseDT.R b/R/rowwiseDT.R index 81114ead6..ad19e6ab5 100644 --- a/R/rowwiseDT.R +++ b/R/rowwiseDT.R @@ -13,6 +13,21 @@ rowwiseDT = function(...) { nrows = length(body) %/% ncols if (length(body) != nrows * ncols) stopf("There are %d columns but the number of cells is %d, which is not an integer multiple of the columns", ncols, length(body)) + is_problematic = vapply_1b( + body, + function(v) !(is.atomic(v) || is.null(v) || typeof(v) == "list") + ) + if (any(is_problematic)) { + first_problem_idx = which(is_problematic)[1L] + col_idx = (first_problem_idx - 1L) %% ncols + 1L + col_name = header[col_idx] + obj_type = class1(body[[first_problem_idx]]) + stopf( + "In column '%s', received an object of type '%s'.\nComplex objects (like functions, formulas, or calls) must be wrapped in list() to be stored in a data.table column.\nPlease use `list(...)` for this value.", + col_name, + obj_type + ) + } # make all the non-scalar elements to a list needs_list = lengths(body) != 1L body[needs_list] = lapply(body[needs_list], list) diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 05e0b5017..3245ba9c8 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -21655,3 +21655,16 @@ local({ ...123 = 'a' test(2339.11, DT[, .....123], DT) }) + +# rowwiseDT() valid and invalid handling of complex objects #7219 +test(2340.1, rowwiseDT(x =, y =, 1, 2, 3, 4), data.table(x = c(1, 3), y = c(2, 4))) +test(2340.2, rowwiseDT(x =, func =, + 1, list(\(x) x + 1), + 2, list(function(z) z * 2)), + data.table(x = c(1, 2), func = list(\(x) x + 1, function(z) z * 2))) +test(2340.3, rowwiseDT(x =, func =, 1, \(x) x + 1), + error = "In column 'func', received an object of type 'function'.*wrap.*list") +test(2340.4, rowwiseDT(x =, expr =, 1, quote(a + b)), + error = "In column 'expr', received an object of type 'call'.*wrap.*list") +test(2340.5, rowwiseDT(x =, plist =, 1, as.pairlist(list(123))), + error = "In column 'plist', received an object of type 'pairlist'.*wrap.*list")