Skip to content

Unintuitive warning when referencing a value that doesn't exist during creation of new column in J #5648

Description

@D3SL

This is hard to describe in words so here is a simple reprex:

library(data.table)

foo<-data.table(col1=letters[1:10])

foo[,col3:=foo[col1=="a",]$col2]

##Returns the below error:

Warning message:
In `[.data.table`(foo, , `:=`(col3, foo[col1 == "a", ]$col2)) :
  Column 'col3' does not exist to remove

Because there is no col2 at all the value retrieved is NULL, which gets interpreted as trying to delete col3 rather than create it. In isolation this is a pretty obvious "duh" moment but in practice the reason this is going to happen in the first place is because someone's accidentally lost track of what order they've done things in.

I think a minor tweak to the error message would be a big help for anyone who's gotten themselves mixed up like that:

In `[.data.table`(foo, , `:=`(col3, foo[col1 == "a", ]$col2)) :
  value passed to `:=` is NULL but column 'col3' does not exist to remove
  If you are trying to create 'col3' check if value exists

Activity

  1. changed the title [-]Unintuitive error when referencing a value that doesn't exist during creation of new column in J[/-] [+]Unintuitive warning when referencing a value that doesn't exist during creation of new column in J[/+] on Dec 6, 2023
  2. ben-schwen commented on Dec 6, 2023

    @ben-schwen
    Member

    Since the warning is thrown in assign.c

    warning(_("Column '%s' does not exist to remove"),CHAR(STRING_ELT(newcolnames,newcolnum)));

    and used in several functions, e.g. set, let and :=, I would favor something like:

    Tried to assign NULL to column 'col3', but column 'col3' does not exist to remove.

  3. joshhwuu commented on Mar 20, 2024

    @joshhwuu
    Member

    As far as I understand, to fix this issue I would just have to change the warning in assign.c and change an old test as well as maybe add a new test. If so, I'll start a PR, or if there are any other changes required to make this change please advise. Thanks!

  4. MichaelChirico commented on Mar 20, 2024

    @MichaelChirico
    Member

    SGTM! If changing the message breaks a test, just fix that test, no need for a new one. If it doesn't break any test, please add a new one.

  5. joshhwuu commented on Mar 20, 2024

    @joshhwuu
    Member

    SGTM! If changing the message breaks a test, just fix that test, no need for a new one. If it doesn't break any test, please add a new one.

    RESOLVED

    Hmm... A test (316) failed but it's not failing as I expected. It sends a bunch of C code and ends with a segfault. Even if I change the failing test to have the proper expected output this error occurs. Are there any other places where the C code is tested where I might have to change a test?

    Error printout:

    Traceback:
    1: [.data.table(DT, , :=(c, NULL))
    2: DT[, :=(c, NULL)]
    3: doTryCatch(return(expr), name, parentenv, handler)
    4: tryCatchOne(expr, names, parentenv, handlers[[1L]])
    5: tryCatchList(expr, classes, parentenv, handlers)
    6: tryCatch(x, error = eHandler)
    7: withCallingHandlers(tryCatch(x, error = eHandler), warning = wHandler, message = mHandler)
    8: withCallingHandlers(expr, message = function(c) if (inherits(c, classes)) tryInvokeRestart("muffleMessage"))
    9: suppressMessages(withCallingHandlers(tryCatch(x, error = eHandler), warning = wHandler, message = mHandler))
    10: test(316, DT[, :=(c, NULL)], data.table(a = 20:22, b = 23:25), warning = "Tried to assign NULL to column 'c', but column 'c' does not exist to remove")
    11: eval(exprs[i], envir)
    12: eval(exprs[i], envir)
    13: sys.source(fn, envir = env)
    14: doTryCatch(return(expr), name, parentenv, handler)
    15: tryCatchOne(expr, names, parentenv, handlers[[1L]])
    16: tryCatchList(expr, classes, parentenv, handlers)
    17: tryCatch(expr, error = function(e) { call <- conditionCall(e) if (!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch))) call <- sys.call(-4L) dcall <- deparse(call, nlines = 1L) prefix <- paste("Error in", dcall, ": ") LONG <- 75L sm <- strsplit(conditionMessage(e), "\n")[[1L]] w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], type = "b") if (w > LONG) prefix <- paste0(prefix, "\n ") } else prefix <- "Error : " msg <- paste0(prefix, conditionMessage(e), "\n") .Internal(seterrmessage(msg[1L])) if (!silent && isTRUE(getOption("show.error.messages"))) { cat(msg, file = outFile) .Internal(printDeferredWarnings()) } invisible(structure(msg, class = "try-error", condition = e))})
    18: try(sys.source(fn, envir = env), silent = silent)
    19: test.data.table()
    An irrecoverable exception occurred. R is aborting now ...
    Segmentation fault

    I'll do some digging with the traceback for now.

    Found the issue... Little bit rusty with C, obvious change, just forgot to pass an extra column name even after adding an extra '%s' to the warning, so it would segfault. Sorry about that!

  6. MichaelChirico commented on Mar 20, 2024

    @MichaelChirico
    Member

    Found the issue... Little bit rusty with C, obvious change.

    Please describe the issue+solution in your edit! You never know when someone will stumble upon this comment in the future facing the same issue and you could wind up helping them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions