Changing how output is printed to the console
Asked Answered
B

1

10

When I print something directly to the console (type some variable name, such as x, rather than using the print function print(x)), I'd like it to print differently from the way that it normally prints. My idea is that the printing is done by some function. If that's the case, all I have to do is replace that function with a function of my own. However, I cannot figure out what the internal function that does the printing is.

Here is what I've tried so far.

.real_cat = cat
cat = function(x) .real_cat("*** cat ***", x, "\n")

cat(2345)
2345    # no

Printing to console is not done via cat. What about print?

.real_print = print
print = function(x) .real_cat("*** print ***", x, "\n")
print(2345)
2345    # no
"hello" # no
I(2345) # yes

Some classes, like AsIs, are printed to console via print, but others, like numeric or character are not. :-(

c("print.numeric", "print.character", "print.AsIs", "print.default") %in% methods("print")
# FALSE FALSE  TRUE  TRUE

Turns out print doesn't even have a separate method for printing numeric or character. Classes that have a print method are printed to the console using print. But classes that do not have a print method are not. Maybe they are printed using the default method?

print.default = function(x) .real_cat("*** print.default ***", x, "\n")
print.default(2345)
2345    # no
"hello" # no

No.

Maybe if I define a method for numeric, then it will print it using that method?

print.numeric = function(x) .real_cat("*** print.numeric ***", x, "\n")
print.numeric(2345)
2345    # no

print.character = function(x) .real_cat("*** print.character ***", x, "\n")
print.character("hello")
"hello" # no

Here is where I get stuck. I cannot figure out any way to have some basic classes like numeric or character print out directly to console using my own print function.

If this helps, here is the reason that I want to do this. I am writing a package to pretty-print values (https://github.com/prettyprint/prettyprint). Too many times, the output of an analysis is too hard to read, and therefore understand. Yes, you can make it pretty using format, signif, and round, and that's basically what the package already does for you in the background.

I would like to make pretty-printing as easy as possible for the user. At this point, they have to call my pretty-print function (pp(x)). I'd like to play around with giving the user the option to have the result pretty print automatically. (I would print both the non-pretty and the pretty version of the value, to make sure nothing is lost in the prettifying.)

Burleson answered 6/1, 2016 at 16:46 Comment(1)
A workaround with implicit classes would be to add a class attribute to the object and use a print method. E.g. print.numeric = function(x, ...) cat("numeric: \n", unclass(x), "\n"); xx = c(1, 2, 3); xx; attr(xx, "class") = "numeric"; xx. Or you could define your own "class" and its print method.Deferential
C
8

See this comment in the source:

 *  print.default()  ->  do_printdefault (with call tree below)
 *
 *  auto-printing   ->  PrintValueEnv
 *                      -> PrintValueRec
 *                      -> call print() for objects
 *  Note that auto-printing does not call print.default.
 *  PrintValue, R_PV are similar to auto-printing.
 *
 *  do_printdefault
 *  -> PrintDefaults
 *  -> CustomPrintValue
 *      -> PrintValueRec
 *          -> __ITSELF__  (recursion)
 *          -> PrintGenericVector   -> PrintValueRec  (recursion)
 *          -> printList            -> PrintValueRec  (recursion)
 *          -> printAttributes      -> PrintValueRec  (recursion)
 *          -> PrintExpression
 *          -> printVector      >>>>> ./printvector.c
 *          -> printNamedVector >>>>> ./printvector.c
 *          -> printMatrix      >>>>> ./printarray.c
 *          -> printArray       >>>>> ./printarray.c

Consequently, auto-printing can only involve method dispatch for explicit classes (with a class attribute, a.k.a. objects). I assume a numeric is handled by printVector. Please check this yourself.

I adds a class AsIs (creating an object) and then print.AsIs is dispatched:

class(I(3))
#[1] "AsIs"
Carpus answered 6/1, 2016 at 17:14 Comment(2)
I see here github.com/wch/r-source/blob/trunk/src/main/printvector.c a C function called printVector. How do I figure out which R function calls it?Burleson
This is all handled at the C level. Unless you are printing an object, auto-printing does not involve R functions.Carpus

© 2022 - 2024 — McMap. All rights reserved.