To provide an answer, from ?":=" :
Unlike <- for data.fram, (potentially large) LHS does not force the type (often small) of RHS. Instead, RHS is enforced as LHS if necessary. Where this suggests that double-precision values are forcibly bound to an integer column, a warning is given (regardless of whether fractional data is truncated). The motivation for this is efficiency. It’s best to choose column types and stick to them. Changing a column type is possible, but deliberately harder: providing a full column as RHS. . This RHS is then pushed into this column slot, and we call this syntax plonk or replace the column syntax if you prefer. To create a full-length vector of a new type , you, as a user, are more aware of what is happening, and you are really going to change the type of the column to the clearer readers of your code.
The motivation for all this is large tables (say 10 GB in RAM), of course. Not 1 or 2 row tables.
Simply put: if length (RHS) == nrow (DT), then RHS (and any type) will be laid in this column slot. Even if these lengths are 1. If the length (RHS) (DT) memory for the column (and its type) is stored in place, but RHS is forced and reused to replace elements (subsets) in this column.
If I need to change the type of a column in a large table, I write:
DT[, col := as.numeric(col)]
here as.numeric allocates a new vector, coherent col, into this new memory, which is then pushed into the column slot. It is as effective as possible. The reason plonk is length (RHS) == nrow (DT).
If you want to overwrite the column with another type containing a specific default value:
DT[, col := rep(21.5,nrow(DT))]
If col was an integer type before, then it will change to enter a numeric number containing 21.5 for each line. Otherwise, just DT[, col := 21.5] will lead to a warning about forcing 21.5 to 21 (if DT is not only 1 line!)