Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if the output of a function is assigned to an object in R

Tags:

r

Inside an R function, is it possible to detect if the user has assigned the output to an object?

For example, I would like to print on console some information only if the output is not assigned to an object, I am looking for something like this

fun <- function(a){
           b <- a^2
           if(!<OUTPUT ASSIGNED>) cat('a squared is ', b)
           return(invisible(b))
} 

So that the result on console would be different whether the function output is assigned or not, e.g:

> fun(5)
> a squared is 25
>
> out <- fun(5)
>
>
like image 879
Roberto Avatar asked Feb 17 '19 09:02

Roberto


3 Answers

Not sure if I've completely thought this one through, but this seems to work for the example you've given. (Note it's important to use = or assign or .Primitive("<-") inside the fun you'd like to subject to this treatment.)

fun <- function(a){
  b = a^2   # can't use <- here
  if (!identical(Sys.getenv("R_IS_ASSIGNING"), "true")) cat('a squared is ', b)
  return(invisible(b))
}

`<-` <- function(a, b) {
  Sys.setenv("R_IS_ASSIGNING" = "true")
  eval.parent(substitute(.Primitive("<-")(a, b)))
  Sys.unsetenv("R_IS_ASSIGNING")
}

fun(5)
#> a squared is  25
out <- fun(6)
out
#> [1] 36

Created on 2019-02-17 by the reprex package (v0.2.1)

like image 164
Hugh Avatar answered Oct 06 '22 07:10

Hugh


If I correctly understand what do you need it's better to use custom print method:

print.squared_value = function(x, ...){
    cat('a squared is', x, "\n")
    x
}

fun = function(a){
    b = a^2
    class(b) = union("squared_value", class(b))
    b
}

fun(2)
# a squared is 4

UPDATE:

fun = function(a){
    b = a^2
    invisible(b)
}


h = taskCallbackManager()
# add a callback
h$add(function(expr, value, ok, visible) {
    # if it was a call 'fun' without assinment
    if(is.call(expr) && identical(expr[[1]], quote(fun))){
        cat('a squared is', value, "\n")    
    }

    return(TRUE)
}, name = "simpleHandler")

fun(2)
# a squared is 4
b = fun(2)
b
# [1] 4

# remove handler
removeTaskCallback("R-taskCallbackManager")
like image 30
Gregory Demin Avatar answered Oct 06 '22 07:10

Gregory Demin


If I understood well, this could do the trick:

fun <- function(a){
           b <- a^2
           if(sum(unlist(lapply(lapply(ls(envir = .GlobalEnv), get), function(x){ identical(x,a^2)})))==0) cat('a squared is ', b)
           return(invisible(b))
} 

So:

ls(envir=.GlobalEnv) will return all objects in your global environment

lapply(ls(envir = .GlobalEnv), get): will return a list with the content of all objects in your global environment

lapply(lapply(ls(envir = .GlobalEnv), get), function(x){ identical(x,a^2)}): will return a logical list checking if the content of any of all objects in your global environment is identical to the output of your function

sum(unlist(lapply(lapply(ls(envir = .GlobalEnv), get), function(x){ identical(x,a^2)})))==0 if none of the content of any of all objects is identical to hte ouput of your function, then... cat!

I hope this helps you! Best!

like image 20
LocoGris Avatar answered Oct 06 '22 09:10

LocoGris