···11+---
22+title: "A Chain Reaction"
33+date: '2023-12-11'
44+spoiler: "The limits of my language mean the limits of my world."
55+---
66+77+I wrote a bit of JSX in my editor:
88+99+```js
1010+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
1111+ Hello, <i>Alice</i>!
1212+</p>
1313+```
1414+1515+Right now, this information only exists on *my* device. But with a bit of luck, it will travel through time and space to *your* device, and appear on *your* screen.
1616+1717+```js eval
1818+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
1919+ Hello, <i>Alice</i>!
2020+</p>
2121+```
2222+2323+The fact that this works is a marvel of engineering.
2424+2525+Deep inside of your browser, there are pieces of code that know how to display a paragraph or draw text in italics. These pieces of code are different between different browsers, and even between different versions of the same browser. Drawing to the screen is also done differently on different operating systems.
2626+2727+However, because these concepts have been given agreed-upon *names* ([`<p>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p) for a paragraph, [`<i>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i) for italics), I can refer to them without worrying how they *really* work on your device. I can't directly access their internal logic but I know which information I can pass to them (such as a CSS [`className`](https://developer.mozilla.org/en-US/docs/Web/API/Element/className)). Thanks to the web standards, I can be reasonably sure my greeting will appear as I intended.
2828+2929+Tags like `<p>` and `<i>` let us refer to the built-in browser concepts. However, names don't *have to* refer to something built-in. For example, I'm using CSS classes like [`text-2xl`](https://tailwindcss.com/docs/font-size) and [`font-sans`](https://tailwindcss.com/docs/font-family) to style my greeting. I didn't come up with those names myself--they come from a CSS library called Tailwind. I've included it on this page which lets me use any of the CSS class names it defines.
3030+3131+So why do we like giving names to things?
3232+3333+---
3434+3535+I wrote `<p>` and `<i>`, and my editor recognized those names. So did your browser. If you've done some web development, you probably recognized them too, and maybe even guessed what would appear on the screen by reading the markup. In that sense, names help us start with a bit of a shared understanding.
3636+3737+Fundamentally, computers execute relatively basic kinds of instructions--like adding or multiplying numbers, writing stuff to memory and reading from it, or communicating with external devices like a display. Merely showing a `<p>` on your screen could involve running hundreds of thousands of such instructions.
3838+3939+If you saw all the instructions your computer ran to display a `<p>` on the screen, you could hardly guess what they're doing. It's like trying to figure out which song is playing by analyzing all the atoms bouncing around the room. It would seem incomprehensible! You'd need to "zoom out" to see what's going on.
4040+4141+To describe a complex system, or to instruct a complex system what to do, it helps to separate its behavior into layers that build on each other's concepts.
4242+4343+This way, people working on screen drivers can focus on how to send the right colors to the right pixels. Then people working on text rendering can focus on how each character should turn into a bunch of pixels. And that lets people like me focus on picking just the right color for my "paragraphs" and "italics".
4444+4545+We like names because they let us forget what's behind them.
4646+4747+---
4848+4949+I've used many names that other people came up with. Some are built into the browsers, like `<p>` and `<i>`. Some are built into the tools I'm using, like `text-2xl` and `font-sans`. These may be my building blocks, but what am *I* building?
5050+5151+For example, what is this?
5252+5353+```js
5454+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
5555+ Hello, <i>Alice</i>!
5656+</p>
5757+```
5858+5959+```js eval
6060+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
6161+ Hello, <i>Alice</i>!
6262+</p>
6363+```
6464+6565+From your browser's perspective, this is a paragraph with certain CSS classes (which make it large and purple) and some text inside (part of it is in italics).
6666+6767+But from *my* perspective, it's *a greeting for Alice.* Although my greeting *happens* to be a paragraph, most of the time I want to think about it this way instead:
6868+6969+```js
7070+<Greeting person={alice} />
7171+```
7272+7373+Giving this concept a name provides me with some newfound flexibility. I can now display multiple `Greeting`s without copying and pasting their markup. I can pass different data to them. If I wanted to change how all greetings look and behave, I could do it in a single place. Turning `Greeting` into its own concept lets me adjust *"which greetings to display"* separately from *"what a greeting is"*.
7474+7575+However, I have also introduced a problem.
7676+7777+Now that I've given this concept a name, the "language" in my mind is different from the "language" that your browser speaks. Your browser knows about `<p>` and `<i>`, but it has never heard of a `<Greeting>`--that's my own concept. If I wanted your browser to understand what I mean, I'd have to "translate" this piece of markup to only use the concepts that your browser already knows.
7878+7979+I'd need to turn this:
8080+8181+```js
8282+<Greeting person={alice} />
8383+```
8484+8585+into this:
8686+8787+```js
8888+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
8989+ Hello, <i>Alice</i>!
9090+</p>
9191+```
9292+9393+How would I go about that?
9494+9595+---
9696+9797+To name something, I need to define it.
9898+9999+For example, `alice` does not mean anything until I define `alice`:
100100+101101+```js
102102+const alice = {
103103+ firstName: 'Alice',
104104+ birthYear: 1970
105105+};
106106+```
107107+108108+Now `alice` refers to that JavaScript object.
109109+110110+Similarly, I need to actually *define* what my concept of a `Greeting` means.
111111+112112+I will define a `Greeting` for any `person` as a paragraph showing "Hello, " followed by *that* person's first name in italics, plus an exclamation mark:
113113+114114+```js
115115+function Greeting({ person }) {
116116+ return (
117117+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
118118+ Hello, <i>{person.firstName}</i>!
119119+ </p>
120120+ );
121121+}
122122+```
123123+124124+Unlike `alice`, I defined `Greeting` as a function. This is because *a greeting* would have to be different for every person. `Greeting` is a piece of code--it performs a *transformation* or a *translation*. It *turns* some data into some UI.
125125+126126+That gives me an idea for what to do with this:
127127+128128+```js
129129+<Greeting person={alice} />
130130+```
131131+132132+Your browser wouldn't know what a `Greeting` is--that's my own concept. But now that I wrote a definition for that concept, I can *apply* this definition to "unpack" what I meant. You see, *a greeting for a person is actually a paragraph:*
133133+134134+```js {3-5}
135135+function Greeting({ person }) {
136136+ return (
137137+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
138138+ Hello, <i>{person.firstName}</i>!
139139+ </p>
140140+ );
141141+}
142142+```
143143+144144+Plugging the `alice`'s data into that definition, I end up with this final JSX:
145145+146146+```js
147147+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
148148+ Hello, <i>Alice</i>!
149149+</p>
150150+```
151151+152152+At this point I only refer to the browser's own concepts. By substituting the `Greeting` with what I defined it to be, I have "translated" it for your browser.
153153+154154+```js eval
155155+function Greeting({ person }) {
156156+ return (
157157+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
158158+ Hello, <i>{person.firstName}</i>!
159159+ </p>
160160+ );
161161+}
162162+163163+const alice = {
164164+ firstName: 'Alice',
165165+ birthYear: 1970
166166+};
167167+168168+<Greeting person={alice} />
169169+```
170170+171171+Now let's teach a computer to do the same thing.
172172+173173+---
174174+175175+Take a look at what JSX is made of.
176176+177177+```js
178178+const originalJSX = <Greeting person={alice} />;
179179+console.log(originalJSX.type); // Greeting
180180+console.log(originalJSX.props); // { firstName: 'Alice', birthYear: 1970 }
181181+```
182182+183183+Under the hood, JSX constructs an object with the `type` property corresponding to the tag, and the `props` property corresponding to the JSX attributes.
184184+185185+You can think of `type` as being the "code" and `props` as being the "data". To get the result, you need to plug that data *into* that code like I've done earlier.
186186+187187+Here is a little function I wrote that does exactly that:
188188+189189+```js
190190+function translateForBrowser(originalJSX) {
191191+ const { type, props } = originalJSX;
192192+ return type(props);
193193+}
194194+```
195195+196196+In this case, `type` will be `Greeting` and `props` will be `{ person: alice }`, so `translateForBrowser(<Greeting person={alice} />)` will return the result of calling `Greeting` with `{ person: alice }` as the argument.
197197+198198+Which, as you might recall from the previous section, would give me this:
199199+200200+```js
201201+<p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
202202+ Hello, <i>Alice</i>!
203203+</p>
204204+```
205205+206206+And that's exactly what I wanted!
207207+208208+You can verify that feeding my original piece of JSX to `translateForBrowser` will produce the "browser JSX" that only refers to concepts like `<p>` and `<i>`.
209209+210210+```js {5-7}
211211+const originalJSX = <Greeting person={alice} />;
212212+console.log(originalJSX.type); // Greeting
213213+console.log(originalJSX.props); // { firstName: 'Alice', birthYear: 1970 }
214214+215215+const browserJSX = translateForBrowser(originalJSX);
216216+console.log(browserJSX.type); // 'p'
217217+console.log(browserJSX.props); // { className: 'text-2xl font-sans text-purple-400 dark:text-purple-500', children: ['Hello', { type: 'i', props: { children: 'Alice' }, '!'] }
218218+```
219219+220220+There are many things I could do with that "browser JSX". For example, I could turn it into an HTML string to be sent to the browser. I could also convert it into a sequence of instructions that update an already existing DOM node. For now, I won't be focusing on the different ways to use it. All that matters right now is that by the time I have the "browser JSX", there is nothing left to "translate".
221221+222222+It's as if my `<Greeting>` has dissolved, and `<p>` and `<i>` are the residue.
223223+224224+---
225225+226226+Let's try something a tiny bit more complex. Suppose I want to wrap my greeting inside a [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) tag so that it appears collapsed by default:
227227+228228+```js {1,3}
229229+<details>
230230+ <Greeting person={alice} />
231231+</details>
232232+```
233233+234234+The browser should display it like this (click "Details" to expand it!)
235235+236236+```js eval
237237+function Greeting({ person }) {
238238+ return (
239239+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
240240+ Hello, <i>{person.firstName}</i>!
241241+ </p>
242242+ );
243243+}
244244+245245+const alice = {
246246+ firstName: 'Alice',
247247+ birthYear: 1970
248248+};
249249+250250+<details className="pb-8">
251251+ <Greeting person={alice} />
252252+</details>
253253+```
254254+255255+So now my task is now to figure out how to turn this:
256256+257257+```js
258258+<details>
259259+ <Greeting person={alice} />
260260+</details>
261261+```
262262+263263+into this:
264264+265265+```js
266266+<details>
267267+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
268268+ Hello, <i>Alice</i>!
269269+ </p>
270270+</details>
271271+```
272272+273273+Let's see if `translateForBrowser` can already handle that.
274274+275275+```js {2-4,9}
276276+const originalJSX = (
277277+ <details>
278278+ <Greeting person={alice} />
279279+ </details>
280280+);
281281+console.log(originalJSX.type); // 'details'
282282+console.log(originalJSX.props); // { children: { type: Greeting, props: { person: alice } } }
283283+284284+const browserJSX = translateForBrowser(originalJSX);
285285+```
286286+287287+You will get an error inside of the `translateForBrowser` call:
288288+289289+```js {3}
290290+function translateForBrowser(originalJSX) {
291291+ const { type, props } = originalJSX;
292292+ return type(props); // 🔴 TypeError: type is not a function
293293+}
294294+```
295295+296296+What happened here? My `translateForBrowser` implementation assumed that `type`--that is, `originalJSX.type`--is always a function like `Greeting`.
297297+298298+However, notice that `originalJSX.type` is actually a *string* this time:
299299+300300+```js {6}
301301+const originalJSX = (
302302+ <details>
303303+ <Greeting person={alice} />
304304+ </details>
305305+);
306306+console.log(originalJSX.type); // 'details'
307307+console.log(originalJSX.props); // { children: { type: Greeting, props: { person: alice } } }
308308+```
309309+310310+When you start a JSX tag with a lower case (like `<details>`), by convention it's assumed that you *want* a built-in tag rather than some function you defined.
311311+312312+Since built-in tags don't have any code associated with them (that code is somewhere inside your browser!), the `type` will be a string like `'details'`. How `<details>` work is opaque to my code--all I really know is its name.
313313+314314+Let's split the logic in two cases, and skip translating the built-ins for now:
315315+316316+```js {3,5-7}
317317+function translateForBrowser(originalJSX) {
318318+ const { type, props } = originalJSX;
319319+ if (typeof type === 'function') {
320320+ return type(props);
321321+ } else if (typeof type === 'string') {
322322+ return originalJSX;
323323+ }
324324+}
325325+```
326326+327327+After this change, `translateForBrowser` will only attempt to call some function if the original JSX's `type` actually *is* a function like `Greeting`.
328328+329329+So that's the result I wanted, right?...
330330+331331+```js
332332+<details>
333333+ <Greeting person={alice} />
334334+</details>
335335+```
336336+337337+Wait. What I wanted is this:
338338+339339+```js
340340+<details>
341341+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
342342+ Hello, <i>Alice</i>!
343343+ </p>
344344+</details>
345345+```
346346+347347+In my translation process, I want to *skip over* the `<details>` tag because its implementation is opaque to me. I can't do anything useful with it--it is fully up to the browser. However, anything *inside* of it may still need to be translated!
348348+349349+Let's fix `translateForBrowser` to translate any built-in tag's children:
350350+351351+```js {6-12}
352352+function translateForBrowser(originalJSX) {
353353+ const { type, props } = originalJSX;
354354+ if (typeof type === 'function') {
355355+ return type(props);
356356+ } else if (typeof type === 'string') {
357357+ return {
358358+ type,
359359+ props: {
360360+ ...props,
361361+ children: translateForBrowser(props.children)
362362+ }
363363+ };
364364+ }
365365+}
366366+```
367367+368368+With this change, when it meets an element like `<details>...</details>`, it will return another `<details>...</details>` tag, but the stuff *inside* of it would be translated with my function again--so the `Greeting` will be gone:
369369+370370+```js
371371+<details>
372372+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
373373+ Hello, <i>Alice</i>!
374374+ </p>
375375+</details>
376376+```
377377+378378+And *now* I am speaking the browser's "language" again:
379379+380380+```js eval
381381+<details className="pb-8">
382382+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
383383+ Hello, <i>Alice</i>!
384384+ </p>
385385+</details>
386386+```
387387+388388+The `Greeting` has been dissolved.
389389+390390+---
391391+392392+Now suppose that I try to define an `ExpandableGreeting`:
393393+394394+```js
395395+function ExpandableGreeting({ person }) {
396396+ return (
397397+ <details>
398398+ <Greeting person={person} />
399399+ </details>
400400+ );
401401+}
402402+```
403403+404404+Here is my new original JSX:
405405+406406+```js
407407+<ExpandableGreeting person={alice} />
408408+```
409409+410410+If I run it through `translateForBrowser`, I'll get this JSX in return:
411411+412412+```js
413413+<details>
414414+ <Greeting person={alice} />
415415+</details>
416416+```
417417+418418+But that's not what I wanted! It still has a `Greeting` in it, and we don't consider a piece of JSX "browser-ready" until *all* of my own concepts are gone.
419419+420420+This is a bug in my `translateForBrowser` function. When it calls a function like `ExpandableGreeting`, it will return its output, and not do anything else. But we need to keep on going! That returned JSX *also* needs to be translated.
421421+422422+Luckily, there is an easy way I can solve this. When I call a function like `ExpandableGreeting`, I can take the JSX it returned and translate *that* next:
423423+424424+```js {4-5}
425425+function translateForBrowser(originalJSX) {
426426+ const { type, props } = originalJSX;
427427+ if (typeof type === 'function') {
428428+ const returnedJSX = type(props);
429429+ return translateForBrowser(returnedJSX);
430430+ } else if (typeof type === 'string') {
431431+ return {
432432+ type,
433433+ props: {
434434+ ...props,
435435+ children: translateForBrowser(props.children)
436436+ }
437437+ };
438438+ }
439439+}
440440+```
441441+442442+I also need to stop the process when there's nothing left to translate, like if it receives `null` or a string. If it receives an array of things, I need to translate each of them. With these two fixes, `translateForBrowser` is complete:
443443+444444+```js {2-7}
445445+function translateForBrowser(originalJSX) {
446446+ if (originalJSX == null || typeof originalJSX !== 'object') {
447447+ return originalJSX;
448448+ }
449449+ if (Array.isArray(originalJSX)) {
450450+ return originalJSX.map(translateForBrowser);
451451+ }
452452+ const { type, props } = originalJSX;
453453+ if (typeof type === 'function') {
454454+ const returnedJSX = type(props);
455455+ return translateForBrowser(returnedJSX);
456456+ } else if (typeof type === 'string') {
457457+ return {
458458+ type,
459459+ props: {
460460+ ...props,
461461+ children: translateForBrowser(props.children)
462462+ }
463463+ };
464464+ }
465465+}
466466+```
467467+468468+Now, suppose that I start with this:
469469+470470+```js
471471+<ExpandableGreeting person={alice} />
472472+```
473473+474474+It will turn into this:
475475+476476+```js
477477+<details>
478478+ <Greeting person={alice} />
479479+</details>
480480+```
481481+482482+Which will turn into this:
483483+484484+```js
485485+<details>
486486+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
487487+ Hello, <i>Alice</i>!
488488+ </p>
489489+</details>
490490+```
491491+492492+And at that point, the process will stop.
493493+494494+---
495495+496496+Let's see how this works one more time, with a bit of extra depth.
497497+498498+I'll define `WelcomePage` like this:
499499+500500+```js
501501+function WelcomePage() {
502502+ return (
503503+ <section>
504504+ <h1 className="text-3xl font-sans pb-2">Welcome</h1>
505505+ <ExpandableGreeting person={alice} />
506506+ <ExpandableGreeting person={bob} />
507507+ <ExpandableGreeting person={crystal} />
508508+ </section>
509509+ );
510510+}
511511+```
512512+513513+Now let's say I start the process with this original JSX:
514514+515515+```js
516516+<WelcomePage />
517517+```
518518+519519+Can you retrace the sequence of transformations in your head?
520520+521521+Let's do it step by step together.
522522+523523+First, imagine `WelcomePage` dissolving, leaving behind its output:
524524+525525+```js {1-6}
526526+<section>
527527+ <h1 className="text-3xl font-sans pb-2">Welcome</h1>
528528+ <ExpandableGreeting person={alice} />
529529+ <ExpandableGreeting person={bob} />
530530+ <ExpandableGreeting person={crystal} />
531531+</section>
532532+```
533533+534534+Then imagine each `ExpandableGreeting` dissolving, leaving behind *its* output:
535535+536536+```js {3-11}
537537+<section>
538538+ <h1 className="text-3xl font-sans pb-2">Welcome</h1>
539539+ <details>
540540+ <Greeting person={alice} />
541541+ </details>
542542+ <details>
543543+ <Greeting person={bob} />
544544+ </details>
545545+ <details>
546546+ <Greeting person={crystal} />
547547+ </details>
548548+</section>
549549+```
550550+551551+Then imagine each `Greeting` dissolving, leaving behind *its* output:
552552+553553+```js {4-6,9-11,14-16}
554554+<section>
555555+ <h1 className="text-3xl font-sans pb-2">Welcome</h1>
556556+ <details>
557557+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
558558+ Hello, <i>Alice</i>!
559559+ </p>
560560+ </details>
561561+ <details>
562562+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
563563+ Hello, <i>Bob</i>!
564564+ </p>
565565+ </details>
566566+ <details>
567567+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
568568+ Hello, <i>Crystal</i>!
569569+ </p>
570570+ </details>
571571+</section>
572572+```
573573+574574+And now there is nothing left to "translate". All *my* concepts have dissolved.
575575+576576+```js eval
577577+<section className="pb-8">
578578+ <h1 className="text-3xl font-sans pb-2">Welcome</h1>
579579+ <details>
580580+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
581581+ Hello, <i>Alice</i>!
582582+ </p>
583583+ </details>
584584+ <details>
585585+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
586586+ Hello, <i>Bob</i>!
587587+ </p>
588588+ </details>
589589+ <details>
590590+ <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
591591+ Hello, <i>Crystal</i>!
592592+ </p>
593593+ </details>
594594+</section>
595595+```
596596+597597+This feels like a chain reaction. You mix a bit of data and code, and it keeps transforming until there is no more code to run, and only the residue is left.
598598+599599+It would be nice if there was a library that could do this for us.
600600+601601+But wait, here's a question. These transformations have to happen *somewhere* on the way between your computer and mine. So where *do* they happen?
602602+603603+Do they happen on your computer?
604604+605605+Or do they happen on mine?