Menu
Coddy logo textTech

Print and Format Methods

Part of the Object Oriented Programming section of Coddy's R journey. Lesson 4 of 57.

When a value is printed, R calls the function print(). Without anything special for the class, an S3 object prints as its list followed by the class attribute, which is hard to read:

m <- structure(list(amount = 9.5, currency = "EUR"), class = "money")
print(m)

Output:

$amount
[1] 9.5

$currency
[1] "EUR"

attr(,"class")
[1] "money"

A method is a function named generic.class. When print() gets an object of class money, it looks for print.money() and calls it instead. A print method writes with cat() and ends with invisible(x), so it returns the object without printing it a second time:

print.money <- function(x, ...) {
  cat("<money ", x$amount, " ", x$currency, ">\n", sep = "")
  invisible(x)
}
m <- structure(list(amount = 9.5, currency = "EUR"), class = "money")
print(m)
m

Output:

<money 9.5 EUR>
<money 9.5 EUR>

format() is the generic for turning a value into text. A format.money() method returns the text instead of printing it, so other code can put it into a sentence, and the print method can reuse it:

format.money <- function(x, ...) {
  sprintf("%.2f %s", x$amount, x$currency)
}
print.money <- function(x, ...) {
  cat("Money:", format(x), "\n")
  invisible(x)
}
m <- structure(list(amount = 9.5, currency = "EUR"), class = "money")
m
cat("You owe", format(m), "\n")

Output:

Money: 9.50 EUR 
You owe 9.50 EUR 

A method takes the same arguments as its generic. print() and format() are declared as function(x, ...), so their methods start with x, ... too. The ... accepts extra arguments such as digits that a caller may pass. Methods work wherever the generic is called, for example inside vapply():

format.money <- function(x, ...) sprintf("%.2f %s", x$amount, x$currency)
wallet <- list(
  structure(list(amount = 3, currency = "EUR"), class = "money"),
  structure(list(amount = 0.5, currency = "USD"), class = "money")
)
print(vapply(wallet, format, character(1)))

Output:

[1] "3.00 EUR" "0.50 USD"
challenge icon

Challenge

Easy

new_money() in Money.R is given. Add two methods to the same file:

  • format.money(x, ...) returns the amount with two decimal places and the currency: 9.50 EUR.
  • print.money(x, ...) prints <money 9.50 EUR> on its own line, using format(), and returns invisible(x).

The supplied code reads lines 9.5 EUR, prints every money object, then prints list: with all the formatted amounts joined by + .

Your code goes in Money.R. main.R holds the supplied input/output code and cannot be edited.

Try it yourself

source("Money.R")

# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
all <- list()
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  m <- new_money(as.numeric(p[1]), p[2])
  print(m)
  all[[length(all) + 1]] <- m
}
cat("list: ", paste(vapply(all, format, character(1)), collapse = " + "), "\n", sep = "")
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Online R compiler