# Sets, Relations & Functions

> The three ideas almost all of math (and a lot of code) is built from: a set is a collection of distinct things, a relation connects things, and a function maps each input to exactly one output. Learn these and the rest of math has a vocabulary.


---

# Sets, Relations & Functions

Here's a quiet secret about mathematics: almost all of it is built from three ideas, and you already use
all three in code. A **set** is a collection of distinct things (a `Set` in your language of choice). A
**relation** is a way things are connected (rows in a database table). A **function** is a rule that
turns each input into exactly one output (a pure function, or a lookup `map`). Get these three solid and
you've got the vocabulary the rest of math is written in.

This guide assumes nothing beyond [Why Math Isn't Your Enemy](/guides/why-math-isnt-your-enemy) - if you
can read the notation from that guide, you're ready. We'll build each idea from the ground up, with
real examples and runnable code, and keep showing how the math object you're learning is the same thing
as a tool you already reach for.

## How to read this
- **Want the foundation fast?** [Phase 1](01-sets.md) on sets is the bedrock everything else stands on.
- **Want it to stick?** Read in order - relations and functions are defined in terms of sets, so Phase 1
  earns the rest.

## The phases
1. **[Sets: Collections of Distinct Things](01-sets.md)** - membership, subsets, and the operations
   (union, intersection, difference) - with the empty set and why duplicates don't count.
2. **[Relations & Functions](02-relations-and-functions.md)** - ordered pairs, what makes a relation a
   *function*, and domain/codomain/range without the fog.
3. **[Why This Is the Vocabulary of Everything](03-the-vocabulary-of-everything.md)** - how sets and
   functions quietly power types, databases, and data structures.

> With this vocabulary in hand, the Mathematics track moves on to numbers and number systems, counting,
> and probability.


---

# Sets: Collections of Distinct Things

Almost everything else in this guide - relations, functions, the machinery you'll lean on later - is built on one humble idea: the set. You already think in sets all the time; you haven't been handed the vocabulary yet. This phase hands it to you, slowly and with no surprises.

## What a set is

A **set** is a collection of things where two rules hold:

- **Order doesn't matter.** The collection has no "first" or "last".
- **Duplicates don't count.** A thing is either in the set or it isn't. There's no "in it twice".

That's the whole definition. The things inside are called **elements** (or **members**).

We write a set by listing its elements inside curly braces:

```
{1, 2, 3}
```

Because order doesn't matter, `{1, 2, 3}` and `{3, 1, 2}` are the *same set*. And because duplicates don't count, `{1, 2, 2, 3}` is that same set too - the repeated `2` adds nothing.

You meet sets constantly without naming them:

- **The set of weekdays:** `{Monday, Tuesday, Wednesday, Thursday, Friday}`. Listing Tuesday twice wouldn't create a second Tuesday.
- **The set of users who liked a post.** A user either liked it or didn't. Liking it twice is meaningless - they're in the set, full stop.
- **The set of vowels:** `{a, e, i, o, u}`.

The mental model to carry: a set is a **bag of distinct things where you only ever ask one question - is this thing in the bag or not?** Not *how many times*, not *in what position*. Only in or out.

## Membership: ∈ and ∉

That one question - "is this thing in the bag?" - gets its own symbol.

- `x ∈ S` reads "**x is an element of S**" (x is in the set).
- `x ∉ S` reads "**x is not an element of S**".

With `S = {a, e, i, o, u}`:

- `a ∈ S` is true.
- `b ∉ S` is true.

The `∈` symbol is a stylized "e" for *element*. If unfamiliar notation makes you tense up, that's normal and it passes - there's a gentle warm-up in [Why math isn't your enemy](/guides/why-math-isnt-your-enemy).

## The empty set

A set can have no elements at all. This is the **empty set**, written `∅` or `{ }`.

It sounds like a technicality, but it's genuinely useful - it's the answer to "which weekdays start with the letter Z?" The plain answer is *none*, and `∅` is how we write *none* as a set. Often you don't want a special case for "nothing"; you want "nothing" to be an ordinary set you can work with.

There is exactly one empty set, and it lives inside every other set's story (you'll see why in the next section).

## Subsets and equality

Sometimes one set sits entirely inside another.

`A ⊆ B` reads "**A is a subset of B**" and means: every element of A is also an element of B.

For example, if `A = {1, 2}` and `B = {1, 2, 3}`, then `A ⊆ B` - both `1` and `2` are in B.

Two things worth knowing:

- **Every set is a subset of itself.** `B ⊆ B` is always true, because every element of B is (trivially) in B.
- **The empty set is a subset of every set.** `∅ ⊆ B` is always true. There are no elements in `∅` that could fail to be in B, so the condition holds with nothing to check.

**Set equality** falls out neatly: `A = B` exactly when `A ⊆ B` *and* `B ⊆ A`. In plain words, two sets are equal when they have exactly the same elements - which is why order and duplicates never affect equality.

## The three operations

Most real work with sets comes down to combining them. There are three combinations you'll use over and over. For each, picture two overlapping circles - the classic Venn picture - and ask which region you're keeping.

### Union: A ∪ B

The **union** is everything in **either** set (or both). You keep *both whole circles*.

```
{1, 2, 3} ∪ {3, 4, 5}  =  {1, 2, 3, 4, 5}
```

The `3` appears in both inputs but only once in the result - it's still a set, so it stays distinct. Think "**combine them**".

### Intersection: A ∩ B

The **intersection** is only the things in **both** sets. You keep *just the overlap* - the lens-shaped middle where the circles cross.

```
{1, 2, 3} ∩ {3, 4, 5}  =  {3}
```

Only `3` is in both. Think "**what do they share?**" If two sets share nothing, their intersection is the empty set.

### Difference: A \ B

The **difference** `A \ B` is the things in **A that are not in B**. You keep *the part of A's circle that doesn't overlap*.

```
{1, 2, 3} \ {3, 4, 5}  =  {1, 2}
```

`3` is removed because it's also in B; `4` and `5` were never in A, so they're irrelevant. Think "**A, minus anything B also has**". Order matters here: `B \ A` would be `{4, 5}`, a different answer.

## See it run

Python has sets built in, and they behave exactly like the math. Run this:

```python runnable
a = {1, 2, 3, 3}      # the duplicate 3 collapses
b = {3, 4, 5}
print(a)              # {1, 2, 3}
print(a | b)          # union
print(a & b)          # intersection
print(a - b)          # difference
```

*What just happened:* The first line wrote `3` twice, but a set keeps each element once, so `print(a)` shows `{1, 2, 3}` - the duplicate collapsed. Then `a | b` is the **union** `{1, 2, 3, 4, 5}`, `a & b` is the **intersection** `{3}`, and `a - b` is the **difference** `{1, 2}`. In Python the symbols are `|` for union, `&` for intersection, and `-` for difference.

## For builders

If you write code, you already have this tool. Both Python and JavaScript ship a `Set` type.

- **Deduping a list.** Wrapping a list in a set throws away repeats: in Python `set([1, 1, 2, 3])` gives `{1, 2, 3}`; in JS `new Set([1, 1, 2, 3])`. It's the fastest, most reliable way to answer "what are the unique values here?"
- **Fast membership tests.** Checking `x in my_set` is roughly **O(1)** - constant time, no matter how big the set is. Checking `x in my_list` scans the whole list, which is O(n). If you're repeatedly asking "have I seen this?", reach for a set.
- **Tags and permissions.** These are sets in disguise. "Posts tagged both `python` and `beginner`" is an **intersection**. "Everything a user can do across all their roles" is a **union** of permission sets. "Allowed actions minus the ones currently blocked" is a **difference**. Naming the operation makes the code obvious.

## Recap

- A **set** is an unordered collection of **distinct** elements: order doesn't matter, duplicates don't count.
- `x ∈ S` means x is in S; `x ∉ S` means it isn't.
- The **empty set** `∅` has no elements and is a subset of every set.
- `A ⊆ B` means every element of A is in B; `A = B` when each is a subset of the other.
- The three operations: **union** `∪` (either), **intersection** `∩` (both), **difference** `\` (in A, not B).
- In code: sets dedupe, give O(1) membership, and model tags and permissions cleanly.

> ⚠️ **A set is not a list.** Duplicates silently collapse and order is not guaranteed when you iterate - if you need ordering or repeated values, you want a list (or array), not a set. Reach for a set only when the single question "is this in the collection?" is all you care about.

A quick check before you move on:

```quiz
[
  {
    "q": "Which statement about sets is true?",
    "choices": [
      "{1, 2, 3} and {3, 2, 1} are different sets because the order differs",
      "{1, 2, 2, 3} contains the element 2 twice",
      "{1, 2, 3} and {3, 1, 2} are the same set, and duplicates don't count",
      "A set must always list its elements in increasing order"
    ],
    "answer": 2,
    "explain": "Sets are unordered and hold only distinct elements, so reordering or repeating elements doesn't create a different set."
  },
  {
    "q": "What is the intersection of {1, 2, 3} and {3, 4, 5}?",
    "choices": [
      "{1, 2, 3, 4, 5} - everything in either set",
      "{3} - only what's in both sets",
      "{1, 2} - what's in the first but not the second",
      "{ } - they share nothing"
    ],
    "answer": 1,
    "explain": "Intersection keeps only elements present in both sets. Only 3 appears in both, so the result is {3}."
  },
  {
    "q": "What is the empty set?",
    "choices": [
      "A set containing the single element 0",
      "A set with no elements, written ∅ or { }",
      "A set that can never be a subset of another set",
      "The same thing as an undefined or invalid set"
    ],
    "answer": 1,
    "explain": "The empty set ∅ (also written { }) has no elements at all, and it is a subset of every set."
  }
]
```


---

# Relations & Functions

In Phase 1 you met sets: collections of distinct things, where order doesn't matter and
duplicates don't count. That was the noun. Now comes the verb - how things *connect* to each
other. The quiet surprise: the connection is itself a set. Everything you learned still applies.
We're not starting over; we're stacking one idea on another.

## First, the ordered pair

A set treats `{1, 2}` and `{2, 1}` as the same thing. Order is irrelevant; membership is all
that matters.

Sometimes that's not what you want. A chess move that goes "from square a to square b" becomes a
different move if you swap a and b. The order carries meaning. For that, we use an **ordered
pair**, written with round brackets:

`(a, b)`

The rule that defines it: `(a, b)` equals `(c, d)` only when `a = c` **and** `b = d`. So:

`(1, 2)` is **not** `(2, 1)`

That single change - order now matters - is the whole reason ordered pairs exist. The first slot
and the second slot mean different things, and you can't shuffle them.

## A relation is a set of ordered pairs

Here's the connecting idea. A **relation** is a set whose elements are ordered pairs. That's the
entire definition. Each pair `(a, b)` says "a is connected to b" in whatever way you care about.

An everyday example. Suppose three people own pets:

```
{ (Ana, cat), (Ben, dog), (Ana, parrot) }
```

That set of pairs *is* a relation - the "owns" relation. Notice Ana shows up twice, connected to
two different pets. That's allowed. A relation doesn't restrict how many partners a thing has.

Another classic: "is older than." If Ana is older than Ben, and Ben is older than Cara, the
relation is the set of pairs that hold true:

```
{ (Ana, Ben), (Ana, Cara), (Ben, Cara) }
```

The order in each pair matters here - `(Ana, Ben)` means "Ana is older than Ben," and you can't
flip it. This is why we needed ordered pairs first: relations are built out of them.

And because a relation is a set, every Phase 1 idea carries over. You can ask whether a pair is a
member of it. You can take its union with another relation. It's sets all the way down.

## A function: the one definition that matters

A **function** is a special kind of relation. The special rule:

> **Every input maps to exactly one output.**

Read that again, because it's the load-bearing sentence of this entire guide. Not "at most one,"
not "roughly one" - **exactly one**. Give the function an input, and there is one and only one
output waiting for it. No ambiguity, no choices.

Look back at the pets relation:

```
{ (Ana, cat), (Ben, dog), (Ana, parrot) }
```

Is this a function? No. Ana (an input) maps to *two* outputs: cat and parrot. The rule says
exactly one. One input, two outputs - that breaks it. So "owns a pet" is a relation but **not** a
function.

Now fix it. Suppose each person has exactly one *favorite* food:

```
{ (Ana, sushi), (Ben, tacos), (Cara, sushi) }
```

This **is** a function. Every input (person) maps to exactly one output (their favorite food).
Two inputs can share an output - both Ana and Cara map to sushi - and that's fine. The rule
constrains inputs, not outputs. What's forbidden is one input pointing at two different things.

Say it one more time so it sticks: a function is a relation where **every input maps to exactly
one output**.

## Domain, codomain, and range

Three words that sound interchangeable but aren't. Let's pin them down with one concrete function.

Take the "favorite food" function above, and suppose the menu it's drawn from is
`{sushi, tacos, pizza, salad}`.

- **Domain** - the set of inputs. Here: `{Ana, Ben, Cara}`. These are the things the function
  accepts.
- **Codomain** - the declared set the outputs are *allowed* to come from. Here: the whole menu,
  `{sushi, tacos, pizza, salad}`. It's the promised territory.
- **Range** (also called the **image**) - the outputs that *actually get produced*. Here:
  `{sushi, tacos}`. Nobody picked pizza or salad, so those sit in the codomain but never appear in
  the range.

The relationship to hold onto: the range is always inside the codomain, and it can be smaller. The
codomain is what you *promised* was possible; the range is what *happened*.

## Quick recap of `f(x)` notation

You've seen `f(x)` before - back in [why math isn't your enemy](/guides/why-math-isnt-your-enemy)
it was a machine: feed in `x`, get back `f(x)`. Now you can read it precisely. `f` is the function
(a set of pairs). `x` is an input from the domain. `f(x)` is *the* output - singular, because the
definition guarantees exactly one. When you write `f(3) = 6`, you're naming the pair `(3, 6)` that
lives inside the function.

## See it run

Here are two ways to write the same idea in code: a function defined with `def`, and a finite
function stored as a dictionary.

```python runnable
def double(x):
    return x * 2
print(double(5))

# a dict is a finite function: each key maps to exactly one value
square = {1: 1, 2: 4, 3: 9}
print(square[3])
```

*What just happened:* `double(5)` returned `10` - one input, one output, exactly as the definition
demands. Then the dict `square` mapped the key `3` to the value `9`. A Python dict can't hold the
same key twice with two different values, which is precisely the "every input maps to exactly one
output" rule, enforced by the language. The dict *is* a function, written as a lookup table.

## For builders

You already use functions every day; you don't call them that.

- A **pure function** in code - one that always returns the same output for the same input, with no
  side effects - *is* a mathematical function. Same input, same output, every time. That's the
  definition, restated in a language you compile.
- A **dict / map / hash table** is a **finite function**: a literal list of input-output pairs, one
  value per key. When you write `users[id]`, you're evaluating a function at the point `id`.

Same idea, two notations. Math wrote it as a set of ordered pairs centuries ago; your standard
library wrote it as `{key: value}`. Once you see they're the same thing, the math stops feeling
foreign.

> ⚠️ **Not every relation is a function.** The trap is forgetting the "exactly one" rule. The
> moment a single input maps to two different outputs, you have a relation but *not* a function.
> If you ever graph it, this is what the **vertical line test** checks: draw any vertical line - if
> it crosses the graph more than once, one input is hitting multiple outputs, so it's not a
> function.

## Recap

- An **ordered pair** `(a, b)` cares about order: `(1, 2)` is not `(2, 1)`.
- A **relation** is a set of ordered pairs - a way of connecting things. Because it's a set,
  everything from Phase 1 still applies.
- A **function** is a relation where **every input maps to exactly one output**. One input → two
  outputs breaks it.
- **Domain** = inputs, **codomain** = the declared set of possible outputs, **range** = the outputs
  actually produced (always inside the codomain).
- In code, a pure function and a dict are both functions - same idea, different notation.

A quick check before you move on:

```quiz
[
  {
    "q": "What makes a relation a function?",
    "choices": [
      "Every input maps to exactly one output",
      "Every output comes from exactly one input",
      "It contains no duplicate ordered pairs",
      "The domain and codomain are the same set"
    ],
    "answer": 0,
    "explain": "A function is a relation where each input has exactly one output. Two inputs may share an output, but one input may never map to two different outputs."
  },
  {
    "q": "For the function {(Ana, sushi), (Ben, tacos), (Cara, sushi)} with codomain {sushi, tacos, pizza, salad}, what is the difference between the domain and the range?",
    "choices": [
      "The domain is {Ana, Ben, Cara} (the inputs); the range is {sushi, tacos} (the outputs actually produced)",
      "The domain is {sushi, tacos}; the range is {Ana, Ben, Cara}",
      "The domain and range are both {sushi, tacos, pizza, salad}",
      "The domain is the codomain; the range is empty"
    ],
    "answer": 0,
    "explain": "Domain = the set of inputs. Range = the outputs actually produced, which here is {sushi, tacos} - a subset of the codomain (pizza and salad never appear)."
  },
  {
    "q": "Which statement about the ordered pair (1, 2) is true?",
    "choices": [
      "(1, 2) is a different pair from (2, 1) because order matters",
      "(1, 2) equals (2, 1) because they contain the same numbers",
      "(1, 2) is the same as the set {1, 2}",
      "(1, 2) is only valid if 1 is less than 2"
    ],
    "answer": 0,
    "explain": "In an ordered pair the order is meaningful: (a, b) = (c, d) only when a = c and b = d. So (1, 2) and (2, 1) are different - unlike the set {1, 2}, where order is ignored."
  }
]
```


---

# Why This Is the Vocabulary of Everything

You made it to the part where it pays off.

For two phases you've been collecting three ideas. They probably felt like math
for math's sake - clean little definitions with no obvious home. This phase is
where they walk out of the textbook and into the things you already use every
day. Once you see it, you can't unsee it: the same three shapes hide under
types, database tables, and data structures. You already know the vocabulary -
you were calling it by different names.

## The three ideas, in one breath

Before we spread out, let's pin down what you're carrying.

- A **set** is a collection of distinct things, with no order and no repeats.
  `{1, 2, 3}` is the same set as `{3, 1, 2}`.
- A **relation** connects things from one set to things from another - a list of
  pairs that "go together." (We built these up in
  [Phase 2](02-relations-and-functions.md).)
- A **function** is a special relation with one rule: every input gets *exactly
  one* output. No input is left out, and none points at two answers.

That's it. Three sentences. Now watch them show up everywhere.

## Types are sets

Here's the one that reframes everything for builders.

A **type** in a programming language is a *set of values*. That's the whole
idea. When you say a variable is a `bool`, you're saying it lives in the set
`{true, false}` - two elements, nothing else allowed. Define an enum like
`Color = {Red, Green, Blue}` and you've literally written a set of named values.
An `int` is (conceptually) the set of whole numbers a machine will hold. A
`string` is the set of all possible text values.

So what is type-checking? The compiler asking a membership question: *is this
value an element of that set?* Assigning `7` to a `bool` fails because `7` isn't
in `{true, false}`. The error you've seen a hundred times - "expected `bool`,
found `int`" - is the machine telling you the value isn't a member of the set
you promised.

> **For builders:** "Make invalid states unrepresentable" is advice you've
> probably heard. Now you can hear it precisely: *shrink the set* so the bad
> values aren't elements of the type at all. A type that's exactly the right set
> of values can't hold a wrong one.

This is why a tight type feels safer than a loose one. A type that's "any
string" is a huge set; a type that's "one of these five statuses" is a tiny set.
The smaller the set, the fewer wrong values can sneak in.

## Relations are tables

This one hides in plain sight, and the giveaway is right in the name.

A database table is a **set of rows**. Each row is a tuple - a fixed bundle of
fields, like `(id, name, email)`. The table is the collection of all those
tuples. And a set of tuples is exactly what a *relation* is in the math sense.
That's no coincidence or cute analogy. It's where the term **relational
database** comes from. The math came first; the product was named after it.

We built relations up step by step in [Phase 2](02-relations-and-functions.md):
pairs (and tuples) of things that belong together. A row like
`(42, "Ada", "ada@example.com")` is one of those tuples. The table is the
relation - the whole set of them.

A few things you've done with tables now have crisp names:

- A table with no duplicate rows is a true set (sets don't repeat). That's why a
  primary key exists - it guarantees each row is distinct.
- A `JOIN` combines two relations into a new one based on matching values.
- A `WHERE` filter carves out a *subset* of the rows.

You weren't doing arbitrary data wrangling. You were operating on sets of
tuples, which is the math under the whole field.

## Functions are everywhere

Once you know what a function is - every input mapped to exactly one output -
you start spotting them in code constantly.

- A **hash map** / **dictionary** is a function. Each key maps to exactly one
  value. Look up the same key twice, get the same value. That "one value per
  key" rule *is* the function rule.
- A **pure function** in code (same input, same output, no surprises) is the
  mathematical function almost exactly.
- **`map()`** over a list applies a function to every element and gives you a new
  list - input set in, output set out.
- A **lookup table** or a **routing table** (this URL goes to that handler) is a
  function: each route points at one destination.

> **For builders:** when something *isn't* a function, that's a signal too. If a
> key could map to two values, you don't want a dictionary - you want a list of
> values per key, or a different structure. Noticing "is this one-to-one or
> one-to-many?" is the same question as "is this a function?"

Here's the dictionary-as-function idea made literal. A dict and a function that
does a lookup are two faces of the same thing:

```python runnable
# A dictionary: each key maps to exactly one value. That's a function.
status_name = {200: "OK", 404: "Not Found", 500: "Server Error"}

# Reading the dict is applying the function.
print(status_name[404])

# The exact same mapping, written as a function instead of a table:
def status_name_fn(code):
    return status_name[code]

print(status_name_fn(200))
```

Same mapping, two skins: one stored as data, one written as code. The math
doesn't care which skin you pick - both are functions.

## Composition: do one thing, then the next

There's a fourth move worth naming, because you already do it by instinct.

**Composition** is applying one function and then feeding its result into
another. Do `f`, then do `g` on the answer. In math you'd write `g(f(x))`. In
code, this is the urge behind piping and chaining: take a value, transform it,
transform the result, transform that. A Unix pipeline (`cat file | sort |
uniq`), a chain of method calls, a series of `map`s - all of it is function
composition. You take small, well-understood steps and glue them end to end into
one bigger step.

This feels natural because it *is* natural: a function turns inputs into outputs,
so its output is a perfectly good input for the next function. The shapes fit
together. That's why building software out of small functions you chain together
holds up - each piece is a clean mapping, and composition lets you stack them
without the whole thing turning to mush.

## A peek ahead: how big is a set?

We've talked about *what's in* a set. There's an equally natural question we
haven't touched: *how many* things are in it. The size of a set has a name -
**cardinality** - and it's the quiet bridge from sets to counting. `{true,
false}` has cardinality 2. An enum of five statuses has cardinality 5. Once you
start asking "how big is this set?", you've stepped out of pure structure and
into the territory of numbers and counting. We'll follow that thread later; for
now, notice that "what's in it" and "how many" are different questions, and
both matter.

## You now speak the language

Step back and look at what happened.

You learned three small ideas - set, relation, function - and watched them turn
into the type system, the database, and the data structures you build with. That
wasn't a trick of framing. Those tools were *named after* this math, or grew
straight out of it. When you reach for a dictionary, define an enum, or write a
`JOIN`, you're already thinking in sets and functions. Now you know the words for
it, which means you can reason about it on purpose instead of by feel.

This is also why these ideas are worth the effort: they're the vocabulary the
rest of math is written in. Numbers and number systems are built on sets.
Counting is built on cardinality - the "how big is it" question we teased earlier.
Probability is, underneath, the art of measuring subsets of a set of
possibilities. You'll meet all of those next, already fluent in the grammar. If
sets and functions still feel a little abstract, that's fine - you don't need to
love them, you need to recognize them, and now you will.

If you came into this guide worried that math wasn't for you, it might help to
revisit [why math isn't your enemy](/guides/why-math-isnt-your-enemy) - and if
the "exactly one output" rule reminded you of clean either/or thinking, that's
no accident either; it's close cousins with [what logic actually
is](/guides/what-logic-actually-is).

Quick check before you go - three claims this phase made:

```quiz
[
  {
    "q": "In what sense is a type (like `bool` or an enum) a set?",
    "choices": [
      "A type is the set of values that something of that type can hold",
      "A type is a single value that never changes",
      "A type is a function that returns true or false",
      "A type is unrelated to sets - the resemblance is a coincidence"
    ],
    "answer": 0,
    "explain": "A type is exactly the set of allowed values: `bool` is `{true, false}`. Type-checking asks whether a value is a member of that set."
  },
  {
    "q": "Why is a table in a relational database a good example of a relation?",
    "choices": [
      "Because the rows are sorted, and relations require order",
      "Because a table is a set of rows (tuples), and a relation is a set of tuples",
      "Because every table must have exactly one column",
      "Because tables store numbers, and relations only work on numbers"
    ],
    "answer": 1,
    "explain": "A table is a set of rows, each row a tuple of fields. A relation is a set of tuples - same thing. That's where the name 'relational' comes from."
  },
  {
    "q": "Why does a dictionary (hash map) count as a function in the math sense?",
    "choices": [
      "Because it can store any number of keys",
      "Because looking up a key is fast",
      "Because each key maps to exactly one value",
      "Because keys and values are always the same type"
    ],
    "answer": 2,
    "explain": "A function gives every input exactly one output. A dictionary gives every key exactly one value - that one-value-per-key rule is the function rule."
  }
]
```
