askYesNo no found function

I am trying to eliminate some columns through askYesNo but the function at the end does not execute me when the value is true, can you help me

emp.data <- data.frame(
  emp_id = c (1:5), 
  emp_name = c("Rick","Dan","Michelle","Ryan","Gary"),
  salary = c(623.3,515.2,611.0,729.0,843.25), 
  
  start_date = as.Date(c("2012-01-01", "2013-09-23", "2014-11-15", "2014-05-11",
                         "2015-03-27")),
  stringsAsFactors = FALSE
)


date_Na = list("emp_name")

Delete<- function(){ 
  
  Answer = askYesNo("you want to remove the columns")
  
  if (Answer  == "TRUE" ) emp.data <- emp.data[ ,-which(names(emp.data) %in% date_Na)]
  else print("Columns are not deleted")
}  

when executing the function it does not delete the emp_name column


Solution 1:

Up front: the issue is due to Invisibility.

A few things:

  1. The return value from askYesNo is a logical, so == "TRUE" is just overkill and doing silent coercion from a logical to character. You can just do if (Answer) ....

  2. Since the result can be NA (if "canceled"), then your conditional will fail if the user cancels. In that case, you really should be explicitly checking for NA values as well with if (!is.na(Answer) && Answer) ....

  3. Regardless, your function is returning value, it's just doing it invisibly. You can do one of three things:

    1. If you want to see it and not change the default "invisible" behavior, wrap it in (..):

      Delete()
      # you want to remove the columns (Yes/no/cancel) Yes
      
      (Delete())
      # you want to remove the columns (Yes/no/cancel) Yes
      #   emp_id salary start_date
      # 1      1 623.30 2012-01-01
      # 2      2 515.20 2013-09-23
      # 3      3 611.00 2014-11-15
      # 4      4 729.00 2014-05-11
      # 5      5 843.25 2015-03-27
      

      The (..) forces it to be visible.

    2. You can assign it to a variable and look at that variable itself,

      ret <- Delete()
      # you want to remove the columns (Yes/no/cancel) yes
      ret
      #   emp_id salary start_date
      # 1      1 623.30 2012-01-01
      # 2      2 515.20 2013-09-23
      # 3      3 611.00 2014-11-15
      # 4      4 729.00 2014-05-11
      # 5      5 843.25 2015-03-27
      
    3. You can explicitly return thedata (see function definitions below) from the function, in which case it will "never" be invisible.

      Delete()
      # you want to remove the columns (Yes/no/cancel) yes
      #   emp_id salary start_date
      # 1      1 623.30 2012-01-01
      # 2      2 515.20 2013-09-23
      # 3      3 611.00 2014-11-15
      # 4      4 729.00 2014-05-11
      # 5      5 843.25 2015-03-27
      
  4. BTW, if the user selects "no", the data is not returned at all, even invisibly. Why is this? Because your function does not explicitly return the data. When there is no explicit return(.) statement, then a function returns the value of the last expression evaluated. In the case of a "no", this is print, which is just going to print and then return the (same) string:

    (Delete())
    # you want to remove the columns (Yes/no/cancel) no
    # [1] "Columns are not deleted"   # this is printed from the function
    # [1] "Columns are not deleted"   # this is the return value from print, ergo the return value from the function
    

    (To see that print returns its string, use my (..) trick on print, which normally returns the string invisibly. print("hello") versus (print("hello")).)

  5. Defensively, however, if no columns are found from date_NA, then your function is going to return nothing, which is counter-intuitive, it should return everything. For demonstration,

    date_Na <- "FOO" # obviously not going to be found here
    Delete()
    # you want to remove the columns (Yes/no/cancel) yes
    # data frame with 0 columns and 5 rows
    

    The fix is to not use which: negation of %in% will return a logical vector and always work here.

    Delete <- function() { 
      Answer = askYesNo("you want to remove the columns")
      if (!is.na(Answer) && Answer) emp.data <- emp.data[ ,!names(emp.data) %in% date_Na]
      else print("Columns are not deleted")
      emp.data # return(emp.data) is what we "think" here, but 'return' is rarely necessary/beneficial
    }  
    Delete()
    # you want to remove the columns (Yes/no/cancel) yes
    #   emp_id emp_name salary start_date
    # 1      1     Rick 623.30 2012-01-01
    # 2      2      Dan 515.20 2013-09-23
    # 3      3 Michelle 611.00 2014-11-15
    # 4      4     Ryan 729.00 2014-05-11
    # 5      5     Gary 843.25 2015-03-27
    
  6. Perhaps a tangent, but ... it's generally a bad idea to have a function rely on the presence of variables outside of its scope. You can always assign defaults to function arguments. I would recommend a function definition more along the lines of this, where the user can override the data:

    Delete <- function(dat = emp.data, date_na = "emp_name") { 
      Answer = askYesNo("you want to remove the columns")
      if (is.na(Answer) && Answer) dat <- dat[ ,!names(dat) %in% date_na]
      else print("Columns are not deleted")
      dat # return(dat) is what we "think" here, but 'return' is rarely necessary/beneficial
    }
    

    This may be more OCD, but it starts down the road of some "good practices" in defensive programming.