JavaScript Deep Dive — 04 · Modules, Packaging & TypeScript at Scale
Most "it works on my machine" bugs in modern JavaScript are module bugs. A library works from but not from . The same class fails an check against itself. The bundle ships a 400 KB date library for one helper. The type checker is happy while Node throws . This post goes through the module systems as the spec and Node define them, then how a package tells each consumer which file to load, what bundlers do with the result, and how TypeScript fits in when the codebase has hundreds of packages. It is written against Node 24 LTS, Vite 8, TypeScript 6.0 and 7.0.
> Series map: 00 Engines & Runtime → 01 Event Loop & Concurrency → 02 Objects, Prototypes & Metaprogramming → 03 Async Engineering → 04 Modules, Packaging & TypeScript at Scale (this post) → 05 Performance, Memory & Production Debugging (future: see the extensions table in 05).
Learning Outcome
- Explain ESM's three phases, live bindings, hoisting, cycles and top-level , and contrast them with CommonJS.- Predict what Node does for every mix of , , , and , including .- Write a / map with conditions in the right order, and check it with tools.- Recognise the dual-package hazard and choose a publishing strategy that avoids it.- Use import maps, and know what tree-shaking needs from your code (, pure annotations, no barrels in hot paths).- Describe the 2026 bundler landscape: Vite 8 on Rolldown and Oxc, esbuild, Rollup, and where each fits.- Configure TypeScript for a large codebase: strict flags, , declaration output, project references, and Node's built-in type stripping.- Read and write core type-level code: generics with constraints, conditional types with , mapped types with key remapping.
Chapter 1 — ES modules as the spec defines them
Terminology
- Module record — the engine's parsed representation of one module: its imports, exports and code.- Linking — connecting every import to the exporting module's binding, before any code runs.- Binding — a named slot in a module's environment. An import is a read-only view of the exporter's binding, not a copy of its value.- Module namespace object — the object you get from or : a frozen-shaped, live view of all exports.- TDZ (temporal dead zone) — the window between a // binding being created and being initialised. Reading it throws .
Three phases
A module graph is loaded in three separate phases:
1. Construction — fetch and parse every module reachable through static / declarations. The whole graph is known before anything runs. This is why static imports must be at top level with string-literal specifiers.2. Linking — create each module's bindings and wire imports to exports. A missing named export is a at this point, before any code runs.3. Evaluation — run each module body once, in post-order depth-first order: dependencies before dependents, siblings in source order. If imports and then , and both import , the bodies run in the order , , , .
Consequences:
- Imports are hoisted. An on line 50 is linked before line 1 runs.- Each module runs once per realm, keyed by its resolved URL. is a different module from .- Modules are strict mode, top-level is , and top-level declarations are module-scoped, not global.
Live bindings
CommonJS has no bindings. returns whatever was, and destructuring copies the values:
Cycles
Both systems allow cycles and both can surprise you, in different ways.
| | ESM | CommonJS ||---|---|---|| Module in the cycle not finished yet | Its bindings exist but are uninitialised: reading a // export throws (TDZ). declarations are hoisted and usable. | returns the partial object as it is at that moment. Missing properties are , and no error is raised. || Typical symptom | | far from the cause || Fix | Break the cycle, move shared code into a third module, or only use cyclic imports inside functions called later | Same, or inside the function that needs it |
> Trick: or lists cycles. Run one in CI. Cycles through barrel files ( re-exporting a whole folder) are the most common source in large apps.
Top-level await
A module that uses top-level (ES2022) makes its evaluation asynchronous. Every module that imports it, directly or indirectly, waits for it. Siblings that do not depend on it can still evaluate. The cost is easy to miss: one in a shared delays the start of every module above it in the graph.
Use it for real start-up dependencies (config, WASM instantiation, a connection pool) in applications. Avoid it in libraries. It forces an async graph on every consumer, and in Node it makes the module impossible to (Chapter 2).
Dynamic import and
works in both module systems. It returns a promise of the namespace object and is how code-splitting points are expressed. is the module's own URL. Node adds and (Node 20.11+), which replace / in ESM, and .
Chapter 2 — ESM and CommonJS in Node
How Node decides a file's format
| File | Format ||---|---|| | ESM, always || | CommonJS, always || with nearest | ESM || with | CommonJS || with no | CommonJS, unless the file contains ESM syntax, in which case Node re-parses it as ESM ("syntax detection") |
> Watch out: syntax detection costs a second parse and hides mistakes. Always set explicitly in every you own.
ESM importing CommonJS
always works: the default export is . Named imports () work only if Node's static analyser () can see the names in the source, for example as or . Exports computed at runtime are invisible to it, so you get a at link time.
CommonJS requiring ESM:
For years of an ES module threw , and that single error drove a decade of dual-publishing. That has changed:
| Node version | status ||---|---|| 22.0, 20.17 | Added behind || 23.0, 22.12, 20.19 | Enabled by default (no flag) || 23.5, 22.13, 20.19 | No experimental warning by default || 25.4 | No longer experimental |
Rules:
- The ES module graph must be fully synchronous: no top-level anywhere in it. Otherwise you get .- returns the namespace object. If it has a default export, the namespace also includes , so transpiled CJS consumers see the default export correctly.- An ES module can choose what returns with .- Detect it with . Disable it with .
With Node 20 now past end-of-life and every supported Node line able to synchronous ESM, publishing ESM-only is a reasonable default for new libraries. It still depends on your support matrix, as Chapter 4 explains.
Chapter 3 — : , and conditions
Terminology
- Entry point — the file a bare specifier () or subpath () resolves to.- — the public map from subpaths to files. Once present, only listed subpaths can be imported. Anything else throws .- Condition — a key inside an entry that matches the environment (, , , , , …).- Subpath pattern — a in both key and target, e.g. .- — a private map for the package's own code. Keys must start with .
A realistic map
Object key order is the priority order. The resolver walks the keys in the order written and takes the first one that is in its set of active conditions. The order of the active conditions does not matter. Node documents its built-in conditions from most to least specific: , , , , , . must come last, and must come first.
| Consumer | Active conditions (main ones) | Resolves to ||---|---|---|| TypeScript ( / ) | , plus or | || Vite 8, client build | , , \|, plus | || Node, | , , , | || Node, | , , , | |
matches for and in Node versions that support . It exists so that a package can point both at one ESM file, which removes the dual-package hazard described next. Custom conditions come from (or ), and bundlers have their own setting ( in Vite).
> Common pitfall: putting after . TypeScript stops at the first matching key, which is , and then looks for next to the JS file by extension. That may or may not exist. Run and before every release. Between them they catch most mistakes.
Subpath imports
replaces fragile paths and tsconfig aliases with something Node, bundlers and TypeScript all understand natively. Entries can have conditions too, e.g. a and a implementation of .
Chapter 4 — Dual packages and the hazard
A dual package ships both an ESM build and a CJS build. The dual-package hazard: in one process, some code s the package and some s it. Node then loads both files, creating two module instances with two copies of every piece of module state.
Symptoms:
- is for an error thrown by "the same" class.- A singleton registry, cache or plugin list exists twice, and registrations go missing.- Two copies of a framework runtime complain that hooks or context are being called from a different copy.
Strategies, from most to least preferred in 2026:
| Strategy | How | Trade-off ||---|---|---|| ESM-only | Ship ESM; CJS consumers use | Needs Node 20.19+ / 22.12+ for CJS consumers; no top-level in the graph || One ESM file for everyone | and point at the ESM file, points at a fallback only for old Node | Old Node still gets two copies, which is acceptable if old Node never mixes the two || CJS core + thin ESM wrapper | does | One instance of state; ESM consumers lose tree-shaking || Stateless dual build | Two full builds, no module-level state, no across the API | Works only if you can keep that discipline forever |
> Trick: use on for state that must be a true singleton, and a brand check ( or an function) instead of . This survives two copies and even two different versions in .
Chapter 5 — Modules in the browser
Browsers load ESM natively: is deferred by default, runs in strict mode, and is fetched with CORS. What they cannot do by themselves is resolve bare specifiers like . Import maps (Baseline since 2023) fill that gap:
Import maps are enough for small apps, internal tools, and micro-frontends that share one copy of a framework. For large apps, bundling still wins: fewer round trips, dead-code removal, minification, and hashed file names that can be cached for a long time. fixes the discovery waterfall (A imports B imports C) only when you list the deep modules yourself.
Chapter 6 — Tree-shaking and bundlers
What tree-shaking needs
Tree-shaking removes exports nobody imports. It relies on ESM being static: the bundler can see every import and export without running code. It fails when:
- Code is CommonJS. is a runtime object, so bundlers must keep all of it (with a few heuristics).- A module might have side effects. A top-level , a with static initialisers, or must be kept even if nothing is imported from the module. The bundler has to assume that side effects exist unless told otherwise.- The code uses namespace objects dynamically. with a computed key keeps the whole namespace.
Tell the bundler what is safe:
claims that no file in the package does anything on import, so the bundler may skip whole modules. Lying here breaks CSS imports and polyfills silently.
> Watch out: barrel files ( that re-exports 300 components) are cheap in production builds with correct , but expensive everywhere else. The dev server, test runner and type checker all load and transform every re-exported module. Large codebases import from the leaf module (), and expose subpath to allow it.
The 2026 landscape
| Tool | What it is | Where it fits ||---|---|---|| Vite 8 (March 2026) | Dev server + build, now on Rolldown (Rust bundler) and Oxc (Rust parser/transformer/minifier) | Default for SPAs and many frameworks. Needs Node 20.19+ / 22.12+. esbuild is no longer a direct dependency || Rolldown | Rust bundler with a Rollup-compatible plugin API | Under Vite, or on its own for libraries || Rollup | The original ESM-first bundler, JS | Library builds; its plugin API is the ecosystem standard || esbuild | Go bundler/transpiler, still 0.x, extremely fast | Scripts, CLIs, Lambda bundles, and as a transformer inside other tools || webpack / Rspack | webpack is the mature JS original; Rspack is a Rust reimplementation with a compatible API | Large legacy configs; Module Federation || Turbopack | Next.js's Rust bundler | Next.js only; see the Next.js Deep Dive series |
Before Vite 8, the dev server used esbuild and production builds used Rollup. The two could transform code differently, and occasionally a bug appeared only in . Vite 8 uses one bundler for both, which removes that whole class of problem. It also opens the way to a full-bundle dev mode and module-level persistent caching.
> Trick: measure before tuning. with (or ) shows what is actually in each chunk. The usual big wins are a duplicated dependency, a locale-data import, or a CJS-only library that cannot be tree-shaken.
Chapter 7 — TypeScript at scale
Where TypeScript is in 2026
- TypeScript 6.0 (March 2026) is the last release built on the JavaScript codebase. It changed defaults: , , , (no more automatic inclusion of every package), and . It also deprecated a long list of legacy options: / and , , , , as a lookup root, and the // module formats.- TypeScript 7.0 (July 2026) is the native port, written in Go. The announcement reports typical full-build speed-ups of 8–12×. It still installs as and runs as . The deprecated 6.0 options are now hard errors. 7.0 ships without a programmatic API, which is planned for 7.1. So tools that drive the compiler through its API (Vue, Svelte, Astro and MDX language tooling, some lint rules) may need to stay on 6.0 for now.
A strict baseline
is the flag that finds the most real bugs in existing code, and it is also the noisiest to turn on. Enable it per package through project references rather than all at once.
/ : pick by runtime
| Code runs in | Setting | Effect ||---|---|---|| Node (apps and libraries) | | Follows Node's real rules: , , conditions, file extensions required in relative ESM imports || A bundler (Vite, Next.js, …) | , | Supports , allows extensionless relative imports as bundlers do || A library published for both | | The strictest option; if it type-checks under it works in bundlers too |
Declaration files
Libraries publish files (, plus so that "go to definition" lands in the source). (TS 5.5) requires explicit return and export types, so that each file's declarations can be produced without the type checker. Fast tools such as Oxc can then emit files in parallel. In a monorepo this removes the slowest step from the build graph.
Project references
builds packages in dependency order and skips any whose inputs have not changed, using files. forces the settings that make this safe: declarations on, and every file listed. TypeScript 7 adds to build independent references in parallel. Editors also load only the projects you open, which is what keeps a 500-package monorepo responsive.
Node's built-in type stripping
Node runs files directly by replacing type syntax with whitespace:
| Version | Change ||---|---|| 22.6 | added || 23.6, 22.18 | Type stripping enabled by default || 25.2, 24.12 | Type stripping stable || 26.0 | removed |
It does no type checking, ignores , refuses files under , and only handles erasable syntax. , with runtime code, parameter properties and aliases need a transform and fail. Imports must use the real extension (), and type-only imports must say . The matching compiler settings:
Then runs, and (or ) type-checks in CI.
Chapter 8 — Type-level programming essentials
Types are a small functional language that runs at compile time. Four features cover most real code.
Two operators that keep type-level code small:
- checks a value against a type without widening it: keeps the literal keys.- type parameters () infer as a readonly tuple instead of .
> Watch out: deep recursive conditional types slow down the checker for everyone who imports them. If shows check time dominated by one file, or points at one type, simplify that type. Clever types are a cost the whole team pays on every keystroke.
Practice Exercises
Exercise 1 — Live binding or copy?
Given , what do an ESM importer and a CJS consumer using each see after calling ?
<details><summary>Solution</summary>
Both see through or a named import. returns the module namespace object, which is a live view. The CJS consumer loses liveness only if it destructures: copies at that moment, and it stays .
</details>
Exercise 2 — Fix the exports map
A package has . TypeScript users with who it report missing types, while users are fine. Why, and what is the fix?
<details><summary>Solution</summary>
Key order is priority. For an ESM consumer, TypeScript matches first and never reaches . It resolves and looks for the sibling declaration file , which does not exist. A consumer skips , so it reaches . Put first. If the ESM and CJS builds need different declarations, nest them: . Verify with .
</details>
Exercise 3 — Diagnose the double singleton
An app registers plugins with , but plugins registered from a CJS config file never show up. The app code uses . Explain the bug and give two fixes.
<details><summary>Solution</summary>
This is the dual-package hazard. The app loads and the config loads : two module instances, two registries. Fixes: (1) publish ESM-only, or point / at the ESM file, so that loads the same instance; (2) store the registry on under so that both copies share it.
</details>
Exercise 4 — Why is it in the bundle?
A 3 KB feature ships 180 KB. The bundle visualiser shows all of , imported as . List three possible causes.
<details><summary>Solution</summary>
(1) ships CommonJS only, so it cannot be tree-shaken. (2) It has no , so the bundler keeps every module the barrel re-exports. (3) Its icons are built by top-level calls () without , so each call counts as a possible side effect. Fix at the source, or import from a subpath () if the package exports one.
</details>
Exercise 5 — Strip-types readiness
Which of these lines fail under Node's type stripping, and why? , (User is a type), ,
<details><summary>Solution</summary>
The fails: it needs code generation. The parameter property fails for the same reason. The fails at runtime because it is treated as a value import of a name that does not export at runtime. Write . The casts are erasable and fine. plus catch all three failures at compile time.
</details>
Exercise 6 — Write a type
Write that makes nested objects and arrays readonly, but leaves functions alone.
<details><summary>Solution</summary>
The function check comes first, because functions are objects and would otherwise be mapped. Arrays are handled before plain objects, so that they become rather than objects with numeric keys.
</details>
Cheat-sheet
| Task | How ||---|---|| Force a file's format | / , or in the nearest || in ESM | (Node 20.11+) || an ES module | Works by default in Node 20.19+ / 22.12+ if the graph has no top-level || Control what returns | || Public entry points only | map; add if tools need it || Condition order | Object key order: first, last || One file for import and require | condition || Private aliases | || Check a package before publishing | , || Tree-shake safely | ESM output, , || Find import cycles | or || Bare specifiers without a bundler | || TS for Node code | || TS for bundled code | , || Monorepo builds | + + ( in TS 7) || Fast output | || Run in Node | (22.18+ / 23.6+), with |
What's next
Post 05 closes the series with production concerns: Core Web Vitals and their thresholds, the Performance panel and flame charts, long tasks and , finding memory leaks with heap snapshots and allocation timelines, profiling Node with and , source maps, production error monitoring and RUM, and why most micro-benchmarks lie.
References
- ECMAScript® Language Specification — Modules — module records, linking and evaluation.- MDN — JavaScript modules and import maps.- Node.js — Modules: packages — , , conditions, the dual-package hazard.- Node.js — Loading ECMAScript modules using — the version history above.- Node.js — Modules: TypeScript — type stripping and its limits.- Vite 8.0 is out! and Vite — shared options: .- Announcing TypeScript 6.0 and Announcing TypeScript 7.0.- TypeScript — Modules reference and Project references.- Are the Types Wrong? and publint.
React Deep Dive — 02 · Concurrent React & React 19
React 18 made rendering interruptible, and React 19 built a programming model on top of it. Together they change how a React app handles slow work: instead of debouncing, spinners everywhere and hand-rolled flags, you mark updates by urgency and let React keep the screen responsive, show old content while new content loads, and roll back optimistic changes when a request fails. This post explains the scheduler model first — concurrent rendering and lanes — then the tools that use it: and , , and Suspense for data. The second half covers the React 19 APIs (Actions, , , , , as a prop), from React 19.2, an overview of React Server Components, and React Compiler 1.0. Examples target React 19.2.
> Series map: 00 Rendering Model → 01 Hooks & State Architecture → 02 Concurrent React & React 19 (this post) → 03 Performance, Testing & Architecture at Scale. Future topics: see the "Planned future extensions" table in 03.
Learning Outcome
- Explain what "concurrent" means in React — interruptible rendering on one thread — and what it does not mean.- Describe lanes at a high level and how React maps events to priorities.- Use / to keep input responsive, and know their limits (async , text inputs).- Use to defer an expensive subtree, and compare it with debouncing.- Explain how Suspense works for code and data, and why transitions stop already-shown content from being replaced by a fallback.- Build forms with React 19 Actions: , , .- Use for promises and context, and know the cached-promise rule.- Use to keep hidden UI alive without running its effects.- Draw the server/client boundary of React Server Components and name what can cross it.- Decide how to adopt React Compiler 1.0 in an existing codebase.
Chapter 1 — Concurrent rendering
Terminology
- Blocking (urgent) update — must be shown right away: typing, clicking, pressing a key. Rendered synchronously to the end.- Non-blocking update (Transition) — may take a moment: switching tabs, filtering a big list, navigating. Rendered in time slices and can be interrupted.- Interruptible render — React can stop building the tree (Post 00), handle something more urgent, then restart or resume.- Tearing — part of the UI showing one version of the data and part another. Concurrent rendering must avoid it (Post 01's ).
What "concurrent" means
JavaScript in the browser still runs on one main thread. React does not render in parallel. "Concurrent" means React can keep several versions of the UI in progress and choose which to work on:
1. The user types in a search box while a large result list is being re-rendered as a Transition.2. The keystroke arrives. React pauses (or abandons) the list render at the next yield point.3. It renders and commits the input change synchronously, so the character appears at once.4. It restarts the list render with the newest query.
Without concurrent rendering, step 2 is impossible: a render that started must finish, and a 200 ms list render means 200 ms of input lag.
What concurrent rendering does not do: make a slow component faster. The total work is the same (or a little more, because of restarts). It only changes which work the user waits for.
Opting in. There is no global switch. enables the concurrent renderer, but updates stay blocking unless you mark them: , , or Suspense-related features. An app that uses none of these behaves much like React 17, plus automatic batching.
Chapter 2 — Lanes at a high level
React tracks priority with lanes: bits in a 31-bit integer. Each update gets a lane; each fiber records the lanes of its pending updates (, from Post 00). A bit mask makes it cheap to ask "does this subtree have work at this priority?" and to process several updates of the same priority together.
The main lanes, from most to least urgent (names from the React source; internals, may change):
| Lane (group) | Typical source ||---|---|| | Discrete events: , , , ; || | Continuous events: , , , || | Updates from outside React events: , promise callbacks, initial render || (several) | , , 's background render || | Retrying a Suspense boundary after its data arrives || | Idle work || | Hidden content, e.g. a hidden |
React-DOM picks the lane for an update from the event that is being handled when is called. That is why the same call is urgent in a click handler and lower priority in a .
Three consequences worth knowing:
- Higher lanes interrupt lower ones. A Transition render in progress is paused or thrown away when a Sync update arrives.- Transitions are batched. As of React 19.2, when several Transitions are pending, React can render them together, so a slow Transition can delay a fast one.- Starvation is prevented. A lower-priority lane that keeps being interrupted is eventually marked expired and rendered synchronously, so it cannot be delayed forever.
> Trick: the Performance panel in Chrome shows React's "Scheduler" and "Components" tracks (React 19.2 Performance Tracks), labelled with priorities such as blocking and transition. It is the quickest way to see lanes in a real trace.
Chapter 3 — and
The pattern
If the user clicks "Posts" and then quickly "Contact", React abandons the slow render and shows . is from the click until the Transition commits, so the button can show a pending state while the old tab stays visible and interactive.
Use the standalone (imported from ) outside components, for example in a router or a store, when you do not need .
Async Transitions (React 19)
In React 19 the function passed to can be async. The whole async function is an Action; stays until it finishes:
The inner is there because of a known limitation documented on react.dev: state updates after an are not automatically part of the Transition. React loses the async context at the , so wrap later updates in another .
Limits
- Do not use a Transition for a controlled text input's own value. The input must update synchronously; put only the expensive consequence (the filtered list) behind the Transition, or use .- Only calls made synchronously inside the callback (or inside nested ) are marked. A inside escapes it.- Out-of-order responses are your problem with raw async Transitions: two quick submits can finish in the wrong order. (Chapter 6) queues actions and avoids this.
> Watch out: a Transition does not make a slow component faster. If takes 800 ms to render, the user still waits 800 ms for it; they just are not frozen while waiting. Pair Transitions with the performance work in Post 03.
Chapter 4 —
is the Transition tool for when you do not own the call — typically a value that arrives as a prop.
On each keystroke React first renders with the old deferred value (fast, because is memoised and its prop did not change), commits the input, then renders again in the background with the new value. If another key arrives, the background render is abandoned.
Two details matter:
- (or the React Compiler) is required. Without it, re-renders in the urgent pass too, and nothing is gained.- React 19 added an argument: . On the first render React uses , then renders again in the background with the real value — useful for showing a cheap placeholder first.
Deferred value vs debounce
| | | Debounce (e.g. 300 ms) ||---|---|---|| Delay | None on a fast device; adapts to how slow rendering is | Fixed, even when rendering is fast || Interruptible | Yes: stale background renders are abandoned | No: once the render starts it blocks || Network requests | Does not reduce them by itself | Reduces them |
They solve different problems. protects rendering; debouncing protects the network. A search box that calls an API often uses both: debounce the request, defer the rendering.
Chapter 5 — Suspense for code and data
What Suspense does
A boundary shows its fallback while something inside it is not ready. Children signal "not ready" by suspending. Supported sources:
- components while their code loads (Post 03),- while the promise is pending,- Suspense-enabled data libraries and frameworks (TanStack Query's , Relay, Next.js and other RSC frameworks).
Suspense does not detect a fetch inside . The data source has to integrate with it.
Nested boundaries define the loading sequence: the header can appear as soon as its data arrives, while the posts area keeps its own skeleton. Place boundaries where a designer would put a loading state, not around every component.
Suspense and Transitions
When a component that is already showing suspends again (for example because a new needs new data), React has two choices: replace the content with the fallback, or keep the old content until the new content is ready.
- In a blocking update, React shows the nearest fallback. Existing content disappears — usually a bad experience.- In a Transition, React keeps the old UI on screen and waits; only new boundaries that have never shown content will show their fallback.
That is why routers built for React 18+ wrap navigations in : clicking a link keeps the current page visible (with for a progress bar) instead of flashing a skeleton.
To force a fresh fallback for a different entity, change the boundary's identity: .
React 19 changes
- Sibling pre-warming. When a component suspends, React 19 commits the nearest fallback immediately, without first rendering the rest of the siblings, and then renders the suspended siblings in the background to start their lazy requests.- SSR reveal batching (19.2). Server-rendered Suspense boundaries that resolve close together are revealed in a short batch instead of one by one, which matches client behaviour and prepares for view-transition animations.
> Common pitfall: creating the promise during render: in a client component creates a new promise every render, so it never resolves from React's point of view. Promises passed to must be cached — created by a framework, a data library, or a Server Component and passed down.
Chapter 6 — Actions: , ,
Terminology
- Action — a function, usually async, run inside a Transition. React tracks its pending state, errors and optimistic updates.- Form action — a function passed to (or ). React calls it with the inside a Transition and, when it succeeds, resets uncontrolled fields.- Server Function — an async function marked that runs on the server but can be called from the client (called "Server Action" when used as an action).
What you no longer write: the flag, the to reset it, the error state, the . Calls are queued: each call receives the state returned by the previous one, so fast repeated submits cannot finish out of order. With a Server Function as and a framework that supports it, the form also works before JavaScript loads; tells React which URL the form goes to in that case.
A design-system button that knows whether its parent form is submitting, without prop drilling:
It reads the status of the parent only, so it must be used in a component rendered inside the form — not in the component that renders the form.
The optimistic state exists only while the Action is pending. When the Action ends, React renders with whatever is then — the real list if the save succeeded and the data was refreshed, or the old list if it threw. There is no manual rollback code. The setter must be called inside an Action (a form action or ); outside one, React warns and the optimistic value only flashes.
> Watch out: if the Action succeeds but nothing updates (no refetch, no parent state change), the optimistic item disappears when the Action ends. Optimistic UI needs a real data update behind it.
Chapter 7 — , as a prop, and other React 19 APIs
reads a promise or a context.
Unlike other hooks, can be called in conditions and loops. It still must be called during render, inside a component or hook — not in event handlers.
Smaller React 19 changes worth knowing
| API | What changed ||---|---|| as a prop | Function components receive directly; is not needed (Post 00) || Ref cleanup | Ref callbacks may return a cleanup function || | Render a context as its own provider; still works || Document metadata | , , rendered anywhere are hoisted into || Stylesheets | — React orders them and waits for them before revealing content || Resource hints | , , , from || Errors | Root options , , ; fewer duplicate console errors || Removed | checks, on function components, string refs, legacy context, , |
Chapter 8 — (React 19.2)
hides part of the UI without unmounting it:
When , React:
- hides the children with — the DOM stays, so scroll position, input text and elements are kept;- keeps their state;- cleans up their effects (subscriptions stop, timers clear);- keeps rendering them when their props change, but at a lower priority than visible content.
When the boundary becomes visible again, effects are set up again and the UI appears with its state intact. Compared with , switching back is instant and nothing is lost. A hidden can also pre-render content the user is likely to open next, at low priority.
Things to check before using it:
- Effects must be written correctly (Post 01): hiding runs their cleanup, showing runs setup again. This is exactly what StrictMode's double effect run rehearses.- DOM side effects do not stop automatically. A playing keeps playing when hidden unless an effect cleanup pauses it.- Hidden trees still cost memory. Do not keep dozens of large screens alive.
Chapter 9 — React Server Components: an overview
React Server Components (RSC) split the component tree between two environments. This chapter gives the React-level model; the Next.js Deep Dive series covers routing, caching and deployment.
The rules
- Server Components are the default in an RSC framework. They run on the server (at build time or per request), can be , can read files and databases directly, and send no JavaScript for themselves to the browser. They cannot use state, effects, or browser APIs.- at the top of a file marks a boundary: that module and everything it imports become part of the client bundle. Client Components render on the server for HTML (SSR) and then hydrate in the browser.- Props from a Server Component to a Client Component must be serialisable: primitives, plain objects and arrays, , , , typed arrays, promises, JSX elements, and Server Functions. Ordinary functions and class instances cannot cross.- marks Server Functions: async functions the client can call over the network (for example as a form action). Treat each one as a public API endpoint — validate input and check authorisation inside it.
A Client Component can receive Server Components as (the composition pattern from Post 00): the server renders them and the client only places the result. That is how interactive shells wrap server-rendered content without pulling it into the client bundle.
> Common pitfall: putting at the top of a high-level layout "to make things work". Everything imported below it becomes client code, and the bundle-size benefit of RSC is gone. Push the boundary down to the leaves that need interactivity.
Chapter 10 — React Compiler 1.0
React Compiler reached 1.0 on 7 October 2025. It is a build-time tool (a Babel plugin, , with experimental SWC support) that adds automatic memoisation to components and hooks.
What it does
The compiler analyses each component and hook, works out which values depend on which inputs, and caches JSX, objects, callbacks and computed values so they keep their identity until their inputs change. It can memoise in places where cannot be written, such as after an early return, and at a finer grain than most hand-written code.
The practical effect: the "new object prop breaks " and "inline callback re-renders the child" problems from Posts 00 and 01 mostly disappear, without writing , or .
What it needs
It assumes the Rules of React: pure render, no mutation of props or state, hooks at the top level, no reading refs during render. When it cannot prove a component follows the rules, it skips that component and leaves it as written. The compiler-powered rules in (v6+, in the preset) — , , , , and others — report the code it would skip.
Adopting it
| Setting | Meaning ||---|---|| (default) | Compile functions that look like components (PascalCase, return JSX) or hooks ( prefix) || | Compile only functions with a directive — for gradual rollout || directive | Always skip this function — an escape hatch while fixing a problem || / | Supports React 17 and 18 with the package |
Framework support: Next.js 16 made the option stable (not on by default; builds get slower because it uses Babel), Expo SDK 54 enables it by default, and offers a compiler template.
A realistic rollout:
1. Turn on the lint rules first and fix what they report.2. Enable the compiler for one directory or with mode.3. Run the tests and profile key screens (Post 03).4. Widen the scope.
The React team's guidance on existing / : for new code, rely on the compiler and use them only where precise control is needed (for example, a value used as an effect dependency); for existing code, leave them in place or remove them carefully with tests, because removing them can change the compiled output.
> Watch out: the compiler makes it easy to forget that memoisation is about identity. Code that depends on a value keeping its identity for correctness (an effect that must not re-run) should still say so explicitly, not rely on the compiler's current heuristics.
Practice Exercises
Exercise 1 — No skeleton flash
Clicking "next user" replaces the profile with a skeleton for 300 ms. Keep the old profile visible with a small pending indicator instead.
<details><summary>Solution</summary>
Make the navigation a Transition: and . Already-revealed Suspense content is not replaced by the fallback during a Transition; show as a spinner or reduced opacity.
</details>
Exercise 2 — Rewrite with
Convert a form that uses for and , with , and a , to React 19 Actions.
<details><summary>Solution</summary>
</details>
Exercise 3 — Why did the optimistic item vanish?
A "like" button uses to show . After the request succeeds, the count goes back to the old number. Why?
<details><summary>Solution</summary>
The optimistic value only lives while the Action is pending. When it ends, React renders from the real — which never changed, because nothing refetched or updated the like count after the save. Update the source state (set it from the response, invalidate the query, or refresh the server data) inside the Action.
</details>
Exercise 4 — Find the boundary
A Server Component page passes to a Client Component . The build fails. Explain and fix.
<details><summary>Solution</summary>
A plain function is not serialisable, so it cannot cross from server to client. Move the handler into the Client Component (it can call itself), or, if the work belongs on the server, pass a Server Function marked .
</details>
Exercise 5 — Tabs that keep their state
A settings screen has three tabs; switching tabs loses scroll position and half-filled inputs. Fix it with React 19.2, and name one thing to check in the tab components first.
<details><summary>Solution</summary>
Render all three inside . State and DOM are kept; effects are cleaned up while hidden. Check that each tab's effects have correct cleanups (and that nothing like a media element keeps running), because hiding runs cleanup and showing runs setup again.
</details>
Cheat-sheet
| Need | Tool ||---|---|| Keep typing responsive while a heavy update renders | / || Defer a value you do not set yourself | + || Show old UI while new data loads | Update in a Transition; Suspense keeps revealed content || State after in a Transition | Wrap in another || Form submit with pending + result | || Pending state inside the form | from || Instant feedback, auto rollback | inside an Action || Read a cached promise or context | — may be conditional || Keep hidden UI alive, pause effects | (19.2) || Server-only code, zero client JS | Server Component (RSC framework) || Callable server code | Server Function — validate and authorise || Automatic memoisation | React Compiler 1.0; opt out with |
What's next
Post 03 turns to production work: measuring with the React Profiler, DevTools and Performance Tracks; when , and still matter with and without the compiler; list virtualisation and code splitting; error boundaries; testing with Vitest, React Testing Library and Playwright; accessibility; and the architecture of component libraries (compound components, headless UI, polymorphism). It ends with the table of planned extensions for the series.
The Next.js Deep Dive series takes Chapter 9 further — Server Components in a real router, streaming, caching and Server Functions in production. The JavaScript Deep Dive series covers the event loop and task scheduling that the Scheduler builds on.
References
- React 18 release post — concurrent rendering, transitions, automatic batching.- React 19 release post — Actions, , , , , as a prop.- React 19.2 release post — , , Performance Tracks, SSR changes.- · · · .- · · · .- Server Components · · .- React Compiler 1.0 and compiler configuration.- Next.js 16 release post — stable option.- React source: ReactFiberLane — lane definitions.
React Deep Dive — 01 · Hooks & State Architecture
Hooks look like ordinary function calls, which is exactly why they are misused. becomes a general "when X changes, do Y" tool, context becomes a global store, and every piece of data — server records, form drafts, the selected tab, the page number — ends up in the same soup with effects copying values between them. The result is extra renders, race conditions, and state that disagrees with itself. This post first explains hooks from the inside (the linked list on the fiber from Post 00), then works through effects done right, the less common hooks that solve real problems (, , , ), and context performance. The second half steps up to architecture: sorting state by where its truth lives, and choosing between TanStack Query, Zustand and Redux Toolkit. Examples target React 19.2.
> Series map: 00 Rendering Model → 01 Hooks & State Architecture (this post) → 02 Concurrent React & React 19 → 03 Performance, Testing & Architecture at Scale. Future topics: see the "Planned future extensions" table in 03.
Learning Outcome
- Explain the Rules of Hooks from the implementation: a per-fiber linked list read in call order.- Decide whether logic belongs in render, an event handler, or an effect, using "You Might Not Need an Effect".- Write effects with correct cleanup, and without race conditions on fast-changing inputs.- Choose between , and .- Subscribe to external stores safely with , including the snapshot-caching rule.- Use for state with rules, and for non-reactive logic inside effects.- Diagnose and fix context re-render storms.- Classify state as server, client, URL or form state, and pick a tool for each.- Compare TanStack Query, Zustand and Redux Toolkit on the trade-offs that matter at scale.
Chapter 1 — How hooks are stored, and why the rules exist
Terminology
- Hook — a function whose name starts with and that reads or writes per-component data kept by React.- Hook list — for a function component, points at the first hook object; each hook object has a pointer. React walks the list in call order.- Dispatcher — the internal object that decides what means right now: the "mount" version creates hook objects, the "update" version walks existing ones.- Reactive value — props, state, context, and anything computed from them during render. These can change between renders.
The linked list
On mount, each hook call appends a node to the list. On update, each hook call takes the next node:
React has no names for these nodes. The only thing that connects "the second hook call in this render" to "the effect from last render" is position. That is the whole reason for the two rules:
1. Call hooks only at the top level — not in conditions, loops, after an early , or in nested functions.2. Call hooks only from components or other hooks.
When goes from to a value, render 1 made zero hook calls and render 2 makes one; React throws "Rendered more hooks than during the previous render". Worse cases do not throw: if two calls swap order, each reads the other's value silently.
from React 19 is the documented exception: it can be called inside and loops, because it does not store a hook node (Post 02).
> Trick: custom hooks are not a runtime concept. A custom hook's hooks are inlined into the caller's list. Two components calling get two independent sets of state; nothing is shared unless the hook reads a shared store.
Chapter 2 — Effects done right
What an effect is for
An effect synchronises a component with an external system: a network connection, a browser API, a third-party widget, a subscription. It is not a general "on change" callback. The React docs article "You Might Not Need an Effect" gives a decision rule worth memorising:
| Situation | Where the code goes ||---|---|| Value computed from props/state | Render (compute it inline; if expensive) || Something caused by a user action (submit, click, buy) | Event handler || Reset all state when a prop changes | on the component (Post 00) || Adjust some state when a prop changes | Compute during render, or set state during render with a guard || Tell a parent about a change | Call the parent's callback in the same event handler || Keep in sync with a system outside React | Effect || Fetch data for what is on screen | An effect with cleanup — or better, a data library or framework loader |
The effect version renders once with the old , commits, then renders again. With several chained effects this becomes a cascade of renders, each showing inconsistent data. The lint rule flags the simplest cases.
Cleanup is part of the contract
Every setup needs a matching cleanup ( → , → , → ) so that setup → cleanup → setup is equivalent to one setup. StrictMode tests exactly this in development (Post 00). React runs the cleanup before the next setup (when dependencies change) and on unmount. Cleanup reads the values from its own render — the closure it was created in — not the latest ones.
Race conditions in data effects
A naive has a race. Type "re", then "react". If the "re" request is slower, its response arrives last and overwrites the correct result. Two fixes, often combined:
The flag is the correctness fix; saves bandwidth and server work. Hand-written fetch effects also lack caching, deduplication, retries and a loading/error state machine — which is the argument for Chapter 6.
Dependencies are not a choice
The dependency array must list every reactive value the effect reads. It is a description of what the effect uses, not a setting for "when it runs". If an effect re-runs too often, change the code so it reads fewer reactive values:
- Move objects and functions that do not depend on props inside the effect or outside the component.- Use the updater form so the effect does not read .- Split an effect that does two unrelated things into two effects.- Move non-reactive logic into an Effect Event (Chapter 4).
> Common pitfall: is almost always a stale-closure bug waiting to happen. The code will read a value from the render the effect was created in, forever.
Chapter 3 — , and
Layout effects
| Hook | Runs | Use for ||---|---|---|| | Before layout effects; before refs are attached | CSS-in-JS libraries injecting rules. Not for app code. || | After DOM mutation, before the browser paints; blocks paint | Measuring layout, then setting state to reposition (tooltips, popovers, auto-sizing) || | Usually after paint | Everything else |
The state update inside is processed synchronously before paint, so the user sees only the final position. With the first position would flash.
> Watch out: does nothing during server rendering, and heavy work in it delays every paint. Keep it to measure-then-set.
Reading a mutable store (a Redux store, a browser API, a WebSocket cache) with + has a subtle bug under concurrent rendering: tearing. A paused render can show part of the tree with the old store value and part with the new one. is the supported fix:
Two rules:
1. must return the same value while the store has not changed. React compares with . Returning a new object each call () makes React think the store changed on every check, which ends in an infinite re-render loop. Return an immutable snapshot the store keeps, or cache it.2. Define outside the component (or memoise it). A new function each render makes React resubscribe each render.
Updates coming from an external store are always rendered synchronously (they cannot be part of a non-blocking transition), which is the price of never tearing. Zustand, Redux (via ) and TanStack Query all build on this hook.
Chapter 4 — , and context performance
for state with rules
When the next state depends on the previous one through rules — a form wizard, a multi-select, an editor — a reducer puts the rules in one pure, testable function:
Benefits beyond style: has a stable identity, so it can be passed down or used in effects without being a dependency; the reducer can be unit-tested without React; actions describe what happened ("added"), which makes logs readable. Reducers must be pure — StrictMode calls them twice in development.
(stable in React 19.2)
Sometimes an effect needs the latest value of something without reacting to it. The classic case: connect to a chat room when changes, and show a notification using the current — but do not reconnect when changes.
shipped as stable in React 19.2 (October 2025), after a long time as an experimental API. Its limits are deliberate:
- Call the returned function only from inside effects (or other Effect Events in the same component) — not during render and not from event handlers.- Do not put it in a dependency array, and do not pass it to other components or hooks. Its identity changes on purpose.- Do not use it to silence a dependency that should re-run the effect.
Use v6 or later so the linter understands it.
Context performance
Context is a way to pass a value down without props. It is not a state manager, and it has no selectors: every consumer of a context renders when the value changes (), and does not stop it.
Three fixes, from cheapest to strongest:
3. Use a store with selectors when many components each need a small slice of a fast-changing value (a document, a canvas, a live dashboard). Put the store object in context (it never changes) and read slices with -based selectors — which is what Zustand and React-Redux do.
> Trick: context is excellent for values that change rarely: theme, locale, the current user, a store instance, a feature-flag client. It is poor for values that change on every keystroke.
Chapter 5 — Classifying state
Terminology
- Server state — a cached copy of data whose truth lives on a server: users, orders, search results. It can go stale, can be changed by other people, and needs fetching, caching, invalidation and retries.- Client (UI) state — data that exists only in this browser tab: an open modal, a selected row, a draft, a multi-step wizard position.- URL state — state that should survive reload, back/forward, and sharing a link: filters, sort, page, selected tab, search query.- Form state — in-progress user input, its validation and submission status.- Derived state — anything computable from the above. It should not be stored at all.
Why the classification matters
Most "state management" pain comes from putting server state into a client store. Many older Redux codebases held , , and hand-written thunks for every entity, reinventing a cache without invalidation. Once server state moves to a query cache, the remaining client state is usually small enough that , and a little context cover most of it.
A practical sort for each piece of state:
1. Can it be computed from other state? Compute it. Do not store it.2. Is the truth on a server? Query cache.3. Should a copied link or the back button restore it? URL.4. Is it user input before submit? Form state (uncontrolled inputs, a form library, or React 19 — Post 02).5. Is it used by one component or a small subtree? / , placed as low as possible.6. Is it shared across distant parts and changes often? A client store.
Ask the questions in order; the first yes decides.
URL state in practice
The URL is now the single source of truth; there is no copy to keep in sync. Libraries such as add typed parsers and batching for search params across React Router, Next.js and others. The Next.js Deep Dive series covers in Server Components.
> Common pitfall: copying a prop or a query result into "to edit it" creates two sources of truth. Either keep a separate draft that is explicitly initialised from the source (and reset with a ), or edit the source directly.
Chapter 6 — Server state with TanStack Query
TanStack Query (v5) is a cache for asynchronous data keyed by a serialisable query key. Components subscribe to keys; the cache handles fetching, deduplication, staleness, background refetching, retries and garbage collection.
What the cache gives you, and the defaults worth knowing:
| Concept | Default (v5) | Meaning ||---|---|---|| | | Data is stale immediately; a new subscriber or window focus triggers a background refetch || | 5 minutes | How long unused data stays in the cache (called before v5) || | 3 (client) | Failed queries retry with exponential backoff || | | Refetch stale queries when the tab regains focus || Deduplication | always | Many components with the same key share one request || | passed to | Aborted when the query is cancelled or no longer needed |
Status fields: means "no data yet" (v5 renamed the old ), means "a request is in flight", which is also true during background refetches. Show a spinner on , and at most a subtle indicator on .
Key design points at scale:
- Query key factories keep keys consistent: returns , so hits every todo query by prefix.- Set a realistic per resource. is safe but chatty; reference data can be minutes or .- integrates with Suspense (Post 02) and guarantees is defined.- In a framework with server rendering, prefetch on the server and hydrate the cache, or let the framework's own loaders own server state (Next.js Deep Dive).
> Watch out: putting query results into a Zustand or Redux store "so other components can read them" recreates the stale-copy problem. Other components should call the same query hook; deduplication makes it free.
Chapter 7 — Client stores: Zustand vs Redux Toolkit
When client state is shared widely and changes often, a store with selectors beats context: each component subscribes to a slice and renders only when that slice changes.
Zustand
A small store built on . No provider needed; the hook is the store.
In Zustand v5, a selector that returns a new object on every call without can cause an infinite render loop — the same snapshot rule as Chapter 3.
Redux Toolkit
The official, modern way to write Redux: (with Immer for "mutating" syntax), (good defaults, DevTools, a check for accidental mutation in development), and RTK Query for server state.
Trade-offs
| | Zustand | Redux Toolkit | TanStack Query ||---|---|---|---|| Solves | Shared client state | Shared client state + (RTK Query) server state | Server state || Boilerplate | Very low | Moderate | Low || Provider | Not needed | | || Selectors | Hook selector; for objects | ; for derived data | Per-query; option || DevTools / time travel | Via middleware | First-class Redux DevTools | TanStack Query DevTools || Enforced structure | None — team discipline | Actions + reducers, event log | Query keys || Good fit | Editors, canvases, app-wide UI state in small/medium teams | Large teams that want one enforced pattern and an auditable action log | Any app talking to an API |
Rules of thumb:
- Start with TanStack Query for server state and local state for the rest. Many apps never need a client store after that.- Reach for Zustand when a few pieces of client state are shared widely and change often.- Choose Redux Toolkit when the team is large, needs strong conventions, action logging or time-travel debugging, or already runs Redux.- Keep derived data out of every store; compute it with selectors (memoised with when expensive).
> Common pitfall: a selector like returns a new array every time, so the component renders on every store change. Select the raw data and derive it in the component with , or use a memoised selector.
Practice Exercises
Exercise 1 — Hook order
Why does this crash when changes from to an object? Fix it.
<details><summary>Solution</summary>
The first render calls zero hooks, the next calls one; React reads the hook list by position and detects the mismatch. Move the hook above the early return (or split into two components: returns ).
</details>
Exercise 2 — The frozen counter
The display sticks at 1. Why? Fix it without adding to the dependencies.
<details><summary>Solution</summary>
The interval callback closed over from the first render, which is always 0, so it sets 1 forever. Use the updater form, : the effect no longer reads , the empty dependency list is now honest, and the interval never restarts.
</details>
Exercise 3 — Snapshot caching
This hook causes "Maximum update depth exceeded". Why, and how do you fix it?
<details><summary>Solution</summary>
returns a new object on every call, so says the store changed every time React checks, and React re-renders forever. Keep an immutable snapshot object in the store and replace it only on change ( inside the setter), then . Or read two primitives with two separate subscriptions.
</details>
Exercise 4 — Context storm
A value is , rebuilt on each render of the provider. A slider updates a setting 60 times a second, and 400 consumers re-render. Give two fixes.
<details><summary>Solution</summary>
(1) Split: put (stable, via or 's ) in its own context, so action-only consumers never render; and memoise the settings value. (2) Move settings into a store (Zustand, or a small store in context) and have each consumer select only the field it shows; only consumers of the changed field render.
</details>
Exercise 5 — Classify
Classify each and name where it should live: the logged-in user's profile; the "sort by" dropdown on a product list; whether the sidebar is collapsed; an unsent comment draft; the number of items in the cart shown in the header; the total price of the cart.
<details><summary>Solution</summary>
Profile — server state (query cache). Sort — URL state (search params), so links and back button work. Sidebar collapsed — client state ( near the layout, or if it should persist). Comment draft — form state (uncontrolled input or form state; optionally persisted). Cart items — server state if the cart is stored on the server, otherwise shared client state (a store). Total price — derived: compute from cart items; never store it.
</details>
Cheat-sheet
| Topic | Rule ||---|---|| Hook storage | Linked list on the fiber, read by call order || Rules of Hooks | Top level only; components and hooks only; is the exception || Derived value | Compute in render; only if expensive || User-caused action | Event handler, not effect || Reset on prop change | || Effect | Only to sync with an external system; always pair setup with cleanup || Fetch in effect | flag + ; better: a query library || External store | ; returns a cached value || Latest value, not a dependency | (stable in 19.2) || Context | For rarely changing values; split state and actions; memoise value || Server state | TanStack Query ( 0, 5 min by default in v5) || URL state | Router search params (, ) || Shared client state | Zustand (small, selectors) or Redux Toolkit (structure, DevTools) || Selectors | Return stable values; / |
What's next
Post 02 covers concurrent React: how React schedules work by priority (lanes), , and , Suspense for data, and the React 19 Actions model — , , and . It also introduces , React Server Components at the level a React engineer needs (the Next.js Deep Dive series goes deeper), and React Compiler 1.0, which changes how much of Chapter 4's / you write by hand.
For closures and stale values at the language level, see the JavaScript Deep Dive series. For how Vue solves the same "fine-grained subscription" problem with reactive proxies instead of selectors, see the Vue Deep Dive series.
References
- Rules of Hooks and Rules of React.- You Might Not Need an Effect · Synchronizing with Effects · Removing Effect Dependencies.- · · · .- and React 19.2 release post.- Scaling Up with Reducer and Context.- TanStack Query docs — including "Important Defaults" and the v5 migration guide.- Zustand docs — and the v5 migration notes.- Redux Toolkit docs and Redux style guide.- eslint-plugin-react-hooks — rule list.
Real Analysis — 03 · Differentiation, the Mean Value Theorem and Taylor's Theorem
Calculus courses teach the derivative as a set of rules. Analysis asks what the rules rest on. This post defines the derivative as a limit, proves that differentiable functions are continuous, and proves the product and chain rules without the usual gap. The centre of the post is the Mean Value Theorem. It is the one tool that turns information about $f'$ into information about $f$, and almost every later result depends on it: "zero derivative means constant", L'Hôpital's rule, and Taylor's theorem with a remainder you can actually bound. Along the way you meet functions that break naive intuition: a derivative that exists everywhere but is not continuous, a smooth function whose Taylor series is useless, and a continuous function with no derivative anywhere. It builds on the $\varepsilon$–$\delta$ limits, the Extreme Value Theorem and the Intermediate Value Theorem from post 02.
> Series map: 00 The Real Numbers & Completeness → 01 Sequences & Series → 02 Topology of ℝ & Continuity → 03 Differentiation & Taylor's Theorem (this post) → 04 The Riemann Integral → 05 Uniform Convergence & Power Series.
Learning Outcome
- Define the derivative as a limit of difference quotients and compute it from the definition.- Prove that a function differentiable at a point is continuous there, and show with $\lvert x\rvert$ that the converse fails.- Prove the product rule and the chain rule, using the "linear approximation" form of the derivative to avoid dividing by zero.- State and prove the Interior Extremum Theorem, Rolle's Theorem, the Mean Value Theorem and Cauchy's Generalised Mean Value Theorem.- Use the Mean Value Theorem to prove "$f' = 0$ implies constant", monotonicity tests and numeric inequalities.- State and prove Darboux's theorem, and explain why $x^2\sin(1/x)$ matters.- Apply L'Hôpital's rule with all of its hypotheses checked.- State and prove Taylor's theorem with the Lagrange remainder, and use it to get a proven error bound.- Place the smooth non-analytic function $e^{-1/x^2}$ and Weierstrass's nowhere-differentiable function in the hierarchy of smoothness.
Chapter 1 — The derivative as a limit
Terminology
- Interval — in this post, $I$ always means an interval of $\mathbb{R}$ with more than one point.- Difference quotient — for $x \neq c$, the slope of the secant line through $(c, f(c))$ and $(x, f(x))$, that is $\frac{f(x) - f(c)}{x - c}$.- Derivative at a point — the limit of the difference quotient as $x \to c$, when that limit exists as a real number.- One-sided derivative — the same limit taken only from the right ($x \to c^+$) or only from the left. At an endpoint of a closed interval only one side makes sense, and "differentiable at the endpoint" means the one-sided derivative exists.- Differentiable on an interval — differentiable at every point of it.- Class $C^k$ — $C^k(I)$ is the set of functions whose first $k$ derivatives exist on $I$ and whose $k$-th derivative is continuous. $C^\infty$ means derivatives of every order exist.
Definition
Let $f : I \to \mathbb{R}$ and $c \in I$. Then $f$ is differentiable at $c$ if the limit
$$f'(c) = \lim{x \to c} \frac{f(x) - f(c)}{x - c}$$
exists (as a real number). In $\varepsilon$–$\delta$ form: for every $\varepsilon > 0$ there is $\delta > 0$ such that $0 < \lvert x - c\rvert < \delta$ and $x \in I$ imply
$$\left\lvert \frac{f(x) - f(c)}{x - c} - f'(c) \right\rvert < \varepsilon.$$
Writing $x = c + h$ gives the equivalent form $f'(c) = \lim{h \to 0} \frac{f(c+h) - f(c)}{h}$.
Worked example. For $f(x) = x^2$ and $c = 3$:
$$\frac{x^2 - 9}{x - 3} = x + 3 \quad (x \neq 3), \qquad \text{so} \qquad f'(3) = \lim{x \to 3} (x + 3) = 6.$$
The cancellation is legal because the limit never looks at $x = 3$ itself.
Worked example: the absolute value at 0. For $f(x) = \lvert x\rvert$ the difference quotient at $0$ is $\frac{\lvert x\rvert}{x}$, which is $1$ for $x > 0$ and $-1$ for $x < 0$. The right-hand limit is $1$, the left-hand limit is $-1$, so the two-sided limit does not exist. The function $\lvert x\rvert$ is continuous at 0 but not differentiable there. Its graph has a corner.
Differentiable implies continuous
Theorem. If $f : I \to \mathbb{R}$ is differentiable at $c$, then $f$ is continuous at $c$.
Proof. For $x \neq c$,
$$f(x) - f(c) = \frac{f(x) - f(c)}{x - c} \cdot (x - c).$$
As $x \to c$ the first factor tends to $f'(c)$ and the second tends to $0$. By the product rule for limits (post 01, carried over to functions via sequences in post 02), $f(x) - f(c) \to f'(c) \cdot 0 = 0$. So $\lim{x \to c} f(x) = f(c)$. $\blacksquare$
The converse is false: $\lvert x\rvert$ is continuous at 0 and not differentiable there. Chapter 7 shows something much stronger: a function can be continuous everywhere and differentiable nowhere.
The linear-approximation form (Carathéodory)
The following reformulation removes every risky division from later proofs.
Lemma. $f$ is differentiable at $c$ if and only if there is a function $\varphi : I \to \mathbb{R}$ that is continuous at $c$ and satisfies
$$f(x) - f(c) = \varphi(x)\,(x - c) \quad \text{for all } x \in I.$$
In that case $f'(c) = \varphi(c)$.
Proof. If $f'(c)$ exists, define $\varphi(x) = \frac{f(x) - f(c)}{x - c}$ for $x \neq c$ and $\varphi(c) = f'(c)$. The identity holds (at $x = c$ both sides are 0) and $\varphi$ is continuous at $c$ by the definition of $f'(c)$. Conversely, if such a $\varphi$ exists, then for $x \neq c$ the difference quotient equals $\varphi(x)$, which tends to $\varphi(c)$. $\blacksquare$
Read it as: near $c$, $f$ changes by "slope times displacement", where the slope $\varphi(x)$ is allowed to wobble but settles to $f'(c)$.
Chapter 2 — Rules of differentiation
Theorem (algebra of derivatives). Let $f, g$ be differentiable at $c$ and $k \in \mathbb{R}$. Then
- $(f + g)'(c) = f'(c) + g'(c)$ and $(kf)'(c) = k f'(c)$;- $(fg)'(c) = f'(c)g(c) + f(c)g'(c)$;- if $g(c) \neq 0$, then $(f/g)'(c) = \dfrac{f'(c)g(c) - f(c)g'(c)}{g(c)^2}$.
Proof of the product rule. Add and subtract $f(x)g(c)$:
$$\frac{f(x)g(x) - f(c)g(c)}{x - c} = f(x)\,\frac{g(x) - g(c)}{x - c} + g(c)\,\frac{f(x) - f(c)}{x - c}.$$
As $x \to c$: $f(x) \to f(c)$ because differentiable implies continuous, and the two quotients tend to $g'(c)$ and $f'(c)$. $\blacksquare$
The sum rule is immediate from limit laws. For the quotient rule, first prove $(1/g)'(c) = -g'(c)/g(c)^2$ (note that $g(x) \neq 0$ near $c$ by continuity), then apply the product rule.
The chain rule, done properly
Theorem (chain rule). Let $g : I \to \mathbb{R}$ be differentiable at $c$, let $g(I) \subseteq J$ for an interval $J$, and let $f : J \to \mathbb{R}$ be differentiable at $g(c)$. Then $f \circ g$ is differentiable at $c$ and
$$(f \circ g)'(c) = f'(g(c)) \cdot g'(c).$$
The tempting wrong proof. Write
$$\frac{f(g(x)) - f(g(c))}{x - c} = \frac{f(g(x)) - f(g(c))}{g(x) - g(c)} \cdot \frac{g(x) - g(c)}{x - c}$$
and let $x \to c$. This breaks whenever $g(x) = g(c)$ for $x$ arbitrarily close to $c$, because then you divide by zero infinitely often. That really happens: $g(x) = x^2 \sin(1/x)$ (with $g(0) = 0$) takes the value $0$ at $x = 1/(n\pi)$ for every integer $n \geq 1$.
Correct proof. By the lemma, there is $\psi$ continuous at $d = g(c)$ with $f(y) - f(d) = \psi(y)(y - d)$ for all $y \in J$, and $\psi(d) = f'(d)$. There is also $\varphi$ continuous at $c$ with $g(x) - g(c) = \varphi(x)(x - c)$ and $\varphi(c) = g'(c)$. Put $y = g(x)$:
$$f(g(x)) - f(g(c)) = \psi(g(x))\,\bigl(g(x) - g(c)\bigr) = \psi(g(x))\,\varphi(x)\,(x - c).$$
The function $x \mapsto \psi(g(x))\varphi(x)$ is continuous at $c$: $g$ is continuous at $c$, $\psi$ is continuous at $g(c)$, and products of functions continuous at $c$ are continuous at $c$. By the lemma again, $f \circ g$ is differentiable at $c$ with derivative $\psi(g(c))\varphi(c) = f'(g(c))\,g'(c)$. $\blacksquare$
No division by $g(x) - g(c)$ appears anywhere.
> Trick: whenever a proof wants to divide by something that might be zero, try the Carathéodory form. It turns "limit of a quotient" into "continuity of a factor", and continuity composes cleanly.
Chapter 3 — Extrema, Rolle and the Mean Value Theorem
Interior extremum theorem
Theorem. Let $f : (a, b) \to \mathbb{R}$ have a maximum (or minimum) at $c \in (a, b)$, and let $f$ be differentiable at $c$. Then $f'(c) = 0$.
Proof (maximum case). For $x > c$ we have $f(x) - f(c) \leq 0$ and $x - c > 0$, so the difference quotient is $\leq 0$; the right-hand limit gives $f'(c) \leq 0$. For $x < c$ the numerator is $\leq 0$ and the denominator $< 0$, so the quotient is $\geq 0$; the left-hand limit gives $f'(c) \geq 0$. Hence $f'(c) = 0$. $\blacksquare$
> Watch out: the point must be interior. $f(x) = x$ on $[0, 1]$ has its maximum at $1$ and $f'(1) = 1$. And the converse fails: $f(x) = x^3$ has $f'(0) = 0$ but no extremum at $0$.
Rolle's theorem
Theorem (Rolle). Let $f$ be continuous on $[a, b]$ and differentiable on $(a, b)$, with $f(a) = f(b)$. Then there is $c \in (a, b)$ with $f'(c) = 0$.
Proof. By the Extreme Value Theorem (post 02), $f$ attains a maximum $M$ and a minimum $m$ on the compact set $[a, b]$. If both are attained only at the endpoints, then $M = m = f(a)$ and $f$ is constant, so $f'(c) = 0$ for every $c \in (a, b)$. Otherwise one of them is attained at some interior $c$, and the interior extremum theorem gives $f'(c) = 0$. $\blacksquare$
All three hypotheses matter. Continuity at the endpoints: $f(x) = x$ on $[0,1)$ with $f(1) = 0$. Differentiability inside: $\lvert x\rvert$ on $[-1, 1]$. Equal end values: $x$ on $[0, 1]$.
The Mean Value Theorem
Theorem (MVT). Let $f$ be continuous on $[a, b]$ and differentiable on $(a, b)$. Then there is $c \in (a, b)$ with
$$f'(c) = \frac{f(b) - f(a)}{b - a}.$$
Geometrically: somewhere the tangent line is parallel to the secant line through the end points.
Proof. Subtract the secant line. Let
$$h(x) = f(x) - \left( f(a) + \frac{f(b) - f(a)}{b - a}\,(x - a) \right).$$
Then $h$ is continuous on $[a, b]$, differentiable on $(a, b)$, and $h(a) = h(b) = 0$. Rolle gives $c \in (a, b)$ with $0 = h'(c) = f'(c) - \frac{f(b) - f(a)}{b - a}$. $\blacksquare$
Worked example. $f(x) = x^3$ on $[0, 2]$. The secant slope is $\frac{8 - 0}{2 - 0} = 4$. Solve $f'(c) = 3c^2 = 4$ in $(0, 2)$: $c = \frac{2}{\sqrt 3} \approx 1.1547$. The theorem only promises that such a $c$ exists; here you can find it.
Consequences
Corollary 1 (zero derivative). If $f'(x) = 0$ for every $x$ in an interval $I$, then $f$ is constant on $I$.
Proof. Take $x < y$ in $I$. The MVT on $[x, y]$ gives $f(y) - f(x) = f'(c)(y - x) = 0$. $\blacksquare$
The interval matters: $f(x) = \operatorname{sign}(x)$ on $\mathbb{R} \setminus \{0\}$ has $f' = 0$ everywhere on its domain but is not constant, because the domain is not an interval.
Corollary 2 (same derivative). If $f' = g'$ on an interval, then $f - g$ is constant. This is why antiderivatives are unique "up to $+C$".
Corollary 3 (monotonicity). On an interval $I$, with $f$ differentiable on $I$:
| Hypothesis on the interval | Conclusion ||---|---|| $f' \geq 0$ | $f$ is increasing ($x < y \Rightarrow f(x) \leq f(y)$) || $f' > 0$ | $f$ is strictly increasing || $f' \leq 0$ or $f' < 0$ | decreasing or strictly decreasing || $\lvert f'\rvert \leq M$ | $\lvert f(x) - f(y)\rvert \leq M\lvert x - y\rvert$ (Lipschitz) |
Each line is one application of $f(y) - f(x) = f'(c)(y - x)$. The converse of line 2 fails: $x^3$ is strictly increasing but $f'(0) = 0$.
Worked example: a Lipschitz bound. Since $\lvert \cos\rvert \leq 1$, the last line gives $\lvert \sin a - \sin b\rvert \leq \lvert a - b\rvert$ for all real $a, b$.
Worked example: estimating a square root. Apply the MVT to $\sqrt{x}$ on $[100, 101]$: $\sqrt{101} - 10 = \frac{1}{2\sqrt c}$ for some $c \in (100, 101)$. Since $10 < \sqrt c < \sqrt{101}$,
$$0.04975\ldots = \frac{1}{2\sqrt{101}} < \sqrt{101} - 10 < \frac{1}{20} = 0.05.$$
The true value is $\sqrt{101} - 10 = 0.049875\ldots$, inside the bracket.
Cauchy's generalised Mean Value Theorem
Theorem (Cauchy MVT). Let $f, g$ be continuous on $[a, b]$ and differentiable on $(a, b)$. Then there is $c \in (a, b)$ with
$$\bigl(f(b) - f(a)\bigr)\,g'(c) = \bigl(g(b) - g(a)\bigr)\,f'(c).$$
Proof. Let $h(x) = \bigl(f(b) - f(a)\bigr) g(x) - \bigl(g(b) - g(a)\bigr) f(x)$. A direct computation gives $h(a) = f(b)g(a) - g(b)f(a) = h(b)$. Rolle gives $c$ with $h'(c) = 0$, which is the claim. $\blacksquare$
With $g(x) = x$ this is the ordinary MVT. The version with two functions is what L'Hôpital's rule needs.
Chapter 4 — Derivatives are not arbitrary functions
A derivative that is not continuous
Let
$$g(x) = \begin{cases} x^2 \sin(1/x) & x \neq 0, \\ 0 & x = 0. \end{cases}$$
At $0$: $\left\lvert \frac{g(x) - g(0)}{x} \right\rvert = \lvert x \sin(1/x)\rvert \leq \lvert x\rvert \to 0$, so $g'(0) = 0$. For $x \neq 0$ the ordinary rules give
$$g'(x) = 2x\sin(1/x) - \cos(1/x).$$
As $x \to 0$ the first term tends to $0$ but $\cos(1/x)$ oscillates between $-1$ and $1$ for ever. So $g'$ exists at every point of $\mathbb{R}$, yet $\lim{x \to 0} g'(x)$ does not exist. A function can be differentiable everywhere with a discontinuous derivative. In the notation of Chapter 1: $g$ is differentiable on $\mathbb{R}$ but $g \notin C^1(\mathbb{R})$.
Darboux's theorem
Discontinuous derivatives still cannot jump. They always have the intermediate value property.
Theorem (Darboux). Let $f$ be differentiable on $[a, b]$ (one-sided at the endpoints). If $y$ lies strictly between $f'(a)$ and $f'(b)$, then there is $c \in (a, b)$ with $f'(c) = y$.
Proof. Assume $f'(a) < y < f'(b)$ (the other case is symmetric). Let $g(x) = f(x) - yx$. Then $g$ is differentiable on $[a, b]$ with $g'(a) = f'(a) - y < 0$ and $g'(b) = f'(b) - y > 0$. As a continuous function on $[a, b]$, $g$ attains a minimum at some $c$ (EVT).
- $c \neq a$: since $g'(a) < 0$, the quotient $\frac{g(x) - g(a)}{x - a}$ is negative for $x$ slightly bigger than $a$, so $g(x) < g(a)$ there, and $a$ is not a minimum.- $c \neq b$: since $g'(b) > 0$, the quotient $\frac{g(x) - g(b)}{x - b}$ is positive for $x$ slightly smaller than $b$; the denominator is negative, so $g(x) < g(b)$, and $b$ is not a minimum.
So $c \in (a, b)$ and the interior extremum theorem gives $g'(c) = 0$, that is, $f'(c) = y$. $\blacksquare$
Note that the proof does not use the Intermediate Value Theorem for $f'$, because $f'$ need not be continuous.
Consequence. A derivative cannot have a jump discontinuity. For example, there is no differentiable $F : \mathbb{R} \to \mathbb{R}$ with $F'(x) = \operatorname{sign}(x)$ for all $x$: that function takes the values $-1$ and $1$ but never $\tfrac12$.
> Common pitfall: "has the intermediate value property" does not imply "continuous". The derivative $g'$ above has the property (by Darboux) and is discontinuous at $0$.
Chapter 5 — L'Hôpital's rule
Theorem (L'Hôpital, zero-over-zero form). Let $f, g$ be differentiable on $(a, b)$, with $g'(x) \neq 0$ for all $x \in (a, b)$. Suppose
$$\lim{x \to a^+} f(x) = 0, \qquad \lim{x \to a^+} g(x) = 0, \qquad \lim{x \to a^+} \frac{f'(x)}{g'(x)} = L,$$
where $L \in \mathbb{R}$ (the rule also holds for $L = \pm\infty$). Then $\lim{x \to a^+} \frac{f(x)}{g(x)} = L$. The same holds for $x \to b^-$, for two-sided limits, and for $x \to \pm\infty$.
Proof ($L$ finite). Extend $f$ and $g$ to $[a, b)$ by $f(a) = g(a) = 0$; they are now continuous on $[a, x]$ for each $x \in (a, b)$. By Rolle, $g(x) \neq 0$ (otherwise $g' = 0$ somewhere in $(a, x)$). Cauchy's MVT on $[a, x]$ gives $cx \in (a, x)$ with
$$\frac{f(x)}{g(x)} = \frac{f(x) - f(a)}{g(x) - g(a)} = \frac{f'(cx)}{g'(cx)}.$$
Given $\varepsilon > 0$, choose $\delta$ with $\left\lvert \frac{f'(t)}{g'(t)} - L \right\rvert < \varepsilon$ for $a < t < a + \delta$. If $a < x < a + \delta$ then $a < cx < a + \delta$ too, so $\left\lvert \frac{f(x)}{g(x)} - L\right\rvert < \varepsilon$. $\blacksquare$
The infinity-over-infinity form. The same conclusion holds if instead $\lim{x \to a^+} \lvert g(x)\rvert = \infty$ (nothing more is needed about $f$). The proof is a little longer; see Rudin, Theorem 5.13.
Worked example. Find $\lim{x \to 0} \frac{x - \sin x}{x^3}$.
1. $f(x) = x - \sin x$ and $g(x) = x^3$ both tend to $0$; the quotient of derivatives is $\frac{1 - \cos x}{3x^2}$, still of the form $0/0$.2. Differentiate again: $\frac{\sin x}{6x}$, still $0/0$.3. Once more: $\frac{\cos x}{6} \to \frac16$.
Reading the chain backwards, each step's hypotheses hold near $0$: the denominators $x^3$, $3x^2$, $6x$ have derivatives $3x^2$, $6x$, $6$, which are non-zero for $x \neq 0$. So
$$\lim{x \to 0} \frac{x - \sin x}{x^3} = \frac16.$$
> Common pitfall: the rule goes one way only. With $f(x) = x + \sin x$ and $g(x) = x$ as $x \to \infty$, $f/g = 1 + \frac{\sin x}{x} \to 1$, but $f'/g' = 1 + \cos x$ has no limit. The rule is silent, not wrong: its hypothesis "the limit of $f'/g'$ exists" fails.
> Watch out: check the $0/0$ or $\infty/\infty$ form first. $\lim{x \to 0} \frac{x + 1}{x + 2} = \frac12$, but "differentiating" top and bottom gives $1$.
Chapter 6 — Taylor's theorem
Taylor polynomials
If $f$ is $n$ times differentiable at $a$, its Taylor polynomial of degree $n$ at $a$ is
$$Pn(x) = \sum{k=0}^{n} \frac{f^{(k)}(a)}{k!}(x - a)^k = f(a) + f'(a)(x - a) + \dots + \frac{f^{(n)}(a)}{n!}(x - a)^n.$$
It is the unique polynomial of degree at most $n$ whose value and first $n$ derivatives at $a$ match those of $f$. $P1$ is the tangent line. The remainder is $Rn(x) = f(x) - Pn(x)$. Everything useful about Taylor polynomials is a statement about $Rn$.
The theorem
Theorem (Taylor, Lagrange remainder). Let $n \geq 0$. Suppose $f^{(n)}$ is continuous on $[a, b]$ and differentiable on $(a, b)$. Then there is $c \in (a, b)$ with
$$f(b) = \sum{k=0}^{n} \frac{f^{(k)}(a)}{k!}(b - a)^k + \frac{f^{(n+1)}(c)}{(n+1)!}(b - a)^{n+1}.$$
The same holds with $b < a$ (then $c$ lies between $b$ and $a$). For $n = 0$ this is exactly the MVT.
Proof. Let $Pn$ be the Taylor polynomial at $a$ and choose the number $M$ so that
$$f(b) = Pn(b) + M(b - a)^{n+1}.$$
Define $g(x) = f(x) - Pn(x) - M(x - a)^{n+1}$ on $[a, b]$. Because $Pn^{(k)}(a) = f^{(k)}(a)$ for $k \leq n$ and every derivative of order at most $n$ of $(x-a)^{n+1}$ vanishes at $a$,
$$g(a) = g'(a) = \dots = g^{(n)}(a) = 0, \qquad g(b) = 0.$$
- Rolle on $[a, b]$ with $g(a) = g(b) = 0$ gives $x1 \in (a, b)$ with $g'(x1) = 0$.- Rolle on $[a, x1]$ with $g'(a) = g'(x1) = 0$ gives $x2 \in (a, x1)$ with $g''(x2) = 0$.- Continue: after $n + 1$ steps you have $x{n+1} \in (a, b)$ with $g^{(n+1)}(x{n+1}) = 0$.
(The hypotheses let each step apply Rolle: $g^{(k)}$ is continuous on $[a, b]$ and differentiable on $(a, b)$ for every $k \leq n$.) Since $Pn$ has degree at most $n$, $Pn^{(n+1)} = 0$, and the $(n+1)$-th derivative of $M(x - a)^{n+1}$ is $(n+1)!\,M$. So $0 = f^{(n+1)}(x{n+1}) - (n+1)!\,M$. With $c = x{n+1}$, $M = \frac{f^{(n+1)}(c)}{(n+1)!}$, which is the claim. $\blacksquare$
The error bound you actually use. If $\lvert f^{(n+1)}(t)\rvert \leq K$ for all $t$ between $a$ and $x$, then
$$\lvert f(x) - Pn(x)\rvert \leq \frac{K}{(n+1)!}\,\lvert x - a\rvert^{n+1}.$$
Worked example 1: the number e
Take $f(x) = e^x$, $a = 0$, $x = 1$. Every derivative is $e^x$, so $Pn(1) = \sum{k=0}^{n} \frac{1}{k!}$ and
$$e - Pn(1) = \frac{e^{c}}{(n+1)!} \quad \text{for some } c \in (0, 1).$$
You also need a bound on $e$ that does not use this computation. The standard one is $e < 3$: expanding $(1 + 1/m)^m$ with the binomial theorem shows that every term of the sequence defining $e$ is at most $\sum{k=0}^{m} \frac{1}{k!}$, and since $k! \geq 2^{k-1}$ this is at most $1 + 1 + \tfrac12 + \tfrac16 + \bigl(\tfrac18 + \tfrac1{16} + \dots\bigr) = \tfrac{35}{12} < 3$. With $e^c < e < 3$ you get $0 < e - Pn(1) < \frac{3}{(n+1)!}$.
With $n = 7$:
$$P7(1) = 1 + 1 + \tfrac12 + \tfrac16 + \tfrac1{24} + \tfrac1{120} + \tfrac1{720} + \tfrac1{5040} = \frac{685}{252} = 2.718253968\ldots,$$
and the error is below $\frac{3}{8!} = \frac{3}{40320} \approx 7.44 \times 10^{-5}$. The true error is $e - \frac{685}{252} \approx 2.79 \times 10^{-5}$, inside the bound. The bound is honest: it is proved, not observed.
Worked example 2: sin(0.1) with an almost sharp bound
For $f = \sin$ at $a = 0$ the derivatives cycle through $\sin, \cos, -\sin, -\cos$, so
$$\sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \dots$$
The coefficient of $x^4$ is $0$, so $P3 = P4$. Use the degree-4 remainder, which involves $f^{(5)} = \cos$ with $\lvert\cos\rvert \leq 1$:
$$\lvert \sin(0.1) - P4(0.1)\rvert \leq \frac{(0.1)^5}{5!} = \frac{10^{-5}}{120} \approx 8.33 \times 10^{-8}.$$
Here $P4(0.1) = 0.1 - \frac{0.001}{6} = \frac{599}{6000} = 0.0998333\ldots$, while $\sin(0.1) = 0.0998334166\ldots$. The actual error is $8.3313 \times 10^{-8}$, just under the bound $8.3333 \times 10^{-8}$.
> Trick: when the next Taylor coefficient is zero, the degree-$n$ polynomial equals the degree-$(n+1)$ one, and you may use the smaller, higher-order remainder. For $\sin$ and $\cos$ this gains a whole power of $x$ for free.
> Watch out: the bound needs $K$ to bound $f^{(n+1)}$ on the whole interval between $a$ and $x$, not just at $a$. For $e^x$ on $[0, 1]$ that is why you need $e < 3$ first.
Chapter 7 — Smooth, analytic, and the monsters
Smooth but not analytic
Let
$$f(x) = \begin{cases} e^{-1/x^2} & x \neq 0, \\ 0 & x = 0. \end{cases}$$
Claim. $f$ is $C^\infty$ on $\mathbb{R}$ and $f^{(k)}(0) = 0$ for every $k \geq 0$.
Sketch of proof. For $x \neq 0$, induction shows $f^{(k)}(x) = pk(1/x)\,e^{-1/x^2}$ for some polynomial $pk$. At $0$, use the definition and induction: $\frac{f^{(k)}(x) - 0}{x} = \frac1x pk(1/x) e^{-1/x^2}$, and with $t = 1/x$ this is a polynomial in $t$ times $e^{-t^2}$, which tends to $0$ as $\lvert t\rvert \to \infty$ because $e^{t^2}$ outgrows every power of $t$. So $f^{(k+1)}(0) = 0$. $\blacksquare$
Consequently every Taylor polynomial of $f$ at $0$ is the zero polynomial, and $Rn(x) = f(x) > 0$ for every $x \neq 0$ and every $n$. The Taylor series at $0$ converges everywhere, to the wrong function. So "infinitely differentiable" does not imply "equal to its Taylor series". A function that equals its Taylor series near each point is called (real) analytic; this $f$ is smooth but not analytic at $0$. Taylor's theorem is not wrong here: it only claims the remainder has the Lagrange form, and here the remainder simply does not go to $0$. Post 05 returns to this with power series.
Continuous but nowhere differentiable
Theorem (Weierstrass, 1872). Let $0 < a < 1$, let $b$ be an odd positive integer, and let $ab > 1 + \frac{3\pi}{2}$. Then
$$W(x) = \sum{n=0}^{\infty} a^n \cos(b^n \pi x)$$
is continuous at every $x \in \mathbb{R}$ and differentiable at no $x \in \mathbb{R}$.
For example, $a = \frac12$, $b = 13$ gives $ab = 6.5 > 1 + \frac{3\pi}{2} \approx 5.712$. Continuity comes from the Weierstrass M-test of post 05: $\lvert a^n \cos(b^n \pi x)\rvert \leq a^n$ and $\sum a^n$ converges, so the series converges uniformly, and uniform limits of continuous functions are continuous. The non-differentiability proof is a careful estimate of difference quotients (Hardy showed in 1916 that $ab \geq 1$ is enough). The picture to keep: the graph has corners at every scale, like $\lvert x\rvert$ at $0$, but everywhere.
The hierarchy
| Class | Example that is in this class but not the next ||---|---|| continuous | $\lvert x\rvert$ (not differentiable at 0) || differentiable | $x^2\sin(1/x)$ (derivative not continuous at 0) || $C^1$ | $x\lvert x\rvert$ (derivative $2\lvert x\rvert$, not differentiable at 0) || $C^\infty$ | $e^{-1/x^2}$ (not analytic at 0) || analytic | $\sin x$, $e^x$, polynomials |
Each row is strictly larger than the next. Weierstrass's $W$ sits in row 1 and is as far from row 2 as possible.
Practice Exercises
Exercise 1. Show that $f(x) = x\lvert x\rvert$ is differentiable on $\mathbb{R}$ with $f'(x) = 2\lvert x\rvert$, and that $f'$ is not differentiable at $0$.
<details><summary>Solution</summary>
For $x > 0$, $f(x) = x^2$ so $f'(x) = 2x$; for $x < 0$, $f(x) = -x^2$ so $f'(x) = -2x$. At $0$: $\frac{f(x) - f(0)}{x} = \lvert x\rvert \to 0$, so $f'(0) = 0$. In all cases $f'(x) = 2\lvert x\rvert$. Then $f' = 2\lvert x\rvert$ has a corner at $0$ (difference quotients $\pm 2$), so $f''(0)$ does not exist. So $f \in C^1(\mathbb{R})$ but $f$ is not twice differentiable.
</details>
Exercise 2. Find the point $c$ promised by the MVT for $f(x) = \sqrt{x}$ on $[1, 4]$.
<details><summary>Solution</summary>
Secant slope $\frac{\sqrt4 - \sqrt1}{4 - 1} = \frac13$. Solve $f'(c) = \frac{1}{2\sqrt c} = \frac13$: $\sqrt c = \frac32$, so $c = \frac94 = 2.25$, which lies in $(1, 4)$.
</details>
Exercise 3. Prove that $\ln(1 + x) < x$ for every $x > 0$.
<details><summary>Solution</summary>
Apply the MVT to $\ln(1 + t)$ on $[0, x]$: $\ln(1 + x) - \ln 1 = \frac{1}{1 + c}\,x$ for some $c \in (0, x)$. Since $c > 0$, $\frac{1}{1 + c} < 1$, so $\ln(1 + x) < x$.
</details>
Exercise 4. Compute $\lim{x \to 0} \frac{1 - \cos x}{x^2}$ with L'Hôpital's rule, checking the hypotheses.
<details><summary>Solution</summary>
Both $1 - \cos x$ and $x^2$ tend to $0$, both are differentiable, and $(x^2)' = 2x \neq 0$ for $x \neq 0$. The quotient of derivatives is $\frac{\sin x}{2x} \to \frac12$ (using $\frac{\sin x}{x} \to 1$, or one more application of the rule). So the limit is $\frac12$.
</details>
Exercise 5. Approximate $\sqrt{1.1}$ by the degree-2 Taylor polynomial of $\sqrt{1 + x}$ at $0$, and prove an error bound.
<details><summary>Solution</summary>
$f(x) = (1 + x)^{1/2}$ gives $f(0) = 1$, $f'(0) = \frac12$, $f''(0) = -\frac14$, so $P2(x) = 1 + \frac{x}{2} - \frac{x^2}{8}$ and $P2(0.1) = 1 + 0.05 - 0.00125 = 1.04875$. The third derivative is $f'''(t) = \frac38 (1 + t)^{-5/2}$, which is at most $\frac38$ for $t \in (0, 0.1)$. So
$$\lvert \sqrt{1.1} - 1.04875\rvert \leq \frac{3/8}{3!}(0.1)^3 = \frac{1}{16000} = 6.25 \times 10^{-5}.$$
Check: $\sqrt{1.1} = 1.0488088\ldots$, an error of about $5.88 \times 10^{-5}$. Since $f''' > 0$ the remainder is positive, so $1.04875$ is an underestimate.
</details>
Exercise 6. Suppose $f : \mathbb{R} \to \mathbb{R}$ satisfies $\lvert f(x) - f(y)\rvert \leq (x - y)^2$ for all $x, y$. Prove that $f$ is constant.
<details><summary>Solution</summary>
For $x \neq y$, $\left\lvert \frac{f(x) - f(y)}{x - y}\right\rvert \leq \lvert x - y\rvert$. Letting $x \to y$ gives $f'(y) = 0$ for every $y$. By Corollary 1 of the MVT on the interval $\mathbb{R}$, $f$ is constant.
</details>
Exercise 7. Can the floor function $\lfloor x \rfloor$ be the derivative of some function $F$ on $[0, 2]$?
<details><summary>Solution</summary>
No. On $[0, 2]$ the floor function takes the values $0$, $1$ and $2$ but never $\frac12$. If $F' = \lfloor x \rfloor$ on $[0, 2]$, Darboux's theorem on $[0, 1]$ (where $F'(0) = 0$ and $F'(1) = 1$) would give $c$ with $F'(c) = \frac12$. Contradiction.
</details>
Cheat-sheet
| Result | Hypotheses | Conclusion ||---|---|---|| Differentiable ⇒ continuous | $f'(c)$ exists | $f$ continuous at $c$ || Carathéodory form | $f'(c)$ exists | $f(x) - f(c) = \varphi(x)(x - c)$, $\varphi$ continuous at $c$ || Chain rule | $g'(c)$ and $f'(g(c))$ exist | $(f\circ g)'(c) = f'(g(c))g'(c)$ || Interior extremum | max or min at interior $c$, $f'(c)$ exists | $f'(c) = 0$ || Rolle | continuous on $[a,b]$, diff. on $(a,b)$, $f(a) = f(b)$ | some $f'(c) = 0$ || MVT | continuous on $[a,b]$, diff. on $(a,b)$ | $f(b) - f(a) = f'(c)(b - a)$ || Cauchy MVT | same, for $f$ and $g$ | $(f(b) - f(a))g'(c) = (g(b) - g(a))f'(c)$ || Darboux | diff. on $[a,b]$ | $f'$ has the intermediate value property || L'Hôpital | $0/0$ or $\infty/\infty$, $g' \neq 0$, $f'/g' \to L$ | $f/g \to L$ || Taylor (Lagrange) | $f^{(n)}$ continuous on $[a,b]$, diff. on $(a,b)$ | $Rn = \frac{f^{(n+1)}(c)}{(n+1)!}(b - a)^{n+1}$ || Error bound | $\lvert f^{(n+1)}\rvert \leq K$ between $a$ and $x$ | $\lvert Rn(x)\rvert \leq \frac{K}{(n+1)!}\lvert x - a\rvert^{n+1}$ || Smooth but not analytic | $e^{-1/x^2}$ | all $f^{(k)}(0) = 0$, Taylor series is $0$ |
What's next
Post 04 builds the Riemann integral from scratch: partitions, upper and lower Darboux sums, the Riemann criterion, and proofs that continuous and monotone functions are integrable. The Mean Value Theorem from this post is the engine of the proof of the Fundamental Theorem of Calculus there, and a relative of $x^2\sin(1/x)$ returns as a warning about what that theorem needs.
References
- Stephen Abbott, Understanding Analysis, 2nd ed., Springer (Undergraduate Texts in Mathematics), 2015 — Chapter 5, "The Derivative", including Darboux's theorem and a continuous nowhere-differentiable function.- Walter Rudin, Principles of Mathematical Analysis, 3rd ed., McGraw-Hill, 1976 — Chapter 5 (Theorems 5.10 MVT, 5.12 Darboux, 5.13 L'Hôpital, 5.15 Taylor).- Robert G. Bartle and Donald R. Sherbert, Introduction to Real Analysis, 4th ed., Wiley, 2011 — Chapter 6, including the Carathéodory form of the chain rule.- Michael Spivak, Calculus, 4th ed., Publish or Perish, 2008 — Chapters 10–11 and 20 (Taylor polynomials and remainders).- Jiří Lebl, Basic Analysis I: Introduction to Real Analysis, free textbook — jirka.org/ra, Chapter 4.- MIT OpenCourseWare, 18.100A Real Analysis (Fall 2020), lecture notes on differentiation and Taylor's theorem.- G. H. Hardy, "Weierstrass's non-differentiable function", Transactions of the American Mathematical Society 17 (1916), 301–325.
> Note: this post is in progress. Planned additions: the Peano and integral forms of the Taylor remainder, convex functions and the second-derivative test, a full proof that the Weierstrass function is nowhere differentiable, and Newton's method with its quadratic error bound.
React Deep Dive — 00 · Rendering Model
Most React bugs that survive code review are not syntax mistakes. They are wrong beliefs about the rendering model: "props changed, so the child re-renders", "setting state updates the variable", "this effect runs once", "the key is only for the warning". Each belief works in the demo and fails in production — as lost input state, a stale value, a double request, or a list that shows the wrong row after a sort. This series is for engineers who already ship React and want the model that sits under it. Post 00 builds that model from the ground: what an element, a component and an instance really are; the render and commit phases; the Fiber tree and its work loop; the reconciliation heuristics; keys and identity; batching; StrictMode; and refs. Examples target React 19.2, with notes where React 18 behaves differently.
> Series map: 00 Rendering Model (this post) → 01 Hooks & State Architecture → 02 Concurrent React & React 19 → 03 Performance, Testing & Architecture at Scale. Future topics: see the "Planned future extensions" table in 03.
Learning Outcome
- Tell apart an element, a component and a component instance, and say where state actually lives.- Describe the three steps of an update — trigger, render, commit — and what is allowed in each.- Explain the Fiber data structure, the two trees ( and ), and why rendering can be paused.- Predict when React keeps state and when it throws it away, from the element type and position alone.- Use keys on purpose: to keep identity across reorders, and to reset a subtree.- List the exact reasons a component renders, and the bailouts that stop a render.- Explain automatic batching (React 18+) and the snapshot behaviour of state.- Read StrictMode's double calls as a test, not a bug, and know what React 19 changed.- Use refs for values that must not trigger a render, including ref cleanup functions and as a prop.
Chapter 1 — Elements, components and instances
Terminology
- Element — a plain, immutable object that describes what should be on screen: . Cheap to create, thrown away after each render.- Component — a function (or class) that takes props and returns elements. It is a description of a description.- Instance — the thing that holds state for one mounted use of a component. For function components React does not expose an instance object; the state lives on an internal fiber.- Host component — a platform element such as or (a string ). The renderer (, React Native) turns it into a real node.- Renderer — the package that owns the host environment. holds the component model; owns the DOM.
What JSX becomes
With the automatic JSX runtime (the default in Vite, Next.js and TypeScript's ), this:
compiles to roughly:
The result is an ordinary object (, ). Nothing has rendered yet; has not even been called. The element only records which component to call and with which props. React decides later whether to call it at all.
Where state lives
State does not live "in the function". A function component is called again on every render, and its local variables are new each time. The state lives on the fiber that React created when it first mounted that element at that position in the tree. reads from and writes to that fiber.
This has one big consequence that the rest of the post keeps returning to: identity is decided by position and type (and key), not by the component's name or by which variable held the element.
> Trick: say "React calls my component" instead of "my component runs". It keeps the right model in mind: React owns the call, the timing, and how many times it happens.
Chapter 2 — Trigger, render, commit
Every screen update goes through the same three steps.
1. Trigger. Something schedules an update: the initial , or a / call, or a change in an external store read with .2. Render. React calls the components that may have changed and builds the next tree of elements. It compares that tree with the previous one (reconciliation) and records which host nodes need changes.3. Commit. React applies the recorded changes to the DOM in one go, attaches refs, and runs effects.
Render phase: pure and interruptible
In the render phase React only calculates. It calls your components and compares results. Because of concurrent rendering (Post 02), the render phase can be paused to let the browser handle input, restarted when a more urgent update arrives, or thrown away if the result is no longer needed.
That is why components must be pure during render: same props, state and context in, same elements out, and no side effects. An call, a render counter in a module variable, a write to a ref — any of these can run twice, or run for a render that never commits.
Commit phase: synchronous and never partial
The commit phase is not interruptible. Once React starts committing, the whole tree is applied in one synchronous pass, so the user never sees half an update. Inside the commit, the order is:
| Step | What happens ||---|---|| Before mutation | for classes || Mutation | DOM nodes inserted, updated, removed; old ref detached; layout-effect cleanups of changed components || Layout | refs attached; setups; / || (browser paints) | || Passive | cleanups then setups |
runs after the DOM is changed but before the browser paints, so it can measure layout and set state without a visible flicker. normally runs after paint. The React docs add one detail: when the update came from a discrete interaction such as a click, React may run the effects before paint. Do not depend on either timing for correctness; use when you need "before paint".
> Watch out: "render" in React does not mean "paint to the screen". A component can render many times with zero DOM changes, and the DOM only changes in the commit. Profilers (Post 03) show render time and commit time separately for this reason.
Chapter 3 — The Fiber tree and the work loop
This chapter describes internals. They are not public API and they change between versions, but the shape has been stable since React 16 and it explains most observable behaviour.
Terminology
- Fiber — an internal object, one per element in the tree (components and host nodes). It is both the "instance" and a unit of work.- tree — the fibers that match what is on screen now.- tree — the tree being built during a render.- Alternate — each fiber points to its twin in the other tree. React reuses the pair instead of allocating new objects (double buffering).- Lanes — a bit mask on each fiber that says which priorities of pending work it has. Post 02 covers them.- Flags — bits on a fiber that say what the commit must do: place, update, delete, run effects.
What a fiber holds
A simplified view of the fields that matter for understanding behaviour:
Two fields explain a lot:
- of a function component points to a linked list of hooks in call order. That is the real reason hooks must be called in the same order every render (Post 01).- lets React skip whole subtrees. If a fiber has no own work and is empty, React reuses the whole subtree from without calling any component in it.
The work loop
The tree is a linked list (, , ), so React can walk it with a plain loop instead of recursion. That is what makes pausing possible: the loop can stop after any fiber and resume later from a saved pointer.
- goes down: it calls the component (or bails out), then reconciles the returned children into child fibers.- goes back up: for host fibers it creates or prepares DOM nodes (not yet attached) and bubbles flags upward so the commit knows where to look.- asks the Scheduler whether the current time slice is used up. Synchronous updates use a loop without this check; transitions use the one above. The slice is only a few milliseconds long, so the browser gets regular chances to handle input.
When the root completes, React swaps the pointer: the tree becomes . That swap happens during the commit, which is why a half-finished render is never visible.
> Trick: the React DevTools "Components" tab shows the fiber tree (host and component fibers), not the DOM. When a DevTools tree and the Elements panel disagree about nesting, the fiber tree is what React reconciles.
Chapter 4 — Reconciliation heuristics
Comparing two arbitrary trees optimally is expensive; the general algorithms are roughly O(n³). React uses two heuristics that make it O(n):
1. Different element types produce different trees. If the at a position changes ( → , → ), React unmounts the old subtree — destroying its DOM and its state — and mounts a new one.2. Keys mark stable identity among siblings. Within one list of children, React matches old and new children by key (or by index when there is no key).
When the type and key match, React keeps the fiber, keeps the state, and updates the props.
Same position, same type: state survives
Both branches produce a at the same position. React sees the same type, so it keeps the state of and only changes the prop. This surprises people who expect "a different branch" to mean "a fresh component".
Different type: state is lost
Change it to and the type at that position changes, so the subtree is remounted and its state is gone.
The component-inside-component bug
Every render of creates a new function. The element type is compared by reference, so from this render is a different type from last render. Every row is unmounted and remounted on every render: state resets, focus is lost, effects re-run, and it is slow. Define components at module level. The lint rule in v6 reports this pattern.
> Common pitfall: conditional wrappers change the tree shape. keeps in slot 2 either way, but moves to a different depth and resets its state every time flips.
Chapter 5 — Keys, identity and state preservation
What keys do
A key is an identity among siblings. React uses it to match children between two renders. With keys, moving an item moves its fiber (state and DOM included). Without keys, React matches by index.
holds local state (say, an "editing" flag and an uncontrolled ). Sort the list, and the row at index 0 now receives a different prop but keeps the old state and the old input text. The data moved; the identity did not.
Rules:
- Keys must be stable, unique among siblings, and come from the data (). Not — that remounts every row on every render.- Index keys are fine only for lists that are never reordered, filtered or inserted into, and whose rows hold no state.- Keys do not need to be globally unique; two different lists can reuse the same keys.- is not a prop. The child cannot read ; pass the id again as a separate prop if the child needs it.
Keys to reset state on purpose
Because a new key means a new identity, a key is the cleanest way to reset a subtree:
The alternative — an effect that watches and resets five pieces of state — renders once with stale state, then again with the reset state, and is easy to get wrong when a new piece of state is added.
A key can go on a when each item renders several siblings (); the short syntax cannot take a key.
> Watch out: the "missing key" warning only covers arrays. Unstable identity from a changing type or a changing tree depth (Chapter 4) produces no warning at all.
Chapter 6 — When a component renders, and when it does not
The four reasons a component renders
1. Initial mount.2. Its own state changed (, ), or an external store it subscribes to with changed.3. Its parent rendered. By default, when a component renders, React renders all of its children, whether their props changed or not.4. A context it reads changed ( or ), compared with .
What is not on the list: "its props changed". Props are an input to a render that already happens because the parent rendered. A parent can pass identical props and the child still renders; is what makes React compare them.
Bailouts
React skips work in these cases:
| Case | What React does ||---|---|| where | Usually skips the update. React may still call the component once before it can tell the result is the same, but it does not go on into the children or commit. || Fiber has no pending work and its props object is the same reference as last time | Reuses the fiber and skips calling it; checks to decide whether to go deeper. || and every prop is equal | Skips the render (unless its own state or a read context changed). || Subtree has no pending lanes | Whole subtree reused from . |
The second row is the basis of the children-as-props pattern:
was created by the parent, not by . When re-renders on every scroll, is the same element object as before, so React bails out of without any . Moving state down, or lifting content up into , often beats memoisation.
Context is not a bailout-friendly channel
Every component that reads a context renders when the provided value changes, and does not stop that. A provider whose value is a new object on each render makes every consumer render on every parent render:
Post 01 covers the fixes (stable values, splitting contexts, selectors via external stores). In React 19 you can write directly; still works.
Adjusting state when a prop changes
Sometimes state must follow a prop. The effect version renders twice with a stale frame in between. React supports setting state during render for the component that is rendering, guarded by a comparison:
React throws away the JSX of the first pass and re-runs the component immediately, before children render. Prefer a reset or deriving the value; use this only when those do not fit.
> Common pitfall: "I wrapped the child in and it still renders." Check, in order: a new object/array/function prop created in the parent's render; a context the child reads; the child's own state; passed as JSX (a new element object every render, so never matches).
Chapter 7 — Batching and state snapshots
State is a snapshot
One click shows 1, not 3. is a constant for this render; each call queues "replace with 0 + 1". An updater function reads the queued value instead:
three times gives 3. The still prints 0. The new value exists only in the next render.
Automatic batching (React 18+)
React groups several state updates into a single render. Before React 18 this happened only inside React event handlers; updates in , promises or native listeners each caused their own render. With (React 18+), batching is automatic everywhere:
Apps still on the legacy root kept the old behaviour in React 18; React 19 removed , so every React 19 app batches automatically.
Opting out with
Rarely you need the DOM to be updated now, for example to scroll to a newly added item:
forces a synchronous render and commit. It is expensive and it defeats concurrent features for that update, so keep it for DOM-measurement cases.
> Trick: batching also explains why a click handler that calls three different functions produces one entry, not three, in the Profiler.
Chapter 8 — StrictMode
changes nothing in production. In development it runs extra checks by doing things twice, to expose code that is not pure or not cleaned up.
| What is doubled (development only) | What it catches ||---|---|| Component function bodies | Side effects during render, mutation of props or state || initialisers and updaters, reducers | Impure initialisers and reducers || Class , , | Same, for classes || Effects: setup → cleanup → setup on mount | Missing cleanup (duplicate subscriptions, leaked timers, double connections) || Ref callbacks on mount (React 19) | Missing ref cleanup |
React 19 changes two details: during the double render, and reuse the result of the first call; and ref callbacks are also run twice on mount, to simulate a component being hidden and shown again (for example by a Suspense fallback).
The effect double-run is the one people fight. It is a simulation of what really happens in production when a component is unmounted and mounted again: route changes with cached screens, hiding and showing (Post 02), Fast Refresh. If an effect breaks when run twice, it will break there too.
> Watch out: "fixing" StrictMode with a flag to skip the second effect run hides the missing cleanup instead of fixing it. The leak comes back in production the first time the component remounts.
Chapter 9 — Refs
: a box that survives renders
Writing does not schedule a render. That makes refs right for values the UI does not display: timer ids, the previous value, an , a DOM node, a third-party widget instance.
Rules that keep refs safe:
- Do not read or write during render (except lazy initialisation, below). The render would depend on a value React does not track, and concurrent rendering can run that render more than once. The lint rule flags this.- Read and write them in event handlers and effects.- In React 19 with TypeScript, needs an argument (), and all refs are mutable.- Lazy initialisation is the one allowed render-time access: .
DOM refs and callback refs with cleanup
React sets to the DOM node in the commit and back to when it is removed. For logic that must run when a node appears or goes away, use a callback ref. React 19 lets it return a cleanup function:
With a cleanup returned, React calls the cleanup on detach instead of calling the callback with . Because the arrow function above is a new function every render, React detaches and re-attaches it on every render; wrap it in (or let the React Compiler memoise it) if that is costly.
as a prop (React 19)
Function components now receive as a normal prop. is no longer needed and the React team plans to deprecate it:
To expose a small imperative API instead of the raw node, combine the prop with .
> Trick: keep imperative handles small and verb-shaped (, , ). Exposing the whole DOM node lets every parent reach in and couple itself to your markup.
Practice Exercises
Exercise 1 — Predict the state
Click three times while is , then flip . Does the count reset? Now change the code so that it does.
<details><summary>Solution</summary>
It does not reset. Both branches render at the same position with the same type, so React keeps the fiber and its state and only updates . To reset, give the branches different keys:
</details>
Exercise 2 — The index-key bug
Build a list of three rows, each with an uncontrolled , keyed by index. Type into row 0, then prepend an item. Explain what you see, then fix it.
<details><summary>Solution</summary>
The typed text stays in the first input, which now belongs to the new item. React matched children by index, so the fiber (and its DOM input) at index 0 was kept and given new props; only applies on mount. Fix: , so the existing row's fiber moves to index 1 together with its DOM node.
</details>
Exercise 3 — Count the renders
After one click, which components render?
<details><summary>Solution</summary>
, and all render. renders because its parent rendered. renders because is a new object literal on every render, so the comparison fails. Hoist the object to module scope (or it, or let the React Compiler do it) and bails out.
</details>
Exercise 4 — Make it StrictMode-safe
This effect sends two "join" messages in development. Fix it without disabling StrictMode.
<details><summary>Solution</summary>
Pair the setup with a cleanup so that setup → cleanup → setup leaves the server in the right state:
If the protocol cannot express "leave", the join belongs in the event that caused it (for example the click that opened the room), not in an effect.
</details>
Exercise 5 — Batching
What does one click show and log?
<details><summary>Solution</summary>
The button shows (the queue is "replace with n + 5", then "add 1"). The log prints the old : the timeout's closure captured this render's constant.
</details>
Cheat-sheet
| Topic | Rule ||---|---|| Element | Plain immutable object ; creating it does not call the component || Where state lives | On the fiber at that position in the tree || Update steps | Trigger → render (pure, can pause or be discarded) → commit (sync, all at once) || Two trees | (on screen) and (being built); swapped at commit || Type changes at a position | Subtree unmounted, state lost || Same type at a position | Fiber kept, props updated, state kept || Keys | Stable ids among siblings; new key = new identity = reset || Component renders when | Mount, own state/store change, parent renders, read context changes || Not a reason | "Its props changed" on its own || Cheap bailout | Pass content as ; move state down || fails when | New object/array/function props, JSX , context, own state || Batching | Automatic everywhere with (React 18+) || StrictMode (dev) | Double render, double initialisers, setup→cleanup→setup, double ref callbacks (19) || Refs | Not read/written during render; ref callbacks may return cleanup (19); is a prop (19) |
What's next
Post 01 builds on the fiber model to explain hooks: why they are stored as a linked list and must be called in a fixed order, how to write effects that do not race or leak (and when an effect is the wrong tool), , , , context performance, and the now-stable . It then steps up a level to state architecture: sorting state into server state, client state and URL state, and choosing between TanStack Query, Zustand and Redux Toolkit.
For the language layer under all of this — closures, the event loop and microtasks that explain stale values and effect timing — see the JavaScript Deep Dive series. The Next.js Deep Dive and Vue Deep Dive series cover the framework built on React's server model and the other major reactivity model, for comparison.
References
- Render and Commit — the trigger, render, commit steps.- Preserving and Resetting State — position, type and key identity.- Rendering Lists — keys and why index keys break.- Keeping Components Pure and Rules of React.- Queueing a Series of State Updates — updater functions and batching.- · · · .- React 19 release post and React 19 upgrade guide — as a prop, ref cleanup, StrictMode changes.- React 18 automatic batching — the batching change.- React source: ReactFiber and ReactFiberWorkLoop — the internals described in Chapter 3.
AWS Course — 08 · Infrastructure as Code — Terraform on AWS
Posts 01-07 used the AWS CLI and console to build a real workload. Both are fine for learning; both are wrong for production. The final base post covers Infrastructure as Code (IaC): declarative, version-controlled, repeatable definitions of every resource. The series uses Terraform as the primary tool — the de facto industry standard at present — with a fair comparison against CloudFormation, CDK, and Pulumi. By the end of this post, the entire 3-tier architecture from Post 03 fits in 150 lines of HCL anyone on the team can read, review, and redeploy.
> Series map: 00 Foundations → 01 Network First → 02 Compute & Storage → 03 Scale & Survive → 04 Managed Data → 05 Serverless & Events → 06 Workflow Orchestration → 07 Observability & Security → 08 Infrastructure as Code (this post). Future extensions: containers (ECS/EKS), edge (CloudFront/Route53), CI/CD pipelines, multi-account organisations, FinOps deep dive.
Learning Outcome
- Understand why IaC matters and the trade-offs between tools.- Install Terraform and set up an AWS provider.- Write resources, variables, outputs, modules.- Use a remote backend (S3 + DynamoDB) for state.- Apply Terraform's plan / apply / destroy cycle safely.- Structure a real repository: envs (dev/staging/prod), modules, secrets, CI/CD.- Compare Terraform vs CloudFormation vs CDK vs Pulumi.
Chapter 1 — Why IaC
| Without IaC | With IaC ||-------------|----------|| Resources created by clicking — no record of how | Every resource in a git-tracked file || Re-creating in another region/account = pain | in a new workspace || Drift between environments | Same code, parameterised || Code review for app code only | Code review for infrastructure too || Recovery from incident = guesswork | Re-apply from version control |
In serious organisations, clicking in the console for production is an audit finding. Even small projects benefit: the second time you destroy and rebuild a test environment is when IaC pays for itself.
Chapter 2 — Tool comparison
| Tool | Language | Vendor | When ||------|----------|--------|------|| Terraform / OpenTofu | HCL | HashiCorp / Linux Foundation | most multi-cloud, most ops teams, default in 2026 || CloudFormation | YAML / JSON | AWS | AWS-only stacks that benefit from native rollback + drift detection || AWS CDK | TypeScript / Python / Java / Go | AWS | teams comfortable with code-defined infra, complex constructs || Pulumi | TypeScript / Python / Go / C# | Pulumi | multi-cloud with general-purpose language preferred || AWS SAM | YAML | AWS | serverless-first projects (extends CloudFormation) || Ansible / Chef / Puppet | YAML / Ruby | various | config management of existing servers, not IaC |
Terraform's hegemony comes from:- Multi-cloud + huge provider ecosystem (AWS, Azure, GCP, Datadog, GitHub, Cloudflare, etc.).- Mature module ecosystem (the registry).- Clear state model + plan/apply workflow.
For pure AWS shops, CDK is increasingly popular — it generates CloudFormation under the hood but lets you write in familiar code with constructs that bundle common patterns.
> Note: in 2023 HashiCorp changed Terraform's licence; the OpenTofu fork (Linux Foundation, MPL-2.0) is a drop-in replacement many teams now prefer. The HCL syntax + provider plugins are compatible.
Chapter 3 — Terraform install + first resource
A minimal AWS provider + resource:
Workflow:
Chapter 4 — Core HCL constructs
Variables
Pass at apply time:
Outputs
Print with after apply.
Locals
Resources with foreach / count
Chapter 5 — Modules
A module is a reusable bundle of resources. The full 3-AZ VPC from Post 01 can be a module:
Consume:
Public registry
For many common patterns, use a pre-built module instead of writing your own:
The official repos cover VPC, EKS, RDS, ALB, ASG, IAM, Lambda — production-ready, peer-reviewed, well-tested.
Chapter 6 — Remote state
By default Terraform stores state locally in . For teams, store it in S3 + a DynamoDB lock table:
Setup once: create the bucket + lock table by hand (or with a tiny bootstrap Terraform run). Then every subsequent project uses the backend.
Watch out: the state file contains every value — including secrets you passed to resources. Encrypt the bucket, restrict access tightly, and treat state with the same care as a database backup.
Chapter 7 — Project layout
A real Terraform repo for a multi-env workload:
Each is an independent Terraform root. Same modules, different parameters. Promotions are PRs that change values + module versions.
Chapter 8 — The plan / apply discipline
Rules everyone in the team should follow:
1. Always review the plan before apply. Terraform happily replaces a database if the configuration says so.2. Use on stateful resources (RDS, S3 buckets with data).3. Workspaces or directories isolate envs — never one state file for dev + prod.4. Lock files () are committed — pins provider versions.5. Pin module + provider versions. Floating versions break builds quietly.
> Trick: when you see in a for a resource you don't want destroyed (an RDS, an EBS volume with data), stop. Either the change is wrong, or you need , or you need a migration approach. Never just apply through it.
Chapter 9 — Putting it all together: a 3-tier app in Terraform
Compressed example tying Posts 01-04 together:
This is 150 lines for the whole stack. Adding a new region is a directory copy + 2 variable changes.
Chapter 10 — CI/CD for Terraform
A typical pipeline (GitHub Actions / GitLab CI / CodePipeline):
1. PR opened with changes.2. CI runs , , .3. The plan is posted as a PR comment for review.4. On merge to , CI runs against the target env.5. Optionally run , , for static security analysis.
Use Atlantis or AWS-managed alternatives like CodePipeline + CodeBuild for centralised Terraform automation.
For high-stakes envs, gate apply behind manual approval in the pipeline. Belt-and-braces: even with a perfect plan, a second pair of eyes catches the case where the plan and the intent diverge.
Chapter 11 — Common Terraform pitfalls
| Pitfall | Fix ||---------|-----|| State file lost or corrupted | use remote backend; backup the bucket || Two people apply simultaneously | DynamoDB lock table || Drift (resource changed in console) | run regularly; to reconcile || Provider version floats and breaks | pin versions in || Secrets in committed to git | use SSM / Secrets Manager, fetch via data sources || Big monolith refactors | split into modules + per-env directories || Resource destroyed accidentally | on stateful things || Drift you can't reconcile | as a last resort, then to re-attach |
Practice Exercises
Exercise 1 — Hello Terraform
Install Terraform; write a minimal that creates a single S3 bucket; run .
Exercise 2 — Variables + outputs
Parameterise the bucket name with a variable; add an output for the bucket ARN. Use .
Exercise 3 — Remote backend
Create an S3 bucket + DynamoDB lock table (by hand or with a tiny bootstrap module). Configure your Exercise 1 module to use the S3 backend. Confirm no longer appears locally.
Exercise 4 — VPC module
Use the public module to recreate the 3-AZ VPC from Post 01. Compare line count vs the CLI walkthrough.
Exercise 5 — Full 3-tier stack
Wire up Chapter 9's example end-to-end. Apply to a fresh AWS account, hit the ALB DNS, confirm responses come from the EC2 instances. Destroy.
Exercise 6 — Pipeline
Push your Terraform repo to GitHub. Add a GitHub Actions workflow that runs + + on PRs and on merge. Bonus: add + .
Cheat-sheet
| What | How ||------|-----|| Init | || Plan | || Apply | || Destroy | || Format | || Validate | || Workspace | || Variable file | || Remote state | S3 bucket + DynamoDB lock table || Public modules | || Prevent destroy | || Replace one resource | || Import existing | || Tools | tflint, tfsec, checkov for static analysis || Alternative | OpenTofu (drop-in OSS fork) |
Course base complete — what's next
This concludes the base AWS course. You've covered:
- Cloud foundations + account setup.- Network-first design with VPC.- Compute + storage with EC2 / EBS / S3.- High availability with ALB + ASG + Multi-AZ.- Managed data: RDS, Aurora, DynamoDB, ElastiCache.- Serverless + events: Lambda, API Gateway, SQS, SNS, EventBridge.- Workflow orchestration: Step Functions + Saga.- Production-ready observability + security baseline.- Infrastructure as Code with Terraform.
That covers a sizable fraction of what a working cloud engineer touches week-to-week.
Planned future extensions
| # | Topic | Why it follows ||---|-------|----------------|| 09 | Containers — ECS Fargate + EKS basics | modern alternative to EC2 + ASG || 10 | Edge — CloudFront, Route 53, ACM | global perf + DNS || 11 | CI/CD — CodePipeline, CodeBuild, CodeDeploy, GitHub Actions | release safely || 12 | Multi-account — AWS Organizations, SSO, Control Tower, landing zones | enterprise scale || 13 | FinOps — Cost Explorer, Budgets, Compute Optimizer, Savings Plans modelling | reduce spend without losing capacity || 14 | Data analytics — Glue, Athena, Kinesis, Redshift, OpenSearch | the analytics half of the platform || 15 | ML on AWS — SageMaker overview, Bedrock | applied AI || 16 | Disaster recovery — backup strategies, RTO/RPO, cross-region failover | survive worst case |
References
- Terraform AWS provider docs- Terraform AWS modules- HashiCorp Learn — Terraform tracks- OpenTofu — the open-source fork.- Terraform: Up & Running by Yevgeniy Brikman — the canonical book.- AWS CloudFormation User Guide for comparison.- AWS CDK Workshop for the CDK perspective.
> Note: this post — and this base course — is in progress. Planned additions: full Terraform-only walkthrough of the 3-tier app with screenshots; CDK and CloudFormation versions of the same stack for direct comparison; Atlantis vs Terraform Cloud vs Spacelift overview.
Real Analysis — 02 · Topology of the Real Line and Continuity
Calculus states that a continuous function on a closed interval has a maximum and takes every value in between. Both facts can fail on an open interval or on the rationals, and the reason is not the function but the set it lives on. This post first studies subsets of $\mathbb{R}$ — open, closed and compact sets — and then functions: the $\varepsilon$–$\delta$ definition of a limit and of continuity, with fully worked $\delta$'s, the Extreme Value Theorem, the Intermediate Value Theorem, and uniform continuity. It builds directly on the Axiom of Completeness (Real Analysis 00) and on Bolzano–Weierstrass and sequences (Real Analysis 01).
> Series map: 00 The Real Numbers & Completeness → 01 Sequences & Series → 02 Topology of ℝ & Continuity (this post) → 03 Differentiation & Taylor's Theorem → 04 The Riemann Integral → 05 Uniform Convergence & Power Series.
Learning Outcome
- Define open sets, limit points, closed sets and closure, and decide which of these a given set is.- Define compactness by sequences and by open covers, and prove one direction of the Heine–Borel Theorem.- State the $\varepsilon$–$\delta$ definition of a functional limit and its sequential criterion, and use the criterion to prove that a limit does not exist.- Prove continuity from the definition, with an explicit $\delta$ for $f(x) = x^2$ at a point, and check it numerically.- Prove that continuous images of compact sets are compact, and deduce the Extreme Value Theorem.- Prove the Intermediate Value Theorem using the supremum.- Define uniform continuity, show that $1/x$ and $x^2$ fail it on suitable domains, and prove that continuous functions on compact sets are uniformly continuous.- Describe the discontinuity sets of the Dirichlet and Thomae functions.
Chapter 1 — Open and closed sets
Terminology
- $\varepsilon$-neighbourhood — $V\varepsilon(a) = (a - \varepsilon, a + \varepsilon)$.- Open set — $O \subseteq \mathbb{R}$ is open if for every $a \in O$ there is $\varepsilon > 0$ with $V\varepsilon(a) \subseteq O$. Every point has some room around it inside the set.- Limit point of $A$ — a point $x$ (in $A$ or not) such that every $V\varepsilon(x)$ contains a point of $A$ other than $x$.- Isolated point of $A$ — a point of $A$ that is not a limit point of $A$.- Closed set — a set that contains all of its limit points.- Closure — $\overline{A} = A \cup L$, where $L$ is the set of limit points of $A$.- Complement — $A^c = \mathbb{R} \setminus A$.
Examples of open sets
- $\mathbb{R}$ and $\emptyset$ are open (the second vacuously).- Every open interval $(a, b)$ is open: for $x \in (a,b)$ take $\varepsilon = \min(x - a,\ b - x)$; then $V\varepsilon(x) \subseteq (a,b)$.- $[0, 1)$ is not open: no neighbourhood of $0$ fits inside it.
Theorem. (i) Any union of open sets is open. (ii) A finite intersection of open sets is open.
Proof. (i) A point of the union lies in some $O\lambda$, and a neighbourhood inside $O\lambda$ is inside the union. (ii) If $a \in O1 \cap \cdots \cap ON$, choose $\varepsiloni$ with $V{\varepsiloni}(a) \subseteq Oi$ and take $\varepsilon = \mini \varepsiloni > 0$. $\blacksquare$
The word "finite" in (ii) matters: $\bigcap{n=1}^\infty \left(-\frac1n, \frac1n\right) = \{0\}$, which is not open. With infinitely many $\varepsiloni$ the minimum can be $0$.
Limit points and closed sets
Theorem. $x$ is a limit point of $A$ if and only if $x = \lim an$ for some sequence $(an)$ in $A$ with $an \ne x$ for all $n$.
Proof. ($\Rightarrow$) For each $n$ pick $an \in V{1/n}(x) \cap A$ with $an \ne x$; then $\lvert an - x \rvert < 1/n \to 0$. ($\Leftarrow$) Given $\varepsilon$, the terms $an$ with $n$ large lie in $V\varepsilon(x)$, are in $A$, and differ from $x$. $\blacksquare$
So a set is closed exactly when it contains the limit of every convergent sequence of its points (constant sequences included, for points of $A$ itself).
| Set | Limit points | Open? | Closed? ||-----|--------------|-------|---------|| $[a, b]$ | $[a, b]$ | no | yes || $(a, b)$ | $[a, b]$ | yes | no || $\{1/n : n \in \mathbb{N}\}$ | $\{0\}$ | no | no ($0$ missing) || $\{0\} \cup \{1/n : n \in \mathbb{N}\}$ | $\{0\}$ | no | yes || $\mathbb{Z}$ | none | no | yes (vacuously) || $\mathbb{Q}$ | $\mathbb{R}$ (density) | no | no || $\mathbb{R}$, $\emptyset$ | $\mathbb{R}$, none | yes | yes |
Theorem. A set is open if and only if its complement is closed. Consequently, finite unions and arbitrary intersections of closed sets are closed (De Morgan's laws).
Proof of one direction. Let $O$ be open and let $x$ be a limit point of $O^c$. If $x \in O$, some $V\varepsilon(x) \subseteq O$ contains no point of $O^c$, contradicting that $x$ is a limit point of $O^c$. So $x \in O^c$, and $O^c$ is closed. $\blacksquare$
The closure $\overline{A}$ is the smallest closed set containing $A$; for example $\overline{\mathbb{Q}} = \mathbb{R}$ and $\overline{(a,b)} = [a,b]$.
> Watch out: "closed" is not the opposite of "open". A set can be both ($\mathbb{R}$, $\emptyset$ — the only two such subsets of $\mathbb{R}$) or neither ($[0,1)$, $\mathbb{Q}$).
Chapter 2 — Compact and connected sets
Terminology
- Compact (sequential definition) — $K$ is compact if every sequence in $K$ has a subsequence that converges to a limit in $K$.- Open cover of $A$ — a collection of open sets $\{O\lambda\}$ whose union contains $A$. A finite subcover is a finite subcollection that still covers $A$.- Compact (cover definition) — every open cover of $K$ has a finite subcover.- Bounded set — $\lvert x \rvert \le M$ for all $x$ in the set, for some $M$.
Heine–Borel
Theorem (Heine–Borel). For $K \subseteq \mathbb{R}$ the following are equivalent:(i) $K$ is compact (sequential definition);(ii) $K$ is closed and bounded;(iii) every open cover of $K$ has a finite subcover.
Proof of (ii) ⇒ (i). Let $(xn)$ be a sequence in $K$. It is bounded because $K$ is, so by Bolzano–Weierstrass (Real Analysis 01) it has a convergent subsequence $x{nk} \to x$. Either $x$ equals infinitely many of the $x{nk}$, so $x \in K$, or it is a limit point of $K$, and then $x \in K$ because $K$ is closed. $\blacksquare$
Proof of (i) ⇒ (ii). If $K$ were unbounded, choose $xn \in K$ with $\lvert xn \rvert > n$; no subsequence is bounded, so none converges. If $K$ were not closed, some limit point $x \notin K$ is the limit of a sequence in $K$; every subsequence also tends to $x \notin K$. $\blacksquare$
The equivalence with (iii) takes more work; see Abbott Section 3.3 and Rudin Theorems 2.40–2.41.
Nested compact sets. If $K1 \supseteq K2 \supseteq K3 \supseteq \cdots$ are nonempty compact sets, then $\bigcapn Kn \ne \emptyset$. (Pick $xn \in Kn$. The sequence lies in $K1$, so a subsequence converges to some $x \in K1$. For each fixed $m$, the terms with $nk \ge m$ lie in the closed set $Km$, so $x \in Km$.) This generalizes the Nested Interval Property of Real Analysis 00 from intervals to any compact sets.
Examples. $[0,1]$ and the Cantor set (an intersection of closed sets, inside $[0,1]$) are compact. $(0,1)$ is not: the sequence $1/n$ has every subsequence tending to $0 \notin (0,1)$. Equivalently, the open cover $\{(1/n, 1) : n \ge 2\}$ of $(0,1)$ has no finite subcover, since the union of finitely many of these sets is $(1/N, 1)$ for the largest $N$ used, which misses $(0, 1/N]$. $\mathbb{R}$ is closed but not bounded, so not compact.
> Trick: use the sequential definition when you have a sequence in hand (most proofs in this post). Use the cover definition to pass from "local" information at each point to a "global" statement with finitely many pieces.
Connected sets
Two nonempty sets $A, B$ are separated if $\overline{A} \cap B = \emptyset$ and $A \cap \overline{B} = \emptyset$. A set is connected if it is not a union of two separated sets.
Theorem. A set $E \subseteq \mathbb{R}$ is connected if and only if it is an interval: whenever $a < c < b$ with $a, b \in E$, also $c \in E$.
$\mathbb{Q}$ is not connected: $\mathbb{Q} = \{r < \sqrt2\} \cup \{r > \sqrt2\}$ splits it into two separated pieces. This gap is exactly why the Intermediate Value Theorem fails for functions on $\mathbb{Q}$.
Chapter 3 — Limits of functions
Terminology
- Functional limit — let $f : A \to \mathbb{R}$ and let $c$ be a limit point of $A$. Then $\lim{x \to c} f(x) = L$ means: for every $\varepsilon > 0$ there is $\delta > 0$ such that for all $x \in A$ with $0 < \lvert x - c \rvert < \delta$, $\lvert f(x) - L \rvert < \varepsilon$.- The condition $0 < \lvert x - c \rvert$ means the value $f(c)$ (if it exists) plays no role in the limit.
A first example
Claim. $\lim{x \to 2} (3x + 1) = 7$.
Proof. $\lvert (3x + 1) - 7 \rvert = 3 \lvert x - 2 \rvert$. Given $\varepsilon > 0$, let $\delta = \varepsilon / 3$. If $0 < \lvert x - 2 \rvert < \delta$ then $\lvert (3x+1) - 7 \rvert < 3\delta = \varepsilon$. $\blacksquare$
For a linear function, $\delta$ is simply $\varepsilon$ divided by the slope. Nonlinear functions need one extra step (Chapter 4).
The sequential criterion
Theorem. $\lim{x \to c} f(x) = L$ if and only if for every sequence $(xn)$ in $A$ with $xn \ne c$ and $xn \to c$, the sequence $f(xn) \to L$.
Proof of (⇒). Let $\varepsilon > 0$ and take the $\delta$ from the definition. Since $xn \to c$, there is $N$ with $\lvert xn - c \rvert < \delta$ for $n \ge N$, and $xn \ne c$. So $\lvert f(xn) - L \rvert < \varepsilon$ for $n \ge N$. $\blacksquare$
Proof of (⇐). Suppose the limit is not $L$. Negating the definition (Real Analysis 00): there is $\varepsilon0 > 0$ such that for every $\delta > 0$ some $x \in A$ has $0 < \lvert x - c \rvert < \delta$ and $\lvert f(x) - L \rvert \ge \varepsilon0$. Apply this with $\delta = 1/n$ for each $n$ to get $xn \ne c$ with $\lvert xn - c \rvert < 1/n$, so $xn \to c$, but $\lvert f(xn) - L \rvert \ge \varepsilon0$ for all $n$, so $f(xn) \not\to L$. $\blacksquare$
The same pattern — negate the $\varepsilon$–$\delta$ statement, then use $\delta = 1/n$ to build a sequence — proves the sequential criteria for continuity and for uniform continuity below.
Corollary (divergence criterion). If two sequences $xn \to c$ and $yn \to c$ (terms $\ne c$) have $f(xn)$ and $f(yn)$ tending to different limits, then $\lim{x \to c} f(x)$ does not exist.
Example. $f(x) = \sin(1/x)$ at $c = 0$. Take $xn = \frac{1}{2n\pi}$ and $yn = \frac{1}{2n\pi + \pi/2}$. Both tend to $0$, but $\sin(1/xn) = \sin(2n\pi) = 0$ and $\sin(1/yn) = \sin(2n\pi + \pi/2) = 1$ for every $n$. The limit does not exist: the graph oscillates between $-1$ and $1$ infinitely often near $0$.
Chapter 4 — Continuity
Terminology
- Removable discontinuity at $c$ — $\lim{x \to c} f(x)$ exists but differs from $f(c)$ (or $f(c)$ is undefined).- Jump discontinuity — the one-sided limits $\lim{x \to c^-} f(x)$ and $\lim{x \to c^+} f(x)$ both exist but are different.- Essential discontinuity — at least one one-sided limit does not exist, as for $\sin(1/x)$ at $0$.- Lipschitz function — there is $K \ge 0$ with $\lvert f(x) - f(y) \rvert \le K \lvert x - y \rvert$ for all $x, y$ in the domain.
Definition
$f : A \to \mathbb{R}$ is continuous at $c \in A$ if for every $\varepsilon > 0$ there is $\delta > 0$ such that for all $x \in A$ with $\lvert x - c \rvert < \delta$, $\lvert f(x) - f(c) \rvert < \varepsilon$. It is continuous on $A$ if it is continuous at every point of $A$.
Equivalently (sequential criterion): $f$ is continuous at $c$ if and only if $xn \to c$ with $xn \in A$ implies $f(xn) \to f(c)$. If $c$ is a limit point of $A$, this is the same as $\lim{x \to c} f(x) = f(c)$. At an isolated point of $A$ every function is continuous.
Worked example: a delta for x squared at c = 3
Claim. $f(x) = x^2$ is continuous at $c = 3$.
Scratch work. Factor: $\lvert x^2 - 9 \rvert = \lvert x - 3 \rvert \, \lvert x + 3 \rvert$. The factor $\lvert x - 3 \rvert$ is what $\delta$ controls; the factor $\lvert x + 3 \rvert$ must be bounded. Agree in advance that $\delta \le 1$. Then $\lvert x - 3 \rvert < 1$ gives $2 < x < 4$, so $\lvert x + 3 \rvert < 7$, and
$$\lvert x^2 - 9 \rvert < 7 \lvert x - 3 \rvert.$$
This is less than $\varepsilon$ when $\lvert x - 3 \rvert < \varepsilon / 7$.
Proof. Let $\varepsilon > 0$ and set $\delta = \min\left(1, \frac{\varepsilon}{7}\right)$. If $\lvert x - 3 \rvert < \delta$, then $\lvert x - 3 \rvert < 1$, so $\lvert x + 3 \rvert < 7$, and $\lvert x^2 - 9 \rvert < 7 \cdot \frac{\varepsilon}{7} = \varepsilon$. $\blacksquare$
Checking with numbers. For $\varepsilon = 1$ the rule gives $\delta = \min(1, 1/7) = 1/7 \approx 0.1429$. The worst case is at the right end, $x = 3 + \tfrac17$: $x^2 - 9 = \tfrac67 + \tfrac{1}{49} = \tfrac{43}{49} \approx 0.878 < 1$. At the left end, $9 - (3 - \tfrac17)^2 = \tfrac{41}{49} \approx 0.837 < 1$. The largest $\delta$ that works is $\sqrt{10} - 3 \approx 0.1623$; the proof's $\delta$ is a little smaller, which is fine — any $\delta$ that works is enough.
| $\varepsilon$ | $\delta = \min(1, \varepsilon/7)$ | worst $\lvert x^2 - 9\rvert$ at $x = 3 + \delta$ | largest valid $\delta$ ||---------------|-----------------------------------|----------------------------------------------------|------------------------|| $1$ | $1/7 \approx 0.1429$ | $43/49 \approx 0.8776$ | $\sqrt{10} - 3 \approx 0.1623$ || $0.1$ | $1/70 \approx 0.01429$ | $421/4900 \approx 0.08592$ | $\sqrt{9.1} - 3 \approx 0.01662$ |
> Trick: the "$\delta = \min(1, \dots)$" move is the standard way to handle a nonlinear factor: first restrict $x$ to a fixed interval around $c$ to bound the awkward factor by a constant, then divide $\varepsilon$ by that constant.
Building continuous functions
Algebraic Continuity Theorem. If $f$ and $g$ are continuous at $c$, so are $kf$, $f + g$, $fg$, and $f/g$ (if $g(c) \ne 0$).
Proof. Use the sequential criterion: if $xn \to c$ then $f(xn) \to f(c)$ and $g(xn) \to g(c)$, and the Algebraic Limit Theorem (Real Analysis 01) does the rest. $\blacksquare$
Since $f(x) = x$ and constants are continuous, every polynomial is continuous on $\mathbb{R}$, and every rational function is continuous wherever its denominator is not zero.
Composition. If $g$ is continuous at $c$ and $f$ is continuous at $g(c)$, then $f \circ g$ is continuous at $c$.
Proof. Let $\varepsilon > 0$. Choose $\eta > 0$ with $\lvert y - g(c) \rvert < \eta \Rightarrow \lvert f(y) - f(g(c)) \rvert < \varepsilon$. Then choose $\delta > 0$ with $\lvert x - c \rvert < \delta \Rightarrow \lvert g(x) - g(c) \rvert < \eta$. Chaining, $\lvert x - c \rvert < \delta \Rightarrow \lvert f(g(x)) - f(g(c)) \rvert < \varepsilon$. $\blacksquare$
So $\sqrt{1 + x^2}$, $\sin(x^3)$ and $e^{\cos x}$ are continuous (given that the square root, sine, cosine and exponential functions are continuous on their domains).
Chapter 5 — Continuous functions on compact sets and intervals
Compactness is preserved
Theorem. If $f : K \to \mathbb{R}$ is continuous and $K$ is compact, then $f(K) = \{f(x) : x \in K\}$ is compact.
Proof. Let $(yn)$ be a sequence in $f(K)$; write $yn = f(xn)$ with $xn \in K$. By compactness a subsequence $x{nk} \to x \in K$. By continuity $y{nk} = f(x{nk}) \to f(x) \in f(K)$. So every sequence in $f(K)$ has a subsequence converging in $f(K)$. $\blacksquare$
The Extreme Value Theorem
Theorem (EVT). If $f : K \to \mathbb{R}$ is continuous and $K$ is compact and nonempty, then $f$ attains a maximum and a minimum: there are $x0, x1 \in K$ with $f(x0) \le f(x) \le f(x1)$ for all $x \in K$.
Proof. $f(K)$ is compact, hence bounded, so $s = \sup f(K)$ exists (Axiom of Completeness). By the $\varepsilon$-characterization, for each $n$ there is $yn \in f(K)$ with $s - 1/n < yn \le s$, so $yn \to s$. Since $f(K)$ is closed, $s \in f(K)$: $s = f(x1)$ for some $x1 \in K$. The minimum is the same argument with $\inf$. $\blacksquare$
Every hypothesis is needed:
| Function and domain | What fails | Max attained? ||---------------------|------------|---------------|| $f(x) = x$ on $(0, 1)$ | domain not closed | no ($\sup = 1$ not reached) || $f(x) = x$ on $[0, \infty)$ | domain not bounded | no (unbounded) || $f(x) = 1/x$ on $(0, 1]$ | domain not closed | no (unbounded) || $f(0) = 0$, $f(x) = 1 - x$ on $(0, 1]$ | $f$ not continuous at $0$ | no ($\sup = 1$ not reached) |
The Intermediate Value Theorem
Theorem (IVT). Let $f : [a, b] \to \mathbb{R}$ be continuous, and let $L$ be a number strictly between $f(a)$ and $f(b)$. Then there is $c \in (a, b)$ with $f(c) = L$.
Proof (via the supremum). Replacing $f$ by $f - L$ (and by $-f$ if needed), assume $f(a) < 0 < f(b)$ and find $c$ with $f(c) = 0$. Let
$$S = \{x \in [a, b] : f(x) < 0\}.$$
$S$ contains $a$ and is bounded above by $b$, so $c = \sup S$ exists, and $a \le c \le b$.
$f(c) > 0$ is impossible. By continuity there is $\delta > 0$ with $f(x) > 0$ for $x \in (c - \delta, c]$ (take $\varepsilon = f(c)$). Then no point of $S$ lies in $(c - \delta, c]$, and none lies above $c$, so $c - \delta$ is an upper bound of $S$ smaller than $c$. Contradiction.
$f(c) < 0$ is impossible. Then $c \ne b$ since $f(b) > 0$, and by continuity $f(x) < 0$ on $[c, c + \delta)$ for some $\delta > 0$ (small enough that $c + \delta \le b$). So $c + \delta/2 \in S$, contradicting that $c$ is an upper bound.
Hence $f(c) = 0$, and $c \ne a, b$ since $f(a) < 0 < f(b)$. $\blacksquare$
A second proof: $f([a,b])$ is connected (continuous images of connected sets are connected), hence an interval by the theorem in Chapter 2, so it contains every value between $f(a)$ and $f(b)$. A third uses bisection and the Nested Interval Property — which is also an algorithm.
Worked example. $p(x) = x^3 + x - 1$ has a root in $(0,1)$, since $p(0) = -1 < 0 < 1 = p(1)$. Bisection narrows it:
| interval | midpoint $m$ | $p(m)$ | keep ||----------|--------------|--------|------|| $[0, 1]$ | $0.5$ | $-0.375$ | $[0.5, 1]$ || $[0.5, 1]$ | $0.75$ | $0.171875$ | $[0.5, 0.75]$ || $[0.5, 0.75]$ | $0.625$ | $\approx -0.1309$ | $[0.625, 0.75]$ || $[0.625, 0.75]$ | $0.6875$ | $\approx 0.01245$ | $[0.625, 0.6875]$ |
The root is $\approx 0.6823$. (It is the only real root: $p'(x) = 3x^2 + 1 > 0$, so $p$ is strictly increasing.)
> Common pitfall: the IVT says nothing about functions on sets with gaps. On $\mathbb{Q} \cap [0, 2]$, the continuous function $g(x) = x^2 - 2$ is negative at $0$ and positive at $2$ but has no rational zero.
Chapter 6 — Uniform continuity
Definition
$f : A \to \mathbb{R}$ is uniformly continuous on $A$ if for every $\varepsilon > 0$ there is $\delta > 0$ such that for all $x, y \in A$ with $\lvert x - y \rvert < \delta$, $\lvert f(x) - f(y) \rvert < \varepsilon$.
Compare the quantifiers:
- continuous on $A$: $\forall c\ \ \forall \varepsilon\ \ \exists \delta\ \ \forall x$ — $\delta$ may depend on $\varepsilon$ and on $c$;- uniformly continuous: $\forall \varepsilon\ \ \exists \delta\ \ \forall c\ \ \forall x$ — one $\delta$ works at every point.
The example of 1/x
Take $f(x) = 1/x$ on $(0, 1]$ and $\varepsilon = 1$. At a point $c$, the largest $\delta$ that works is decided on the left side, where the graph is steeper:
$$\frac{1}{c - \delta} - \frac{1}{c} = \frac{\delta}{c(c - \delta)} = \varepsilon \quad\Longleftrightarrow\quad \delta = \frac{\varepsilon c^2}{1 + \varepsilon c}.$$
| point $c$ | $1$ | $1/2$ | $1/4$ | $1/10$ ||-----------|-----|-------|-------|--------|| largest $\delta$ for $\varepsilon = 1$ | $1/2$ | $1/6 \approx 0.167$ | $1/20 = 0.05$ | $1/110 \approx 0.00909$ |
At each point a $\delta$ exists, so $1/x$ is continuous on $(0,1]$. But the best $\delta$ tends to $0$ as $c \to 0$, so no single $\delta$ serves every point: $1/x$ is not uniformly continuous on $(0,1]$. The domain is bounded but not closed, and the missing point $0$ is exactly where things go wrong.
Proving a function is not uniformly continuous
Sequential criterion. $f$ is not uniformly continuous on $A$ if and only if there are $\varepsilon0 > 0$ and sequences $(xn), (yn)$ in $A$ with $\lvert xn - yn \rvert \to 0$ but $\lvert f(xn) - f(yn) \rvert \ge \varepsilon0$ for all $n$.
- $1/x$ on $(0,1]$: $xn = \frac{1}{n+1}$, $yn = \frac{1}{n+2}$. Then $\lvert xn - yn \rvert = \frac{1}{(n+1)(n+2)} \to 0$ but $\lvert f(xn) - f(yn) \rvert = 1$.- $x^2$ on $\mathbb{R}$: $xn = n$, $yn = n + \frac1n$. Then $\lvert xn - yn \rvert = \frac1n \to 0$ but $\lvert yn^2 - xn^2 \rvert = 2 + \frac{1}{n^2} \ge 2$. The graph gets steeper without bound.- $\sin(1/x)$ on $(0,1)$: $xn = \frac{1}{2n\pi}$, $yn = \frac{1}{2n\pi + \pi/2}$ from Chapter 3. Their distance tends to $0$ and the values differ by $1$. This function is bounded and continuous on $(0,1)$, yet not uniformly continuous.
On a bounded interval, $x^2$ is uniformly continuous: on $[-M, M]$, $\lvert x^2 - y^2 \rvert = \lvert x + y \rvert \lvert x - y \rvert \le 2M \lvert x - y \rvert$, so $\delta = \varepsilon / (2M)$ works everywhere. More generally, a Lipschitz function ($\lvert f(x) - f(y) \rvert \le K \lvert x - y \rvert$ for all $x, y$) is uniformly continuous with $\delta = \varepsilon / K$.
Compact domains fix everything
Theorem. A continuous function on a compact set $K$ is uniformly continuous on $K$.
Proof. Suppose not. By the sequential criterion there are $\varepsilon0 > 0$ and $xn, yn \in K$ with $\lvert xn - yn \rvert \to 0$ and $\lvert f(xn) - f(yn) \rvert \ge \varepsilon0$. By compactness a subsequence $x{nk} \to x \in K$. Then
$$\lvert y{nk} - x \rvert \le \lvert y{nk} - x{nk} \rvert + \lvert x{nk} - x \rvert \to 0,$$
so $y{nk} \to x$ too. By continuity at $x$, both $f(x{nk})$ and $f(y{nk})$ tend to $f(x)$, so $\lvert f(x{nk}) - f(y{nk}) \rvert \to 0$. This contradicts $\lvert f(x{nk}) - f(y{nk}) \rvert \ge \varepsilon0$. $\blacksquare$
This theorem is the reason the Riemann integral of a continuous function on $[a, b]$ exists (Real Analysis 04): one $\delta$ for the whole interval controls every subinterval of a partition at once.
> Watch out: "continuous on $(0,1)$ and bounded" does not give uniform continuity ($\sin(1/x)$), and neither does "continuous on a closed set" ($x^2$ on $\mathbb{R}$). The hypothesis is closed and bounded.
Chapter 7 — How discontinuous can a function be?
Dirichlet's function $g(x) = 1$ for $x \in \mathbb{Q}$ and $g(x) = 0$ for $x \notin \mathbb{Q}$ is discontinuous at every point. Given $c$, the density of $\mathbb{Q}$ and of the irrationals (Real Analysis 00) gives a sequence of rationals $xn \to c$ and a sequence of irrationals $yn \to c$, with $g(xn) = 1$ and $g(yn) = 0$; they cannot both tend to $g(c)$.
A function continuous at exactly one point. $h(x) = x \, g(x)$ (equal to $x$ on $\mathbb{Q}$ and $0$ elsewhere) is continuous at $0$, since $\lvert h(x) \rvert \le \lvert x \rvert$ (take $\delta = \varepsilon$), and discontinuous at every $c \ne 0$ by the same two-sequence argument.
Thomae's function.
$$t(x) = \begin{cases} 1 & x = 0, \\ 1/q & x = p/q \text{ in lowest terms, } q \ge 1, \\ 0 & x \notin \mathbb{Q}. \end{cases}$$
- Discontinuous at every rational $c = p/q$: $t(c) = 1/q > 0$, but irrationals $yn \to c$ have $t(yn) = 0$.- Continuous at every irrational $c$: given $\varepsilon > 0$, choose $q0$ with $1/q0 < \varepsilon$. In the interval $(c - 1, c + 1)$ only finitely many rationals have denominator $q < q0$, and none equals $c$. Choose $\delta > 0$ so small that $V\delta(c)$ avoids all of them. Every $x \in V\delta(c)$ is then irrational ($t(x) = 0$) or has denominator $\ge q0$ ($t(x) \le 1/q0 < \varepsilon$). So $\lvert t(x) - t(c) \rvert < \varepsilon$.
So Thomae's function is continuous exactly on the irrationals. The reverse is impossible: no function $f : \mathbb{R} \to \mathbb{R}$ is continuous exactly on $\mathbb{Q}$. The proof uses the Baire Category Theorem (Abbott Sections 3.5 and 4.6).
| Function | Continuous at | Discontinuous at ||----------|---------------|------------------|| polynomials | all of $\mathbb{R}$ | nowhere || $x \mapsto \sin(1/x)$, $0 \mapsto 0$ | $x \ne 0$ | $0$ (no limit) || Dirichlet $g$ | nowhere | all of $\mathbb{R}$ || $x \, g(x)$ | $0$ only | $x \ne 0$ || Thomae $t$ | irrationals | rationals |
Practice Exercises
1. Is $A = \{1 + 1/n : n \in \mathbb{N}\} \cup \{1\}$ open, closed, compact? Find its limit points.
<details><summary>Solution</summary>
The only limit point is $1$, which is in $A$, so $A$ is closed. It is bounded (inside $[1, 2]$), so it is compact by Heine–Borel. It is not open: no neighbourhood of $2$ lies in $A$.
</details>
2. Show directly from the cover definition that $[0, \infty)$ is not compact.
<details><summary>Solution</summary>
The sets $On = (-1, n)$, $n \in \mathbb{N}$, are open and cover $[0,\infty)$. A finite subcollection has union $(-1, N)$ for the largest index $N$ used, which misses $N$. So there is no finite subcover.
</details>
3. Prove from the definition that $f(x) = 5x - 2$ is continuous at every $c$, and that $\lim{x \to 1} \frac{x^2 - 1}{x - 1} = 2$.
<details><summary>Solution</summary>
$\lvert f(x) - f(c) \rvert = 5 \lvert x - c \rvert$, so $\delta = \varepsilon / 5$ works. For the limit: for $x \ne 1$, $\frac{x^2 - 1}{x - 1} = x + 1$, and $\lvert (x + 1) - 2 \rvert = \lvert x - 1 \rvert$, so $\delta = \varepsilon$ works. The value at $x = 1$ is undefined, which does not matter for the limit.
</details>
4. Prove that $f(x) = x^2$ is continuous at $c = -2$. Give $\delta$ as a formula in $\varepsilon$ and check it for $\varepsilon = 0.5$.
<details><summary>Solution</summary>
$\lvert x^2 - 4 \rvert = \lvert x + 2 \rvert \lvert x - 2 \rvert$. If $\lvert x + 2 \rvert < 1$ then $-3 < x < -1$, so $\lvert x - 2 \rvert < 5$. Take $\delta = \min(1, \varepsilon/5)$. For $\varepsilon = 0.5$, $\delta = 0.1$; the worst case is $x = -2.1$: $x^2 - 4 = 0.41 < 0.5$ (and at $x = -1.9$: $4 - 3.61 = 0.39$).
</details>
5. Show that $f(x) = \sqrt{x}$ is uniformly continuous on $[0, \infty)$. (Hint: split into $[0, 1]$ and $[1, \infty)$, or show $\lvert \sqrt{x} - \sqrt{y} \rvert \le \sqrt{\lvert x - y \rvert}$.)
<details><summary>Solution</summary>
For $0 \le y \le x$: $(\sqrt{x} - \sqrt{y})^2 \le (\sqrt{x} - \sqrt{y})(\sqrt{x} + \sqrt{y}) = x - y$, so $\lvert \sqrt{x} - \sqrt{y} \rvert \le \sqrt{\lvert x - y \rvert}$. Given $\varepsilon$, $\delta = \varepsilon^2$ works for all $x, y \ge 0$.
</details>
6. Show that every polynomial of odd degree has a real root.
<details><summary>Solution</summary>
Let $p(x) = an x^n + \cdots + a0$ with $n$ odd and $an > 0$ (else use $-p$). Then $p(x) / x^n \to an > 0$ as $x \to \pm\infty$, so $p(x) > 0$ for large positive $x$ and, since $x^n < 0$ for $x < 0$, $p(x) < 0$ for large negative $x$. Pick such points $a < b$ and apply the IVT on $[a, b]$.
</details>
7. Let $f : [0, 1] \to [0, 1]$ be continuous. Prove that $f$ has a fixed point: some $c$ with $f(c) = c$.
<details><summary>Solution</summary>
Let $g(x) = f(x) - x$, continuous on $[0,1]$. Then $g(0) = f(0) \ge 0$ and $g(1) = f(1) - 1 \le 0$. If either is $0$ you are done; otherwise $g(0) > 0 > g(1)$ and the IVT gives $c \in (0, 1)$ with $g(c) = 0$.
</details>
Cheat-sheet
| Concept | Definition or statement | Standard example ||---------|-------------------------|------------------|| Open | every point has a $V\varepsilon$ inside | $(a,b)$; not $[0,1)$ || Closed | contains all limit points | $[a,b]$, $\mathbb{Z}$; not $\mathbb{Q}$ || Open vs closed | $O$ open iff $O^c$ closed | $\mathbb{R}$, $\emptyset$ are both || Compact | every sequence has a subsequence converging in $K$ | $[a,b]$, Cantor set || Heine–Borel | compact iff closed and bounded iff finite subcovers | $(0,1)$ fails || Functional limit | $0 < \lvert x - c\rvert < \delta$ gives $\lvert f(x) - L\rvert < \varepsilon$ | $\sin(1/x)$ at $0$: none || Continuity | $\lvert x - c\rvert < \delta$ gives $\lvert f(x) - f(c)\rvert < \varepsilon$ | $x^2$ at $3$: $\delta = \min(1, \varepsilon/7)$ || EVT | continuous on compact: max and min attained | fails for $x$ on $(0,1)$ || IVT | continuous on $[a,b]$ takes all values between | root of $x^3 + x - 1$ near $0.6823$ || Uniform continuity | one $\delta$ for all points | $1/x$ on $(0,1]$ fails || Compact ⇒ UC | continuous on compact is uniformly continuous | $x^2$ on $[-M, M]$ || Thomae | continuous exactly on the irrationals | Dirichlet: nowhere |
What's next
Real Analysis 03 defines the derivative as a functional limit and proves the theorems that make calculus work, such as the Mean Value Theorem (whose proof needs the Extreme Value Theorem from this post) and Taylor's theorem with remainder.
References
- Stephen Abbott, Understanding Analysis, 2nd edition, Springer, 2015 — Chapter 3 (basic topology of $\mathbb{R}$) and Chapter 4 (functional limits and continuity; Section 4.6 on sets of discontinuity).- Walter Rudin, Principles of Mathematical Analysis, 3rd edition, McGraw-Hill, 1976 — Chapter 2 (basic topology) and Chapter 4 (continuity).- Robert G. Bartle and Donald R. Sherbert, Introduction to Real Analysis, 4th edition, Wiley, 2011 — Chapters 4–5 and 11.- Terence Tao, Analysis I, 4th edition, Springer, 2022 — Chapter 9 (continuous functions on $\mathbb{R}$).- Michael Spivak, Calculus, 4th edition, Publish or Perish, 2008 — Chapters 5–8 (limits, continuity, the three hard theorems).- MIT OpenCourseWare, 18.100A Real Analysis, Fall 2020 (Casey Rodriguez), lecture notes: https://ocw.mit.edu/courses/18-100a-real-analysis-fall-2020/
> Note: this post is in progress. Planned additions: the proof that sequential compactness implies the open-cover property; perfect sets and the Baire Category Theorem; monotone functions and their (countable) sets of jump discontinuities.
Real Analysis — 01 · Sequences and Series
A sequence is the simplest infinite process in mathematics, and its limit is the idea on which the rest of analysis is built: derivatives, integrals and continuity are all limits in disguise. This post makes "the terms get closer and closer to $a$" precise with the $\varepsilon$–$N$ definition, works through explicit proofs with concrete numbers, and then proves the big structural theorems that rest on the completeness of $\mathbb{R}$ from Real Analysis 00: the Monotone Convergence Theorem, Bolzano–Weierstrass and the Cauchy criterion. The second half turns to infinite series — sums of infinitely many numbers — with the standard convergence tests and the surprising fact that reordering the terms of some series changes the sum.
> Series map: 00 The Real Numbers & Completeness → 01 Sequences & Series (this post) → 02 Topology of ℝ & Continuity → 03 Differentiation & Taylor's Theorem → 04 The Riemann Integral → 05 Uniform Convergence & Power Series.
Learning Outcome
- State the $\varepsilon$–$N$ definition of convergence and write complete proofs that specific sequences converge, with an explicit $N$.- Prove that limits are unique and that convergent sequences are bounded.- Prove the sum and product parts of the Algebraic Limit Theorem, and use the Order Limit Theorem and the squeeze theorem.- Prove the Monotone Convergence Theorem and apply it to a recursively defined sequence.- Prove the Bolzano–Weierstrass Theorem by bisection and use subsequences to show divergence.- Define Cauchy sequences, $\limsup$ and $\liminf$, and state the Cauchy criterion.- Decide convergence of series with the divergence, comparison, ratio, root and alternating series tests.- Distinguish absolute from conditional convergence and state the Riemann rearrangement theorem.
Chapter 1 — The limit of a sequence
Terminology
- Sequence — a function from $\mathbb{N}$ to $\mathbb{R}$, written $(an) = (a1, a2, a3, \dots)$.- $\varepsilon$-neighbourhood of $a$ — the interval $V\varepsilon(a) = (a - \varepsilon, a + \varepsilon)$, the points within distance $\varepsilon$ of $a$.- Converges — $(an)$ converges to $a$, written $an \to a$ or $\lim an = a$, if for every $\varepsilon > 0$ there is $N \in \mathbb{N}$ such that $\lvert an - a \rvert < \varepsilon$ for all $n \ge N$.- Diverges — does not converge to any real number.- Tail — the terms $aN, a{N+1}, \dots$ from some index on.- Bounded — there is $M > 0$ with $\lvert an \rvert \le M$ for all $n$.
The definition says: whatever tolerance $\varepsilon$ is demanded, the whole tail from some $N$ on lies inside the band $V\varepsilon(a)$. The $N$ is allowed to depend on $\varepsilon$ (a smaller band usually needs a larger $N$). Finitely many early terms never matter.
A worked proof with explicit numbers
Claim. $\displaystyle an = \frac{2n+1}{n+3} \to 2$.
Scratch work. Compute the distance to the limit:
$$\lvert an - 2 \rvert = \left\lvert \frac{2n + 1 - 2(n+3)}{n+3} \right\rvert = \frac{5}{n+3}.$$
This is less than $\varepsilon$ exactly when $n + 3 > 5/\varepsilon$, i.e. $n > 5/\varepsilon - 3$.
Proof. Let $\varepsilon > 0$. By the Archimedean property choose $N \in \mathbb{N}$ with $N > 5/\varepsilon - 3$. For $n \ge N$,
$$\lvert an - 2 \rvert = \frac{5}{n+3} \le \frac{5}{N+3} < \varepsilon. \qquad \blacksquare$$
Checking with numbers. The first terms are $a1 = \tfrac34$, $a2 = 1$, $a3 = \tfrac76$, $a4 = \tfrac97$, $a5 = \tfrac{11}{8}$, increasing towards $2$.
| $\varepsilon$ | condition $n > 5/\varepsilon - 3$ | smallest $N$ | check at $N - 1$ | check at $N$ ||---------------|-----------------------------------|--------------|------------------|--------------|| $0.25$ | $n > 17$ | $18$ | $a{17} = 1.75$, distance $0.25$ (not $< 0.25$) | $a{18} = \tfrac{37}{21} \approx 1.7619$, distance $\approx 0.2381$ || $0.1$ | $n > 47$ | $48$ | $a{47} = 1.9$, distance $0.1$ (not $< 0.1$) | $a{48} = \tfrac{97}{51} \approx 1.9020$, distance $\approx 0.0980$ || $0.01$ | $n > 497$ | $498$ | $a{497} = 1.99$, distance $0.01$ | $a{498} = \tfrac{997}{501} \approx 1.9900$, distance $\approx 0.00998$ |
The term $a{17}$ lands exactly on the edge of the band for $\varepsilon = 0.25$; since the definition uses a strict inequality, the tail starts at $N = 18$. Any larger $N$ also works — the definition asks for some $N$, not the smallest.
> Trick: in the scratch work, simplify $\lvert an - a \rvert$ and then bound it above by something simple. You do not need the exact solution of $\lvert an - a \rvert < \varepsilon$. For $bn = \frac{n+1}{n^2}$, for example, $\lvert bn - 0 \rvert = \frac{n+1}{n^2} \le \frac{2n}{n^2} = \frac{2}{n}$, so any $N > 2/\varepsilon$ works.
More examples
$1/\sqrt{n} \to 0$. Given $\varepsilon > 0$ choose $N > 1/\varepsilon^2$. For $n \ge N$, $\sqrt{n} \ge \sqrt{N} > 1/\varepsilon$, so $1/\sqrt{n} < \varepsilon$.
$r^n \to 0$ for $0 \le r < 1$. If $r = 0$ it is trivial. Otherwise write $r = \frac{1}{1 + h}$ with $h > 0$. Bernoulli's inequality (Real Analysis 00) gives $(1+h)^n \ge 1 + nh > nh$, so $0 < r^n < \frac{1}{nh}$, which is less than $\varepsilon$ once $n > \frac{1}{h\varepsilon}$. The same bound on $\lvert r \rvert^n$ covers $-1 < r < 0$.
$(-1)^n$ diverges. Suppose $(-1)^n \to a$. Take $\varepsilon = 1$: there is $N$ with $\lvert (-1)^n - a \rvert < 1$ for $n \ge N$. Using $n = N$ and $n = N + 1$ (one even, one odd),
$$2 = \lvert 1 - (-1) \rvert \le \lvert 1 - a \rvert + \lvert a - (-1) \rvert < 1 + 1 = 2,$$
a contradiction.
Uniqueness and boundedness
Theorem. A sequence has at most one limit.
Proof. Suppose $an \to a$ and $an \to b$. Let $\varepsilon > 0$. There are $N1, N2$ with $\lvert an - a \rvert < \varepsilon/2$ for $n \ge N1$ and $\lvert an - b \rvert < \varepsilon/2$ for $n \ge N2$. For $n = \max(N1, N2)$,
$$\lvert a - b \rvert \le \lvert a - an \rvert + \lvert an - b \rvert < \varepsilon.$$
Since $\varepsilon$ was arbitrary, $a = b$ by the equality lemma of Real Analysis 00. $\blacksquare$
Theorem. Every convergent sequence is bounded.
Proof. Let $an \to a$. With $\varepsilon = 1$ there is $N$ such that $\lvert an - a \rvert < 1$, hence $\lvert an \rvert < \lvert a \rvert + 1$, for $n \ge N$. Put $M = \max\{\lvert a1 \rvert, \dots, \lvert a{N-1} \rvert, \lvert a \rvert + 1\}$. Then $\lvert an \rvert \le M$ for all $n$. $\blacksquare$
The converse is false: $(-1)^n$ is bounded and divergent.
> Common pitfall: choosing $N$ that depends on $n$. In "$\forall \varepsilon\ \exists N\ \forall n \ge N$" the order says $N$ is chosen after $\varepsilon$ but before $n$. "Take $N = n + 1$" is not a proof.
Chapter 2 — Limit theorems
The Algebraic Limit Theorem
Theorem. Let $an \to a$ and $bn \to b$. Then(i) $c\,an \to c\,a$ for every $c \in \mathbb{R}$;(ii) $an + bn \to a + b$;(iii) $an bn \to ab$;(iv) $an / bn \to a / b$, provided $b \ne 0$ (and $bn \ne 0$ for all $n$).
Proof of (ii). Let $\varepsilon > 0$. Choose $N1$ with $\lvert an - a \rvert < \varepsilon/2$ for $n \ge N1$, and $N2$ with $\lvert bn - b \rvert < \varepsilon/2$ for $n \ge N2$. For $n \ge \max(N1, N2)$,
$$\lvert (an + bn) - (a + b) \rvert \le \lvert an - a \rvert + \lvert bn - b \rvert < \tfrac{\varepsilon}{2} + \tfrac{\varepsilon}{2} = \varepsilon. \qquad \blacksquare$$
Proof of (iii). Add and subtract $an b$:
$$\lvert an bn - ab \rvert = \lvert an (bn - b) + (an - a) b \rvert \le \lvert an \rvert \lvert bn - b \rvert + \lvert b \rvert \lvert an - a \rvert.$$
$(an)$ converges, so it is bounded: $\lvert an \rvert \le M$ for some $M > 0$. Let $\varepsilon > 0$. Choose $N1$ with $\lvert bn - b \rvert < \frac{\varepsilon}{2M}$ for $n \ge N1$, and $N2$ with $\lvert an - a \rvert < \frac{\varepsilon}{2(\lvert b \rvert + 1)}$ for $n \ge N2$. (The $+1$ avoids dividing by zero when $b = 0$.) For $n \ge \max(N1, N2)$,
$$\lvert an bn - ab \rvert < M \cdot \frac{\varepsilon}{2M} + \lvert b \rvert \cdot \frac{\varepsilon}{2(\lvert b \rvert + 1)} < \frac{\varepsilon}{2} + \frac{\varepsilon}{2} = \varepsilon. \qquad \blacksquare$$
Part (iv) is proved by first showing $1/bn \to 1/b$: the key step is that $\lvert bn \rvert > \lvert b \rvert / 2$ for all large $n$ (reverse triangle inequality), which keeps $1/\lvert bn \rvert$ bounded.
Example. Rewriting $an = \frac{2n+1}{n+3} = \frac{2 + 1/n}{1 + 3/n}$, the theorem gives $\lim an = \frac{2 + 0}{1 + 0} = 2$ at once, since $1/n \to 0$. The explicit $\varepsilon$–$N$ proof of Chapter 1 is what the theorem packages.
Order and squeezing
Order Limit Theorem. Let $an \to a$ and $bn \to b$.(i) If $an \ge 0$ for all $n$, then $a \ge 0$.(ii) If $an \le bn$ for all $n$, then $a \le b$.(iii) If $c \le bn$ for all $n$, then $c \le b$; if $an \le c$ for all $n$, then $a \le c$.
Proof of (i). Suppose $a < 0$. Take $\varepsilon = \lvert a \rvert$. For large $n$, $\lvert an - a \rvert < \lvert a \rvert$, which gives $an < a + \lvert a \rvert = 0$, a contradiction. Part (ii) is (i) applied to $bn - an$, and (iii) is (ii) with a constant sequence. $\blacksquare$
> Watch out: strict inequalities are not preserved. $1/n > 0$ for every $n$, but $\lim 1/n = 0$. Limits turn $<$ into $\le$.
Squeeze theorem. If $xn \le yn \le zn$ for all $n$ and $xn \to \ell$, $zn \to \ell$, then $yn \to \ell$. Example: $0 \le \frac{\lvert\sin n\rvert}{n} \le \frac1n$, so $\frac{\sin n}{n} \to 0$.
Chapter 3 — Monotone sequences
Terminology
- Increasing — $an \le a{n+1}$ for all $n$. Decreasing — $an \ge a{n+1}$ for all $n$.- Monotone — increasing or decreasing.
The Monotone Convergence Theorem
Theorem. A monotone sequence converges if and only if it is bounded. An increasing bounded sequence converges to $\sup\{an : n \in \mathbb{N}\}$.
Proof. Convergent implies bounded (Chapter 1). Conversely, let $(an)$ be increasing and bounded. The set $\{an\}$ is nonempty and bounded above, so by the Axiom of Completeness $s = \sup\{an\}$ exists. Let $\varepsilon > 0$. Since $s - \varepsilon$ is not an upper bound, some $aN > s - \varepsilon$. For $n \ge N$, monotonicity and $s$ being an upper bound give
$$s - \varepsilon < aN \le an \le s,$$
so $\lvert an - s \rvert < \varepsilon$. The decreasing case is the same with the infimum. $\blacksquare$
The theorem proves that a limit exists without knowing its value in advance — the essential use of completeness. In $\mathbb{Q}$ it fails: the increasing bounded sequence $1, 1.4, 1.41, 1.414, \dots$ of decimal truncations of $\sqrt{2}$ has no rational limit.
Worked example: a recursive sequence for the square root of 2
Define $x1 = 1$ and
$$x{n+1} = \frac12 \left( xn + \frac{2}{xn} \right).$$
(This is Newton's method for $x^2 - 2 = 0$.) The first terms are
| $n$ | $xn$ | decimal | $xn^2 - 2$ ||-----|-------|---------|-------------|| 1 | $1$ | $1$ | $-1$ || 2 | $3/2$ | $1.5$ | $0.25$ || 3 | $17/12$ | $1.416667$ | $\approx 6.94 \times 10^{-3}$ || 4 | $577/408$ | $1.414216$ | $\approx 6.01 \times 10^{-6}$ || 5 | $665857/470832$ | $1.414214$ | $\approx 4.51 \times 10^{-12}$ |
Step 1 — bounded below by $\sqrt{2}$ from $n = 2$ on. All $xn > 0$ by induction. For any $x > 0$,
$$\frac12\left(x + \frac2x\right) - \sqrt{2} = \frac{x^2 - 2\sqrt{2}\,x + 2}{2x} = \frac{(x - \sqrt{2})^2}{2x} \ge 0,$$
so $x{n+1} \ge \sqrt{2}$ for every $n \ge 1$.
Step 2 — decreasing from $n = 2$ on. For $n \ge 2$, $xn^2 \ge 2$, so
$$xn - x{n+1} = \frac{xn}{2} - \frac{1}{xn} = \frac{xn^2 - 2}{2xn} \ge 0.$$
Step 3 — find the limit. The tail $(xn){n \ge 2}$ is decreasing and bounded below, so by the Monotone Convergence Theorem $xn \to L$ for some $L \ge \sqrt{2} > 0$. The shifted sequence $x{n+1}$ has the same limit, and the Algebraic Limit Theorem applied to the recursion gives $L = \frac12 (L + 2/L)$, i.e. $L^2 = 2$. Since $L > 0$, $L = \sqrt{2}$. $\blacksquare$
> Common pitfall: solving $L = \frac12(L + 2/L)$ before proving the limit exists. For $x{n+1} = 2xn$ with $x1 = 1$ the same trick "gives" $L = 2L$, so $L = 0$ — but $xn = 2^{n-1}$ diverges. Existence first (monotone and bounded), then the equation.
The number $e$ arises the same way: $\left(1 + \frac1n\right)^n$ is increasing and bounded above by $3$, so it converges, and its limit is defined to be $e$ (Bartle and Sherbert, Section 3.3).
Chapter 4 — Subsequences, Bolzano–Weierstrass and Cauchy sequences
Terminology
- Subsequence of $(an)$ — a sequence $(a{nk}) = (a{n1}, a{n2}, \dots)$ with $n1 < n2 < n3 < \cdots$. It keeps infinitely many terms, in order.- Cauchy sequence — for every $\varepsilon > 0$ there is $N$ such that $\lvert an - am \rvert < \varepsilon$ for all $m, n \ge N$. The terms get close to each other, with no limit mentioned.- Limit superior — $\limsup an = \lim{n \to \infty} yn$ where $yn = \sup\{ak : k \ge n\}$. Limit inferior — the same with $\inf$.
Theorem. If $an \to a$, every subsequence also converges to $a$. (Given $\varepsilon$ and $N$ for $(an)$, use the same $N$: $nk \ge k$, so $k \ge N$ implies $nk \ge N$.)
This gives the quickest divergence proofs: find two subsequences with different limits. For $(-1)^n$, the even terms tend to $1$ and the odd terms to $-1$.
Bolzano–Weierstrass
Theorem (Bolzano–Weierstrass). Every bounded sequence has a convergent subsequence.
Proof (bisection). Let $\lvert an \rvert \le M$ and $I1 = [-M, M]$. Choose $n1 = 1$. Split $I1$ into two closed halves; at least one contains $an$ for infinitely many $n$. Call it $I2$ and choose $n2 > n1$ with $a{n2} \in I2$. Continue: $I{k+1}$ is a half of $Ik$ containing infinitely many terms, and $n{k+1} > nk$ has $a{n{k+1}} \in I{k+1}$. The intervals are closed, bounded and nested, with length $2M / 2^{k-1}$ for $Ik$. By the Nested Interval Property there is $x$ in every $Ik$. Both $x$ and $a{nk}$ lie in $Ik$, so
$$\lvert a{nk} - x \rvert \le \frac{2M}{2^{k-1}} \to 0.$$
Hence $a{nk} \to x$. $\blacksquare$
The Cauchy criterion
Theorem (Cauchy criterion). A sequence of real numbers converges if and only if it is a Cauchy sequence.
Proof. ($\Rightarrow$) If $an \to a$, choose $N$ with $\lvert an - a \rvert < \varepsilon/2$ for $n \ge N$. For $m, n \ge N$, $\lvert an - am \rvert \le \lvert an - a \rvert + \lvert a - am \rvert < \varepsilon$.
($\Leftarrow$) Let $(an)$ be Cauchy.Bounded: with $\varepsilon = 1$ there is $N$ with $\lvert an - aN \rvert < 1$ for $n \ge N$, so $\lvert an \rvert < \lvert aN \rvert + 1$ for $n \ge N$; take the maximum with the first $N - 1$ terms.A subsequence converges: by Bolzano–Weierstrass, $a{nk} \to a$ for some $a$.The whole sequence follows: given $\varepsilon > 0$, choose $N$ with $\lvert an - am \rvert < \varepsilon/2$ for $m, n \ge N$, and choose $k$ with $nk \ge N$ and $\lvert a{nk} - a \rvert < \varepsilon/2$. For $n \ge N$,
$$\lvert an - a \rvert \le \lvert an - a{nk} \rvert + \lvert a{nk} - a \rvert < \varepsilon. \qquad \blacksquare$$
The Cauchy criterion lets you prove convergence using only the terms themselves. In $\mathbb{Q}$ it fails: the Newton sequence of Chapter 3 is a Cauchy sequence of rationals with no rational limit. Completeness of $\mathbb{R}$ can be defined by "every Cauchy sequence converges" together with the Archimedean property; it is equivalent to the Axiom of Completeness.
> Watch out: "consecutive terms get close" is not the Cauchy condition. For $an = \sqrt{n}$, $a{n+1} - an = \frac{1}{\sqrt{n+1} + \sqrt{n}} \to 0$, yet $an \to \infty$. Cauchy requires $\lvert an - am \rvert$ small for all pairs $m, n \ge N$.
Limit superior and inferior
For a bounded sequence, $yn = \sup\{ak : k \ge n\}$ is decreasing (a supremum over a smaller set) and bounded, so $\limsup an = \lim yn$ always exists by the Monotone Convergence Theorem; likewise $\liminf$. Always $\liminf an \le \limsup an$.
Example. $an = (-1)^n\left(1 + \frac1n\right)$: the terms are $-2, \tfrac32, -\tfrac43, \tfrac54, \dots$. The even terms decrease to $1$ and the odd terms increase to $-1$, so $\limsup an = 1$ and $\liminf an = -1$, although no term equals $1$ or $-1$.
Theorem. A bounded sequence converges if and only if $\liminf an = \limsup an$, and then the limit is this common value.
$\limsup$ is the largest limit of any subsequence and $\liminf$ the smallest. These notions give the sharp form of the root test in Chapter 6.
Chapter 5 — Infinite series
Terminology
- Series — an expression $\sum{k=1}^\infty ak$. Its partial sums are $sn = a1 + a2 + \cdots + an$.- Converges — the sequence $(sn)$ converges; its limit $S$ is the sum, written $\sum{k=1}^\infty ak = S$.- Diverges — $(sn)$ does not converge.
A series is a sequence in disguise: every question about $\sum ak$ is a question about $(sn)$.
Geometric and telescoping series
Geometric series. For $r \ne 1$, $sn = \sum{k=0}^{n-1} r^k = \frac{1 - r^n}{1 - r}$ (multiply by $1 - r$ and cancel). If $\lvert r \rvert < 1$, then $r^n \to 0$ and
$$\sum{k=0}^\infty r^k = \frac{1}{1 - r}.$$
If $\lvert r \rvert \ge 1$ the series diverges (its terms do not tend to $0$). Example: $\sum{k=1}^\infty \left(\tfrac12\right)^k = \frac{1}{1 - 1/2} - 1 = 1$.
Telescoping series. $\frac{1}{k(k+1)} = \frac1k - \frac{1}{k+1}$, so the partial sums collapse: $sn = 1 - \frac{1}{n+1} \to 1$. Hence $\sum{k=1}^\infty \frac{1}{k(k+1)} = 1$.
The divergence test
Theorem. If $\sum ak$ converges, then $ak \to 0$.
Proof. $ak = sk - s{k-1}$, and both $sk$ and $s{k-1}$ tend to the same limit $S$. $\blacksquare$
So $\sum \frac{k}{k+1}$ diverges, since its terms tend to $1$. The converse is false, and the harmonic series is the standard counterexample.
The harmonic series diverges
Theorem. $\sum{k=1}^\infty \frac1k$ diverges, although $\frac1k \to 0$.
Proof. Group the terms in blocks that end at powers of $2$:
$$s{2^m} = 1 + \tfrac12 + \left(\tfrac13 + \tfrac14\right) + \left(\tfrac15 + \cdots + \tfrac18\right) + \cdots + \left(\tfrac{1}{2^{m-1}+1} + \cdots + \tfrac{1}{2^m}\right).$$
Each bracket has $2^{j-1}$ terms, each at least $\frac{1}{2^j}$, so each bracket is at least $\frac12$. Hence $s{2^m} \ge 1 + \frac{m}{2}$. The partial sums are increasing and unbounded, so the series diverges. $\blacksquare$
The actual values confirm the bound: $s2 = 1.5$, $s4 \approx 2.083$, $s8 \approx 2.718$, $s{16} \approx 3.381$, $s{32} \approx 4.058$, each at least $1 + m/2$. The growth is very slow — $sn$ grows like $\ln n$.
The Cauchy criterion for series
Applying the Cauchy criterion to $(sn)$: $\sum ak$ converges if and only if for every $\varepsilon > 0$ there is $N$ such that for all $n > m \ge N$,
$$\lvert a{m+1} + a{m+2} + \cdots + an \rvert < \varepsilon.$$
"The blocks far out add up to almost nothing." The harmonic series fails this: the block from $m+1$ to $2m$ is always at least $m \cdot \frac{1}{2m} = \frac12$.
Chapter 6 — Convergence tests
Comparison
Comparison test. Suppose $0 \le ak \le bk$ for all $k$.(i) If $\sum bk$ converges, so does $\sum ak$.(ii) If $\sum ak$ diverges, so does $\sum bk$.
Proof. The partial sums of $\sum ak$ are increasing and bounded by $\sum bk$; apply the Monotone Convergence Theorem. Part (ii) is the contrapositive of (i). $\blacksquare$
Example: $\sum 1/k^2$ converges. For $k \ge 2$, $\frac{1}{k^2} < \frac{1}{k(k-1)} = \frac{1}{k-1} - \frac1k$, a telescoping series with sum $1$. So $\sum{k=1}^\infty \frac{1}{k^2} < 1 + 1 = 2$ converges. (Its exact value, $\pi^2/6 \approx 1.645$, is Euler's solution of the Basel problem.)
$p$-series. $\sum \frac{1}{k^p}$ converges if and only if $p > 1$. (Cauchy condensation or the integral test, Abbott Section 2.4.)
Ratio and root tests
Ratio test. Suppose $ak \ne 0$ and $\lim \left\lvert \frac{a{k+1}}{ak} \right\rvert = r$. If $r < 1$, $\sum ak$ converges absolutely; if $r > 1$, it diverges; if $r = 1$, the test says nothing.
Root test. Let $r = \limsup \lvert ak \rvert^{1/k}$. If $r < 1$, $\sum ak$ converges absolutely; if $r > 1$, it diverges; if $r = 1$, no conclusion.
Both tests compare with a geometric series: if $r < 1$, pick $q$ with $r < q < 1$; eventually $\lvert ak \rvert \le C q^k$.
Example. $\sum{k=1}^\infty \frac{k}{2^k}$: $\frac{a{k+1}}{ak} = \frac{k+1}{2k} \to \frac12 < 1$, so it converges. (Its sum is $2$.)
> Watch out: $r = 1$ is genuinely inconclusive. Both $\sum 1/k$ (divergent) and $\sum 1/k^2$ (convergent) have ratio limit $1$.
Alternating series
Alternating Series Test. If $(ak)$ is decreasing and $ak \to 0$, then $\sum{k=1}^\infty (-1)^{k+1} ak = a1 - a2 + a3 - \cdots$ converges.
Proof sketch. The even partial sums $s{2n} = (a1 - a2) + \cdots + (a{2n-1} - a{2n})$ increase; the odd ones $s{2n+1} = a1 - (a2 - a3) - \cdots$ decrease; and $s{2n} \le s{2n+1}$ with $s{2n+1} - s{2n} = a{2n+1} \to 0$. So the intervals $[s{2n}, s{2n+1}]$ are nested with lengths going to $0$, and all partial sums converge to the single common point. $\blacksquare$
The proof also gives the error bound: the sum lies between any two consecutive partial sums, so $\lvert S - sn \rvert \le a{n+1}$.
Example. The alternating harmonic series converges:
$$1 - \frac12 + \frac13 - \frac14 + \cdots = \ln 2 \approx 0.6931.$$
(The value $\ln 2$ comes from the Taylor series of $\ln(1 + x)$ evaluated at $x = 1$; the test itself gives only convergence.)
Absolute and conditional convergence
- $\sum ak$ converges absolutely if $\sum \lvert ak \rvert$ converges.- It converges conditionally if it converges but $\sum \lvert ak \rvert$ diverges.
Theorem. Absolute convergence implies convergence.
Proof. By the triangle inequality $\lvert a{m+1} + \cdots + an \rvert \le \lvert a{m+1} \rvert + \cdots + \lvert an \rvert$. If $\sum \lvert ak \rvert$ satisfies the Cauchy criterion, so does $\sum ak$. $\blacksquare$
The alternating harmonic series converges conditionally: it converges, but $\sum \frac1k$ diverges.
Rearrangements
A rearrangement of $\sum ak$ is $\sum a{f(k)}$ for a bijection $f : \mathbb{N} \to \mathbb{N}$ — the same terms in a different order.
Theorem. If $\sum ak$ converges absolutely, every rearrangement converges to the same sum.
Riemann rearrangement theorem. If $\sum ak$ converges conditionally, then for every $L \in \mathbb{R}$ there is a rearrangement that converges to $L$ (and there are rearrangements that diverge).
The idea: the positive terms alone and the negative terms alone both diverge. Add positive terms until you pass $L$, then negative terms until you drop below $L$, and repeat; since $ak \to 0$, the overshoots shrink to $0$.
Example. Rearrange the alternating harmonic series as "one positive term, then two negative terms":
$$1 - \frac12 - \frac14 + \frac13 - \frac16 - \frac18 + \frac15 - \frac{1}{10} - \frac{1}{12} + \cdots$$
Group each block of three. Since $\frac{1}{2k-1} - \frac{1}{4k-2} = \frac{1}{4k-2}$, the $k$-th block is
$$\frac{1}{4k-2} - \frac{1}{4k} = \frac12 \left( \frac{1}{2k-1} - \frac{1}{2k} \right).$$
So the block sums add up to half of the alternating harmonic series: the rearranged series converges to $\tfrac12 \ln 2$, not $\ln 2$. (The partial sums that stop inside a block differ from the block sums by terms tending to $0$, so they have the same limit.)
> Common pitfall: treating an infinite sum like a finite one. Regrouping, reordering and term-by-term manipulations are safe for absolutely convergent series, and can fail for conditionally convergent ones.
Practice Exercises
1. Prove from the definition that $\frac{3n - 1}{n + 2} \to 3$. Find the smallest valid $N$ for $\varepsilon = 0.1$.
<details><summary>Solution</summary>
$\left\lvert \frac{3n-1}{n+2} - 3 \right\rvert = \frac{7}{n+2}$. Given $\varepsilon$, choose $N > 7/\varepsilon - 2$; then for $n \ge N$, $\frac{7}{n+2} \le \frac{7}{N+2} < \varepsilon$. For $\varepsilon = 0.1$ the condition is $n > 68$, so the smallest $N$ is $69$ (at $n = 68$ the distance is $\frac{7}{70} = 0.1$ exactly, which is not $< 0.1$).
</details>
2. Prove that if $an \to a$ then $\lvert an \rvert \to \lvert a \rvert$. Is the converse true?
<details><summary>Solution</summary>
By the reverse triangle inequality, $\big\lvert \lvert an \rvert - \lvert a \rvert \big\rvert \le \lvert an - a \rvert$, so the same $N$ works. The converse is false: $an = (-1)^n$ has $\lvert an \rvert \to 1$ but diverges. (It is true when $a = 0$.)
</details>
3. Let $x1 = 3$ and $x{n+1} = \frac12 xn + 1$. Prove that $(xn)$ converges and find its limit.
<details><summary>Solution</summary>
Claim: $xn > 2$ and decreasing. If $xn > 2$ then $x{n+1} = \frac12 xn + 1 > 2$. And $xn - x{n+1} = \frac12 xn - 1 = \frac12(xn - 2) > 0$. So $(xn)$ is decreasing and bounded below by $2$, hence converges to some $L$. Taking limits in the recursion: $L = \frac12 L + 1$, so $L = 2$. (Terms: $3, 2.5, 2.25, 2.125, \dots$; in fact $xn = 2 + 2^{1-n}$.)
</details>
4. Use subsequences to show that $an = \cos\left(\frac{n\pi}{2}\right)$ diverges, and find its $\limsup$ and $\liminf$.
<details><summary>Solution</summary>
The terms cycle $0, -1, 0, 1, \dots$ (for $n = 1, 2, 3, 4, \dots$). The subsequence $a{4k} = 1 \to 1$ and $a{4k+2} = -1 \to -1$ have different limits, so $(an)$ diverges. Every tail contains both $1$ and $-1$, so $\limsup an = 1$ and $\liminf an = -1$.
</details>
5. Decide whether each series converges: (a) $\sum \frac{1}{2^k + k}$; (b) $\sum \frac{k^2}{3^k}$; (c) $\sum \frac{1}{\sqrt{k}}$; (d) $\sum (-1)^k \frac{1}{\sqrt{k}}$.
<details><summary>Solution</summary>
(a) Converges: $0 < \frac{1}{2^k + k} < \frac{1}{2^k}$, a convergent geometric series. (b) Converges by the ratio test: $\frac{(k+1)^2}{3k^2} \to \frac13 < 1$. (c) Diverges: $\frac{1}{\sqrt{k}} \ge \frac1k$ and the harmonic series diverges. (d) Converges by the Alternating Series Test ($1/\sqrt{k}$ decreases to $0$), but only conditionally, by (c).
</details>
6. Show that $\sum{k=1}^\infty \frac{1}{k(k+2)} = \frac34$.
<details><summary>Solution</summary>
$\frac{1}{k(k+2)} = \frac12\left(\frac1k - \frac{1}{k+2}\right)$. The partial sum telescopes, leaving the first two positive and last two negative terms: $sn = \frac12\left(1 + \frac12 - \frac{1}{n+1} - \frac{1}{n+2}\right) \to \frac12 \cdot \frac32 = \frac34$.
</details>
7. Give an example of a bounded sequence with no convergent subsequence, or explain why none exists. Then give an unbounded sequence with a convergent subsequence.
<details><summary>Solution</summary>
None exists: Bolzano–Weierstrass says every bounded sequence has a convergent subsequence. An unbounded example: $an = n$ for odd $n$ and $an = 0$ for even $n$; the even terms form a constant, convergent subsequence.
</details>
Cheat-sheet
| Result | Statement | Key idea ||--------|-----------|----------|| Limit | $\forall \varepsilon\ \exists N\ \forall n \ge N:\ \lvert an - a\rvert < \varepsilon$ | simplify, bound, solve for $n$ || Example | $\frac{2n+1}{n+3} \to 2$; $\varepsilon = 0.1$ needs $N = 48$ | distance $= \frac{5}{n+3}$ || Unique, bounded | limits unique; convergent implies bounded | $\varepsilon/2$ trick; $\varepsilon = 1$ || Algebraic limits | sums, products, quotients ($b \ne 0$) | add and subtract a middle term || Order limits | $an \le bn$ implies $a \le b$ | $<$ becomes $\le$ || Monotone Convergence | monotone + bounded implies convergent | the limit is the sup || Bolzano–Weierstrass | bounded implies a convergent subsequence | bisection + nested intervals || Cauchy criterion | convergent iff Cauchy | BW + one subsequence || Divergence test | $ak \not\to 0$ implies divergence | converse false || Harmonic | $\sum 1/k = \infty$ | $s{2^m} \ge 1 + m/2$ || Geometric | $\sum{k \ge 0} r^k = \frac{1}{1-r}$ for $\lvert r\rvert < 1$ | $sn = \frac{1 - r^n}{1 - r}$ || Ratio / root | limit $< 1$: converges; $> 1$: diverges | compare with geometric || Alternating | decreasing to $0$: converges; error $\le a{n+1}$ | nested partial sums || Rearrangement | absolute: same sum; conditional: any sum | $\tfrac12 \ln 2$ example |
What's next
Real Analysis 02 moves from sequences to sets and functions: open and closed sets, compactness (where Bolzano–Weierstrass becomes Heine–Borel), limits of functions via the $\varepsilon$–$\delta$ definition and its sequential form, continuity, the Extreme and Intermediate Value Theorems, and uniform continuity.
References
- Stephen Abbott, Understanding Analysis, 2nd edition, Springer, 2015 — Chapter 2 (sequences and series), Section 2.7 (rearrangements).- Walter Rudin, Principles of Mathematical Analysis, 3rd edition, McGraw-Hill, 1976 — Chapter 3 (numerical sequences and series; Theorem 3.54 is Riemann's theorem).- Robert G. Bartle and Donald R. Sherbert, Introduction to Real Analysis, 4th edition, Wiley, 2011 — Chapter 3 (sequences, including the number $e$) and Chapter 9 (infinite series).- Terence Tao, Analysis I, 4th edition, Springer, 2022 — Chapters 6–7.- Konrad Knopp, Theory and Application of Infinite Series, Dover reprint, 1990 — the classic reference for convergence tests.- MIT OpenCourseWare, 18.100A Real Analysis, Fall 2020 (Casey Rodriguez), lecture notes: https://ocw.mit.edu/courses/18-100a-real-analysis-fall-2020/
> Note: this post is in progress. Planned additions: full proofs of the quotient rule for limits and of the ratio and root tests; Cauchy condensation; and the proof of the Riemann rearrangement theorem.
JavaScript Deep Dive — 03 · Async Engineering
Post 01 explained when callbacks run: tasks, microtasks, and the rendering steps between them. This post is about building systems on top of that machinery. Knowing that yields to the microtask queue is the easy part. The hard part is everything production adds: a request that must be cancelled when the user navigates away, a fan-out of 10,000 calls that must not open 10,000 sockets, a flaky dependency that needs retries without turning a blip into a retry storm, a stream that must not buffer a 4 GB file into memory, and an error that must still say why it happened after passing through five layers. The examples target the current platform: ES2025 plus the parts of ES2026 already shipped in Node 24 and evergreen browsers.
> Series map: 00 Engines & Runtime → 01 Event Loop & Concurrency → 02 Objects, Prototypes & Metaprogramming → 03 Async Engineering (this post) → 04 Modules, Packaging & TypeScript at Scale → 05 Performance, Memory & Production Debugging (future: see the extensions table in 05).
Learning Outcome
- Describe a promise as a state machine, predict when each combinator settles, and use / .- Find the code paths that produce unhandled rejections, and know how Node and browsers react to them.- Explain what / desugars to and what each costs.- Cancel work end to end with , and .- Write and consume async iterators (with cleanup on early ), and use WHATWG and Node streams with real backpressure.- Build a concurrency limiter, retries with backoff and full jitter, timeouts that stop the work, idempotency keys and chains.
Chapter 1 — Promises as a state machine
Terminology
- Pending / fulfilled / rejected — the three states. A promise leaves pending at most once.- Settled — fulfilled or rejected. Resolved is different: a promise is resolved once its fate is locked in, which can happen while it is still pending (resolved to another promise).- Thenable — any object with a callable method. Promise machinery adopts thenables, which is why does not fulfil with a promise value.- Reaction — a callback registered with //. Reactions always run as microtasks, never synchronously.- Handled — a rejected promise that has at least one rejection reaction attached. The host tracks this to report unhandled rejections.
Resolution is not fulfilment
Resolving with a thenable queues a job that calls . That job costs extra microtask ticks, which matters for ordering puzzles and for the vs discussion in Chapter 3.
The four combinators
All four take an iterable and return one promise. They differ in what "done" means.
| Combinator | Fulfils when | Rejects when | Empty input ||---|---|---|---|| | every input fulfils (values in input order) | the first input rejects | fulfils with || | every input settles (never rejects) | never | fulfils with || | the first input fulfils | every input rejects, with an | rejects with || | the first input to settle fulfils | the first input to settle rejects | stays pending forever |
A worked example with three inputs: rejects at 20 ms, fulfils at 30 ms, fulfils at 80 ms.
The most important row is the one that is not in the table: no combinator cancels the losers. When rejects at 20 ms, and keep running, their sockets stay open, and their results are thrown away. Cancellation is a separate mechanism (Chapter 4), and you have to wire it in yourself.
> Common pitfall: is not a timeout. It stops waiting after 5 s. The work carries on, holding its connection and memory, and its eventual rejection may even become unhandled.
Newer helpers
is the right tool when resolution happens in a different scope from creation: event emitters, request/response correlation by ID, test harnesses. If you find yourself storing functions in a , it is also where leaks start. Every stored resolver needs a timeout or an abort path, or a lost reply keeps it (and everything it closes over) alive forever.
Chapter 2 — Unhandled rejections
A rejection is "unhandled" if no rejection reaction is attached by the time the host checks. Hosts check after the microtask queue drains, so "attached later" means "attached in a later task".
| Host | Behaviour ||---|---|| Browsers | Fire on (or the worker global). If a handler is attached later, fire . The page keeps running. || Node 15+ | Default mode : emit ; if nothing listens, raise it as an uncaught exception and exit the process. |
Where they come from
Promises stored and never awaited (a cache entry, a "warm-up" call) are the fourth source.
> Watch out: "fixes" crashes by hiding bugs. If you install a handler in Node, log with full context and then decide: exit (usually right, under a supervisor) or keep going (only if you can prove the state is still sound).
Chapter 3 — What async/await compiles to
An function is a generator driven by promises. Before engines shipped native support, transpilers emitted almost exactly this:
Three consequences follow directly from this shape:
1. The body runs synchronously until the first . Code before it is not deferred. A throw there still becomes a rejection, not a synchronous exception.2. Every suspends, even on a non-promise. still resumes in a microtask. Its cost is small, but never zero.3. The call stack is gone after the first . The resumed frame is called from the microtask checkpoint. V8 rebuilds "async stack traces" from the promise chain, which only works when the chain is made of s in functions.
What an await costs
The V8 team's 2018 work (and the spec change that followed) cut the cost of on a native promise from at least three microtask ticks and two extra promises down to one tick in the common case. That makes micro-optimising pointless in application code. What still costs real time:
- Sequential awaits that could be parallel. takes . takes . This one mistake explains a large share of slow API handlers.- inside hot loops over in-memory data. Each iteration becomes a microtask. Process synchronously, and only at I/O boundaries.- Needless wrappers around functions that return a promise already. Each one adds a promise and a hop.
vs
Inside , changes behaviour; outside it only changes timing, and it can even be slightly faster. Returning a promise from an function resolves the outer promise with a thenable, and that adoption takes extra ticks. It also keeps the function in async stack traces. The old lint rule was deprecated in ESLint for these reasons. typescript-eslint's rule, with its default option, encodes the correct policy.
Chapter 4 — Cancellation with AbortSignal
JavaScript has no way to cancel a promise, and that is deliberate. A promise is a read-only view of a result, so cancelling the view does not stop the work. The platform's answer is a separate capability object: an owns an , and you pass the signal into every operation that should stop.
Terminology
- — the writer side. aborts its signal once. Later calls do nothing.- — the reader side: , , , and an event.- Reason — any value. It defaults to a named . aborts with a named .- Composite signal — aborts as soon as any input aborts, with that input's reason.
The pattern
This time both requests really stop: closes the connection and rejects with . Many APIs accept a signal directly: , (the listener is removed on abort), Node's , , , , , and most modern database drivers.
Making your own functions abortable
Rules for a well-behaved abortable function:
1. Check on entry, since the signal may already be aborted.2. Reject with , not with a new error, so that callers can tell a timeout from a user cancel.3. Remove the listener on the success path. A long-lived signal (a whole page's lifetime, say) with thousands of leftover listeners is a real memory leak, and Node warns once a signal has more than the default maximum number of listeners.4. Pass the signal down to everything you call.
> Watch out: CPU-bound loops do not notice aborts by themselves. Call between chunks of work, and yield to the event loop between chunks (Post 01), or the abort event cannot even be delivered.
> Trick: in React effects, create one per effect run and call in the cleanup. That single line prevents both the stale-response race and "state update on unmounted component" noise. The React Deep Dive series covers this in detail.
Chapter 5 — Async iterators and streams
Async iteration
An async iterable has a method whose returns a promise of . consumes it and, on , or , calls the iterator's , which is where cleanup lives.
Useful built-ins that speak this protocol: Node streams, , , web (Chrome 124+, Firefox 110+; Safari added it last, so check your support matrix), and (ES2026) to collect one into an array.
> Common pitfall: async generators are pull-based and sequential. never fetches page 2 until the consumer asks for more. That is great for memory, and wrong when you wanted prefetching. Add a bounded buffer explicitly if you need read-ahead.
WHATWG streams and backpressure
Streams add what iterators lack: a queue with a size limit and a signal back upstream when the queue is full. That signal is backpressure.
Terminology
- Queuing strategy — how chunks are measured: (one per chunk) or .- — the queue size at which the stream reports "full".- — . Zero or negative means "stop producing".- Pull source — a source whose is called only when . This is backpressure done for you.
and carry backpressure end to end: a slow writer makes the transform's queue fill, which stops reads from the network, which lets the TCP receive window close, which slows the sender. also takes a signal.
A source with a method gets backpressure for free: the stream calls only while . The failure mode is a push source that ignores . For example, a that subscribes to a WebSocket and calls for every message. The queue then grows without bound. Either check and pause the upstream, or drop and count messages on purpose.
Node streams
Node's older stream API uses the same idea in a different form: returns when the buffer is over , and you must wait for . Hand-written loops that ignore the return value are the classic Node memory blow-up. Use :
propagates errors and destroys all stages on failure. does neither, and it leaks file descriptors on error. Converting between the two worlds: , , .
Chapter 6 — Concurrency limits
with 10,000 items starts 10,000 requests at once. The results are socket exhaustion, rate-limit responses, a database connection pool drained in milliseconds, and memory for 10,000 pending responses. Bound it.
A worker pool with fail-fast cancellation
This pool keeps at most calls in flight, returns results in input order, and fails fast: the first error aborts the other workers' in-flight calls. If you need partial results instead, catch inside and return an record.
When tasks arrive over time (webhooks, UI events) rather than as one array, the same idea becomes a queue: keep an counter, push records (made with ), and start the next record whenever one settles. Libraries such as do exactly this.
> Watch out: a limiter with an unbounded queue only moves the memory problem somewhere else. Under sustained overload, reject new work when the queue passes a bound (load shedding), and return 429 or 503 to the caller. Never let the queue grow until the process dies.
> Trick: pick the limit from the downstream resource, not from your CPU count. Examples: the DB pool size minus headroom, the vendor's documented rate limit, the number of sockets per host your HTTP agent allows.
Chapter 7 — Timeouts, retries and idempotency
Timeouts
Every network call needs a deadline, and the deadline must also cancel the work, which is why beats . In a multi-step operation, create one deadline per request, , and pass that same signal to every step. Each later step then gets whatever time is left, instead of its own full timeout.
Retries with exponential backoff and full jitter
Retrying immediately makes an overloaded dependency worse. Exponential backoff spaces the attempts out. Jitter stops a thousand clients that failed together from retrying together. The AWS Architecture Blog analysis (Marc Brooker, "Exponential Backoff and Jitter") found full jitter, , to be a strong default.
is a small helper that reads the response header (seconds or an HTTP date) and returns when there is none. With , and , the call makes up to 5 attempts. The sleep ceilings before the four retries are 100, 200, 400 and 800 ms, so the worst-case total sleep is 1,500 ms. The actual sleep is uniform below each ceiling.
Retry discipline that matters more than the formula:
- Retry in one layer only. If the browser, the BFF and the service each make 3 attempts (1 try + 2 retries), one user click can become 3 × 3 × 3 = 27 calls at the bottom layer, exactly when that layer is struggling.- Use a retry budget. For example, allow retries only while they are under 10% of recent requests. A circuit breaker that fails fast while the dependency is down is the same idea taken further.- Only retry idempotent operations, or make them idempotent first.
Idempotency
An operation is idempotent if doing it twice has the same effect as doing it once. HTTP defines , , and as idempotent (RFC 9110). is not. That matters because a timeout does not tell you whether the server did the work: the request may have succeeded and only the response was lost.
The standard fix is an idempotency key. The client generates a unique key per logical operation and sends it on every attempt. The server records the key with the result and returns the stored result for repeats. The pattern was popularised by Stripe's API and is being standardised as the header (an IETF httpapi working-group draft).
Server side, the key needs a unique constraint and a "claim first, then do the work" order. Otherwise two concurrent attempts both see "no record yet" and both charge the card.
> Common pitfall: generating the key inside the retried function. Every attempt gets a fresh key, so the protection disappears exactly when it is needed.
Chapter 8 — Errors that keep their cause
Async code crosses many layers, and each layer that catches and re-throws tends to lose information. Since ES2022 every constructor takes a :
Node's (and so ) prints the whole chain with markers, and browser consoles show it too. When you serialise a chain for logs yourself, walk with a depth limit, because a chain can contain a cycle.
Related tools:
- (ES2021): several errors at once, with . uses it. Use it yourself for "3 of 5 replicas failed".- (ES2026): a cross-realm brand check. It is true for errors from iframes or contexts, where is false.- Custom error classes with a stable and a field make and alerting rules simple and robust. Matching on message strings is fragile.
> Watch out: can carry secrets. A wrapped database error may include the SQL and its parameters. Serialise chains deliberately at the API boundary, and send the full chain only to internal logs.
Practice Exercises
Exercise 1 — Predict the order
What does this print?
<details><summary>Solution</summary>
. The async function body runs synchronously up to the , so comes before . The microtasks run in the order they were queued: the (3), (4), then the continuation (6). The timer callback (2) is a task, so it runs after the microtask queue drains.
</details>
Exercise 2 — Combinator choice
For each case pick a combinator: (a) load five widgets and show whichever succeed; (b) query three mirrors and use the first good answer; (c) a checkout that needs price, stock and tax, all or nothing.
<details><summary>Solution</summary>
(a) , then render the ones. (b) . It ignores mirrors that fail and only rejects (with ) if all fail. Pair it with an so that the losers are cancelled once a winner arrives. (c) with a shared signal, aborted in the , so that the other two stop once one fails.
</details>
Exercise 3 — Fix the crash
This Node handler crashes the process on some requests. Why? Fix it.
<details><summary>Solution</summary>
If rejects while the handler is still awaiting , that rejection has no handler yet. Node's default mode turns it into an uncaught exception. Fix: . Also make sure your framework forwards async errors to its error middleware (Express 5 does; Express 4 needs a wrapper).
</details>
Exercise 4 — Abortable wait-for-event
Write that resolves with the first event of , rejects with the right reason on abort or timeout, and leaves no listeners behind.
<details><summary>Solution</summary>
Passing to means one removes every listener on every path.
</details>
Exercise 5 — Backoff arithmetic
With full jitter, , and 5 retries, list the ceilings and the worst-case total sleep.
<details><summary>Solution</summary>
Ceilings for n = 0…4: 200, 400, 800, 1,600, 3,000 (3,200 capped). Worst-case total = 200 + 400 + 800 + 1,600 + 3,000 = 6,000 ms. The expected total is half of that, 3,000 ms, because each sleep is uniform on . This total must fit inside the caller's own deadline, or the retries are wasted.
</details>
Cheat-sheet
| Need | Use ||---|---|| All must succeed | + shared , abort in || First success wins | (rejects with ) || First settle wins | , never on its own as a timeout || Timeout that cancels | || Combine caller cancel + timeout | || Byte/text pipeline with backpressure | || Bound fan-out | worker pool / limiter sized to the downstream resource || Retry delay | full jitter: , honour || Safe retries of POST | generated once per logical operation |
What's next
Post 04 moves from runtime behaviour to code organisation: ESM vs CommonJS semantics (live bindings, top-level and what it does to module graphs, cycles), / and conditions, dual packages and their hazards, in current Node, import maps, tree-shaking, today's bundlers, and TypeScript at scale. That covers strict flags, module resolution, declaration files, project references, and Node's built-in type stripping.
References
- ECMAScript® Language Specification — Promise objects — the state machine, jobs and combinators.- MDN — Using promises and Promise.- V8 — Faster async functions and promises — the await optimisation and zero-cost async stack traces.- MDN — AbortSignal — , , .- DOM Standard — Aborting ongoing activities — the guidance for API authors that Chapter 4 follows.- Streams Standard and MDN — Streams API concepts — queuing strategies and backpressure.- Node.js — Stream and Process: unhandled rejections.- V8 — Explicit resource management.- AWS Architecture Blog — Exponential Backoff and Jitter.- RFC 9110 — HTTP Semantics, idempotent methods and IETF draft — The Idempotency-Key HTTP Header Field.- MDN — Error: cause.
Real Analysis — 00 · The Real Numbers and Completeness
Calculus teaches how to use limits, derivatives and integrals. Real analysis asks why they work at all: what a real number is, what "gets arbitrarily close" means, and which hidden assumption makes the Intermediate Value Theorem or the convergence of $\sum 1/n^2$ true. The answer, again and again, is one property of $\mathbb{R}$ that the rationals $\mathbb{Q}$ lack: completeness, the fact that $\mathbb{R}$ has no gaps. This course rebuilds single-variable calculus on that one axiom, with proofs. It follows the standard undergraduate route of Abbott's Understanding Analysis, with Rudin's Principles of Mathematical Analysis, Bartle and Sherbert's Introduction to Real Analysis, Tao's Analysis I and Spivak's Calculus as parallel reading. This first post sets up the language of proof, the axioms of an ordered field, the supremum and the Axiom of Completeness, and its first consequences: the Archimedean property, density of $\mathbb{Q}$, the existence of $\sqrt{2}$, nested intervals, and the fact that $\mathbb{R}$ is uncountable.
> Series map: 00 The Real Numbers & Completeness (this post) → 01 Sequences & Series → 02 Topology of ℝ & Continuity → 03 Differentiation & Taylor's Theorem → 04 The Riemann Integral → 05 Uniform Convergence & Power Series.
Learning Outcome
- Read and write statements with the quantifiers "for all" ($\forall$) and "there exists" ($\exists$), and negate nested statements such as "for every $\varepsilon > 0$ there is a $\delta > 0$ …" correctly.- Use the three core proof patterns — direct proof, proof by contradiction, and induction — and prove that $\sqrt{2}$ is irrational.- List the ordered field axioms and prove the triangle inequality from them.- Define upper bound, supremum and infimum, and use the $\varepsilon$-characterization of the supremum.- State the Axiom of Completeness and explain why $\mathbb{Q}$ fails it.- Prove the Archimedean property, the density of $\mathbb{Q}$ in $\mathbb{R}$, and the existence of $\sqrt{2}$ in $\mathbb{R}$.- State and prove the Nested Interval Property.- Show that $\mathbb{Q}$ is countable and that $\mathbb{R}$ is uncountable (Cantor's diagonal argument), and describe the Cantor set.
Chapter 1 — Logic and proof
Analysis is written in a small, precise language. Most mistakes in a first analysis course are not mistakes about numbers; they are mistakes about quantifiers.
Terminology
- Statement — a sentence that is either true or false, e.g. "$7$ is prime".- Implication "$P \Rightarrow Q$" — "if $P$ then $Q$". It is false only when $P$ is true and $Q$ is false.- Converse of $P \Rightarrow Q$ — the statement $Q \Rightarrow P$. It is a different statement and may be false.- Contrapositive of $P \Rightarrow Q$ — the statement $\neg Q \Rightarrow \neg P$. It is logically equivalent to the original.- Universal quantifier $\forall$ — "for all". Existential quantifier $\exists$ — "there exists (at least one)".- Counterexample — one specific object that shows a "for all" statement is false.
Negating quantified statements
The two rules are:
$$\neg\big(\forall x,\ P(x)\big) \iff \exists x,\ \neg P(x), \qquad \neg\big(\exists x,\ P(x)\big) \iff \forall x,\ \neg P(x).$$
To negate a nested statement, move the $\neg$ from left to right, flipping every quantifier it passes, and negate the final condition. The definition of "the sequence $(an)$ converges to $a$" (see Real Analysis 01) is
$$\forall \varepsilon > 0\ \ \exists N \in \mathbb{N}\ \ \forall n \ge N:\ \ \lvert an - a \rvert < \varepsilon.$$
Its negation, "$(an)$ does not converge to $a$", is
$$\exists \varepsilon > 0\ \ \forall N \in \mathbb{N}\ \ \exists n \ge N:\ \ \lvert an - a \rvert \ge \varepsilon.$$
In words: there is one fixed tolerance $\varepsilon$ such that, however far out you go, some later term is still at least $\varepsilon$ away from $a$.
The same mechanical rule applies to continuity (see Real Analysis 02). "$f$ is continuous at $c$" is $\forall \varepsilon > 0\ \exists \delta > 0\ \forall x:\ \lvert x - c\rvert < \delta \Rightarrow \lvert f(x) - f(c)\rvert < \varepsilon$. Its negation is
$$\exists \varepsilon > 0\ \ \forall \delta > 0\ \ \exists x:\ \ \lvert x - c \rvert < \delta \ \text{ and } \ \lvert f(x) - f(c) \rvert \ge \varepsilon.$$
Note that the negation of an implication $A \Rightarrow B$ is "$A$ and not $B$", not another implication.
> Watch out: the order of quantifiers matters. "$\forall x\ \exists y:\ y > x$" (every real number has a larger one) is true in $\mathbb{R}$. "$\exists y\ \forall x:\ y > x$" (one number is larger than all of them) is false. Swapping $\forall$ and $\exists$ changes the meaning completely. In analysis the classic example is uniform continuity (Real Analysis 02), which differs from continuity only by the position of one quantifier.
Three proof patterns
Direct proof. Assume the hypothesis, reach the conclusion by valid steps. Example: if $m$ and $n$ are even, $m + n$ is even. Write $m = 2a$, $n = 2b$; then $m + n = 2(a + b)$.
Contrapositive and contradiction. To prove $P \Rightarrow Q$ you may prove $\neg Q \Rightarrow \neg P$ instead. In a proof by contradiction you assume the statement is false and derive something impossible. Example: if $n^2$ is even, then $n$ is even. Contrapositive: if $n$ is odd, $n = 2k + 1$, then $n^2 = 4k^2 + 4k + 1 = 2(2k^2 + 2k) + 1$ is odd.
Induction. To prove $P(n)$ for all $n \in \mathbb{N} = \{1, 2, 3, \dots\}$, prove the base case $P(1)$ and the inductive step $P(n) \Rightarrow P(n+1)$. This works because of the well-ordering principle: every nonempty subset of $\mathbb{N}$ has a least element (if $P$ failed somewhere, look at the least failure).
Example (Bernoulli's inequality). For every $x \ge -1$ and every $n \in \mathbb{N}$, $(1 + x)^n \ge 1 + nx$.
Proof. For $n = 1$ both sides equal $1 + x$. Suppose $(1+x)^n \ge 1 + nx$. Since $1 + x \ge 0$, multiplying both sides by $1 + x$ keeps the inequality:
$$(1+x)^{n+1} \ge (1 + nx)(1 + x) = 1 + (n+1)x + nx^2 \ge 1 + (n+1)x,$$
because $nx^2 \ge 0$. $\blacksquare$
The hypothesis $x \ge -1$ is used exactly once, to multiply an inequality by a non-negative number. Bernoulli's inequality is the standard tool for showing $r^n \to 0$ when $\lvert r \rvert < 1$ (Real Analysis 01).
The square root of 2 is irrational
Theorem. There is no rational number $r$ with $r^2 = 2$.
Proof. Suppose, for contradiction, that $r = p/q$ with integers $p, q$, $q \ne 0$, and $r^2 = 2$. Cancel common factors, so that $p$ and $q$ are not both even. Then $p^2 = 2q^2$, so $p^2$ is even, and by the contrapositive example above $p$ is even: $p = 2k$. Substituting, $4k^2 = 2q^2$, so $q^2 = 2k^2$ is even, and $q$ is even. Now $p$ and $q$ are both even, contradicting the choice of $p/q$ in lowest terms. $\blacksquare$
This is the first sign that $\mathbb{Q}$ has gaps: the rationals whose square is less than $2$ creep up towards a point that is not there.
Chapter 2 — Ordered fields and absolute value
Terminology
- Field — a set $F$ with two operations $+$ and $\cdot$ satisfying the field axioms below.- Ordered field — a field with a relation $<$ satisfying the order axioms below.- Absolute value — $\lvert x \rvert = x$ if $x \ge 0$ and $\lvert x \rvert = -x$ if $x < 0$.- Distance between $x$ and $y$ — the number $\lvert x - y \rvert$.
The axioms
A field satisfies, for all $x, y, z$:
| Axiom | Addition | Multiplication ||-------|----------|----------------|| Closure | $x + y \in F$ | $xy \in F$ || Associative | $(x+y)+z = x+(y+z)$ | $(xy)z = x(yz)$ || Commutative | $x + y = y + x$ | $xy = yx$ || Identity | $x + 0 = x$ | $1 \cdot x = x$, with $1 \ne 0$ || Inverse | some $-x$ has $x + (-x) = 0$ | if $x \ne 0$, some $x^{-1}$ has $x x^{-1} = 1$ || Distributive | $x(y+z) = xy + xz$ | (links the two operations) |
An ordered field also has a relation $<$ such that:
1. Trichotomy: for all $x, y$ exactly one of $x < y$, $x = y$, $y < x$ holds.2. Transitivity: $x < y$ and $y < z$ imply $x < z$.3. Addition: $x < y$ implies $x + z < y + z$.4. Multiplication: $x < y$ and $0 < z$ imply $xz < yz$.
Everything in high-school algebra follows. For example, $x^2 \ge 0$ for all $x$, and $0 < 1$ (since $1 = 1^2$ and $1 \ne 0$). If $x < y$ and $z < 0$ then $yz < xz$: multiplying by a negative number flips an inequality.
Both $\mathbb{Q}$ and $\mathbb{R}$ are ordered fields. So these axioms cannot be what distinguishes them; Chapter 3 adds the one axiom that does.
The triangle inequality
Three facts about absolute value, all checked by cases on the signs: $\lvert xy \rvert = \lvert x \rvert \lvert y \rvert$; $-\lvert x \rvert \le x \le \lvert x \rvert$; and for $a \ge 0$, $\lvert x \rvert \le a \iff -a \le x \le a$.
Theorem (triangle inequality). For all real $x, y$: $\lvert x + y \rvert \le \lvert x \rvert + \lvert y \rvert$.
Proof. Add $-\lvert x \rvert \le x \le \lvert x \rvert$ and $-\lvert y \rvert \le y \le \lvert y \rvert$:
$$-(\lvert x \rvert + \lvert y \rvert) \le x + y \le \lvert x \rvert + \lvert y \rvert.$$
By the third fact with $a = \lvert x \rvert + \lvert y \rvert$, this says $\lvert x + y \rvert \le \lvert x \rvert + \lvert y \rvert$. $\blacksquare$
Two forms are used constantly:
- Distance form: $\lvert a - b \rvert \le \lvert a - c \rvert + \lvert c - b \rvert$ (put $x = a - c$, $y = c - b$). Going from $a$ to $b$ via $c$ is never shorter.- Reverse triangle inequality: $\big\lvert \lvert x \rvert - \lvert y \rvert \big\rvert \le \lvert x - y \rvert$. (From $\lvert x \rvert = \lvert (x - y) + y \rvert \le \lvert x - y \rvert + \lvert y \rvert$, and the same with $x$ and $y$ swapped.)
> Trick: almost every $\varepsilon$ proof in this course is "add and subtract a middle term, then use the triangle inequality". When you see $\lvert an bn - ab \rvert$, write it as $\lvert an bn - an b + an b - ab \rvert$ and split.
Proving that two numbers are equal
Lemma. Two real numbers $a$ and $b$ are equal if and only if for every $\varepsilon > 0$, $\lvert a - b \rvert < \varepsilon$.
Proof. If $a = b$ then $\lvert a - b \rvert = 0 < \varepsilon$. Conversely, suppose $a \ne b$. Then $\varepsilon0 = \lvert a - b \rvert > 0$, and $\lvert a - b \rvert < \varepsilon0$ is false. $\blacksquare$
This is how analysis proves equalities: not by computing both sides, but by showing their distance is smaller than any positive tolerance.
Chapter 3 — Supremum, infimum and completeness
Terminology
- Upper bound — $b$ is an upper bound of $A \subseteq \mathbb{R}$ if $a \le b$ for every $a \in A$. $A$ is bounded above if it has one.- Lower bound, bounded below — the same with $\ge$. Bounded means bounded above and below.- Supremum (least upper bound) — $s = \sup A$ if (i) $s$ is an upper bound of $A$, and (ii) $s \le b$ for every upper bound $b$ of $A$.- Infimum (greatest lower bound) — $\inf A$, defined the same way with the inequalities reversed.- Maximum — an element of $A$ that is an upper bound of $A$. A set may have a supremum but no maximum.
A supremum is unique when it exists: if $s1$ and $s2$ are both least upper bounds, then $s1 \le s2$ and $s2 \le s1$.
Examples
| Set $A$ | $\sup A$ | Attained (a max)? | $\inf A$ ||---------|----------|-------------------|----------|| $[0, 1]$ | $1$ | yes | $0$ || $(0, 1)$ | $1$ | no | $0$ || $\{1 - 1/n : n \in \mathbb{N}\}$ | $1$ | no | $0$ (a min) || $\{1/n : n \in \mathbb{N}\}$ | $1$ | yes | $0$ (not a min) || $\mathbb{N}$ | none (not bounded above) | — | $1$ |
For $A = \{1 - 1/n\}$: $1$ is an upper bound since $1/n > 0$. If $b < 1$, the Archimedean property (Chapter 4) gives $n$ with $1/n < 1 - b$, so $1 - 1/n > b$ and $b$ is not an upper bound. For example, $b = 0.85$ is beaten by $1 - \tfrac17 = \tfrac67 \approx 0.857$ (and $n = 7$ is the first index that works, since $1 - \tfrac16 \approx 0.833$). Hence $\sup A = 1$, and $1 \notin A$.
The epsilon characterization
Lemma. Let $s$ be an upper bound of $A$. Then $s = \sup A$ if and only if for every $\varepsilon > 0$ there is some $a \in A$ with $s - \varepsilon < a$.
Proof. ($\Rightarrow$) Let $\varepsilon > 0$. Since $s - \varepsilon < s$ and $s$ is the least upper bound, $s - \varepsilon$ is not an upper bound. So some $a \in A$ has $a > s - \varepsilon$.
($\Leftarrow$) Let $b$ be any upper bound with $b < s$. Put $\varepsilon = s - b > 0$. By hypothesis some $a \in A$ has $a > s - \varepsilon = b$, contradicting that $b$ is an upper bound. So every upper bound $b$ satisfies $b \ge s$, and $s = \sup A$. $\blacksquare$
In pictures: nothing in $A$ lies to the right of $s$, but every window $(s - \varepsilon, s]$, however narrow, contains a point of $A$.
The Axiom of Completeness
> Axiom of Completeness (least upper bound property). Every nonempty set of real numbers that is bounded above has a supremum in $\mathbb{R}$.
$\mathbb{R}$ is defined to be an ordered field that satisfies this axiom. (Such a field exists and is unique up to an order-preserving isomorphism; the standard constructions use Dedekind cuts, as in Rudin Chapter 1, or Cauchy sequences of rationals, as in Tao Chapter 5. This course takes the axiom as the starting point, as Abbott does.)
The axiom for infima follows. If $A$ is nonempty and bounded below, then $-A = \{-a : a \in A\}$ is nonempty and bounded above, and $\inf A = -\sup(-A)$.
Why $\mathbb{Q}$ fails the axiom. Let $S = \{r \in \mathbb{Q} : r^2 < 2\}$. It is nonempty ($1 \in S$) and bounded above by $2$. Suppose it had a least upper bound $s$ in $\mathbb{Q}$. The argument in Chapter 4 (existence of $\sqrt{2}$) shows that $s^2 < 2$ and $s^2 > 2$ are both impossible, so $s^2 = 2$; but no rational squares to $2$. So $S$ has no supremum in $\mathbb{Q}$: the rationals have a hole exactly where $\sqrt{2}$ should be. Concretely, $1, 1.4, 1.41, 1.414, \ldots$ are in $S$ (their squares are below $2$; for example $1.414^2 = 1.999396$), while $1.5, 1.42, 1.415, \ldots$ are rational upper bounds ($1.415^2 = 2.002225$). Every rational upper bound can be improved, and the two lists close in on a point that $\mathbb{Q}$ does not contain.
Working with suprema
Two small results, each proved with the lemma above, are used often.
- Shift: for $c \in \mathbb{R}$, $\sup(A + c) = \sup A + c$, where $A + c = \{a + c : a \in A\}$. (If $s = \sup A$, then $s + c$ is an upper bound of $A + c$, and for each $\varepsilon$ some $a > s - \varepsilon$ gives $a + c > (s + c) - \varepsilon$.)- Order: if $A \subseteq B$, $A$ is nonempty and $B$ is bounded above, then $\sup A \le \sup B$. (Every upper bound of $B$ is an upper bound of $A$.)
> Common pitfall: assuming $\sup A \in A$. The supremum of $(0,1)$ is $1$, which is not in the set. Proofs that pick "the largest element of $A$" are wrong unless $A$ is finite or known to have a maximum.
Chapter 4 — First consequences of completeness
The Archimedean property
Theorem (Archimedean property).(i) For every $x \in \mathbb{R}$ there is $n \in \mathbb{N}$ with $n > x$.(ii) For every $y > 0$ there is $n \in \mathbb{N}$ with $1/n < y$.
Proof. (i) Suppose not: then $x$ is an upper bound of $\mathbb{N}$, so by completeness $\alpha = \sup \mathbb{N}$ exists. Then $\alpha - 1$ is not an upper bound, so some $n \in \mathbb{N}$ has $n > \alpha - 1$. But then $n + 1 > \alpha$ and $n + 1 \in \mathbb{N}$, contradicting that $\alpha$ is an upper bound of $\mathbb{N}$.(ii) Apply (i) to $x = 1/y$: some $n > 1/y$, so $1/n < y$. $\blacksquare$
This property looks obvious, yet the proof needs completeness: there are ordered fields (for example suitably ordered fields of rational functions) with "infinitely large" elements, where it fails.
Density of the rationals
Theorem (density of $\mathbb{Q}$). For all real $a < b$ there is a rational $r$ with $a < r < b$.
Proof. By the Archimedean property choose $n \in \mathbb{N}$ with $1/n < b - a$. Let $m$ be the least integer with $m > na$ (it exists by the Archimedean property and well-ordering), so $m - 1 \le na < m$. Then $a < m/n$, and
$$m \le na + 1 < na + n(b - a) = nb,$$
using $1 < n(b - a)$. So $a < m/n < b$. $\blacksquare$
The idea: steps of size $1/n$ are shorter than the interval, so one of the points $m/n$ must land inside.
Corollary. The irrationals are dense too: between any $a < b$ there is an irrational number. (Find a rational $r \ne 0$ with $a/\sqrt{2} < r < b/\sqrt{2}$; then $r\sqrt{2}$ is irrational and lies in $(a, b)$.)
Existence of the square root of 2
Theorem. There is $\alpha \in \mathbb{R}$ with $\alpha^2 = 2$.
Proof sketch. Let $T = \{t \in \mathbb{R} : t^2 < 2\}$. It is nonempty ($1 \in T$) and bounded above by $2$ (if $t > 2$ then $t^2 > 4$). Let $\alpha = \sup T$; note $\alpha \ge 1$. Show that the other two cases of trichotomy are impossible.
Case $\alpha^2 < 2$. For $n \in \mathbb{N}$,
$$\left(\alpha + \tfrac{1}{n}\right)^2 = \alpha^2 + \frac{2\alpha}{n} + \frac{1}{n^2} \le \alpha^2 + \frac{2\alpha + 1}{n}.$$
Choose $n$ with $\frac{1}{n} < \frac{2 - \alpha^2}{2\alpha + 1}$ (Archimedean property). Then $(\alpha + 1/n)^2 < 2$, so $\alpha + 1/n \in T$, contradicting that $\alpha$ is an upper bound.
Case $\alpha^2 > 2$. Now $\left(\alpha - \tfrac{1}{n}\right)^2 > \alpha^2 - \frac{2\alpha}{n}$. Choose $n$ with $\frac{1}{n} < \frac{\alpha^2 - 2}{2\alpha}$; then $(\alpha - 1/n)^2 > 2$, and $\alpha - 1/n > 0$. Any $t \in T$ with $t > \alpha - 1/n > 0$ would have $t^2 > (\alpha - 1/n)^2 > 2$, which is impossible. So $\alpha - 1/n$ is an upper bound of $T$ smaller than $\alpha$ — a contradiction.
So $\alpha^2 = 2$. $\blacksquare$
The same argument, with $\mathbb{Q}$ in place of $\mathbb{R}$, is the proof that $\{r \in \mathbb{Q} : r^2 < 2\}$ has no supremum in $\mathbb{Q}$: its supremum would have to square to $2$. With more algebra it gives $n$-th roots of every positive real.
The Nested Interval Property
Theorem (Nested Interval Property). For each $n \in \mathbb{N}$ let $In = [an, bn]$ be a closed bounded interval, with $I1 \supseteq I2 \supseteq I3 \supseteq \cdots$. Then $\bigcap{n=1}^\infty In \ne \emptyset$.
Proof. Nesting means $a1 \le a2 \le \cdots$ and $\cdots \le b2 \le b1$, and $an \le bm$ for all $n, m$ (with $k = \max(n,m)$: $an \le ak \le bk \le bm$). So the set $A = \{an : n \in \mathbb{N}\}$ is nonempty and bounded above by every $bm$. Let $x = \sup A$. Then $an \le x$ for all $n$ (upper bound) and $x \le bm$ for all $m$ (each $bm$ is an upper bound and $x$ is the least). So $x \in In$ for every $n$. $\blacksquare$
If in addition the lengths $bn - an$ shrink to $0$, the intersection is exactly one point.
> Watch out: both hypotheses are needed. The open intervals $(0, 1/n)$ are nested but their intersection is empty (any $x > 0$ is excluded once $1/n < x$). The closed but unbounded intervals $[n, \infty)$ are nested with empty intersection too. And in $\mathbb{Q}$ the property fails: intervals of rationals closing in on $\sqrt{2}$ have no common rational point.
Together with the Archimedean property, the Nested Interval Property is equivalent to the Axiom of Completeness. It is the version used in bisection arguments (Bolzano–Weierstrass in Real Analysis 01, the Intermediate Value Theorem in Real Analysis 02).
Chapter 5 — Countable and uncountable sets
Completeness makes $\mathbb{R}$ enormously larger than $\mathbb{Q}$, even though both are dense. Cardinality makes "larger" precise.
Terminology
- Function $f : A \to B$ — a rule assigning to each $a \in A$ one element $f(a) \in B$.- One-to-one (injective) — $f(a1) = f(a2)$ implies $a1 = a2$.- Onto (surjective) — every $b \in B$ equals $f(a)$ for some $a$.- Bijection — one-to-one and onto. $A$ and $B$ have the same cardinality, written $A \sim B$, if a bijection $A \to B$ exists.- Countable — $A \sim \mathbb{N}$ (an infinite list $a1, a2, a3, \dots$ with every element appearing exactly once). Uncountable — infinite and not countable.
The rationals are countable
First, $\mathbb{Z}$ is countable: the list $0, 1, -1, 2, -2, 3, -3, \dots$ is the bijection $f : \mathbb{N} \to \mathbb{Z}$ with $f(n) = (n-1)/2$ for odd $n$ and $f(n) = -n/2$ for even $n$.
Theorem. $\mathbb{Q}$ is countable.
Proof. For each $n \in \mathbb{N}$ let $An$ be the set of rationals that can be written as $\pm p/q$ in lowest terms with integers $p \ge 0$, $q \ge 1$ and $p + q = n$. For example $A1 = \{0\}$, $A2 = \{1, -1\}$, $A3 = \{1/2, -1/2, 2, -2\}$. Each $An$ is finite, the $An$ are disjoint, and every rational lies in exactly one of them. List $A1$, then $A2$, then $A3$, and so on. This list contains every rational exactly once, so it is a bijection with $\mathbb{N}$. $\blacksquare$
The reals are uncountable
Theorem (Cantor, 1874; diagonal argument 1891). The interval $(0, 1)$, and hence $\mathbb{R}$, is uncountable.
Proof. Every $x \in (0,1)$ has a decimal expansion $x = 0.d1 d2 d3 \ldots$. It is unique if expansions ending in an infinite string of $9$s are excluded (so $0.4999\ldots$ is written $0.5000\ldots$). Suppose $f : \mathbb{N} \to (0,1)$ were onto, and write
$$\begin{aligned}f(1) &= 0.\,a{11}\, a{12}\, a{13}\, a{14} \ldots \\f(2) &= 0.\,a{21}\, a{22}\, a{23}\, a{24} \ldots \\f(3) &= 0.\,a{31}\, a{32}\, a{33}\, a{34} \ldots \\&\ \ \vdots\end{aligned}$$
Define $x = 0.b1 b2 b3 \ldots$ by $bn = 2$ if $a{nn} \ne 2$ and $bn = 3$ if $a{nn} = 2$. This $x$ lies in $(0,1)$, its expansion has no $9$s (so it is the unique allowed one), and it differs from $f(n)$ in the $n$-th digit for every $n$. So $x \ne f(n)$ for all $n$, and $f$ is not onto. $\blacksquare$
Since $(0,1) \sim \mathbb{R}$ (for example via $x \mapsto \tan(\pi x - \pi/2)$), $\mathbb{R}$ is uncountable. Consequences:
- The irrationals $\mathbb{R} \setminus \mathbb{Q}$ are uncountable (if they were countable, $\mathbb{R}$ would be a union of two countable sets, which is countable).- Almost all real numbers are irrational, even though the rationals are dense. Density is about where points are; cardinality is about how many.
> Common pitfall: "the diagonal number might equal some $f(n)$ with a different expansion". That is exactly why the proof uses the digits $2$ and $3$ only and excludes trailing $9$s: the number $x$ has only one decimal expansion, so differing in a digit really means being a different number.
The Cantor set
Start with $C0 = [0,1]$. Remove the open middle third to get $C1 = [0, \tfrac13] \cup [\tfrac23, 1]$. Remove the open middle third of each piece to get $C2$, a union of $4$ intervals of length $\tfrac19$. In general $Cn$ is a union of $2^n$ closed intervals of length $3^{-n}$. The Cantor set is $C = \bigcap{n=0}^\infty Cn$.
- Length removed: at step $k$ you remove $2^{k-1}$ intervals of length $3^{-k}$, so the total is $\sum{k=1}^\infty 2^{k-1}/3^k = 1$. The Cantor set has "length zero".- Many points survive: $0$, $1$, $\tfrac13$, $\tfrac23$ and every endpoint stay forever. So does $\tfrac14$, which is never an endpoint: in base $3$, $\tfrac14 = 0.020202\ldots3$, since $\sum{k=1}^\infty 2/9^k = 2/8 = 1/4$.- Uncountable: $x \in C$ exactly when $x$ has a base-$3$ expansion using only the digits $0$ and $2$. Replacing each $2$ by $1$ and reading the result in base $2$ maps $C$ onto $[0,1]$, so $C$ is uncountable.
The Cantor set is the standard example of a set that is "small" in length but "large" in cardinality. It returns in Real Analysis 02 as a closed, compact set that contains no interval.
Practice Exercises
1. Write the negation of: "for every $M > 0$ there is $N \in \mathbb{N}$ such that for all $n \ge N$, $an > M$" (the definition of $an \to \infty$).
<details><summary>Solution</summary>
"There is $M > 0$ such that for every $N \in \mathbb{N}$ there is $n \ge N$ with $an \le M$." In words: there is a level $M$ at or below which infinitely many terms stay.
</details>
2. Prove by induction that $1 + 2 + \cdots + n = \frac{n(n+1)}{2}$ for all $n \in \mathbb{N}$.
<details><summary>Solution</summary>
Base: $1 = \frac{1 \cdot 2}{2}$. Step: if $1 + \cdots + n = \frac{n(n+1)}{2}$, then $1 + \cdots + n + (n + 1) = \frac{n(n+1)}{2} + (n+1) = \frac{(n+1)(n+2)}{2}$, which is the formula for $n + 1$.
</details>
3. Prove that $\sqrt{3}$ is irrational.
<details><summary>Solution</summary>
First, if $3$ divides $n^2$ then $3$ divides $n$: otherwise $n = 3k \pm 1$ and $n^2 = 9k^2 \pm 6k + 1$ leaves remainder $1$ on division by $3$. Now suppose $\sqrt{3} = p/q$ in lowest terms. Then $p^2 = 3q^2$, so $3$ divides $p$; write $p = 3k$. Then $9k^2 = 3q^2$, so $q^2 = 3k^2$ and $3$ divides $q$. Both divisible by $3$ contradicts lowest terms.
</details>
4. Find $\sup A$ and $\inf A$ for $A = \left\{ \frac{n}{n+1} : n \in \mathbb{N} \right\}$ and prove your answer for the supremum.
<details><summary>Solution</summary>
$\inf A = \frac12$ (the minimum, at $n = 1$, since $\frac{n}{n+1} = 1 - \frac{1}{n+1}$ increases with $n$). $\sup A = 1$: it is an upper bound since $\frac{n}{n+1} < 1$. Given $\varepsilon > 0$, choose $n$ with $\frac{1}{n+1} < \varepsilon$ (Archimedean); then $\frac{n}{n+1} = 1 - \frac{1}{n+1} > 1 - \varepsilon$. By the $\varepsilon$-characterization, $\sup A = 1$. It is not attained.
</details>
5. Let $A, B$ be nonempty and bounded above, and $A + B = \{a + b : a \in A, b \in B\}$. Prove $\sup(A + B) = \sup A + \sup B$.
<details><summary>Solution</summary>
Let $s = \sup A$, $t = \sup B$. For $a \in A$, $b \in B$: $a + b \le s + t$, so $s + t$ is an upper bound. Given $\varepsilon > 0$, pick $a > s - \varepsilon/2$ and $b > t - \varepsilon/2$; then $a + b > (s + t) - \varepsilon$. By the $\varepsilon$-characterization, $\sup(A + B) = s + t$.
</details>
6. Show that the intervals $In = (0, 1/n]$ are nested but have empty intersection. Which hypothesis of the Nested Interval Property fails?
<details><summary>Solution</summary>
$1/(n+1) < 1/n$ gives $I{n+1} \subseteq In$. If $x \le 0$, $x \notin I1$. If $x > 0$, choose $n$ with $1/n < x$ (Archimedean); then $x \notin In$. So the intersection is empty. The intervals are not closed (the left endpoint $0$ is missing).
</details>
7. Show that the set of all finite subsets of $\mathbb{N}$ is countable, but the set $\mathcal{P}(\mathbb{N})$ of all subsets of $\mathbb{N}$ is not.
<details><summary>Solution</summary>
Finite subsets: for each $n$, the subsets of $\{1, \dots, n\}$ form a finite collection ($2^n$ sets), and every finite subset of $\mathbb{N}$ belongs to one of these collections. List the first collection, then the new sets of the second, and so on; this lists every finite subset exactly once. All subsets: suppose $f : \mathbb{N} \to \mathcal{P}(\mathbb{N})$ were onto. Let $B = \{n : n \notin f(n)\}$. If $B = f(m)$, then $m \in B \iff m \notin f(m) = B$, a contradiction. (This is Cantor's theorem, the same diagonal idea.)
</details>
Cheat-sheet
| Idea | Statement | Used for ||------|-----------|----------|| Negation | flip each quantifier, negate the final condition | "does not converge", "not continuous" || Triangle inequality | $\lvert x + y\rvert \le \lvert x\rvert + \lvert y\rvert$ | splitting every $\varepsilon$ estimate || Reverse triangle | $\big\lvert \lvert x\rvert - \lvert y\rvert\big\rvert \le \lvert x - y\rvert$ | lower bounds on $\lvert an \rvert$ || Equality lemma | $a = b$ iff $\lvert a - b\rvert < \varepsilon$ for all $\varepsilon > 0$ | proving limits are unique || Supremum | least upper bound; may not be in the set | defining limits, integrals || $\varepsilon$-test | upper bound $s$, and some $a > s - \varepsilon$ for each $\varepsilon$ | every sup computation || Completeness | nonempty + bounded above gives a sup in $\mathbb{R}$ | the one axiom $\mathbb{Q}$ lacks || Archimedean | $\mathbb{N}$ unbounded; $1/n < y$ for some $n$ | choosing $N$ in limit proofs || Density | a rational (and an irrational) in every $(a,b)$ | Dirichlet function, approximation || Nested intervals | closed, bounded, nested: nonempty intersection | bisection proofs || Countable | $\mathbb{N}$, $\mathbb{Z}$, $\mathbb{Q}$ | listing arguments || Uncountable | $\mathbb{R}$, $(0,1)$, irrationals, Cantor set | diagonal argument |
What's next
Real Analysis 01 uses the Axiom of Completeness to study sequences and series: the $\varepsilon$–$N$ definition of a limit with an explicit $N$, the Monotone Convergence Theorem (a supremum in disguise), Bolzano–Weierstrass (nested intervals in disguise), Cauchy sequences, and the convergence tests for infinite series, including why rearranging a series can change its sum.
References
- Stephen Abbott, Understanding Analysis, 2nd edition, Springer (Undergraduate Texts in Mathematics), 2015 — Chapter 1 (the model for this post).- Walter Rudin, Principles of Mathematical Analysis, 3rd edition, McGraw-Hill, 1976 — Chapter 1 (ordered fields, construction of $\mathbb{R}$ by Dedekind cuts) and Chapter 2 (countable sets, the Cantor set).- Robert G. Bartle and Donald R. Sherbert, Introduction to Real Analysis, 4th edition, Wiley, 2011 — Chapters 1–2.- Terence Tao, Analysis I, 4th edition, Springer (Texts and Readings in Mathematics), 2022 — Chapters 2–5 (from the natural numbers to the construction of $\mathbb{R}$).- Michael Spivak, Calculus, 4th edition, Publish or Perish, 2008 — Chapters 1–2 and 8 (least upper bounds).- MIT OpenCourseWare, 18.100A Real Analysis, Fall 2020 (Casey Rodriguez), lecture notes: https://ocw.mit.edu/courses/18-100a-real-analysis-fall-2020/
> Note: this post is in progress. Planned additions: a short construction of $\mathbb{R}$ by Dedekind cuts; a proof that the Nested Interval Property plus the Archimedean property implies completeness; and the Schröder–Bernstein theorem.














