-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeed.xml
More file actions
541 lines (541 loc) · 45.7 KB
/
feed.xml
File metadata and controls
541 lines (541 loc) · 45.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Rodion's Blog</title><link>https://rodio.codeberg.page/</link><description>RSS feed of Rodion's Blog</description><item><title>Winit and WGPU</title><link>https://rodio.codeberg.page/posts/winit.html</link><description><![CDATA[<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Winit and WGPU</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
/* CSS for syntax highlighting */
html { -webkit-text-size-adjust: 100%; }
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; } /* Alert */
code span.an { color: #008000; } /* Annotation */
code span.at { } /* Attribute */
code span.bu { } /* BuiltIn */
code span.cf { color: #0010ff; } /* ControlFlow */
code span.ch { color: #008080; } /* Char */
code span.cn { } /* Constant */
code span.co { color: #008000; } /* Comment */
code span.cv { color: #008000; } /* CommentVar */
code span.do { color: #008000; } /* Documentation */
code span.dt { color: #0010ff; font-style: italic; } /* DataType */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.im { } /* Import */
code span.in { color: #008000; } /* Information */
code span.kw { color: #962eff; } /* Keyword */
code span.op { } /* Operator */
code span.ot { color: #f54927; } /* Other */
code span.pp { color: #8e8e8e; } /* Preprocessor */
code span.sc { color: #008080; } /* SpecialChar */
code span.ss { color: #008080; } /* SpecialString */
code span.st { color: #008080; } /* String */
code span.va { } /* Variable */
code span.vs { color: #008080; } /* VerbatimString */
code span.wa { color: #008000; font-weight: bold; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a href="../index.html" style="font-family: sans-serif;">← back</a>
<header id="title-block-header">
<h1 class="title">Winit and WGPU</h1>
</header>
<p><small>May 24, 2025</small></p>
<p><a href="https://docs.rs/winit/latest/winit/">winit</a> is a Rust
crate (library) that helps with creating windows on different operating
systems and platforms.</p>
<p><a href="https://wgpu.rs">wgpu</a> is a graphics library for Rust
based on the <a href="https://www.w3.org/TR/webgpu/">WebGPU API</a>.
Applications built with it can run natively on Vulkan, Metal, DirectX
12, OpenGL ES, and in browsers via WebAssembly.</p>
<p>You begin by creating a window using winit. To draw something on it,
you first need to create a wgpu surface.</p>
<p>This looks something like this:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> window <span class="op">=</span> winit_event_loop<span class="op">.</span>create_window(window_attributes)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> surface <span class="op">=</span> wgpu_instance<span class="op">.</span>create_surface(<span class="op">&</span>window)<span class="op">.</span>unwrap()<span class="op">;</span></span></code></pre></div>
<p>By looking directly at wgpu’s <code>Cargo.toml</code> (where its
dependencies are declared) we can see that wgpu does not have winit as a
dependency. Likewise, winit does not “know” about wgpu either.</p>
<p><em>How is it possible that a method from one crate takes an instance
of a struct from another (seemingly unrelated) crate?</em></p>
<p>So, let’s have a look starting from wgpu’s perspective.</p>
<h2 id="part-one-surfacetarget">Part One:
<code>SurfaceTarget</code></h2>
<p>Since we’re feeding winit’s window to wgpu’s
<code>create_surface(...)</code>, this mystery would be solved, <em>if
we could see that <code>winit::Window</code> is somehow related to
<code>wgpu::SurfaceTarget</code>.</em></p>
<p>The signature of wgpu’s <code>create_surface(...)</code> method from
above is as follows:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> create_surface<span class="op"><</span><span class="ot">'window</span><span class="op">></span>(</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="op">&</span><span class="kw">self</span><span class="op">,</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> target<span class="op">:</span> <span class="kw">impl</span> <span class="bu">Into</span><span class="op"><</span>SurfaceTarget<span class="op"><</span><span class="ot">'window</span><span class="op">>>,</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>) <span class="op">-></span> <span class="dt">Result</span><span class="op"><</span>Surface<span class="op"><</span><span class="ot">'window</span><span class="op">>,</span> CreateSurfaceError<span class="op">></span> </span></code></pre></div>
<p>Even without knowing much about Rust—and ignoring the
<code>'window</code> <a
href="https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html">lifetimes</a>—
it is hopefully intuitive that <code>create_surface(...)</code> takes
something that can be converted <code>Into</code>
<code>SurfaceTarget</code>. So one might expect to find an
implementation of this <code>Into</code> trait (i.e. interface) for a
winit <code>Window</code> (or <a
href="https://doc.rust-lang.org/rust-by-example/conversion/from_into.html">its
counterpart</a>, <code>From</code>), allowing us to convert the winit
window into <code>SurfaceTarget</code>.</p>
<p>But obviously, there’s no point in searching for something like
<code>impl From<winit::Window> for wgpu::SurfaceTarget</code> or
<code>impl Into<wgpu::SurfaceTarget> for winit::Window</code> in
any of these libraries’ codebases, because they don’t “know” about each
other.</p>
<p>Yet we can easily find this <a
href="https://doc.rust-lang.org/book/ch10-02-traits.html">blanket
implementation</a> in wgpu’s codebase:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span><span class="op"><</span><span class="ot">'a</span><span class="op">,</span> T<span class="op">></span> <span class="bu">From</span><span class="op"><</span>T<span class="op">></span> <span class="cf">for</span> SurfaceTarget<span class="op"><</span><span class="ot">'a</span><span class="op">></span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">where</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> T<span class="op">:</span> WindowHandle <span class="op">+</span> <span class="ot">'a</span><span class="op">,</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> from(window<span class="op">:</span> T) <span class="op">-></span> <span class="dt">Self</span> <span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// snip</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>It says that we can convert <em>from</em> anything that implements
something called <code>WindowHandle</code> <em>into</em>
<code>SurfaceTarget</code>. And because Rust implements
<code>Into</code> for us when it has <code>From</code>, anything that
implements <code>WindowHandle</code> can be converted <em>into</em>
surface target. So behind the scenes, there is
<code>impl<T> Into<SurfaceTarget> for T where T: WindowHandle</code>.</p>
<p>So we now can cut out the middleman—<code>SurfaceTarget</code>—and
our mystery would be solved <em>if we could see that
<code>winit::Window</code> is somehow related to
<code>wgpu::WindowHandle</code>.</em></p>
<h2 id="part-two-windowhandle">Part Two: <code>WindowHandle</code></h2>
<p>So what kind of thing is <code>wgpu::WindowHandle</code>? Let’s go to
its definition:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">/// Super trait for window handles as used in [`SurfaceTarget`].</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">trait</span> WindowHandle<span class="op">:</span> HasWindowHandle <span class="op">+</span> HasDisplayHandle <span class="op">+</span> WasmNotSendSync <span class="op">{}</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span><span class="op"><</span>T<span class="op">></span> WindowHandle <span class="cf">for</span> T <span class="kw">where</span> T<span class="op">:</span> HasWindowHandle <span class="op">+</span> HasDisplayHandle <span class="op">+</span> WasmNotSendSync <span class="op">{}</span></span></code></pre></div>
<p>This blanket implementation means that any type can be treated as a
WindowHandle as long as it implements the three required traits. That’s
a big thing because while <code>WindowHandle</code> comes from the
<code>wgpu</code> create, <code>HasWindowHandle</code> is from another
crate called <code>raw_window_handle</code>.</p>
<p>Now the <code>raw_window_handle</code> crate seems to be the bridge
connecting these two crates (<code>winit</code> and <code>wgpu</code>)
and the key to solving this little mystery—since both crates include it
as a dependency in their Cargo.toml files.</p>
<p>We must now only verify that <code>winit</code>’s <code>Window</code>
implements <code>HasWindowHandle</code> and
<code>HasDisplayHandle</code> and <code>WasmNotSendSync</code></p>
<h2
id="part-three-haswindowhandle-hasdisplayhandle-wasmnotsendsync">Part
Three: <code>HasWindowHandle</code> + <code>HasDisplayHandle</code> +
<code>WasmNotSendSync</code></h2>
<p><code>HasWindowHandle</code> and <code>HasDisplayHandle</code> are
relatively straightforward to find in <code>winit</code>‘s
codebase’(<code>rwh_06</code> is an alias for raw_window_handle version
0.6):</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="pp">rwh_06::</span>HasWindowHandle <span class="cf">for</span> Window <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> window_handle(<span class="op">&</span><span class="kw">self</span>) <span class="op">-></span> <span class="dt">Result</span><span class="op"><</span><span class="pp">rwh_06::</span>WindowHandle<span class="op"><</span><span class="ot">'_</span><span class="op">>,</span> <span class="pp">rwh_06::</span>HandleError<span class="op">></span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// snip</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span> <span class="pp">rwh_06::</span>HasDisplayHandle <span class="cf">for</span> Window <span class="op">{</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">fn</span> display_handle(<span class="op">&</span><span class="kw">self</span>) <span class="op">-></span> <span class="dt">Result</span><span class="op"><</span><span class="pp">rwh_06::</span>DisplayHandle<span class="op"><</span><span class="ot">'_</span><span class="op">>,</span> <span class="pp">rwh_06::</span>HandleError<span class="op">></span> <span class="op">{</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// snip</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>To examine the implementation for <code>WasmNotSendSync</code> we’re
going to need to go to go back to <code>wgpu</code>‘s codebase’ and
(ignoring the conditional compilation attributes for simplicity) there
we can find this blanket implementations:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">// 1:</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">trait</span> WasmNotSendSync<span class="op">:</span> WasmNotSend <span class="op">+</span> WasmNotSync <span class="op">{}</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="co">// 2:</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span><span class="op"><</span>T<span class="op">:</span> WasmNotSend <span class="op">+</span> WasmNotSync<span class="op">></span> WasmNotSendSync <span class="cf">for</span> T <span class="op">{}</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="co">// 3:</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">trait</span> WasmNotSend <span class="op">{}</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="co">// 4:</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span><span class="op"><</span>T<span class="op">></span> WasmNotSend <span class="cf">for</span> T <span class="op">{}</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="co">// 5:</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">trait</span> WasmNotSync <span class="op">{}</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="kw">impl</span><span class="op"><</span>T<span class="op">></span> WasmNotSync <span class="cf">for</span> T <span class="op">{}</span></span></code></pre></div>
<p>So, we’ve got: 1. <code>WasmNotSendSync</code> is obviously
<code>WasmNotSend + WasmNotSync</code>. 2. Anything that implements
<code>WasmNotSend</code> and <code>WasmNotSync</code> automatically
implements <code>WasmNotSendSync</code> 3. <code>WasmNotSend</code> is
just a marker trait 4. Anything can be <code>WasmNotSend</code> since
there is this blanket implementation. 5. Anything can be
<code>WasmNotSync</code> for the same reasons.</p>
<p>Well, it seems like <strong>every type</strong> implements all these
three traits…</p>
<a href="../index.html" style="font-size: 1.5em; font-family: sans-serif;">← back</a>
</body>
</html>
]]></description></item><item><title>WebGPU Demo</title><link>https://rodio.codeberg.page/posts/learnwgpu.html</link><description><![CDATA[<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>WebGPU Demo</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a href="../index.html" style="font-family: sans-serif;">← back</a>
<header id="title-block-header">
<h1 class="title">WebGPU Demo</h1>
</header>
<p><small>Jan 21, 2026</small></p>
<p>Move cursor (slide on mobile) over it:</p>
<canvas id="canvas" style="background-color: black; width: 100%; max-width:400px; height: 20%; max-height: 100px; display: block; padding: 0;">
</canvas>
<script type="module">
import init from "../static/learnwgpu.js";
init()
.catch((error) => {
if (error.message.startsWith("Using exceptions for control flow,")) {
console.log("This is not actually an error:", error);
} else {
throw error;
}
})
.then(() => {
console.log("WASM Loaded");
});
</script>
<p>This thing is done in Rust using the <a
href="https://crates.io/crates/wgpu">wgpu</a> crate. <a
href="https://sotrh.github.io/learn-wgpu/">This is the tutorial I
used</a> and here is <a
href="https://github.com/rodio/rust-play/tree/main/learnwgpu">the source
code</a></p>
<a href="../index.html" style="font-size: 1.5em; font-family: sans-serif;">← back</a>
</body>
</html>
]]></description></item><item><title>Yet Another Explanation of Lifetimes in Rust</title><link>https://rodio.codeberg.page/posts/lifetimes.html</link><description><![CDATA[<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Yet Another Explanation of Lifetimes in Rust</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
/* CSS for syntax highlighting */
html { -webkit-text-size-adjust: 100%; }
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; } /* Alert */
code span.an { color: #008000; } /* Annotation */
code span.at { } /* Attribute */
code span.bu { } /* BuiltIn */
code span.cf { color: #0010ff; } /* ControlFlow */
code span.ch { color: #008080; } /* Char */
code span.cn { } /* Constant */
code span.co { color: #008000; } /* Comment */
code span.cv { color: #008000; } /* CommentVar */
code span.do { color: #008000; } /* Documentation */
code span.dt { color: #0010ff; font-style: italic; } /* DataType */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.im { } /* Import */
code span.in { color: #008000; } /* Information */
code span.kw { color: #962eff; } /* Keyword */
code span.op { } /* Operator */
code span.ot { color: #f54927; } /* Other */
code span.pp { color: #8e8e8e; } /* Preprocessor */
code span.sc { color: #008080; } /* SpecialChar */
code span.ss { color: #008080; } /* SpecialString */
code span.st { color: #008080; } /* String */
code span.va { } /* Variable */
code span.vs { color: #008080; } /* VerbatimString */
code span.wa { color: #008000; font-weight: bold; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<a href="../index.html" style="font-family: sans-serif;">← back</a>
<header id="title-block-header">
<h1 class="title">Yet Another Explanation of Lifetimes in Rust</h1>
</header>
<p><small>Sep 16, 2025</small></p>
<p>This post is my attempt to understand Rust’s lifetimes deeper.</p>
<h2 id="what-is-this-all-about">What is this all about?</h2>
<p>At first glance, writing a piece of code to compare lengths of two
strings can seem trivial. Yet, it is not trivial in Rust, and if other
non-garbage collected languages make it seem trivial, they’re probably
deceiving us a bit.</p>
<p>In fact, comparing two strings is used as a classic example to
explain lifetimes, a fairly complex concept in Rust.</p>
<p>The task is to write a function to compare two strings and return the
longer one. So how hard could it be? Let’s start with the function that
makes the comparison:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">// won't compile</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> longer(x<span class="op">:</span> <span class="op">&</span><span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="dt">str</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> x<span class="op">.</span>len() <span class="op">></span> y<span class="op">.</span>len() <span class="op">{</span> x <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span> y <span class="op">}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>We have two string slices (<code>&str</code>s) as arguments
(references to string data) and return one of them. Seems like a
reasonable choice of argument and return types if we don’t want to
allocate any memory. We’re just operating on the references and the
consumers of our function would need to allocate.</p>
<p>Yet, the Rust compiler would not let us compile it:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>error[E0106]<span class="op">:</span> missing lifetime specifier</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="op">--></span> src<span class="op">/</span>main<span class="op">.</span>rs<span class="op">:</span><span class="dv">1</span><span class="op">:</span><span class="dv">32</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span> <span class="op">|</span> <span class="kw">fn</span> longer(x<span class="op">:</span> <span class="op">&</span><span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="dt">str</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">----</span> <span class="op">----</span> <span class="op">^</span> expected named lifetime parameter</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> <span class="op">=</span> help<span class="op">:</span> this function<span class="ot">'s</span> <span class="cf">return</span> <span class="kw">type</span> contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>help: consider introducing a named lifetime parameter</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> |</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>1 | fn longer<span class="op"><</span><span class="ot">'a</span><span class="op">></span>(x<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span> <span class="op">{</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">++++</span> <span class="op">++</span> <span class="op">++</span> <span class="op">++</span></span></code></pre></div>
<p>The solution is to add a named lifetime parameter as the compiler
clearly pointed out. But why do we need this complication? Well, in
garbage collected languages there’s no such problem, but consider
this:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> longer<span class="op"><</span><span class="ot">'a</span><span class="op">></span>(x<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> x<span class="op">.</span>len() <span class="op">></span> y<span class="op">.</span>len() <span class="op">{</span> x <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span> y <span class="op">}</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">// won't compile</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dt">String</span><span class="pp">::</span>from(<span class="st">"abc"</span>)<span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> result<span class="op">;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> y <span class="op">=</span> <span class="dt">String</span><span class="pp">::</span>from(<span class="st">"abcd"</span>)<span class="op">;</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a> result <span class="op">=</span> longer(<span class="op">&</span>x<span class="op">,</span> <span class="op">&</span>y)<span class="op">;</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="co">// y is dropped here, result is now a dangling pointer</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a> <span class="pp">println!</span>(<span class="st">"The longer one is: {}"</span><span class="op">,</span> result)<span class="op">;</span> <span class="co">// could potentially print some garbage </span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This one fails to compile with the following error:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>error[E0597]<span class="op">:</span> `y` does not live long enough</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> <span class="op">--></span> src<span class="op">/</span>main<span class="op">.</span>rs<span class="op">:</span><span class="dv">11</span><span class="op">:</span><span class="dv">29</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="dv">10</span> <span class="op">|</span> <span class="kw">let</span> y <span class="op">=</span> <span class="dt">String</span><span class="pp">::</span>from(<span class="st">"abcd"</span>)<span class="op">;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">-</span> binding `y` declared here</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="dv">11</span> <span class="op">|</span> result <span class="op">=</span> longer(<span class="op">&</span>x<span class="op">,</span> <span class="op">&</span>y)<span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">^^</span> borrowed value does not live long enough</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="dv">12</span> <span class="op">|</span> <span class="op">}</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">-</span> `y` dropped here <span class="cf">while</span> still borrowed</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="dv">13</span> <span class="op">|</span> <span class="pp">println!</span>(<span class="st">"The longer one is: {}"</span><span class="op">,</span> result)<span class="op">;</span> <span class="co">// could potentially print some garbage</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">------</span> borrow later used here</span></code></pre></div>
<p>We get the dangling pointer because <code>y</code> was deallocated.
We’re not using <code>y</code> directly after the deallocation but the
compiler seems to be able to connect <code>result</code> and
<code>y</code> because we added the lifetime parameter.</p>
<p>When we were writing the <code>longer</code> function the compiler
asked us to specify for how long should both the arguments and the
return value be alive. With these three <code>'a</code>s we said said
that we want the arguments to live at least as long as the return value.
And indeed, we’ve already seen that they can’t live less, and here is
the example that they can live longer (compiles):</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> longer<span class="op"><</span><span class="ot">'a</span><span class="op">></span>(x<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> x<span class="op">.</span>len() <span class="op">></span> y<span class="op">.</span>len() <span class="op">{</span> x <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span> y <span class="op">}</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">pub</span> <span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> x <span class="op">=</span> <span class="dt">String</span><span class="pp">::</span>from(<span class="st">"abc"</span>)<span class="op">;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> y <span class="op">=</span> <span class="dt">String</span><span class="pp">::</span>from(<span class="st">"abcd"</span>)<span class="op">;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> result <span class="op">=</span> longer(<span class="op">&</span>x<span class="op">,</span> <span class="op">&</span>y)<span class="op">;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a> <span class="pp">println!</span>(<span class="st">"The longer one is: {}"</span><span class="op">,</span> result)<span class="op">;</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="co">// y and result are dropped here</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a> <span class="pp">println!</span>(<span class="st">"The first one is: {}"</span><span class="op">,</span> x)<span class="op">;</span> <span class="co">// x is still alive</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 id="what-else-can-we-do-with-lifetimes">What else can we do with
lifetimes?</h2>
<p>Let’s say we want to change our comparison function so that it either
returns the first argument if it is longer, or a static string
otherwise. We could just change the return value and everything would
work:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> longer<span class="op"><</span><span class="ot">'a</span><span class="op">></span>(x<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> x<span class="op">.</span>len() <span class="op">></span> y<span class="op">.</span>len() <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> x</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"the second one"</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>But we can notice that the second parameter is only used for
comparison, but never returned, so its lifetime does not matter as long
as the reference is valid at the time when this function is called. So
we can remove the explicit lifetime annotations for the second argument
so that the callers of our function do not need to worry about the
lifetime of the second argument and have more freedom:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> longer<span class="op"><</span><span class="ot">'a</span><span class="op">></span>(x<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span> <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> x<span class="op">.</span>len() <span class="op">></span> y<span class="op">.</span>len() <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> x</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"the second one"</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The explicit lifetime of the return value stays because the function
can potentially return the reference to the first argument.</p>
<p>In fact, we could also add another lifetime <code>'b</code> like this
(that’s what Rust probably does under the hood anyway):</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> longer<span class="op"><</span><span class="ot">'a</span><span class="op">,</span> <span class="ot">'b</span><span class="op">></span>(x<span class="op">:</span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span><span class="op">,</span> y<span class="op">:</span> <span class="op">&</span><span class="ot">'b</span> <span class="dt">str</span>) <span class="op">-></span> <span class="op">&</span><span class="ot">'a</span> <span class="dt">str</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> x<span class="op">.</span>len() <span class="op">></span> y<span class="op">.</span>len() <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> x</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"the second one"</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The lifetime <code>'b</code> does not appear in the return value and
this illustrates the fact that the return value does not depend on the
the lifetime of the second argument more explicitly.</p>
<h2 id="what-is-the-beauty-of-it">What is the beauty of it?</h2>
<p>I probably can call this an example of the “shift-left” attitude.
Rather than discovering problems at runtime (which would be fully
“shift-right”), we catch them at compile time.</p>
<p>But notice <em>how</em> early these checks occur: the
<code>longer</code> function would not even compile without explicit
runtime annotations, even before we write the main function. Lifetimes
help us to think about the correctness and the consumers of our code in
advance.</p>
<p>Could innovations like this make our software safer, more robust and
less annoying? I hope so.</p>
<a href="../index.html" style="font-size: 1.5em; font-family: sans-serif;">← back</a>
</body>
</html>
]]></description></item></channel></rss>