SECTION 1
Historical Context & Motivation
The R programming language grew out of the S language developed at Bell Laboratories in the 1970s, a time when statisticians needed a way to interactively explore data without the rigid compile-link-run cycle of Fortran or C. Ross Ihaka and Robert Gentleman created R in 1993 at the University of Auckland, deliberately designing it around the concept of an interactive console — a read-evaluate-print loop (REPL) that lets users type an expression, see its result immediately, and iterate rapidly. This philosophy of exploratory, conversational computing was a direct inheritance from S and set R apart from the batch-processing paradigm that dominated scientific computing at the time.
1976 • S Language at Bell Labs
1993 • R is Born
2000 • R 1.0 Released
2011 • RStudio Launches
2020s • Modern R Ecosystem
The central question that this lesson addresses is deceptively simple: when you write R code, how does it actually get executed? R provides two distinct but complementary modes — the interactive console for rapid experimentation and the .R script file for reproducible, versionable programs. Understanding when and how to use each mode is essential for any serious data science or statistical computing work.
SECTION 2
Core Principles & Definitions
Before diving into mechanics, it is important to establish the foundational concepts that underpin R's execution model. Whether you are typing directly into a console or running a saved script, R processes your code through the same interpreter — the difference lies in the source of input and the granularity of execution. The four core principles below define the framework you should use to reason about running R code.
The REPL (Read-Eval-Print Loop)
Script as Persistent Code
Shared Global Environment
source() as the Bridge
source() function reads a .R file and evaluates every expression sequentially in the current session. It is the programmatic equivalent of typing each line into the console.KEY TAKEAWAY
SECTION 3
Visual Explanation — The R Execution Pipeline
The following diagram illustrates how R code flows from the two input sources — the interactive console and a .R script file — through the R interpreter and into the global environment. Notice that both paths converge at the R interpreter, which is the unified engine that parses, evaluates, and produces output for every expression regardless of its origin.
As the diagram makes clear, the interpreter does not distinguish between code entered interactively and code fed in from a file. The critical distinction is one of workflow: the console processes one expression per iteration of the REPL loop, whereas source() feeds the interpreter a batch of expressions from the file, evaluating them top to bottom. Both paths ultimately write bindings into the same global environment, which is why you can define a variable in a script and then inspect it from the console prompt within the same session.
SECTION 4
How It Works — Console vs. Script Execution in Detail
The Interactive Console (REPL)
When you launch R — whether through a terminal, RGui, or the console pane in RStudio — the interpreter enters its REPL cycle. The prompt character > signals that R is in the Read phase, waiting for input. You type an expression such as sqrt(144) and press Enter. The interpreter evaluates the expression, prints the result ([1] 12), and loops back to the prompt. If your expression is incomplete — for instance, you typed 1 + and pressed Enter — R displays the continuation prompt +, indicating it is still in the Read phase and waiting for the rest of the expression.
Console Auto-Printing
invisible() or assign the result to a variable. For example, typing x <- 5 produces no visible output because the assignment operator returns the value invisibly.R Scripts (.R Files)
An R script is simply a plain-text file with a .R extension containing one or more R expressions. You create it in any text editor or the source pane of RStudio. There are three primary ways to execute the code within a script. First, from within an R session, you call source("my_script.R"), which reads the file and evaluates every expression sequentially. Second, in RStudio, you can place your cursor on a line (or select a block) and press Ctrl+Enter (Cmd+Enter on macOS) to send that code to the console for evaluation — a hybrid approach that combines the convenience of a script with the immediacy of the console. Third, from a system shell, you can invoke Rscript my_script.R to run the file in a non-interactive, batch mode, which is critical for automated pipelines and cron jobs.
Auto-Printing Difference in Scripts
source(), bare expressions do not auto-print by default. If your script contains just 42 on a line, nothing appears unless you wrap it in print(42) or call source("file.R", echo = TRUE). This is one of the most common surprises for beginners transitioning from console to script.The source() Function in Depth
The source() function accepts several useful parameters. The echo argument, when set to TRUE, causes each expression to be printed to the console before evaluation, mimicking interactive behavior. The local argument, when set to TRUE, evaluates the script in a local environment rather than the global one — analogous to function-scoped execution, which prevents the script from polluting the caller's namespace. The encoding argument lets you specify character encoding (commonly "UTF-8"), ensuring cross-platform compatibility.
SECTION 5
Detailed Breakdown — Workflow Patterns and Execution Modes
In practice, R programmers do not exclusively use the console or exclusively use scripts — they follow structured workflow patterns that leverage both execution modes at different stages of a project. The diagram below maps these patterns along the lifecycle of a typical data analysis.
The most productive R workflows treat the console and script as complementary tools rather than alternatives. A typical session begins with exploratory data analysis (EDA) at the console: loading a dataset, inspecting its structure with str(), generating quick plots, and testing transformations. Once a sequence of commands proves useful, the analyst migrates it into a .R script to ensure reproducibility. The script can then be run end-to-end via source(), or individual sections can be sent to the console for targeted debugging. Finally, for deployment on servers or CI/CD pipelines, the script is invoked via Rscript in a fully non-interactive batch mode.
- Ctrl+Enter (RStudio) — sends the current line or selection from the script editor to the console for immediate evaluation
- Ctrl+Shift+Enter (RStudio) — runs the entire script from top to bottom in the console, equivalent to source()
- Ctrl+Shift+S (RStudio) — sources the current script file (same as typing source("file.R") in the console)
SECTION 6
Worked Example — From Console Exploration to .R Script
This worked example walks through a realistic scenario: computing the body mass index (BMI) for a small dataset, starting with interactive exploration and finishing with a reproducible script.
Console to Script: BMI Computation
- 1
Step 1 — Explore Interactively in the Console
Open R or RStudio. At the console prompt, create two vectors for height (in meters) and weight (in kilograms):> height <- c(1.75, 1.60, 1.82, 1.68)> weight <- c(70, 55, 90, 65)These assignment statements return invisibly, so no output appears. Verify by typing> height, which auto-prints the vector.[1] 1.75 1.60 1.82 1.68 - 2
Step 2 — Compute BMI at the Console
BMI is weight divided by height squared. R's vectorized operations make this a single expression:> bmi <- weight / height^2Inspect the result by typing> bmiat the prompt.[1] 22.857 21.484 27.170 23.030 - 3
Step 3 — Test a Summary at the Console
Use> round(mean(bmi), 2)to compute the group average BMI. The console auto-prints the scalar result immediately.[1] 23.64 - 4
Step 4 — Codify into a .R Script
Open a new file in RStudio (File → New File → R Script) or any text editor. Save it asbmi_analysis.R. Write the following content:# bmi_analysis.R — Compute and report BMI height <- c(1.75, 1.60, 1.82, 1.68) weight <- c(70, 55, 90, 65) bmi <- weight / height^2 cat("Individual BMIs:", round(bmi, 2), "\n") cat("Mean BMI:", round(mean(bmi), 2), "\n")Note the use ofcat()instead of relying on auto-printing, sincesource()does not auto-print bare expressions. - 5
Step 5 — Run the Script via source()
Back in the console, execute:> source("bmi_analysis.R")All five lines are evaluated sequentially. Thecat()calls produce console output. Alternatively, from a system terminal:$ Rscript bmi_analysis.RThis runs R non-interactively and exits when the script completes.Individual BMIs: 22.86 21.48 27.17 23.03 Mean BMI: 23.64
SECTION 7
Console vs. Script — Strengths and Limitations
Choosing between the console and a script is not a binary decision but a matter of context. The table below summarizes the trade-offs across several important dimensions that affect everyday R programming.
| Dimension | Console (REPL) | .R Script |
|---|---|---|
| Reproducibility | Low — history is session-bound and hard to reconstruct | High — the entire analysis is captured in a file |
| Iteration Speed | Very fast — immediate feedback per expression | Moderate — requires re-sourcing or selective execution |
| Version Control | Not practical — console input is ephemeral | Excellent — Git tracks every change to the .R file |
| Auto-Printing | Yes — bare expressions auto-print results | No — must use print() or cat() explicitly |
| Collaboration | Difficult — no shareable artifact | Easy — scripts can be shared, emailed, or committed to a repository |
| Automation | Not possible — requires human at the keyboard | Fully supported — Rscript enables cron jobs and CI/CD |
| Best For | EDA, debugging, learning, quick calculations | Production code, reports, automated pipelines, team projects |
Feature comparison between the interactive console and .R script execution
KEY TAKEAWAY
SECTION 8
Connection to Advanced Execution Paradigms
The console and .R script form the foundation of R's execution model, but modern R extends these primitives into richer paradigms. Understanding the base layer is essential before moving to these more powerful tools, each of which builds directly on the concepts covered in this lesson.
| Paradigm | Based On | Key Enhancement |
|---|---|---|
| R Markdown (.Rmd) | R code chunks embedded in Markdown — each chunk is effectively a mini-script | Literate programming: code, output, and narrative woven into a single document (HTML, PDF, Word) |
| Quarto (.qmd) | Next-generation R Markdown supporting R, Python, Julia, and Observable JS | Cross-language execution with standardized YAML metadata and built-in publishing |
| Shiny Apps | R scripts organized into ui.R, server.R, or a single app.R | Reactive execution: R code re-runs automatically when user inputs change in a web interface |
| R Packages | Collections of .R files in the R/ directory, loaded via library() | Namespaced environments, documentation, testing, and distribution via CRAN |
| targets / make pipelines | DAG-based orchestration of R scripts and functions | Dependency-aware caching: only re-runs steps whose inputs have changed |
Advanced R execution paradigms that build on the console and .R script foundation
Each of these paradigms can be understood as a structured way to organize and trigger the same fundamental operation you have been learning: sending R expressions to the interpreter for evaluation. R Markdown, for instance, extracts code chunks from a document, source()-like evaluates them in order, captures the output, and knits it back into the document. Shiny merely adds a reactive event loop that re-evaluates selected expressions when the user interface signals a change. Mastering the console and script workflow now gives you the mental model needed to reason about all of these tools confidently.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
42 at the R console and having the line 42 inside a .R script that is executed with source("file.R"). Why does this difference exist, and how would you force the script to produce output?Show answer
print() on the value of each evaluated expression as part of its read-eval-print loop. When source() processes a file, it evaluates each expression but does not invoke the print step unless echo = TRUE or print.eval = TRUE is passed. This design prevents scripts from flooding the console with unwanted output during batch execution. To force output, wrap the expression in print(42) or cat(42, "\n") within the script.Question 2: BASIC
greet.R that: (a) assigns your name to a variable name, (b) creates a greeting string using paste0(), and (c) prints it to the console. Then show the exact command to run this script from within an R session.Show answer
name <- "Alice" on line 1, greeting <- paste0("Hello, ", name, "!") on line 2, and print(greeting) on line 3. To execute it from within R, type source("greet.R") at the console prompt. The print() call on line 3 is necessary because source() does not auto-print. The output would be [1] "Hello, Alice!".Question 3: INTERMEDIATE
helpers.R that defines a function zscore <- function(x) (x - mean(x)) / sd(x). You want to use this function in another script analysis.R. Explain how to set this up, discuss what happens if you call source("helpers.R", local = TRUE) inside analysis.R, and describe the scoping implications.Show answer
analysis.R, include source("helpers.R") to load the function definition into the global environment. If you instead use local = TRUE, the function zscore is defined in a temporary local environment that is discarded after source() returns — meaning zscore will not be available in the calling scope. Use local = FALSE (the default) when you need the definitions to persist. The local = TRUE option is useful when a script has side effects you want to contain without polluting the global namespace.Question 4: APPLIED
etl_pipeline.R reads from a database, transforms data, and writes a CSV. Write the cron job entry that runs this script every day at 2:00 AM, and explain the differences between using Rscript versus R CMD BATCH for this use case.Show answer
0 2 * * * /usr/bin/Rscript /home/user/etl_pipeline.R >> /var/log/etl.log 2>&1. Rscript is the modern, preferred approach for non-interactive execution: it starts R without loading a user profile or saving the workspace on exit (no .Rdata file), sends stdout/stderr to the terminal, and returns a meaningful exit code. R CMD BATCH is an older mechanism that creates a .Rout transcript file and, by default, saves the workspace image. For automated pipelines, Rscript is strongly preferred because it integrates cleanly with standard Unix process management conventions.Question 5: CRITICAL THINKING
Show answer
str(), test edge cases of a function, or query help pages with ?function_name without cluttering the script with diagnostic code. Debugging is another critical use case: after a script throws an error, you drop into the console (or use browser()) to inspect the runtime state, test fixes, and then apply them to the script. The console also supports tab-completion for exploring unfamiliar APIs and interactive plotting for visual hypothesis generation. The mature workflow is not console-only or script-only but an iterative cycle: hypothesize and test in the console, then codify validated logic into scripts. Eliminating the console would be analogous to removing the REPL from a Lisp or Python workflow — it would cripple the exploratory phase that precedes good engineering.SUMMARY
Lesson Summary
Summary
R provides two fundamental code execution modes. The interactive console implements a REPL (read-eval-print loop) that processes one expression at a time, automatically prints results, and provides an immediate feedback loop ideal for exploration, debugging, and learning. The .R script file stores a sequence of expressions in a plain-text file that can be executed via source() within a session, sent line-by-line with Ctrl+Enter in RStudio, or run non-interactively via Rscript for batch automation.
Both modes feed expressions to the same R interpreter and share the same global environment. The key behavioral difference is auto-printing: the console prints results automatically while scripts require explicit print() or cat() calls. The optimal workflow iterates between console-based exploration and script-based codification — explore, codify, test, and automate — forming the foundation upon which advanced paradigms like R Markdown, Quarto, Shiny, and package development are built.