flowchart LR
U["User / Keyboard / File"] -->|input| R["R Program"]
R -->|output| C["Console"]
R -->|output| F["File"]
R -->|message| M["Messages / Warnings / Errors"]
style U fill:#e3f2fd,stroke:#1976D2
style R fill:#fff3e0,stroke:#F57C00
style C fill:#e8f5e9,stroke:#388E3C
style F fill:#e8f5e9,stroke:#388E3C
style M fill:#fbe9e7,stroke:#D84315
5 Input and Output Statements
This chapter introduces the two halves of every useful program: getting data in and sending results out. You will learn how R prints values to the console, the difference between implicit auto-printing and explicit print() and cat(), how to format output cleanly with paste(), paste0(), sprintf(), and format(), and the main functions for reading keyboard input or lines from a file. You will also meet the three message-signalling functions message(), warning(), and stop(), which tell the reader of your script whether something is fine, noteworthy, or broken. By the end of this chapter you will be able to write short programs that communicate clearly with their user.
5.1 How R Prints Values
When you type an expression at the R console and press Enter, R evaluates it and prints the result automatically. This behaviour is called auto-printing, and it only happens at the top level. Inside functions, loops, or scripts sourced with source(), auto-printing is suppressed; if you want output, you have to ask for it explicitly.
Auto-printing is the reason R feels so interactive; every expression you type shows its result. Inside a function or loop, however, only explicit print() or cat() calls produce output. Beginners often write a loop that “does nothing” when in fact it is computing values perfectly and simply not printing them.
5.2 print() vs cat()
R has two main functions for printing. They produce different output and are used in different situations.
| Function | What It Does | Typical Use |
|---|---|---|
print() |
Uses R’s full print method for the object; shows quotes on strings, type info on complex objects, and always starts on a new line. |
Showing results while debugging; inside scripts and functions. |
cat() |
Concatenates its arguments and writes them as plain text; no quotes, no [1] prefix, no automatic newline. |
Human-readable messages; composing output from several pieces. |
cat() for People, print() for Objects
If you are composing a readable message for a human (“Processed 42 rows”), use cat(). If you want to show a full R object as it is internally (a data frame, a list, a model object), use print(). The two are complementary, not competitors.
cat()
cat() does not add a trailing newline. If you omit \n, the next piece of output starts on the same line as the previous one, producing confusing output in loops.
5.3 Building Readable Strings: paste(), paste0(), sprintf(), format()
Most real output is not a single value but a sentence that mixes text and values. R provides four core functions for assembling such strings.
| Function | Purpose | Typical Call |
|---|---|---|
paste() |
Joins pieces with a separator (default a space). | paste("Total:", n) |
paste0() |
Same as paste() with sep = "" (no separator). |
paste0("file_", i, ".csv") |
sprintf() |
C-style format strings; precise control of width, decimals, padding. | sprintf("%.2f", pi) |
format() |
Turns a number into a nicely formatted string. | format(1234567, big.mark = ",") |
paste() and paste0() in Action
sprintf() for Precise Formatting
sprintf() is the tool of choice when you need fixed decimal places, padding, or aligned columns.
format() for Numbers
A quick rule of thumb: reach for paste() when you are joining ordinary strings, paste0() when building file names or URLs, sprintf() when decimals, widths, or padding matter, and format() when you need human-readable numbers with grouping marks or fixed precision. Mixing tools in one script is fine; consistency inside a single output statement is what matters.
5.4 Reading Input from the Keyboard
R is usually used in interactive mode, where you type expressions and see results. For programs that need to ask the user a question, R provides two core functions.
| Function | Purpose | Returns |
|---|---|---|
readline(prompt) |
Reads a single line of text from the console. | A character string. |
scan(what = ...) |
Reads one or more values separated by whitespace or a custom separator. | A vector of the requested type. |
readline() and scan() only work when R is attached to an interactive terminal. They cannot prompt the reader inside the webr-powered chunks you see in this book, because webr does not have a keyboard session to read from. The examples below show the exact code you would run in RStudio or the R console on your own machine.
readline() in RStudio or the R Console
# Type this in RStudio's console:
name <- readline(prompt = "What is your name? ")
cat("Hello,", name, "!\n")
When you run that script, R pauses at the prompt, waits for you to type a name and press Enter, and then continues. readline() always returns a character string, even if the user types a number.
Because readline() returns text, any numeric input must be converted explicitly with as.numeric() or as.integer().
# Interactive version (run in RStudio):
raw_age <- readline(prompt = "Enter your age: ")
age <- as.numeric(raw_age)
cat("In ten years you will be", age + 10, "\n")
If the user types something that cannot be converted, as.numeric() returns NA and emits a warning. Always validate the result before using it.
scan() for Multiple Values
scan() reads several values at once. It is handy when you want the user to enter, say, ten numbers separated by spaces.
# Interactive version (run in RStudio):
# Type numbers separated by spaces, then press Enter on an empty line:
nums <- scan(what = numeric())
mean(nums)
sum(nums)
Prompting the user with readline() is fine for demos and classroom exercises. For real analysis scripts, pass inputs as function arguments, command-line arguments, or values read from a configuration file. Scripts that pause for user input are hard to automate, test, or rerun.
5.5 Reading and Writing Files (a First Look)
In practice, most real R programs read data from files, not from the keyboard. Module 3 will cover the tidyverse functions read_csv() and read_excel() in depth. Here we meet the base-R equivalents you should at least recognise.
| Function | Reads or Writes | Produces |
|---|---|---|
readLines(path) |
Reads a text file line by line. | A character vector, one element per line. |
writeLines(x, path) |
Writes a character vector to a text file. | A file on disk. |
read.csv(path) |
Reads a comma-separated file. | A data frame. |
write.csv(x, path) |
Writes a data frame to a CSV. | A file on disk. |
Text files can differ in their encoding (UTF-8, Latin-1, etc.) and in how they end lines (LF on Linux and macOS, CRLF on Windows). When you write files that will be read by other tools, stick with UTF-8 and let R handle line endings with its defaults. If a file read returns strange characters, the encoding is almost always the culprit.
5.6 Signalling Messages, Warnings, and Errors
R separates “informational output” from three other kinds of signals. Each has a dedicated function and a different intent.
| Function | Meaning | Does It Stop Execution? |
|---|---|---|
message() |
Informational note. Shown in red in RStudio but not an error. | No. |
warning() |
Something is suspicious and worth noting; execution continues. | No. |
stop() |
A condition from which the program cannot reasonably continue. | Yes. Raises an error. |
stop()
Use stop() when continuing would produce a wrong answer rather than a slow or noisy one.
print() Where message() or warning() Is Correct
A common beginner habit is to scatter print("something happened") across a script. print() writes to standard output and cannot be suppressed separately from real results. message() writes to standard error, can be silenced with suppressMessages(), and signals intent much more clearly. Use the right tool.
5.7 A Mini End-to-End Example
The snippet below combines formatted output, a computed result, and the signalling functions in a single readable script.
Notice how each piece of output plays a different role: message() narrates progress, warning() flags a data quality issue, cat() plus sprintf() produce the main numeric report, and the vector itself is never auto-printed because every computation happens inside the top-level block but is explicitly consumed.
5.8 Summary
| Concept | Key Takeaway |
|---|---|
| Auto-printing | At the top level, R prints the value of any expression. Inside functions and loops it does not. |
print() vs cat() |
print() shows the R object in full; cat() writes human-readable text. |
paste() and paste0() |
Join strings with and without separators; both are vectorised. |
sprintf() |
C-style format strings; best for decimals, widths, and padding. |
format() |
Human-readable numbers with grouping marks and fixed precision. |
readline() and scan() |
Read keyboard input; only work in interactive R sessions, not in webr. |
| File I/O basics | readLines() / writeLines() for text, read.csv() / write.csv() for tabular data. |
| Signalling | message() for info, warning() for concerns, stop() for fatal errors. |
Clear I/O is what turns a script from “my private notebook” into “something someone else can run”. Adopt a simple habit: one message() at the start of a long computation, cat() plus sprintf() for the results, and warning() or stop() the moment something looks wrong. In the next chapter you will meet R’s basic data types and see how type casting lets you convert between them safely.