Skip to content
Open
15 changes: 15 additions & 0 deletions R/rowwiseDT.R
Original file line number Diff line number Diff line change
Expand Up @@ -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 = typeof(body[[first_problem_idx]])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if typeof is the right choice here. For the problem raised in #7219 class would be a better choice since class would be "function" but typeof would be still "closure".

stopf(
"In column '%s', received an object of type '%s'.\nComplex objects (like functions, models, etc.) must be wrapped in list() to be stored in a data.table column.\nPlease use `list(...)` for this value.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really true? Many models are indeed lists, e.g. lm(mpg~., data=mtcars).

Other thing on top of my head would be expressions which we do not fully support. Storing environments into a data.table seems uncommon to me.

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)
Expand Down
12 changes: 12 additions & 0 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -21620,3 +21620,15 @@ local({
test(2338.9, {fwrite(dd, f, forceDecimal=FALSE); fread(f)}, di)
})

# rowwiseDT() valid and invalid handling of complex objects #7219
test(2339.1, rowwiseDT(x =, y =, 1, 2, 3, 4), data.table(x = c(1, 3), y = c(2, 4)))
test(2339.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(2339.3, rowwiseDT(x =, func =, 1, \(x) x + 1),
error = "In column 'func', received an object of type 'closure'.*wrap.*list")
test(2339.4, rowwiseDT(x =, expr =, 1, quote(a + b)),
error = "In column 'expr', received an object of type 'language'.*wrap.*list")
test(2339.5, rowwiseDT(x =, plist =, 1, as.pairlist(list(123))),
error = "In column 'plist', received an object of type 'pairlist'.*wrap.*list")
Loading