Consider the following function foo
foo <- function(x) {
print(x)
message("test message")
}
I'd like to deliver the message after the result of the function so that if the result is long I don't have to scroll up to see if there was an important message (or change my max.print option). The issue is when I want to assign the result without printing the actual result.
Is there a way to print the result of the function, followed by the message, but also so that when I assign the result nothing at all is printed? Ideally, I'd like to avoid the use of print altogether.
The desired result without assignment is
> foo(5)
# [1] 5
# test message
The desired result with assignment is
> bar <- suppressMessages(foo(5))
> bar
# [1] 5
You can achieve this by creating a class for your foo function, e.g. bar, and then creating a print method for this new class.
For example:
foo <- function(x) {
class(x) <- c("bar", class(x))
x
}
print.bar <- function(x, message=TRUE, ...){
class(x) <- setdiff("bar", class(x))
NextMethod(x)
if(message) message("test message")
}
Now try it:
foo(5)
[1] 5
test message
With assignment:
x <- foo(5)
x
[1] 5
test message
Some other ways of interacting with the print method:
print(x, message=FALSE)
[1] 5
suppressMessages(print(x))
[1] 5
Related
Anyone know if the following can be achieved in R specifically S4
foo <- setClass("foo", contains = "matrix")
foo <- function(m = matrix(1:9, nrow = 3)) new("foo", m)
setMethod("dim", signature = "foo",
function(x) {
dd <- dim(x#.Data)
cat("foo dims: ")
return(dd)
}
)
# followed by
bar <- foo()
How or can it be achieved to distinguish between ...
dim(bar)
# which gives
foo dims: [1] 3 3
# and calling dim to assign the return value to a variable
# ie this call
bardims <- dim(bar)
# which does
foo dims:
# but I don't want it to produce any cat output to the console/screen
in the second case I would like to suppress the cat(....) part of the original "dim,foo-method".
I would not mind defining something like setMethod('<-dim', 'foo', function(.... but I guess that is not available?
Info: I am using R-4.0.5 here
It's generally not a great idea to use cat() to spit out messages in function. It gives users very little control over how they display and makes it very difficult to grab those values should they ever want them.
A possible alternative is to annotate the response with a custom class that will output a message only when print()-ed. Hence it will not show up during assignment because those results are returned invisibly.
Here's an S3 class that can help
annotate_value <- function(val, msg) {
attr(val, "message") <- msg
class(val) <- c("annotated", class(val))
val
}
print.annotated <- function(x) {
class(x) <- setdiff(class(x), "annotated")
cat(attr(x, "message"))
attr(x, "message") <- NULL
print(x)
}
And then you use it like
setMethod("dim", signature = "foo",
function(x) {
dd <- dim(x#.Data)
annotate_value(dd, "foo dims:")
}
)
Then when you run your code, you get the desired output
bar <- foo()
dim(bar)
# foo dims:[1] 3 3
bardims <- dim(bar)
#
It's complicated to explain my use case but I am working on a project that requires parsing text that may throw some errors. I would like to use tryCatch() so that as much of the script can run as possible and alert the user that some code failed. I can use a loop for this but I would like to know why this behaviour exists and if there is an apply function that does do the trick.
When I run the loop or use do.call() on this parsed object, I get just the expected single error mesage. When I use lapply() I get the same error message followed by the ouput of the assignments. I've tried throwing suppress functions around lapply() which, perhaps obviously, did not work. and I get similar output for sapply() and map(). Curious if someone can explain it to me.
test_text <- parse(text = "x <- pi; y <- x; z <- stop()")
eval_try <- function(x) {
tryCatch(
eval(x, envir = .GlobalEnv),
error = function(cond) message("there was an error"),
warning = function(cond) message("there was a warning")
)
}
for (i in seq_along(test_text)) {
eval_try(test_text[i])
}
#> there was an error
do.call("eval_try", list(test_text))
#> there was an error
lapply(test_text, eval_try)
# there was an error
# [[1]]
# [1] 3.141593
#
# [[2]]
# [1] 3.141593
#
# [[3]]
# NULL
The printing you see is the output of the lapply function. You can suppress it by assigning the result to a variable or if you really don't care about storing the output, use the below trick with invisible.
> myfun <- function(x) x
>
> lapply(1:3, FUN = myfun)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
> a <- lapply(1:3, FUN = myfun)
> invisible(lapply(1:3, FUN = myfun))
I want to define (<- and access the name of the left hand side argument :
*<- functions use internally an intermediate '*tmp*' variable. Is it still possible to get the name of x ?
`(<-` <- function(x,value){
print(deparse(substitute(value)))
print(deparse(substitute(x)))
print(match.call())
value
}
foo <- 0
(foo) <- 3
# [1] "3"
# [1] "*tmp*"
# `(<-`(x = `*tmp*`, value = 3)# [1] "3"
I want to get "foo" from inside the function.
I tried to hack it by using tracemem, i.e. calling sapply(ls(envir = parent.frame()),tracemem) and tracemem(x) inside of the functions but the address of foo, *temp* and x are all different.
I hacked it, though I didn't understand everything that I did.
I noticed pryr::address was giving a different kind of results than tracemem and tried it (I had to dig into the code to use pryr:::address2 because pryr::address doesn't have an environment argument).
Then I noticed that mixing the results from tracemem on x and pryr:::address2 on the rest of the objects there was a match (after basic reformatting) :
`(<-` <- function(x,value){
pf <- parent.frame()
all_addresses <- sapply(ls(pf), pryr:::address2, pf)
all_addresses <- all_addresses[names(all_addresses) != "*tmp*"]
all_addresses_short <- gsub("(^|<)[0x]*(.*?)(>|$)","\\2",all_addresses)
x_address <- tracemem(x)
x_address_short <- tolower(gsub("(^|<)[0x]*(.*?)(>|$)","\\2",x_address))
ind <- match(x_address_short, all_addresses_short)
x_name <- names(all_addresses)[ind]
message("all_addresses, using pryr::address2")
print(all_addresses)
print(all_addresses_short)
message("x_address, using tracemem")
print(x_address)
print(x_address_short)
message("x_name, matching substrings")
print(x_name)
value
}
The regex used in gsub calls tries to account for the address formats we get with different systems, I'm not 100% sure that it's general.
output:
foo <- 1
bar <- 2
(foo) <- foo
# all_addresses, using pryr::address2
# (<- bar foo
# "0x1433df50" "0x14937678" "0x14937708"
# (<- bar foo
# "1433df50" "14937678" "14937708"
# x_address, using tracemem
# [1] "<0000000014937708>"
# [1] "14937708"
# x_name, matching substrings
# [1] "foo"
It breaks if x is not a variable name, for example:
foo <- iris
(foo$species) <- 3
We could assume that if the address isn't found x is a list item, and then lookup its address among the addresses of the items of all the lists we have in the parent.frame (recursively), but I think that's enough ugly hacks for today.
1) If you are willing to change it so that the call is:
fooify[foo] <- 99
then we can do it like this where foo need not exist beforehand:
fooify <- structure(NA, class = "fooify")
"[<-.fooify" <- function(x, var, value) {
print(deparse(substitute(var)))
eval.parent(substitute(var <- value))
x
}
# test
if (exists("foo")) rm(foo)
fooify[foo] <- 99
## [1] "foo" <-- this comes from the print statement
foo
## [1] 99
2) := If using := is ok then:
`:=` <- function(lhs, rhs) {
print(deparse(substitute(lhs)))
eval.parent(substitute(lhs <- rhs))
}
# test
if (exists("foo")) rm(foo)
foo := 99
## [1] foo <-- this comes from print statement
foo
## [1] 99
I have defined an S3 class in R that needs its own print method. When I create a list of these objects and print it, R uses my print method for each element of the list, as it should.
I would like to have some control over how much the print method actually shows. Therefore, the print method for my class takes a few additional arguments. However, I have not found a way to make use of these arguments, when printing a list of objects.
To make this more clear, I give an example. The following code defines two objects of class test, a list that contains both objects and a print method for the class:
obj1 <- list(a = 3, b = 2)
class(obj1) <- "test"
obj2 <- list(a = 1, b = 5)
class(obj2) <- "test"
obj_list <- list(obj1, obj2)
print.test <- function(x, show_b = FALSE, ...) {
cat("a is", x$a, "\n")
if (show_b) cat("b is", x$b, "\n")
}
Printing a single object works as expected:
print(obj1)
## a is 3
print(obj2, show_b = TRUE)
## a is 1
## b is 5
When I print obj_list, my print method is used to print each object in the list:
print(obj_list)
## [[1]]
## a is 3
##
## [[2]]
## a is 1
But I would like to be able to tell print() to show b also in this situation. The following (a bit naive...) code does not produce the desired result:
print(obj_list, show_b = TRUE)
## [[1]]
## a is 3
##
## [[2]]
## a is 1
Is it possible to print obj_list and at the same time pass the argument show_b = TRUE to print.test()? How?
Following Josh's suggestion, I found a way to avoid print.default() being called when printing a list. I simply wrote a print method for lists, since none seems to exist as part of base R:
print.list <- function(x, ...) {
list_names <- names(x)
if (is.null(list_names)) list_names <- rep("", length(x))
print_listelement <- function(i) {
if (list_names[i]=="") {
cat("[[",i,"]]\n", sep="")
} else {
cat("$", list_names[i], "\n", sep="")
}
print(x[[i]], ...)
cat("\n")
}
invisible(lapply(seq_along(x), print_listelement))
}
The relevant part is that ... is passed on to print, when the objects inside the list are printed. So now, coming back to the example in the question, printing a list of test objects works together with show_b =TRUE:
print(obj_list, show_b = TRUE)
## [[1]]
## a is 3
## b is 2
##
## [[2]]
## a is 1
## b is 5
However, I am a bit uncomfortable with defining print.list myself. Chances are that it is not working as well as the built-in printing mechanism for lists.
Consider the following function foo
foo <- function(x) {
print(x)
message("test message")
}
I'd like to deliver the message after the result of the function so that if the result is long I don't have to scroll up to see if there was an important message (or change my max.print option). The issue is when I want to assign the result without printing the actual result.
Is there a way to print the result of the function, followed by the message, but also so that when I assign the result nothing at all is printed? Ideally, I'd like to avoid the use of print altogether.
The desired result without assignment is
> foo(5)
# [1] 5
# test message
The desired result with assignment is
> bar <- suppressMessages(foo(5))
> bar
# [1] 5
You can achieve this by creating a class for your foo function, e.g. bar, and then creating a print method for this new class.
For example:
foo <- function(x) {
class(x) <- c("bar", class(x))
x
}
print.bar <- function(x, message=TRUE, ...){
class(x) <- setdiff("bar", class(x))
NextMethod(x)
if(message) message("test message")
}
Now try it:
foo(5)
[1] 5
test message
With assignment:
x <- foo(5)
x
[1] 5
test message
Some other ways of interacting with the print method:
print(x, message=FALSE)
[1] 5
suppressMessages(print(x))
[1] 5