9

There seems to be a minor difference between data.tabel's assignment by reference := in the standard to the functinal form.

Standard form coerces RHS to vector, the functional form does not. A detail, but not documented as I believe.

library(data.table)
dt <- data.table(a = c('a','b','c'))
v <- c('A','B','C')
l <- list(v)

all.equal(copy(dt)[, new := v], copy(dt)[, `:=` (new = v)])
# [1] TRUE
all.equal(copy(dt)[, new := l], copy(dt)[, `:=` (new = l)])
# [1] "Datasets have different column modes. First 3: new(character!=list)"

copy(dt)[, new := l][]
#    a new
# 1: a   A
# 2: b   B
# 3: c   C

copy(dt)[, `:=` (new = l)][]
#    a   new
# 1: a A,B,C
# 2: b A,B,C
# 3: c A,B,C

This is a major Edit of how I asked this question originally.

Machavity
  • 30,841
  • 27
  • 92
  • 100
rluech
  • 606
  • 4
  • 15
  • 1
    Fwiw, you should use `X[Y, on=, col]` not `X[Y, on=][, col]` since the latter creates the join for all columns before selecting the single column needed. – Frank May 19 '17 at 10:48
  • Absolutely, thanks for the hint. Join inherited scope. I have edited the question to make the issue clearer. – rluech May 24 '17 at 11:19
  • 1
    I think this is happening because the RHS should always be a list of column vectors, but in `LHS := RHS`, for convenience it is okay to write it without `list`. The doc says "As long as j returns a list, each element of the list becomes a column in the resulting data.table. This is the default *enhanced* mode." ... but I'm not sure what "enhanced mode" refers to here. – Frank May 24 '17 at 12:04

1 Answers1

2

This is very good question that touches design decision about := operator.

For simple calls using := as an operator, like col := val, we decided to wrap val into a list automatically. This decision was made to make it more convenient for users to assign single column.

When you are using function call form, ":="(col = val) we are not wrapping val into list anymore. It is extended form already. := behaves as an alias to list but updating in-place. You can always check what will be the updated column by changing := into list (or .) like .(col = val).

Not that even when using := as an operator, you still have to provide RHS as list of you are creating 2+ columns, c("col1","col2") := list(val1, val2).

jangorecki
  • 16,384
  • 4
  • 79
  • 160