WEBVTT

1
00:00:00.880 --> 00:00:05.719
<v Speaker 1>So the processor in your smartphone is incredibly fast, like

2
00:00:05.960 --> 00:00:08.720
<v Speaker 1>unbelievably fast. Oh yeah, absolutely, But if you look at

3
00:00:08.759 --> 00:00:12.400
<v Speaker 1>single core clock speeds, that single processor hasn't actually gotten

4
00:00:12.400 --> 00:00:15.359
<v Speaker 1>any faster in like almost twenty years.

5
00:00:15.199 --> 00:00:17.399
<v Speaker 2>Right, which is wild to think.

6
00:00:17.239 --> 00:00:19.960
<v Speaker 1>About, it is, and the reason why it's well, it's

7
00:00:20.320 --> 00:00:22.839
<v Speaker 1>physically impossible to beat the speed of light.

8
00:00:23.039 --> 00:00:26.879
<v Speaker 2>Yeah, that limitation forced a massive pivot in hardware engineering

9
00:00:26.920 --> 00:00:30.120
<v Speaker 2>that honestly, most people never even noticed. Single cores just

10
00:00:30.160 --> 00:00:34.240
<v Speaker 2>stopped accelerating and instead they started multiplying, like we went

11
00:00:34.280 --> 00:00:38.039
<v Speaker 2>from one core to four to sixteen, and suddenly developers

12
00:00:38.039 --> 00:00:41.320
<v Speaker 2>were handed this completely different architectural universe to build on.

13
00:00:41.920 --> 00:00:45.840
<v Speaker 2>It's a shift just as significant as the Industrial Revolution, honestly,

14
00:00:45.960 --> 00:00:48.640
<v Speaker 2>but it's happening silently right inside our devices.

15
00:00:48.880 --> 00:00:52.119
<v Speaker 1>Welcome to this deep dive today. We are unpacking excerpts

16
00:00:52.159 --> 00:00:55.520
<v Speaker 1>from the book Concurrency in dot Net Modern Patterns by

17
00:00:55.560 --> 00:00:58.320
<v Speaker 1>Ricardo Terrell. It's a great book, yeah, and our mission

18
00:00:58.359 --> 00:01:01.960
<v Speaker 1>today is to understand exactly why our hardware hit this

19
00:01:02.159 --> 00:01:06.280
<v Speaker 1>literal physical wall and how the entire way we write software,

20
00:01:06.480 --> 00:01:10.400
<v Speaker 1>like the invisible architecture holding our digital lives together, has

21
00:01:10.439 --> 00:01:14.400
<v Speaker 1>to radically shift toward concurrency and functional programming to overcome it.

22
00:01:14.560 --> 00:01:17.719
<v Speaker 2>Exactly, because if we don't change how we code, all

23
00:01:17.719 --> 00:01:21.079
<v Speaker 2>that multi core computing potential goes entirely to waste.

24
00:01:21.120 --> 00:01:21.920
<v Speaker 1>It really does.

25
00:01:22.079 --> 00:01:24.280
<v Speaker 2>To really wrap our heads around the software shift, we

26
00:01:24.359 --> 00:01:26.480
<v Speaker 2>have to look at the physics that broke Moore's law.

27
00:01:27.000 --> 00:01:30.840
<v Speaker 2>You know, for decades, transistor density doubled and CPU speeds

28
00:01:30.920 --> 00:01:33.000
<v Speaker 2>just kept climbing and climbing.

29
00:01:32.640 --> 00:01:34.000
<v Speaker 1>Right the golden age of computing.

30
00:01:34.159 --> 00:01:37.000
<v Speaker 2>Yeah, but right around two thousand and five, single core

31
00:01:37.040 --> 00:01:40.200
<v Speaker 2>clock speeds just slammed into a plateau at around three

32
00:01:40.239 --> 00:01:41.719
<v Speaker 2>point five gigahers.

33
00:01:41.319 --> 00:01:43.519
<v Speaker 1>Okay, let's unpack this because the scale here is just

34
00:01:43.560 --> 00:01:46.719
<v Speaker 1>mind blowing. At a three point five gigahertz clock speed,

35
00:01:47.159 --> 00:01:50.120
<v Speaker 1>a processor is completing one cycle every two point eight

36
00:01:50.200 --> 00:01:54.000
<v Speaker 1>five nanoseconds. And we know that nothing in the universe,

37
00:01:54.239 --> 00:01:57.439
<v Speaker 1>including the electrical data signals moving across the silk and chip,

38
00:01:57.680 --> 00:01:58.959
<v Speaker 1>can travel faster than light.

39
00:01:59.599 --> 00:02:03.079
<v Speaker 2>Wait, so you're telling me the literal physical laws of

40
00:02:03.120 --> 00:02:05.400
<v Speaker 2>the universe, like the speed of light is the only

41
00:02:05.439 --> 00:02:08.520
<v Speaker 2>reason my smartphone's single processor isn't getting faster.

42
00:02:08.840 --> 00:02:11.560
<v Speaker 1>If we connect this to the bigger picture, yes, exactly.

43
00:02:11.879 --> 00:02:16.199
<v Speaker 1>See in a vacuum, light travels roughly one foot per nanosecond. Okay,

44
00:02:16.400 --> 00:02:19.639
<v Speaker 1>but inside a silicon medium, it's actually a bit slower.

45
00:02:20.240 --> 00:02:23.520
<v Speaker 1>So in that tiny two point eighty five nanosecond window,

46
00:02:23.759 --> 00:02:27.360
<v Speaker 1>a signal can only physically propagate about thirty centimeters.

47
00:02:27.400 --> 00:02:27.840
<v Speaker 2>Wow.

48
00:02:28.240 --> 00:02:31.560
<v Speaker 1>Now, if hardware engineers wanted to push a CPU to say,

49
00:02:31.800 --> 00:02:35.199
<v Speaker 1>one hundred gigahertz, the cycle time drops to point zero

50
00:02:35.240 --> 00:02:36.960
<v Speaker 1>one nanoseconds.

51
00:02:36.280 --> 00:02:38.400
<v Speaker 2>Which means the signal only has time to travel about

52
00:02:38.400 --> 00:02:41.039
<v Speaker 2>three milimeters exactly. So the entire CPU core would have

53
00:02:41.039 --> 00:02:44.080
<v Speaker 2>to be manufactured at point three millimeters in size just

54
00:02:44.159 --> 00:02:46.000
<v Speaker 2>for the signals to reach the other side of the

55
00:02:46.080 --> 00:02:47.719
<v Speaker 2>chip in time for the next clock cycle.

56
00:02:47.879 --> 00:02:50.759
<v Speaker 1>Right, and cramming that much switching frequency into a space

57
00:02:51.080 --> 00:02:55.159
<v Speaker 1>literally a fraction of a millimeter wide creates well catastrophic

58
00:02:55.240 --> 00:02:56.800
<v Speaker 1>energy dissipation because of the sheet.

59
00:02:57.080 --> 00:03:00.520
<v Speaker 2>Yeah, the heat generated would literally melt the crystal structure

60
00:03:00.599 --> 00:03:05.439
<v Speaker 2>of the chip. So hardware engineers realized they couldn't rewrite

61
00:03:05.439 --> 00:03:08.479
<v Speaker 2>the laws of physics, and they couldn't magically stop thermal

62
00:03:08.560 --> 00:03:10.080
<v Speaker 2>dynamics from existing.

63
00:03:10.319 --> 00:03:12.919
<v Speaker 1>Right, So their solution was to stop trying to make

64
00:03:12.960 --> 00:03:17.120
<v Speaker 1>one single core infinitely faster and just start stamping out

65
00:03:17.120 --> 00:03:18.680
<v Speaker 1>more of them on the same die.

66
00:03:18.759 --> 00:03:22.000
<v Speaker 2>Exactly, They just give us more cores. But this dumps

67
00:03:22.000 --> 00:03:26.080
<v Speaker 2>a massive problem directly into the lapse of software developers.

68
00:03:25.639 --> 00:03:28.319
<v Speaker 1>Which brings up this really great coffee shop analogy from

69
00:03:28.319 --> 00:03:32.800
<v Speaker 1>the source material to explain how software historically handled tasks

70
00:03:33.000 --> 00:03:34.240
<v Speaker 1>versus how it has to handle them.

71
00:03:34.240 --> 00:03:36.080
<v Speaker 2>Now, oh, I love this analogy.

72
00:03:36.159 --> 00:03:38.759
<v Speaker 1>Yeah. So, if you have one barista and they work sequentially,

73
00:03:39.159 --> 00:03:41.759
<v Speaker 1>they grind the coffee, brew it, steam the milk, and

74
00:03:41.759 --> 00:03:44.759
<v Speaker 1>combine it one instruction at a time. It's safe, but it's.

75
00:03:44.680 --> 00:03:47.879
<v Speaker 2>Really slow, right, So if that barista decides to multitask,

76
00:03:48.120 --> 00:03:51.919
<v Speaker 2>they start the espresso dripping, spin around, and immediately start

77
00:03:51.960 --> 00:03:53.000
<v Speaker 2>steaming the milk.

78
00:03:52.800 --> 00:03:54.360
<v Speaker 1>Like time slicing exactly.

79
00:03:54.479 --> 00:03:57.840
<v Speaker 2>Yeah, they aren't doing two things simultaneously, but the operating

80
00:03:57.879 --> 00:04:01.719
<v Speaker 2>system uses time slicing to which their context between tasks

81
00:04:01.759 --> 00:04:03.879
<v Speaker 2>so fast it utilizes the downtime.

82
00:04:04.280 --> 00:04:07.800
<v Speaker 1>But the real leap is true parallelism. The manager just

83
00:04:07.879 --> 00:04:11.599
<v Speaker 1>hires a second barista and builds a completely second espresso station.

84
00:04:12.479 --> 00:04:15.439
<v Speaker 1>Now you have two independent actors making two completely different

85
00:04:15.520 --> 00:04:18.399
<v Speaker 1>drinks at the exact same millisecond. And to show the

86
00:04:18.480 --> 00:04:21.800
<v Speaker 1>scale of this parallel explosion, the source points to Pixar.

87
00:04:22.040 --> 00:04:23.839
<v Speaker 2>This is a crazy stat it is.

88
00:04:24.240 --> 00:04:26.959
<v Speaker 1>Rendering the original Toy Story movie in nineteen ninety five

89
00:04:27.279 --> 00:04:31.480
<v Speaker 1>required a server farm of one hundred processors. Processing a

90
00:04:31.519 --> 00:04:35.519
<v Speaker 1>modern animated movie today it takes twenty four thousand cores.

91
00:04:35.759 --> 00:04:39.079
<v Speaker 2>Yeah, and that explosion in parallel processing power is exactly

92
00:04:39.160 --> 00:04:41.800
<v Speaker 2>why software has to change. If you take a legacy

93
00:04:41.800 --> 00:04:44.959
<v Speaker 2>sequential application like code designed for one barista and run

94
00:04:45.000 --> 00:04:47.439
<v Speaker 2>it on a modern machine with eight cores, you have

95
00:04:47.560 --> 00:04:50.920
<v Speaker 2>one thread working frantically while seven other cores just sit there.

96
00:04:50.839 --> 00:04:54.319
<v Speaker 1>Idle, totally wasted. Exactly, So the obvious answer seems to be,

97
00:04:54.360 --> 00:04:56.879
<v Speaker 1>you know, just divide the workup, run the software in parallel.

98
00:04:57.279 --> 00:04:59.399
<v Speaker 1>But let's talk about what happens when you take standard

99
00:04:59.480 --> 00:05:02.959
<v Speaker 1>object or code and toss it into a multi core environment.

100
00:05:03.639 --> 00:05:06.319
<v Speaker 1>You have independent threads trying to modify a shared state,

101
00:05:06.360 --> 00:05:08.240
<v Speaker 1>and it turns into an absolute disaster.

102
00:05:08.680 --> 00:05:11.879
<v Speaker 2>Oh, a total nightmare, because mutable state is the core

103
00:05:11.920 --> 00:05:16.480
<v Speaker 2>philosophy of traditional imperative programming. Variables are designed to be

104
00:05:16.560 --> 00:05:19.720
<v Speaker 2>changed over time. But when two threads hit the exact

105
00:05:19.759 --> 00:05:23.199
<v Speaker 2>same memory address at the exact same microsecond, you get

106
00:05:23.279 --> 00:05:24.120
<v Speaker 2>race conditions.

107
00:05:24.319 --> 00:05:28.240
<v Speaker 1>The book illustrates this beautifully imagine a variable X sitting

108
00:05:28.279 --> 00:05:30.920
<v Speaker 1>in memory with a value of forty two. Thread one

109
00:05:30.959 --> 00:05:33.600
<v Speaker 1>and thread two both need to add one to X.

110
00:05:33.759 --> 00:05:34.560
<v Speaker 2>Okay, in a.

111
00:05:34.480 --> 00:05:37.879
<v Speaker 1>Perfect sequence, thread one adds one to make it forty three,

112
00:05:38.160 --> 00:05:40.759
<v Speaker 1>and then thread two comes in adds one and makes

113
00:05:40.759 --> 00:05:43.920
<v Speaker 1>it forty four. But in a parallel world they overlap.

114
00:05:44.120 --> 00:05:47.199
<v Speaker 2>Yeah, so thread one reads the value forty two from memory,

115
00:05:47.519 --> 00:05:50.040
<v Speaker 2>but before thread one can finish its calculation and save

116
00:05:50.079 --> 00:05:52.720
<v Speaker 2>the new value, thread two swoops in and reads the

117
00:05:52.800 --> 00:05:54.199
<v Speaker 2>exact same memory address.

118
00:05:54.319 --> 00:05:57.240
<v Speaker 1>It also sees forty two exactly, so thread one writes

119
00:05:57.279 --> 00:06:00.560
<v Speaker 1>forty three back to memory, but thread two is completely

120
00:06:00.560 --> 00:06:03.040
<v Speaker 1>oblivious to that. It adds one to its own original

121
00:06:03.040 --> 00:06:06.000
<v Speaker 1>read to forty two and just overwrites the memory address

122
00:06:06.040 --> 00:06:06.800
<v Speaker 1>with forty three again.

123
00:06:06.879 --> 00:06:09.839
<v Speaker 2>Right, the data is completely corrupted and entire calculation was

124
00:06:09.879 --> 00:06:11.160
<v Speaker 2>just swallowed hole by the system.

125
00:06:11.240 --> 00:06:13.279
<v Speaker 1>So it's like two people trying to edit the exact

126
00:06:13.279 --> 00:06:16.240
<v Speaker 1>same sentence in a shared document at the exact same millisecond.

127
00:06:16.519 --> 00:06:19.800
<v Speaker 2>Yes, that's exactly what it's like. And to prevent that

128
00:06:19.879 --> 00:06:25.399
<v Speaker 2>document overright, developers historically introduced locks known as mutual exclusion. Okay,

129
00:06:25.480 --> 00:06:29.680
<v Speaker 2>the padlocks, Right, A thread places a lock on the variable,

130
00:06:29.800 --> 00:06:33.160
<v Speaker 2>barring any other thread from touching it until the operation completes.

131
00:06:33.680 --> 00:06:37.360
<v Speaker 2>But locking a resource creates an entirely new hazard, which

132
00:06:37.439 --> 00:06:38.720
<v Speaker 2>is deadlocks.

133
00:06:38.959 --> 00:06:41.600
<v Speaker 1>Oh man, so we give them padlocks, but then they

134
00:06:41.639 --> 00:06:43.839
<v Speaker 1>just accidentally lock each other out of the building entirely.

135
00:06:44.000 --> 00:06:46.279
<v Speaker 2>Pretty much, it's the ultimate software traffic jam.

136
00:06:46.480 --> 00:06:47.199
<v Speaker 1>How does that happen?

137
00:06:47.240 --> 00:06:50.040
<v Speaker 2>Well, Thread one locks resource A, but realizes it needs

138
00:06:50.079 --> 00:06:54.600
<v Speaker 2>resource B to finish its execution. Meanwhile, thread two has

139
00:06:54.680 --> 00:06:58.000
<v Speaker 2>already locked resource B, but it needs resource A to

140
00:06:58.000 --> 00:07:02.120
<v Speaker 2>finish its job. Oh no, Thread one sits idle waiting

141
00:07:02.120 --> 00:07:05.240
<v Speaker 2>on thread too. Thread two sits idle waiting on thread one.

142
00:07:05.319 --> 00:07:07.839
<v Speaker 2>They are locked in a circular weight for eternity, and

143
00:07:07.879 --> 00:07:09.639
<v Speaker 2>the entire application just freezes.

144
00:07:09.839 --> 00:07:12.319
<v Speaker 1>Okay, So if you're listening to this and thinking, well,

145
00:07:12.319 --> 00:07:15.040
<v Speaker 1>I just won't share mutable data between my threads, let's

146
00:07:15.040 --> 00:07:17.319
<v Speaker 1>put that to the test. Take a task that divides

147
00:07:17.399 --> 00:07:20.720
<v Speaker 1>data up perfectly, like sorting a massive list. Quick sort

148
00:07:20.839 --> 00:07:24.399
<v Speaker 1>is a classic algorithm that picks a pivot point and

149
00:07:24.480 --> 00:07:27.680
<v Speaker 1>splits a lift into two independent halves. There is no

150
00:07:27.839 --> 00:07:29.959
<v Speaker 1>shared state to lock, so we should be able to

151
00:07:30.000 --> 00:07:32.120
<v Speaker 1>just split that list up throw one hundred threads at it.

152
00:07:32.160 --> 00:07:32.800
<v Speaker 1>And watch it fly.

153
00:07:33.040 --> 00:07:35.959
<v Speaker 2>And that is the exact logical assumption developers make when

154
00:07:35.959 --> 00:07:40.399
<v Speaker 2>transitioning to multi coore. But Ricardo Terrell tested this assumption

155
00:07:40.519 --> 00:07:43.759
<v Speaker 2>with a pretty brutal benchmark. Oh he took a list

156
00:07:43.800 --> 00:07:48.160
<v Speaker 2>of one million random items and sorted it sequentially on

157
00:07:48.240 --> 00:07:50.959
<v Speaker 2>a single thread. It took six point five seconds.

158
00:07:51.079 --> 00:07:56.160
<v Speaker 1>Okay. Then he parallelized it using Microsoft's task parallel library. Yep,

159
00:07:56.360 --> 00:07:59.040
<v Speaker 1>every single time the algorithm split the list into two

160
00:07:59.079 --> 00:08:02.120
<v Speaker 1>smaller halves, it'spond a brand new thread to handle the

161
00:08:02.160 --> 00:08:04.720
<v Speaker 1>new split. So we're taking a six point five second

162
00:08:04.720 --> 00:08:08.199
<v Speaker 1>sequential task and spreading it across all the CPU core simultaneously.

163
00:08:08.560 --> 00:08:10.720
<v Speaker 1>But I'm looking at this kicksort benchmark from the source

164
00:08:11.000 --> 00:08:14.439
<v Speaker 1>and this makes zero sense. The processing time almost double

165
00:08:14.519 --> 00:08:18.639
<v Speaker 1>to over twelve seconds. Why is the hardware actively punishing

166
00:08:18.639 --> 00:08:19.160
<v Speaker 1>the code?

167
00:08:19.319 --> 00:08:21.600
<v Speaker 2>Well, the hardware isn't punishing the code. The operating system

168
00:08:21.680 --> 00:08:25.199
<v Speaker 2>is drowning and administrative paperwork. What the developer failed to

169
00:08:25.240 --> 00:08:29.399
<v Speaker 2>account for is thread overhead. Creating a thread, allocating a

170
00:08:29.439 --> 00:08:32.120
<v Speaker 2>memory block for its call stack, and scheduling it on

171
00:08:32.159 --> 00:08:34.960
<v Speaker 2>the CPU. All of that takes computational effort.

172
00:08:35.120 --> 00:08:38.440
<v Speaker 1>Here's where it gets really interesting. This is exactly like

173
00:08:38.600 --> 00:08:42.679
<v Speaker 1>hiring one thousand chefs to make a single Omelet the

174
00:08:42.759 --> 00:08:46.519
<v Speaker 1>administrative overhead of them bumping into each other, communicating and

175
00:08:46.600 --> 00:08:50.159
<v Speaker 1>figuring out who gets to use this batchela takes far

176
00:08:50.320 --> 00:08:52.840
<v Speaker 1>longer than just letting one chef cook. You have to

177
00:08:52.879 --> 00:08:53.960
<v Speaker 1>balance the workforce.

178
00:08:54.039 --> 00:08:57.000
<v Speaker 2>That is a perfect analogy. If the actual sorting work

179
00:08:57.039 --> 00:08:59.720
<v Speaker 2>assigned to the thread takes less time than the administrative

180
00:08:59.720 --> 00:09:04.399
<v Speaker 2>effort of creating the thread itself, your performance absolutely plummets. Wow,

181
00:09:04.519 --> 00:09:07.600
<v Speaker 2>parallelism isn't magic, you know. It is a resource that

182
00:09:07.679 --> 00:09:10.679
<v Speaker 2>requires strict budgeting. There is an inherent limitation to how

183
00:09:10.759 --> 00:09:12.679
<v Speaker 2>much extra threading actually helps.

184
00:09:12.960 --> 00:09:14.840
<v Speaker 1>So how does the book solve the quick.

185
00:09:14.639 --> 00:09:18.200
<v Speaker 2>Sort disaster by limiting the depth of the recursion. Terrell

186
00:09:18.480 --> 00:09:22.440
<v Speaker 2>introduces a specific mathematical formula to cap the thread creation.

187
00:09:22.960 --> 00:09:25.879
<v Speaker 2>It's the base two logarithm of the processor count plus four.

188
00:09:25.960 --> 00:09:26.759
<v Speaker 1>Okay, bath time.

189
00:09:27.039 --> 00:09:29.759
<v Speaker 2>Yeah, So, if you are running a four corps machine,

190
00:09:29.960 --> 00:09:33.320
<v Speaker 2>this formula tells the program to completely stop spawning new

191
00:09:33.360 --> 00:09:37.039
<v Speaker 2>threads once it reaches roughly sixteen times the processor.

192
00:09:36.559 --> 00:09:39.840
<v Speaker 1>Count, meaning you hit a hard ceiling about thirty six

193
00:09:39.879 --> 00:09:43.919
<v Speaker 1>to sixty four concurrent tasks exactly essentially cap the number

194
00:09:43.919 --> 00:09:45.240
<v Speaker 1>of chefs in the kitchen. Right.

195
00:09:45.480 --> 00:09:48.840
<v Speaker 2>Once the algorithm hits that cap, the remaining small chunks

196
00:09:48.840 --> 00:09:52.399
<v Speaker 2>of the list are simply sorted sequentially by the existing threads.

197
00:09:52.519 --> 00:09:53.279
<v Speaker 1>Oh that smart.

198
00:09:53.360 --> 00:09:57.360
<v Speaker 2>Yeah, the administrative overhead vanishes, the CPU cores remain fully

199
00:09:57.399 --> 00:10:01.159
<v Speaker 2>saturated with actual work, and the sorting time drops dramatically

200
00:10:01.240 --> 00:10:03.840
<v Speaker 2>from the original six point five seconds down to three

201
00:10:03.879 --> 00:10:04.799
<v Speaker 2>point five seconds.

202
00:10:04.840 --> 00:10:07.559
<v Speaker 1>That is incredible. So traditional locks freeze the system with

203
00:10:07.600 --> 00:10:11.600
<v Speaker 1>dead locks, and unbounded threading chokes the CPU with overhead. Ye,

204
00:10:12.240 --> 00:10:15.000
<v Speaker 1>how do we actually write concurrent code that scales safely

205
00:10:15.039 --> 00:10:18.440
<v Speaker 1>and efficiently. This is where the deep dive transitions to

206
00:10:18.480 --> 00:10:21.600
<v Speaker 1>the overarching solution provided by the source material, which is

207
00:10:21.840 --> 00:10:22.799
<v Speaker 1>functional programming.

208
00:10:22.960 --> 00:10:27.200
<v Speaker 2>Yes, functional programming abandons mutable state entirely. Instead of trying

209
00:10:27.279 --> 00:10:30.919
<v Speaker 2>to build complex, fragile guardrails around our variables to keep

210
00:10:30.960 --> 00:10:34.120
<v Speaker 2>them safe from multiple threads, FP asks a much more

211
00:10:34.240 --> 00:10:38.360
<v Speaker 2>radical question, what if variables are never allowed to change?

212
00:10:38.679 --> 00:10:42.279
<v Speaker 1>Wait, a world without variables. That sounds like trying to

213
00:10:42.320 --> 00:10:45.159
<v Speaker 1>do math without an eraser, Right, how do you actually

214
00:10:45.159 --> 00:10:47.799
<v Speaker 1>get anything done if you can't change the state of anything.

215
00:10:48.200 --> 00:10:50.799
<v Speaker 1>If I have a user profile and the user has

216
00:10:50.840 --> 00:10:53.440
<v Speaker 1>a birthday, their age has to update from twenty nine

217
00:10:53.440 --> 00:10:56.919
<v Speaker 1>to thirty. How do you accomplish that without altering the

218
00:10:56.960 --> 00:10:57.919
<v Speaker 1>original variable.

219
00:10:58.240 --> 00:11:01.480
<v Speaker 2>What's fascinating here is that in functional programming you rely

220
00:11:01.600 --> 00:11:03.960
<v Speaker 2>on transformations rather than mutations.

221
00:11:04.000 --> 00:11:05.000
<v Speaker 1>Okay, transformations.

222
00:11:05.080 --> 00:11:08.320
<v Speaker 2>Yeah. You pass the original user profile into a pure function.

223
00:11:08.919 --> 00:11:11.879
<v Speaker 2>That function takes the data, applies the update, and returns

224
00:11:11.879 --> 00:11:14.120
<v Speaker 2>a brand new, complete copy of the profile with the

225
00:11:14.159 --> 00:11:15.120
<v Speaker 2>age set to thirty.

226
00:11:15.279 --> 00:11:16.159
<v Speaker 1>Oh. I see, the.

227
00:11:16.159 --> 00:11:19.519
<v Speaker 2>Original profile remains permanently locked in memory exactly as it was.

228
00:11:20.000 --> 00:11:21.919
<v Speaker 2>Threads can't break what they can't.

229
00:11:21.759 --> 00:11:24.600
<v Speaker 1>Change, and because that original data never changes, it doesn't

230
00:11:24.639 --> 00:11:27.440
<v Speaker 1>matter if ten thousand other threads are reading it at

231
00:11:27.480 --> 00:11:31.279
<v Speaker 1>the exact same time. No thread can ever accidentally overwrite

232
00:11:31.320 --> 00:11:33.360
<v Speaker 1>another thread's work exactly.

233
00:11:33.600 --> 00:11:37.840
<v Speaker 2>If there is no mutable state, race conditions simply cease

234
00:11:37.919 --> 00:11:41.320
<v Speaker 2>to exist. Wow, and without race conditions, we have no

235
00:11:41.440 --> 00:11:45.279
<v Speaker 2>need for mutual exclusion locks, and without locks, deadlocks are

236
00:11:45.320 --> 00:11:46.960
<v Speaker 2>mathematically impossible.

237
00:11:47.200 --> 00:11:48.000
<v Speaker 1>It is huge.

238
00:11:48.120 --> 00:11:51.879
<v Speaker 2>It is the entire category of concurrency hazards that plague

239
00:11:51.919 --> 00:11:54.159
<v Speaker 2>object oriented developers. Just vanishes.

240
00:11:54.279 --> 00:11:57.600
<v Speaker 1>The source material tightly couples this immutability to the concept

241
00:11:57.600 --> 00:12:00.399
<v Speaker 1>of pure functions and referential transparency. Right.

242
00:12:00.559 --> 00:12:04.360
<v Speaker 2>Yeah, A pure function operates in total isolation. It has

243
00:12:04.480 --> 00:12:08.960
<v Speaker 2>absolutely zero side effects the none. It doesn't query a database,

244
00:12:09.000 --> 00:12:11.519
<v Speaker 2>it doesn't mutate a global variable. It doesn't even print

245
00:12:11.519 --> 00:12:14.320
<v Speaker 2>a log to the screen. Its only purpose is to

246
00:12:14.360 --> 00:12:16.200
<v Speaker 2>map an input to an output.

247
00:12:15.879 --> 00:12:19.000
<v Speaker 1>Which leads to referential transparency. If you pass a pure

248
00:12:19.039 --> 00:12:21.840
<v Speaker 1>function the exact same input, it is guaranteed to return

249
00:12:21.840 --> 00:12:25.360
<v Speaker 1>the exact same output every single time, regardless of the

250
00:12:25.360 --> 00:12:29.320
<v Speaker 1>system's global state exactly. That predictability is what makes it

251
00:12:29.440 --> 00:12:33.320
<v Speaker 1>so robust for multiple cores to execute simultaneously.

252
00:12:32.840 --> 00:12:38.159
<v Speaker 2>And this rigid predictability also eliminates entire classes of runtime errors.

253
00:12:38.879 --> 00:12:41.480
<v Speaker 2>The book brings up a notorious piece of computer science

254
00:12:41.559 --> 00:12:45.559
<v Speaker 2>history to highlight this, Tonyhorre's nineteen sixty five invention of

255
00:12:45.600 --> 00:12:46.919
<v Speaker 2>the null reference.

256
00:12:46.879 --> 00:12:51.480
<v Speaker 1>The billion dollar mistake. In traditional imperative languages, a variable

257
00:12:51.559 --> 00:12:54.080
<v Speaker 1>can point to a valid piece of data, or it

258
00:12:54.080 --> 00:12:57.720
<v Speaker 1>can point to null, which is literally nothing, right, and

259
00:12:57.799 --> 00:13:00.960
<v Speaker 1>if your application attempts to access a very expecting an

260
00:13:00.960 --> 00:13:03.799
<v Speaker 1>integer or an object, but encounter as a null, the

261
00:13:03.840 --> 00:13:05.879
<v Speaker 1>whole system throws an exception and crashes.

262
00:13:06.559 --> 00:13:10.159
<v Speaker 2>But functional language is like f sharp strongly discouraged nulls.

263
00:13:10.440 --> 00:13:13.759
<v Speaker 2>They actually force developers to handle the potential absence of

264
00:13:13.840 --> 00:13:18.200
<v Speaker 2>data explicitly using specialized immutable structures. Oh wow, Yeah, you

265
00:13:18.200 --> 00:13:20.960
<v Speaker 2>cannot even compile the program until you have proven to

266
00:13:21.000 --> 00:13:23.519
<v Speaker 2>the compiler that you have handled the nothing case. It

267
00:13:23.559 --> 00:13:26.399
<v Speaker 2>wipes out countless bugs before the code is even executed.

268
00:13:26.639 --> 00:13:29.279
<v Speaker 1>Now, if you're listening to this and thinking, okay, immutability

269
00:13:29.360 --> 00:13:31.840
<v Speaker 1>is great for safety, But how do I actually build

270
00:13:31.879 --> 00:13:35.799
<v Speaker 1>a massive complex application if every function is just an

271
00:13:35.799 --> 00:13:37.879
<v Speaker 1>isolated island returning copies of data.

272
00:13:37.919 --> 00:13:38.720
<v Speaker 2>It's a fair question.

273
00:13:39.000 --> 00:13:41.440
<v Speaker 1>We need to talk about the two main tools functional

274
00:13:41.480 --> 00:13:46.200
<v Speaker 1>programming uses to bridge that gap, composition enclosures. Let's start

275
00:13:46.200 --> 00:13:47.039
<v Speaker 1>with composition.

276
00:13:47.559 --> 00:13:51.200
<v Speaker 2>So, because pure functions strictly take inputs and return outputs,

277
00:13:51.440 --> 00:13:55.320
<v Speaker 2>they act as perfectly standardized building blocks. Function composition is

278
00:13:55.360 --> 00:13:59.120
<v Speaker 2>the mechanism of gluing these small, isolated functions together to

279
00:13:59.200 --> 00:14:01.200
<v Speaker 2>construct complex data pipelines.

280
00:14:01.559 --> 00:14:04.240
<v Speaker 1>The source uses a coffee brewing example for this, which

281
00:14:04.240 --> 00:14:07.519
<v Speaker 1>I love. Say you have a function called grind coffee

282
00:14:07.559 --> 00:14:11.279
<v Speaker 1>that takes raw beans and outputs grounds, okay, and a

283
00:14:11.320 --> 00:14:15.000
<v Speaker 1>separate function called brew coffee that takes grounds and outputs espresso.

284
00:14:15.840 --> 00:14:18.039
<v Speaker 1>In traditional listic code, you have to write it inside

285
00:14:18.039 --> 00:14:22.080
<v Speaker 1>out something like brew coffee parenthesis, grind coffee parenthesis beans.

286
00:14:22.360 --> 00:14:25.200
<v Speaker 1>You practically have to read the syntax backwards to trace

287
00:14:25.279 --> 00:14:25.759
<v Speaker 1>the logic.

288
00:14:26.120 --> 00:14:29.720
<v Speaker 2>Right, it gets messy, but functional languages streamline this pipeline.

289
00:14:29.840 --> 00:14:32.759
<v Speaker 2>F shark uses the greater then greater than operator, allowing

290
00:14:32.759 --> 00:14:36.600
<v Speaker 2>developers to chain functions sequentially, reading naturally from left to right.

291
00:14:36.639 --> 00:14:38.480
<v Speaker 1>Oh, that's so much cleaner it really is.

292
00:14:38.519 --> 00:14:42.200
<v Speaker 2>You literally write grind coffee, then the operator, then brew coffee.

293
00:14:42.720 --> 00:14:45.840
<v Speaker 2>The output of the function on the left flows seamlessly

294
00:14:45.960 --> 00:14:47.639
<v Speaker 2>as the input to the function on the right.

295
00:14:48.159 --> 00:14:48.519
<v Speaker 1>Wow.

296
00:14:48.559 --> 00:14:52.639
<v Speaker 2>You can chain dozens of transformations this way, like add

297
00:14:52.679 --> 00:14:56.000
<v Speaker 2>four operator, multiply by three operator, subtract one.

298
00:14:56.279 --> 00:14:58.519
<v Speaker 1>So what does this all mean? It sounds like composition

299
00:14:58.600 --> 00:15:02.279
<v Speaker 1>is building a perfectly automated assembly line. The raw material

300
00:15:02.360 --> 00:15:06.000
<v Speaker 1>drops in on the left, moves through each highly specialized machine,

301
00:15:06.320 --> 00:15:08.799
<v Speaker 1>and the finished product talks out on the right. Yes, exactly,

302
00:15:08.960 --> 00:15:11.159
<v Speaker 1>Because there are no side effects. You can pick up

303
00:15:11.200 --> 00:15:14.279
<v Speaker 1>that entire assembly line and run fifty parallel copies of

304
00:15:14.320 --> 00:15:17.080
<v Speaker 1>it across multiple cores and they will never jam or

305
00:15:17.120 --> 00:15:18.000
<v Speaker 1>interfere with each other.

306
00:15:18.080 --> 00:15:20.720
<v Speaker 2>A perfectly synchronized factory floor. Yeah, but you know, to

307
00:15:20.720 --> 00:15:23.879
<v Speaker 2>make that assembly line truly adaptable. For real world applications,

308
00:15:24.159 --> 00:15:27.080
<v Speaker 2>we need the second major tool, which is closures. The

309
00:15:27.120 --> 00:15:29.840
<v Speaker 2>book defines a closure as a function that captures free

310
00:15:29.919 --> 00:15:31.759
<v Speaker 2>variables from its surrounding environment.

311
00:15:32.039 --> 00:15:35.759
<v Speaker 1>The example trail uses is an application downloading an image

312
00:15:35.759 --> 00:15:39.600
<v Speaker 1>for the user interface. You trigger an asynchronous request to

313
00:15:39.679 --> 00:15:42.879
<v Speaker 1>download a large image from a server right while that

314
00:15:42.919 --> 00:15:46.080
<v Speaker 1>download is pending. The rest of the program continues executing,

315
00:15:46.559 --> 00:15:50.120
<v Speaker 1>But when the image finally arrives, like a few seconds later,

316
00:15:50.480 --> 00:15:54.120
<v Speaker 1>the internal function updates the correct UI element, even though

317
00:15:54.120 --> 00:15:57.519
<v Speaker 1>the outer function that initiated the request finished its execution

318
00:15:57.759 --> 00:15:58.840
<v Speaker 1>and moved on long ago.

319
00:15:59.120 --> 00:16:03.200
<v Speaker 2>Yeah, the mechanism behind this is brilliant. In traditional programming,

320
00:16:03.240 --> 00:16:06.120
<v Speaker 2>you would have to write all this complex boilerplate code

321
00:16:06.240 --> 00:16:09.240
<v Speaker 2>to store that UI state in a shared memory heap,

322
00:16:09.639 --> 00:16:12.480
<v Speaker 2>keep it safe from other threads, and pass it back

323
00:16:12.519 --> 00:16:15.639
<v Speaker 2>when the network call returned, which is a nightmare exactly.

324
00:16:15.679 --> 00:16:17.720
<v Speaker 2>A closure eliminates that overhead entirely.

325
00:16:17.879 --> 00:16:20.200
<v Speaker 1>Explain exactly how it works under the hood. How does

326
00:16:20.240 --> 00:16:23.360
<v Speaker 1>the function hold on to that specific data without dumping

327
00:16:23.399 --> 00:16:24.440
<v Speaker 1>it into shared memory.

328
00:16:24.600 --> 00:16:27.200
<v Speaker 2>Well, instead of storing the UI state in when the

329
00:16:27.240 --> 00:16:31.559
<v Speaker 2>closure is defined, the runtime compiler automatically hoists those local

330
00:16:31.679 --> 00:16:35.559
<v Speaker 2>variables into a hidden generated class behind the scenes. It

331
00:16:35.639 --> 00:16:39.519
<v Speaker 2>basically takes a pristine snapshot of the environment exactly as

332
00:16:39.600 --> 00:16:42.519
<v Speaker 2>it existed when the function was invoked. Wow, and that

333
00:16:42.639 --> 00:16:45.360
<v Speaker 2>data lives precisely as long as the function needs it to,

334
00:16:45.960 --> 00:16:48.159
<v Speaker 2>entirely isolated from the rest of the application.

335
00:16:48.360 --> 00:16:51.240
<v Speaker 1>So it sounds like if Composition is building a perfectly

336
00:16:51.279 --> 00:16:55.559
<v Speaker 1>automated assembly line, closures are giving each individual worker on

337
00:16:55.600 --> 00:16:59.799
<v Speaker 1>that line a sealed backpack containing only the specific instructions

338
00:17:00.120 --> 00:17:00.759
<v Speaker 1>data they need.

339
00:17:00.919 --> 00:17:02.120
<v Speaker 2>That's a great way to look at it.

340
00:17:02.159 --> 00:17:04.640
<v Speaker 1>They get to carry that backpack around with them no

341
00:17:04.720 --> 00:17:07.119
<v Speaker 1>matter where they are routed in the factory or how

342
00:17:07.160 --> 00:17:09.480
<v Speaker 1>long their specific task takes to complete.

343
00:17:09.759 --> 00:17:13.039
<v Speaker 2>Yeah, and because the compiler and the runtime automatically managed

344
00:17:13.079 --> 00:17:17.599
<v Speaker 2>this isolated memory context via closures, the developer is completely

345
00:17:17.640 --> 00:17:21.279
<v Speaker 2>freed from writing bloated state management code, which is amazing.

346
00:17:21.319 --> 00:17:25.039
<v Speaker 2>It keeps the concurrent code succinct, incredibly readable, and mathematically

347
00:17:25.079 --> 00:17:26.079
<v Speaker 2>safe from corruption.

348
00:17:26.480 --> 00:17:30.079
<v Speaker 1>We have covered incredible ground today. We started by staring

349
00:17:30.119 --> 00:17:33.160
<v Speaker 1>down the immovable physics of the universe, the speed of

350
00:17:33.240 --> 00:17:37.000
<v Speaker 1>light and the thermal melting point of silicon, which forced

351
00:17:37.039 --> 00:17:40.720
<v Speaker 1>hardware engineers to build outward instead of upward ushering in

352
00:17:40.759 --> 00:17:42.359
<v Speaker 1>the multi coore era right.

353
00:17:42.200 --> 00:17:46.000
<v Speaker 2>Which subsequently exposed the fatal flaws of traditional object oriented

354
00:17:46.039 --> 00:17:51.359
<v Speaker 2>programming definitely, we navigated the chaotic concurrency hazards of race conditions,

355
00:17:51.519 --> 00:17:55.680
<v Speaker 2>corrupted data, and application freezing deadlocks caused by sharing mutable

356
00:17:55.759 --> 00:17:57.480
<v Speaker 2>state across independent threads.

357
00:17:57.960 --> 00:18:01.559
<v Speaker 1>We analyze the quick sort benchmark, proving that blindly throwing

358
00:18:01.599 --> 00:18:04.680
<v Speaker 1>threads at a parallel problem just drowns the CPU in

359
00:18:04.720 --> 00:18:09.519
<v Speaker 1>administrative overhead, highlighting the strict need to balance the workload.

360
00:18:09.279 --> 00:18:12.039
<v Speaker 2>Which ultimately led us to the mathematically pure architecture of

361
00:18:12.039 --> 00:18:17.720
<v Speaker 2>functional programming. Yes, by embracing immutability, pure functions, compositional pipelines, enclosures,

362
00:18:17.759 --> 00:18:20.920
<v Speaker 2>developers have a robust framework to write software that scales

363
00:18:21.000 --> 00:18:23.960
<v Speaker 2>fluidly across as many cores as the hardware can supply.

364
00:18:24.279 --> 00:18:26.920
<v Speaker 1>So, whether you are coding the back end architecture of

365
00:18:26.960 --> 00:18:30.480
<v Speaker 1>a mobile app, analyzing a massive big data set, or

366
00:18:30.519 --> 00:18:34.279
<v Speaker 1>honestly just expecting your browser to remain responsive with fifty

367
00:18:34.359 --> 00:18:38.960
<v Speaker 1>separate tabs running simultaneously, this is the invisible structural shift

368
00:18:39.240 --> 00:18:41.160
<v Speaker 1>keeping your technology from locking up.

369
00:18:41.519 --> 00:18:45.759
<v Speaker 2>It is the absolute foundation of modern scalable computing. But

370
00:18:46.480 --> 00:18:49.680
<v Speaker 2>if we connect this to the broader trajectory of hardware,

371
00:18:49.720 --> 00:18:54.079
<v Speaker 2>it raises a really fascinating question. Yeah, the physical limits

372
00:18:54.119 --> 00:18:58.119
<v Speaker 2>of silicon forced us to adopt rigid, mathematically pure software

373
00:18:58.160 --> 00:19:02.680
<v Speaker 2>models like functional programming to safely orchestrate multiple cores. What

374
00:19:02.799 --> 00:19:05.720
<v Speaker 2>happens to our software paradigms when we inevitably transition to

375
00:19:05.799 --> 00:19:08.920
<v Speaker 2>quantum computing? Will developers have to adapt yet again to

376
00:19:08.960 --> 00:19:12.160
<v Speaker 2>write algorithms that can natively process states that are literally

377
00:19:12.200 --> 00:19:14.000
<v Speaker 2>true and false at the exact same time.

378
00:19:14.319 --> 00:19:17.359
<v Speaker 1>Wow, that is a staggering thought to end on from

379
00:19:17.400 --> 00:19:20.039
<v Speaker 1>the thermal ceiling of a melting CPU to the subatomic

380
00:19:20.079 --> 00:19:23.079
<v Speaker 1>possibilities of a quantum computer. Thank you for joining us

381
00:19:23.119 --> 00:19:25.640
<v Speaker 1>as we mapped out the invisible architecture of the devices

382
00:19:25.720 --> 00:19:29.440
<v Speaker 1>powering our world. Keep exploring, keep questioning, and we will

383
00:19:29.440 --> 00:19:31.640
<v Speaker 1>see you on the next deep dive into the source material.
