WEBVTT

1
01:00:01.250 --> 01:00:04.791
(Music)

2
01:00:14.958 --> 01:00:16.666
This is Self-Directed Research.

3
01:00:17.291 --> 01:00:18.666
James and Amos are back with weekly

4
01:00:18.666 --> 01:00:19.958
hyper-focused deep dives.

5
01:00:20.333 --> 01:00:21.625
Make sure to like, follow, and subscribe

6
01:00:21.625 --> 01:00:22.583
wherever you find us.

7
01:00:22.791 --> 01:00:25.458
And as always, visit SDR-Podcast.com

8
01:00:25.458 --> 01:00:27.166
slash episodes for all the presentations,

9
01:00:27.458 --> 01:00:29.041
videos, show notes, and transcripts.

10
01:00:29.666 --> 01:00:31.041
This episode is sponsored by Depot.

11
01:00:31.416 --> 01:00:32.208
Stay tuned at the end

12
01:00:32.208 --> 01:00:33.000
for more information.

13
01:00:33.791 --> 01:00:35.125
James tried something new by recording

14
01:00:35.125 --> 01:00:36.791
first and adding slides later.

15
01:00:37.291 --> 01:00:39.708
This week's episode is Sans I.O.

16
01:00:40.125 --> 01:00:40.375
Meh.

17
01:00:41.250 --> 01:00:43.500
(Music)

18
01:00:45.625 --> 01:00:48.333
So I don't have anything to follow.

19
01:00:48.333 --> 01:00:48.666
Cool.

20
01:00:48.666 --> 01:00:48.958
All right.

21
01:00:49.208 --> 01:00:49.458
Bye.

22
01:00:50.416 --> 01:00:51.416
Yeah, no slides for this one.

23
01:00:51.416 --> 01:00:52.583
This one's going to be a time travel

24
01:00:52.583 --> 01:00:53.458
episodes because I'm going to

25
01:00:53.458 --> 01:00:54.916
write the slides afterwards.

26
01:00:55.250 --> 01:00:57.583
But I had a thing that I used to

27
01:00:57.583 --> 01:00:58.375
recommend to people.

28
01:00:58.750 --> 01:01:01.166
And now after doing a bunch of work, I

29
01:01:01.166 --> 01:01:03.625
found my opinion changing.

30
01:01:03.625 --> 01:01:06.041
So I wanted to see almost what your

31
01:01:06.041 --> 01:01:09.000
opinions were or if I'm missing something

32
01:01:09.000 --> 01:01:10.208
as my opinion shifts.

33
01:01:10.666 --> 01:01:11.458
So-- James, did you

34
01:01:11.458 --> 01:01:13.166
already retire the buddy system?

35
01:01:13.750 --> 01:01:13.958
No.

36
01:01:14.291 --> 01:01:14.458
No.

37
01:01:15.125 --> 01:01:15.958
Scared me for a second.

38
01:01:16.125 --> 01:01:16.541
No.

39
01:01:16.541 --> 01:01:17.458
So have you heard the

40
01:01:17.458 --> 01:01:19.041
phrase Sans I.O. before?

41
01:01:19.583 --> 01:01:20.125
I have.

42
01:01:20.583 --> 01:01:21.750
So this is one of those things that,

43
01:01:21.750 --> 01:01:23.333
especially in Rust, people tend to

44
01:01:23.333 --> 01:01:25.375
recommend of like, hey, when I'm

45
01:01:25.375 --> 01:01:28.458
designing protocols or things like that,

46
01:01:28.916 --> 01:01:31.791
one of the recommended ways is Sans I.O.

47
01:01:31.791 --> 01:01:33.666
So you have all of your code that does

48
01:01:33.666 --> 01:01:36.041
decoding and state machine logic and

49
01:01:36.041 --> 01:01:38.250
stuff like that in normal,

50
01:01:38.500 --> 01:01:39.833
usually blocking functions.

51
01:01:40.333 --> 01:01:41.708
And you handle your actual

52
01:01:41.708 --> 01:01:44.000
I.O. portions outside of that.

53
01:01:44.458 --> 01:01:46.458
And the purported benefits are it's

54
01:01:46.458 --> 01:01:48.541
generally portable for async and not

55
01:01:48.541 --> 01:01:51.583
async because you let the I.O. be I.O.

56
01:01:51.583 --> 01:01:52.958
wherever it's doing I.O.

57
01:01:53.333 --> 01:01:55.458
You get benefits of testability because

58
01:01:55.458 --> 01:01:56.833
when you want to test it, you can just

59
01:01:56.833 --> 01:02:00.083
shove in VEX or slices of bytes that are

60
01:02:00.083 --> 01:02:02.666
pre-manufactured test artifacts and make

61
01:02:02.666 --> 01:02:04.416
sure it goes only to the

62
01:02:04.416 --> 01:02:06.083
next step and things like that.

63
01:02:06.958 --> 01:02:08.291
It is sort of compelling.

64
01:02:08.708 --> 01:02:11.083
But what I've realized is the whole point

65
01:02:11.083 --> 01:02:13.041
of async is to make the

66
01:02:13.041 --> 01:02:15.500
compiler do state machines for you.

67
01:02:15.958 --> 01:02:18.083
And to not have weird like loop match

68
01:02:18.083 --> 01:02:21.500
statements where you're like doing manual

69
01:02:21.500 --> 01:02:22.666
state machine changes.

70
01:02:22.958 --> 01:02:24.875
Someone even in the Rust subreddit today

71
01:02:24.875 --> 01:02:25.750
posted something where

72
01:02:25.750 --> 01:02:26.958
they're like, "Can I do this?"

73
01:02:26.958 --> 01:02:28.458
And they posted some loop match.

74
01:02:28.458 --> 01:02:30.833
And I'm like, "If you just use a regular

75
01:02:30.833 --> 01:02:33.125
async function, you don't need the match

76
01:02:33.125 --> 01:02:35.875
like it's just a for loop with a continue

77
01:02:35.875 --> 01:02:37.291
statement in the middle if you need to

78
01:02:37.291 --> 01:02:38.333
skip back to the first one."

79
01:02:38.500 --> 01:02:40.583
And I've realized particularly with

80
01:02:40.583 --> 01:02:43.666
postcard RPC and post station that if you

81
01:02:43.666 --> 01:02:46.875
do have a good abstraction of the wire,

82
01:02:47.458 --> 01:02:49.333
you can avoid losing out.

83
01:02:49.333 --> 01:02:51.583
So the reason, the negative to doing this

84
01:02:51.583 --> 01:02:53.625
is it becomes difficult because you are

85
01:02:53.625 --> 01:02:55.125
really doing those match

86
01:02:55.125 --> 01:02:56.291
of state machines again.

87
01:02:56.291 --> 01:02:58.208
You go, "Okay, decode the packet.

88
01:02:58.416 --> 01:02:59.666
What does this packet make me do?

89
01:02:59.666 --> 01:03:00.958
It makes me move this state."

90
01:03:00.958 --> 01:03:04.000
And a lot of people reach for enums for

91
01:03:04.000 --> 01:03:05.458
state machines where you

92
01:03:05.458 --> 01:03:07.208
go like match self.state.

93
01:03:07.708 --> 01:03:09.333
And that works fine except for everyone

94
01:03:09.333 --> 01:03:11.375
wants to put data inside of those because

95
01:03:11.375 --> 01:03:12.041
you say, "When I'm in

96
01:03:12.041 --> 01:03:13.083
this mode, I have this data."

97
01:03:13.375 --> 01:03:14.625
And it helps you make sure that you don't

98
01:03:14.625 --> 01:03:16.250
have data that gets stale when you're in

99
01:03:16.250 --> 01:03:17.666
the wrong state and things like that.

100
01:03:18.083 --> 01:03:19.083
And for a lot of these where you might

101
01:03:19.083 --> 01:03:20.750
wanna borrow the contents of those

102
01:03:20.750 --> 01:03:23.791
states, then going to like swap the state

103
01:03:23.791 --> 01:03:25.416
out while you're in the middle of a match

104
01:03:25.416 --> 01:03:27.958
statement for doing this, one, you get

105
01:03:27.958 --> 01:03:29.250
really nested code because

106
01:03:29.250 --> 01:03:30.208
you're in a match statement.

107
01:03:30.208 --> 01:03:31.541
And even if you delegate to functions,

108
01:03:32.333 --> 01:03:33.583
you have to figure out, "Oh, well I'm

109
01:03:33.583 --> 01:03:35.750
already mutably borrowing self.state, so

110
01:03:35.750 --> 01:03:37.333
I can't just pass state to this function

111
01:03:37.333 --> 01:03:38.750
that also mutates self because I'm

112
01:03:38.750 --> 01:03:39.625
already borrowing self.

113
01:03:40.083 --> 01:03:42.375
And if I take the thing out, then I need

114
01:03:42.375 --> 01:03:44.125
a placeholder value, which means what do

115
01:03:44.125 --> 01:03:45.166
I do in my state machine?

116
01:03:45.541 --> 01:03:46.458
If I'm in the placeholder

117
01:03:46.458 --> 01:03:47.958
value, I have to just panic.

118
01:03:47.958 --> 01:03:49.416
So you have a panicking branch in there.

119
01:03:49.833 --> 01:03:50.791
So it's one of those things where it's,

120
01:03:51.000 --> 01:03:52.250
it sounds really good on paper.

121
01:03:52.541 --> 01:03:54.041
You can really enumerate the benefits,

122
01:03:54.583 --> 01:03:55.791
but then it's kind of every time I've

123
01:03:55.791 --> 01:03:57.000
tried to really do it like

124
01:03:57.000 --> 01:03:58.625
that, it works really well.

125
01:03:59.083 --> 01:04:00.000
And then the paper

126
01:04:00.000 --> 01:04:01.625
cuts just keep lining up.

127
01:04:01.666 --> 01:04:02.375
That is true.

128
01:04:02.458 --> 01:04:04.791
Versus really leveraging something like

129
01:04:04.791 --> 01:04:07.750
async where a function is a

130
01:04:07.750 --> 01:04:09.041
hierarchical state machine.

131
01:04:09.583 --> 01:04:10.416
Like if you have one

132
01:04:10.416 --> 01:04:12.250
function, that is a state block.

133
01:04:12.250 --> 01:04:13.916
And if you call another function, that's

134
01:04:13.916 --> 01:04:14.958
another state block.

135
01:04:14.958 --> 01:04:17.000
When I say hierarchical state machines,

136
01:04:17.000 --> 01:04:18.000
do you know what I mean by that?

137
01:04:18.458 --> 01:04:19.333
I do, I do.

138
01:04:20.750 --> 01:04:22.875
You didn't really leave me time to

139
01:04:22.875 --> 01:04:23.666
interject, but you know

140
01:04:23.666 --> 01:04:24.333
what's very fun, James?

141
01:04:24.375 --> 01:04:26.083
I'm excited about this topic, Amos.

142
01:04:26.458 --> 01:04:28.125
You know what's very, very fun, James, is

143
01:04:28.125 --> 01:04:30.333
that I have my shit together in 2025.

144
01:04:30.333 --> 01:04:31.000
That's also an explicit

145
01:04:31.000 --> 01:04:32.083
episode, I'm sorry, kids.

146
01:04:32.125 --> 01:04:32.416
Hell yeah.

147
01:04:33.208 --> 01:04:34.291
I have my shit together, which means I

148
01:04:34.291 --> 01:04:35.041
have a video backlog.

149
01:04:35.791 --> 01:04:36.958
Do you wanna know the name of video I've

150
01:04:36.958 --> 01:04:39.708
already researched, written, shot,

151
01:04:39.708 --> 01:04:41.791
edited, and captioned?

152
01:04:41.875 --> 01:04:43.291
Why Sanzio isn't great.

153
01:04:43.291 --> 01:04:44.458
The case for Sanzio.

154
01:04:44.833 --> 01:04:46.875
Ooh, point counterpoint.

155
01:04:46.958 --> 01:04:49.958
I maintain a crate named RCzip, which is

156
01:04:49.958 --> 01:04:50.833
a Sanzio implementation

157
01:04:50.833 --> 01:04:52.041
of the zip file format.

158
01:04:52.333 --> 01:04:53.750
And that's the topic of the video, and I

159
01:04:53.750 --> 01:04:55.041
explain why it's actually good.

160
01:04:55.291 --> 01:04:57.791
So I can make the same points in podcast

161
01:04:57.791 --> 01:04:59.541
form, because I think, realistically

162
01:04:59.541 --> 01:05:00.416
speaking, the overlay

163
01:05:00.416 --> 01:05:01.458
will be relatively small.

164
01:05:01.666 --> 01:05:03.500
And I'm gonna actually get to bump it off

165
01:05:03.500 --> 01:05:05.291
of you instead of just

166
01:05:05.291 --> 01:05:07.125
talking to my shotgun mic.

167
01:05:07.125 --> 01:05:08.541
But it's very funny, because I knew this

168
01:05:08.541 --> 01:05:09.458
day would come eventually.

169
01:05:09.958 --> 01:05:11.375
And actually, so you say zip file.

170
01:05:11.375 --> 01:05:13.375
So actually, I think I am much more

171
01:05:13.375 --> 01:05:16.250
inclined to agree with things like file

172
01:05:16.250 --> 01:05:19.125
format parsers or things that are not

173
01:05:19.125 --> 01:05:20.916
distributed systems.

174
01:05:21.333 --> 01:05:24.083
Because I think a lot of protocol design

175
01:05:24.083 --> 01:05:25.916
when it comes to distributed systems is

176
01:05:25.916 --> 01:05:28.166
your action and reaction to things.

177
01:05:28.958 --> 01:05:31.708
And surprisingly, there's not as much

178
01:05:31.708 --> 01:05:32.458
difference as you would

179
01:05:32.458 --> 01:05:34.250
think between a file format.

180
01:05:34.250 --> 01:05:35.416
A file format is just kind of like a

181
01:05:35.416 --> 01:05:37.041
fixed distributed system.

182
01:05:37.375 --> 01:05:38.750
It's something that you're talking to and

183
01:05:38.750 --> 01:05:39.958
decoding and things like that,

184
01:05:39.958 --> 01:05:42.458
but-- Well, you will let me know if you

185
01:05:42.458 --> 01:05:44.208
still think that after you, of course,

186
01:05:44.208 --> 01:05:45.833
watch my video about the zip file format.

187
01:05:46.041 --> 01:05:47.791
Because it, well, it's static, yes.

188
01:05:48.125 --> 01:05:49.291
But going from left to

189
01:05:49.291 --> 01:05:50.458
right, no, very much not.

190
01:05:51.333 --> 01:05:54.083
So it's more complicated than TLS even.

191
01:05:54.333 --> 01:05:55.833
But okay, I'll throw one

192
01:05:55.833 --> 01:05:56.958
first argument in the ring.

193
01:05:58.125 --> 01:05:58.833
No pun intended.

194
01:05:59.041 --> 01:06:01.125
It's that the async abstractions we have

195
01:06:01.125 --> 01:06:03.250
now, async retrades in the Tokyo crates

196
01:06:03.416 --> 01:06:05.250
and in the async-sad

197
01:06:05.250 --> 01:06:08.416
crates are not actually good.

198
01:06:09.500 --> 01:06:12.250
And also just not compatible with modern

199
01:06:12.250 --> 01:06:15.291
ways of doing IO, which for me on Linux

200
01:06:15.291 --> 01:06:18.000
and BSDs and now on Windows and whatnot

201
01:06:18.000 --> 01:06:21.500
would be IO-uring, where you would give

202
01:06:21.500 --> 01:06:23.333
ownership of the buffer to the kernel and

203
01:06:23.333 --> 01:06:24.291
then wait for the opportunity to be

204
01:06:24.291 --> 01:06:25.875
completed or canceled before you can

205
01:06:25.875 --> 01:06:26.833
actually free that buffer

206
01:06:26.833 --> 01:06:27.791
or do anything else with it.

207
01:06:28.333 --> 01:06:32.000
And you simply cannot have Tokyo's

208
01:06:32.000 --> 01:06:34.583
async-rein interface and an IO-uring IO

209
01:06:34.583 --> 01:06:36.083
system, which is the most efficient way

210
01:06:36.083 --> 01:06:37.125
of doing IO nowadays.

211
01:06:37.916 --> 01:06:38.541
You simply cannot.

212
01:06:38.958 --> 01:06:40.416
So of course, immediately after that, the

213
01:06:40.416 --> 01:06:42.250
argument goes, you don't need IO-uring

214
01:06:42.250 --> 01:06:44.208
because your application is too slow.

215
01:06:44.208 --> 01:06:45.458
That's not the bottleneck essentially.

216
01:06:45.916 --> 01:06:46.625
So that's a good point.

217
01:06:46.916 --> 01:06:47.458
Facebook needs

218
01:06:47.458 --> 01:06:48.666
IO-uring, you probably don't.

219
01:06:48.750 --> 01:06:49.333
I don't think that's

220
01:06:49.333 --> 01:06:50.125
where I would go with that.

221
01:06:50.125 --> 01:06:51.958
I would say I probably agree with you

222
01:06:52.250 --> 01:06:55.041
that the abstraction isn't great because,

223
01:06:55.708 --> 01:06:57.166
so what Tokyo, especially when you're

224
01:06:57.166 --> 01:06:58.875
talking about like TCP streams and things

225
01:06:58.875 --> 01:07:02.000
like that, you get a stream of data as

226
01:07:02.000 --> 01:07:04.583
bytes and you have to do explicit steps.

227
01:07:04.583 --> 01:07:05.625
So this is one of those things that I've

228
01:07:05.625 --> 01:07:06.625
boiled down in postcard.

229
01:07:06.666 --> 01:07:08.833
Postcard RPCs, wire traits.

230
01:07:08.833 --> 01:07:09.958
So it has wire traits for

231
01:07:09.958 --> 01:07:11.166
both the client and the server.

232
01:07:11.791 --> 01:07:13.500
They don't give you a stream of bytes,

233
01:07:13.708 --> 01:07:14.708
they give you a frame.

234
01:07:15.291 --> 01:07:16.750
And I do, and it depends on whether

235
01:07:16.750 --> 01:07:18.291
you're on no standard or not, but on

236
01:07:18.291 --> 01:07:20.458
desktop, it usually is you give evacuate

237
01:07:20.458 --> 01:07:23.666
as a frame and you receive back evacuate

238
01:07:23.666 --> 01:07:26.666
as a frame, not decoded, but you say this

239
01:07:26.666 --> 01:07:29.583
is one block where I expect framing to be

240
01:07:29.583 --> 01:07:31.083
an explicit step of this.

241
01:07:31.541 --> 01:07:32.458
Now you could probably do something

242
01:07:32.458 --> 01:07:33.916
clever where you have more of like a

243
01:07:33.916 --> 01:07:35.958
buffer pool if you didn't really wanna

244
01:07:35.958 --> 01:07:37.458
recycle VEX, but for my

245
01:07:37.458 --> 01:07:38.916
case, I'm not Facebook.

246
01:07:39.250 --> 01:07:42.666
So for me, leaning on Malek or TC Malek

247
01:07:42.666 --> 01:07:45.000
or JE Malek is probably fine and the VEX

248
01:07:45.000 --> 01:07:46.750
are gonna get reused anyway, but if you

249
01:07:46.750 --> 01:07:48.083
really wanted control over it, you could

250
01:07:48.083 --> 01:07:49.625
have more of like a recyclable buffer

251
01:07:49.625 --> 01:07:50.708
pool or something like that.

252
01:07:51.166 --> 01:07:54.500
But my actual interface is at the frame

253
01:07:54.500 --> 01:07:57.000
level because one, I need to be flexible

254
01:07:57.000 --> 01:07:58.083
because if you're going over a serial

255
01:07:58.083 --> 01:07:59.666
port, you might need to do some

256
01:07:59.666 --> 01:08:01.708
additional encoding or putting checksums

257
01:08:01.708 --> 01:08:02.500
on it because you may not

258
01:08:02.500 --> 01:08:03.750
trust that that's going.

259
01:08:03.750 --> 01:08:05.916
Whereas over, if you decided to use UDP

260
01:08:05.916 --> 01:08:07.875
as your transport, you might just say,

261
01:08:07.875 --> 01:08:09.666
well, the frame's a frame or you might

262
01:08:09.666 --> 01:08:10.583
wanna do it with encryption.

263
01:08:10.791 --> 01:08:12.291
So I have a version that goes over TLS

264
01:08:12.291 --> 01:08:15.375
1.3 using a Russell's.

265
01:08:15.625 --> 01:08:17.083
And so you can choose

266
01:08:17.083 --> 01:08:19.750
where you delineate the frame.

267
01:08:20.375 --> 01:08:22.791
And so frames come in, then there's an

268
01:08:22.791 --> 01:08:24.333
explicit decoding step.

269
01:08:24.625 --> 01:08:27.541
So you turn it from a frame to a struct

270
01:08:27.791 --> 01:08:30.666
or it fails and you reject it and you

271
01:08:30.666 --> 01:08:31.625
handle it like that.

272
01:08:31.625 --> 01:08:32.916
And that's one of those things where I

273
01:08:32.916 --> 01:08:35.375
have implementations of my wire trait

274
01:08:36.041 --> 01:08:37.666
that just use Tokyo channels.

275
01:08:38.250 --> 01:08:39.916
So if I'm doing a unit test or I'm doing

276
01:08:39.916 --> 01:08:41.833
simulation or something like that, I

277
01:08:41.833 --> 01:08:42.458
don't actually wire

278
01:08:42.458 --> 01:08:43.666
it up to a TCP socket.

279
01:08:43.875 --> 01:08:47.041
I just have an MPSC channel where frames

280
01:08:47.041 --> 01:08:49.083
go in, frames come out and

281
01:08:49.083 --> 01:08:50.708
it's very usable for testing.

282
01:08:50.958 --> 01:08:53.916
So I think probably my point is that

283
01:08:53.916 --> 01:08:56.041
Sanzio is sort of throwing the baby out

284
01:08:56.041 --> 01:08:58.958
with the bathwater in that, yes, like a

285
01:08:58.958 --> 01:09:01.291
raw async read, async write isn't a great

286
01:09:01.291 --> 01:09:03.916
interface for a protocol and two,

287
01:09:04.208 --> 01:09:06.750
throwing out all of async just so you can

288
01:09:06.750 --> 01:09:09.250
get your state machines to be explicit

289
01:09:09.250 --> 01:09:12.000
state machines is also sort of losing out

290
01:09:12.000 --> 01:09:14.083
on some real benefit of being able to do

291
01:09:14.083 --> 01:09:16.250
like real control flow like match

292
01:09:16.250 --> 01:09:18.750
statements or early returns or labeled

293
01:09:18.750 --> 01:09:22.041
loop breaks and things like that where it

294
01:09:22.041 --> 01:09:24.041
would be egregious to try and keep that.

295
01:09:24.583 --> 01:09:26.625
You'd have to draw the state diagram and

296
01:09:26.625 --> 01:09:27.958
then all of your match statements go,

297
01:09:28.000 --> 01:09:31.750
okay, this is state transition 1.4a where

298
01:09:31.750 --> 01:09:33.625
I go from here to here versus in code,

299
01:09:33.625 --> 01:09:35.791
you just go, okay, I just break from the

300
01:09:35.791 --> 01:09:37.166
loop and it's tick

301
01:09:37.166 --> 01:09:39.458
inner, break tick inner.

302
01:09:39.458 --> 01:09:40.083
You know what I mean?

303
01:09:40.500 --> 01:09:42.833
Yeah, I love this episode because I get

304
01:09:42.833 --> 01:09:44.708
to be the bad person,

305
01:09:44.708 --> 01:09:45.500
the devil's advocate.

306
01:09:46.583 --> 01:09:48.500
So my first argument was like the Tokyo

307
01:09:48.500 --> 01:09:49.541
async read interface is

308
01:09:49.541 --> 01:09:51.041
bad and it should feel bad.

309
01:09:51.041 --> 01:09:53.291
And you're like, well, I did the pass

310
01:09:53.291 --> 01:09:54.208
around ownership of the

311
01:09:54.208 --> 01:09:56.083
buffer, so I don't have that.

312
01:09:56.083 --> 01:09:56.833
And I agree.

313
01:09:57.208 --> 01:09:59.958
So yeah, in that sense, I would agree,

314
01:09:59.958 --> 01:10:02.416
just make everything async and pass

315
01:10:02.416 --> 01:10:03.583
around ownership of the buffer.

316
01:10:03.916 --> 01:10:05.583
Don't borrow anything mutably across

317
01:10:05.583 --> 01:10:07.958
async wait, wait points essentially.

318
01:10:08.375 --> 01:10:11.916
Next on the my agenda as the devil is to

319
01:10:11.916 --> 01:10:14.208
tell you that unfortunately, I don't know

320
01:10:14.208 --> 01:10:15.875
if you've read the documents of the

321
01:10:15.875 --> 01:10:19.333
bright and shiny async rust future that

322
01:10:19.333 --> 01:10:21.291
they wrote a couple years ago.

323
01:10:21.291 --> 01:10:22.333
There's an async work group.

324
01:10:22.625 --> 01:10:23.666
I forget who's on it.

325
01:10:23.666 --> 01:10:24.916
I absolutely have, but not

326
01:10:24.916 --> 01:10:26.333
in two years or something.

327
01:10:26.791 --> 01:10:27.916
I just remember Barbara.

328
01:10:27.916 --> 01:10:29.333
What does Barbara do in this scenario?

329
01:10:29.625 --> 01:10:30.416
There's always a,

330
01:10:30.416 --> 01:10:31.041
it's a user story thingy.

331
01:10:31.041 --> 01:10:32.416
Barbara is one of the voice of the

332
01:10:32.416 --> 01:10:34.125
customer, user story person.

333
01:10:34.125 --> 01:10:36.208
So they always have a name, so they're

334
01:10:36.208 --> 01:10:36.625
supposed to remember.

335
01:10:36.833 --> 01:10:38.625
I forgot all of it, but it's good.

336
01:10:39.166 --> 01:10:39.875
That's my point.

337
01:10:39.875 --> 01:10:41.708
It's been a few years and I think not a

338
01:10:41.708 --> 01:10:43.333
lot of those have come true.

339
01:10:43.333 --> 01:10:44.916
There's been a lot of compiler level

340
01:10:44.916 --> 01:10:47.500
features shipped, which is amazing.

341
01:10:48.291 --> 01:10:49.833
But I'm waiting on

342
01:10:49.833 --> 01:10:51.125
async stack traces, right?

343
01:10:51.750 --> 01:10:53.166
With synchronous code, you can set a

344
01:10:53.166 --> 01:10:53.708
break point somewhere.

345
01:10:53.958 --> 01:10:56.250
You can just look at a, take a dump of

346
01:10:56.250 --> 01:10:57.333
all the stack traces, you

347
01:10:57.333 --> 01:10:57.916
know where it's blocked.

348
01:10:58.208 --> 01:10:59.208
That's hard to argue with.

349
01:10:59.208 --> 01:11:01.500
As long as you cannot do that with async

350
01:11:01.500 --> 01:11:02.958
rust code, you're gonna feel the pain

351
01:11:02.958 --> 01:11:03.416
whenever you're

352
01:11:03.416 --> 01:11:04.500
inspecting a running system.

353
01:11:05.083 --> 01:11:06.375
And Go has that figured out.

354
01:11:06.375 --> 01:11:09.208
Again, I'm infamous Go hater almost, but

355
01:11:09.208 --> 01:11:11.416
I recognize that every rant about Go, I'm

356
01:11:11.416 --> 01:11:13.000
like, they have great runtime

357
01:11:13.000 --> 01:11:14.958
introspection things because Go routines

358
01:11:14.958 --> 01:11:16.916
are the core of everything.

359
01:11:17.291 --> 01:11:17.916
They have their own

360
01:11:17.916 --> 01:11:18.916
runtime and everything.

361
01:11:18.916 --> 01:11:19.541
That's the point.

362
01:11:20.125 --> 01:11:21.625
So debugging is definitely one of them.

363
01:11:21.625 --> 01:11:23.208
And just introspection in general, not

364
01:11:23.208 --> 01:11:25.375
even talking about backtraces, but one of

365
01:11:25.375 --> 01:11:29.250
my motivations when I was working, I'm

366
01:11:29.250 --> 01:11:30.916
not currently working on my HTTP stack

367
01:11:30.916 --> 01:11:31.500
because nobody's

368
01:11:31.500 --> 01:11:32.791
currently funding me for it.

369
01:11:32.958 --> 01:11:34.500
And I have currently other things to do.

370
01:11:34.500 --> 01:11:35.458
But when I was, one of the big

371
01:11:35.458 --> 01:11:38.666
motivations was that, hyper is great and

372
01:11:38.666 --> 01:11:39.875
fine and I love Sean,

373
01:11:40.083 --> 01:11:41.166
but it's always in code.

374
01:11:41.375 --> 01:11:43.500
So you don't know, you don't even know

375
01:11:43.500 --> 01:11:44.500
where resources are spent.

376
01:11:44.708 --> 01:11:46.333
You don't know where the memory goes.

377
01:11:46.333 --> 01:11:47.833
You don't know where it's spending time.

378
01:11:47.833 --> 01:11:48.708
You don't know anything.

379
01:11:48.708 --> 01:11:49.875
It's all very opaque.

380
01:11:50.333 --> 01:11:51.375
You can't really observe the system.

381
01:11:51.416 --> 01:11:54.916
If you compare it with some C or C++, God

382
01:11:54.916 --> 01:11:56.625
forbid, HTTP servers, they

383
01:11:56.625 --> 01:11:58.041
have knobs for everything.

384
01:11:58.041 --> 01:12:00.041
They export all sorts of metrics.

385
01:12:00.375 --> 01:12:02.333
It matters because it runs on every edge

386
01:12:02.333 --> 01:12:03.541
node of your freaking network.

387
01:12:03.750 --> 01:12:05.000
So you need to know where the memory is

388
01:12:05.000 --> 01:12:06.041
spent, what knobs you

389
01:12:06.041 --> 01:12:07.041
can turn to optimize it.

390
01:12:07.458 --> 01:12:08.833
And with Async Rust, I agree with you.

391
01:12:09.416 --> 01:12:11.625
You can just write the code the way you

392
01:12:11.625 --> 01:12:12.666
would with synchronous code.

393
01:12:13.041 --> 01:12:15.708
You have to add a whole other layer on

394
01:12:15.708 --> 01:12:17.500
top of the existing Async Rust thing

395
01:12:17.500 --> 01:12:19.291
because it's designed to be zero cost.

396
01:12:19.791 --> 01:12:21.958
It's also kind of zero benefits.

397
01:12:23.083 --> 01:12:24.375
(Laughs) There's no extra stuff.

398
01:12:24.375 --> 01:12:25.291
There's no system that

399
01:12:25.291 --> 01:12:27.125
lets you know what's going on.

400
01:12:27.125 --> 01:12:28.666
It's just code that's called.

401
01:12:28.666 --> 01:12:30.500
It registers its interest in something

402
01:12:30.666 --> 01:12:31.625
and then it returns all

403
01:12:31.625 --> 01:12:32.375
the way to the runtime.

404
01:12:32.958 --> 01:12:35.125
And then if a task is blocked, you don't

405
01:12:35.125 --> 01:12:36.625
really know where it's blocked.

406
01:12:37.041 --> 01:12:38.000
And that's where you

407
01:12:38.000 --> 01:12:39.000
tell me about Tokyo console.

408
01:12:39.291 --> 01:12:39.916
Is it not, James?

409
01:12:40.250 --> 01:12:41.041
It's a good tool.

410
01:12:41.041 --> 01:12:42.708
And to be honest, in postcard and

411
01:12:42.708 --> 01:12:44.958
poststation, I do use, I'm not sure so

412
01:12:44.958 --> 01:12:46.125
much in postcard, but definitely in

413
01:12:46.125 --> 01:12:48.166
poststation, I use Tokyo pretty heavily.

414
01:12:48.583 --> 01:12:50.416
And one of the cool things that I do is I

415
01:12:50.416 --> 01:12:52.708
actually wrote a Tokyo sync that

416
01:12:52.708 --> 01:12:54.416
serializes the data and puts it in a

417
01:12:54.416 --> 01:12:56.875
database in a rolling ring buffer.

418
01:12:57.583 --> 01:12:59.750
So I can actually even get Tokyo

419
01:12:59.750 --> 01:13:02.916
instrument, not stack traces, but I don't

420
01:13:02.916 --> 01:13:03.875
have good tooling for it.

421
01:13:03.875 --> 01:13:05.208
I've only had to dip into it once.

422
01:13:05.208 --> 01:13:07.250
Right now I just collect it because if

423
01:13:07.250 --> 01:13:08.708
you collect all the data, you can go back

424
01:13:08.708 --> 01:13:09.500
and make a ring buffer and

425
01:13:09.500 --> 01:13:10.916
it doesn't get sent to me.

426
01:13:11.125 --> 01:13:14.708
I don't do the Grafana or Loki thing, but

427
01:13:14.708 --> 01:13:16.833
it's just stored in the local database

428
01:13:17.250 --> 01:13:18.875
same as incoming messages and stuff.

429
01:13:19.208 --> 01:13:20.666
And I have used that in a couple of times

430
01:13:20.666 --> 01:13:22.666
to figure out like, okay, where was this

431
01:13:22.666 --> 01:13:23.666
task and where was it

432
01:13:23.666 --> 01:13:25.166
spinning and things like that.

433
01:13:25.166 --> 01:13:25.875
And I think you're right.

434
01:13:25.875 --> 01:13:26.833
Like you do have to

435
01:13:26.833 --> 01:13:28.125
proactively set that up.

436
01:13:28.125 --> 01:13:29.250
I don't know, it's interesting.

437
01:13:29.750 --> 01:13:30.500
And maybe this just because

438
01:13:30.500 --> 01:13:32.041
I haven't done this in anger.

439
01:13:32.333 --> 01:13:34.166
I haven't had to debug as

440
01:13:34.166 --> 01:13:35.458
many cursed things on that.

441
01:13:35.458 --> 01:13:36.791
I think part of it is that I'm coming

442
01:13:36.791 --> 01:13:37.500
from sort of the

443
01:13:37.500 --> 01:13:39.916
embedded async world first.

444
01:13:40.291 --> 01:13:42.291
So I'm sort of used to everything needs

445
01:13:42.291 --> 01:13:44.875
to be as simple and as dumb as it can be,

446
01:13:45.125 --> 01:13:46.500
just because you don't have much space.

447
01:13:47.166 --> 01:13:48.833
And I try and do a very similar thing.

448
01:13:48.833 --> 01:13:50.541
Like a lot of the existing frameworks and

449
01:13:50.541 --> 01:13:52.083
things like that, I have strong opinions

450
01:13:52.083 --> 01:13:53.958
of, of just like, I'm the kind of person

451
01:13:53.958 --> 01:13:54.791
that really needs to

452
01:13:54.791 --> 01:13:55.916
understand back to front.

453
01:13:55.916 --> 01:13:57.208
And so maybe this is one of those things

454
01:13:57.208 --> 01:13:58.666
where it doesn't, my

455
01:13:58.666 --> 01:14:00.458
opinions don't generalize.

456
01:14:00.541 --> 01:14:02.250
So maybe this is just a learning about

457
01:14:02.250 --> 01:14:03.875
myself, but I think one of the things

458
01:14:03.875 --> 01:14:05.125
that I've done with postcard RPC is

459
01:14:05.125 --> 01:14:06.750
there's only like, there's you the

460
01:14:06.750 --> 01:14:09.541
client, there's the, I do have IO

461
01:14:09.541 --> 01:14:12.250
workers, because you can share one

462
01:14:12.250 --> 01:14:13.291
connection with multiple

463
01:14:13.291 --> 01:14:14.458
clients and things like that.

464
01:14:14.875 --> 01:14:16.666
But the client really just goes, take it

465
01:14:16.666 --> 01:14:19.291
out of this side, encode it, put it in

466
01:14:19.291 --> 01:14:21.416
the wire and on the other side, it pulls

467
01:14:21.416 --> 01:14:22.125
it out of the wire,

468
01:14:22.458 --> 01:14:23.958
goes, does anyone want this?

469
01:14:24.250 --> 01:14:27.000
No, throw it away or yes, you want this,

470
01:14:27.000 --> 01:14:28.125
put it, put it to you.

471
01:14:28.125 --> 01:14:29.958
So like, maybe that's just one of those

472
01:14:29.958 --> 01:14:31.458
things that it works for postcard RPC,

473
01:14:31.458 --> 01:14:33.708
because it is a stupidly simple protocol

474
01:14:33.833 --> 01:14:36.541
compared to HTTP or a TLS

475
01:14:36.541 --> 01:14:38.583
negotiation or things like that.

476
01:14:38.583 --> 01:14:39.916
But yeah, I don't know

477
01:14:39.916 --> 01:14:41.208
what to think about that.

478
01:14:41.208 --> 01:14:42.416
Because you're right, like you do need

479
01:14:42.416 --> 01:14:44.500
those tools and you need to have the

480
01:14:44.500 --> 01:14:46.458
foresight of knowing how to avoid

481
01:14:46.458 --> 01:14:47.458
stepping in the cracks

482
01:14:47.583 --> 01:14:48.916
before you step in the cracks.

483
01:14:48.916 --> 01:14:50.250
Because otherwise, if you design around

484
01:14:50.250 --> 01:14:51.833
cracks, then you'll find

485
01:14:51.833 --> 01:14:53.333
yourself falling in cracks all day.

486
01:14:53.583 --> 01:14:55.708
Let me ask you this, have you ever had to

487
01:14:55.708 --> 01:14:57.041
box a future because

488
01:14:57.041 --> 01:14:58.000
you ran out of stack?

489
01:14:58.291 --> 01:14:58.458
No.

490
01:14:58.875 --> 01:15:00.333
So yes, you don't know

491
01:15:00.333 --> 01:15:01.250
the pain of Async Rust,

492
01:15:02.416 --> 01:15:02.625
clearly.

493
01:15:03.000 --> 01:15:04.541
Because that's a thing, that's the thing

494
01:15:04.541 --> 01:15:05.333
that happens in Rust,

495
01:15:05.333 --> 01:15:06.458
you write Async Rust code.

496
01:15:06.458 --> 01:15:07.791
First of all, recursion doesn't work.

497
01:15:08.250 --> 01:15:08.916
That sucks.

498
01:15:09.458 --> 01:15:10.750
I just, again, explicit

499
01:15:10.750 --> 01:15:12.041
episodes, I can say it.

500
01:15:12.458 --> 01:15:14.333
It sucks, you try to call the function

501
01:15:14.333 --> 01:15:16.833
recursively and it goes, that would be an

502
01:15:16.833 --> 01:15:17.916
infinite state machine.

503
01:15:17.916 --> 01:15:18.875
And it's not wrong.

504
01:15:19.458 --> 01:15:20.458
But you can do that with

505
01:15:20.458 --> 01:15:21.458
synchronous code somehow.

506
01:15:21.708 --> 01:15:23.250
It just keeps recursing

507
01:15:23.250 --> 01:15:24.583
until there's no more space.

508
01:15:25.375 --> 01:15:26.541
So-- I think that's one of those, but

509
01:15:26.541 --> 01:15:27.583
again, I think this is one

510
01:15:27.583 --> 01:15:28.625
of those embedded biases.

511
01:15:29.083 --> 01:15:30.375
Like I have-- You don't

512
01:15:30.375 --> 01:15:32.166
recurse, you never do, you just iterate.

513
01:15:32.166 --> 01:15:32.916
No, I do recurse.

514
01:15:33.166 --> 01:15:34.875
I do love recursion, don't get me wrong.

515
01:15:34.875 --> 01:15:36.000
I'm actually a big fan of recursion.

516
01:15:36.333 --> 01:15:38.166
I don't tend to use it in Async stuff

517
01:15:38.166 --> 01:15:39.333
because it's more IO based.

518
01:15:39.333 --> 01:15:41.208
I tend to use it for more parsing stuff.

519
01:15:41.458 --> 01:15:42.916
But that's usually synchronous code.

520
01:15:43.375 --> 01:15:44.666
I've never needed to

521
01:15:44.666 --> 01:15:46.041
asynchronously recur.

522
01:15:46.041 --> 01:15:46.875
Or I think like once.

523
01:15:47.166 --> 01:15:48.666
I think I found myself needing that about

524
01:15:48.666 --> 01:15:50.250
once and I did run into it.

525
01:15:50.250 --> 01:15:50.291
But that's the whole point.

526
01:15:50.291 --> 01:15:52.166
That's what you just sold everyone on

527
01:15:52.166 --> 01:15:54.041
about is that you can just write it as if

528
01:15:54.041 --> 01:15:55.166
it's regular code and it

529
01:15:55.166 --> 01:15:56.875
magically makes state machines.

530
01:15:57.083 --> 01:15:59.541
But then that abstraction is leaky and it

531
01:15:59.541 --> 01:16:01.041
breaks down when you try to recurse.

532
01:16:01.250 --> 01:16:02.375
It goes, that's an infinitely

533
01:16:02.375 --> 01:16:03.583
sized type, you can't do that.

534
01:16:03.958 --> 01:16:05.416
And it breaks down when you just write

535
01:16:05.500 --> 01:16:07.583
completely regular code and it just so

536
01:16:07.583 --> 01:16:10.041
happens that it made a fricking future

537
01:16:10.041 --> 01:16:11.916
that is four megabyte large and you

538
01:16:11.916 --> 01:16:13.333
didn't have four megabyte left on the

539
01:16:13.333 --> 01:16:15.166
stack and now everything blows up.

540
01:16:15.166 --> 01:16:17.250
And because it's a stack overflow, it's

541
01:16:17.250 --> 01:16:19.000
not really something you can, I don't

542
01:16:19.000 --> 01:16:20.291
even know if you can catch that.

543
01:16:20.291 --> 01:16:21.791
It just brings the whole application down

544
01:16:21.791 --> 01:16:23.583
and then good luck looking at it because

545
01:16:23.583 --> 01:16:25.750
when this started happening, when the

546
01:16:25.750 --> 01:16:27.833
whole Async ecosystem in Tokyo became

547
01:16:27.833 --> 01:16:29.333
viable enough that people started writing

548
01:16:29.333 --> 01:16:30.000
bigger and bigger web

549
01:16:30.000 --> 01:16:31.000
applications with it.

550
01:16:31.000 --> 01:16:32.958
The tooling to find out what's the size

551
01:16:32.958 --> 01:16:34.750
of my future was nil.

552
01:16:35.083 --> 01:16:37.166
He just had to go around and had a bunch

553
01:16:37.166 --> 01:16:38.833
of, I remember I worked at a

554
01:16:38.833 --> 01:16:40.083
company that had those problems.

555
01:16:40.416 --> 01:16:42.000
I had a bunch of friend statements that

556
01:16:42.000 --> 01:16:43.958
printed the size of different values that

557
01:16:43.958 --> 01:16:44.666
were returned from

558
01:16:44.666 --> 01:16:45.750
functions, so features.

559
01:16:45.958 --> 01:16:47.833
And then you just manually decided which

560
01:16:47.833 --> 01:16:49.208
ones you would box so that

561
01:16:49.208 --> 01:16:50.291
the stack wouldn't blow up.

562
01:16:50.541 --> 01:16:53.500
And those are two huge actual problems

563
01:16:53.500 --> 01:16:55.000
that people run into with Async code.

564
01:16:55.000 --> 01:16:56.666
And I'm not even talking about the build

565
01:16:56.666 --> 01:16:57.541
times and everything.

566
01:16:57.625 --> 01:16:59.083
On embedded, we run into these problems a

567
01:16:59.083 --> 01:17:00.791
lot because when you pass things by

568
01:17:00.791 --> 01:17:02.583
ownership up and down the stack, they'll

569
01:17:02.583 --> 01:17:04.416
be double, triple, quadruple the size.

570
01:17:04.625 --> 01:17:06.458
So I mean, if you are setting up, if

571
01:17:06.458 --> 01:17:07.750
you're configuring your serial port and

572
01:17:07.750 --> 01:17:09.416
you wanna give it a 20 kilobyte buffer to

573
01:17:09.416 --> 01:17:11.541
use, if you're creating that buffer and

574
01:17:11.541 --> 01:17:13.125
then passing it by ownership, it might

575
01:17:13.125 --> 01:17:14.875
show up two, three times on the stack

576
01:17:15.000 --> 01:17:16.000
because we don't have

577
01:17:16.000 --> 01:17:17.666
guaranteed RVO and things like that.

578
01:17:18.208 --> 01:17:18.583
And so-

579
01:17:19.625 --> 01:17:21.375
RVO is return value optimization.

580
01:17:21.958 --> 01:17:25.083
And that's the thing where instead of

581
01:17:25.083 --> 01:17:27.750
allocating space on the stack so that a

582
01:17:27.750 --> 01:17:29.000
function can return a value.

583
01:17:29.041 --> 01:17:32.750
Allocate space in the caller, not the

584
01:17:32.750 --> 01:17:34.625
callee, because normally what happens,

585
01:17:34.833 --> 01:17:36.958
yeah, you allocate the destination and

586
01:17:36.958 --> 01:17:38.791
then the function you call also allocates

587
01:17:38.875 --> 01:17:40.458
that on the stack and then it returns it

588
01:17:40.458 --> 01:17:43.166
by copying it from the called function

589
01:17:43.333 --> 01:17:44.625
into the calling function.

590
01:17:44.958 --> 01:17:45.791
So you have two copies of it.

591
01:17:45.791 --> 01:17:46.625
I have a simpler way to

592
01:17:46.625 --> 01:17:47.875
explain the problem, I think.

593
01:17:48.333 --> 01:17:49.750
Imagine you're making a

594
01:17:49.750 --> 01:17:52.416
very big vec from a literal.

595
01:17:52.833 --> 01:17:53.375
How does it work?

596
01:17:53.583 --> 01:17:55.458
I think if you call the vec macro, it

597
01:17:55.458 --> 01:17:57.083
first puts everything on the stack and

598
01:17:57.083 --> 01:17:58.000
then copies it to the

599
01:17:58.000 --> 01:17:59.291
heap and that's an issue.

600
01:17:59.333 --> 01:17:59.500
Yeah.

601
01:18:00.250 --> 01:18:01.625
Yeah, that's basically the idea.

602
01:18:02.375 --> 01:18:03.375
You're trying to put things on the heap

603
01:18:03.375 --> 01:18:04.500
because you don't have enough stack and

604
01:18:04.500 --> 01:18:05.875
you know that you don't have enough

605
01:18:05.875 --> 01:18:08.708
stack, but then actually it's first put

606
01:18:08.708 --> 01:18:09.875
on the stack and then copied to the heap

607
01:18:09.875 --> 01:18:11.791
by the compiler because it's not smart

608
01:18:11.791 --> 01:18:13.041
enough to figure out that it should go

609
01:18:13.041 --> 01:18:13.750
directly on the heap.

610
01:18:14.166 --> 01:18:16.208
And that's one of the forms

611
01:18:16.208 --> 01:18:17.583
of return value optimization.

612
01:18:17.916 --> 01:18:18.875
I guess really what I'm saying is I've

613
01:18:18.875 --> 01:18:20.458
already been traumatized into always

614
01:18:20.458 --> 01:18:22.000
being cognizant of where my

615
01:18:22.000 --> 01:18:23.416
data is and where it's moving.

616
01:18:23.666 --> 01:18:24.500
Yeah, but it's just like

617
01:18:24.500 --> 01:18:25.625
me saying Rust is easy.

618
01:18:25.916 --> 01:18:26.666
It is now.

619
01:18:26.666 --> 01:18:27.166
That's fair.

620
01:18:27.166 --> 01:18:29.666
And I mean, that's a fair, like maybe

621
01:18:29.666 --> 01:18:31.166
this is also sort of me figuring out

622
01:18:31.166 --> 01:18:32.708
before I read a blog post by saying it's

623
01:18:32.708 --> 01:18:34.291
easy, trying to figure out what my biases

624
01:18:34.291 --> 01:18:35.916
are of like, I've already gone through

625
01:18:35.916 --> 01:18:38.166
the trauma and learning of like when

626
01:18:38.166 --> 01:18:39.750
you're thinking about how data flows,

627
01:18:40.291 --> 01:18:41.208
part of that is thinking

628
01:18:41.208 --> 01:18:42.708
about where that data lives.

629
01:18:43.041 --> 01:18:44.458
And if you are doing something where the

630
01:18:44.458 --> 01:18:46.541
data is moving around a lot, you go, I

631
01:18:46.541 --> 01:18:47.750
should probably just put that on the heap

632
01:18:48.125 --> 01:18:49.458
because it's gonna be cheaper to pass

633
01:18:49.458 --> 01:18:51.791
around like a string or a vec than it is

634
01:18:51.791 --> 01:18:53.458
a stack allocated buffer.

635
01:18:53.708 --> 01:18:55.833
So I've never had a

636
01:18:55.833 --> 01:18:57.958
problem and don't get me wrong.

637
01:18:57.958 --> 01:18:59.500
I haven't written nearly as many

638
01:18:59.500 --> 01:19:01.958
production desktop services as a lot of

639
01:19:01.958 --> 01:19:03.625
folks who are listeners have.

640
01:19:04.041 --> 01:19:05.541
I've written a lot more embedded systems

641
01:19:05.750 --> 01:19:07.250
where you do run into similar problems,

642
01:19:07.541 --> 01:19:09.416
but you have the similar situations.

643
01:19:09.416 --> 01:19:11.791
You will preallocate buffers and pass

644
01:19:11.791 --> 01:19:13.333
around a reference to that preallocated

645
01:19:13.333 --> 01:19:14.791
buffer rather than passing the buffer

646
01:19:14.791 --> 01:19:18.500
around for both speed and, and if you

647
01:19:18.500 --> 01:19:19.833
need a buffer that's half of your total

648
01:19:19.833 --> 01:19:21.791
memory, you don't have room for two.

649
01:19:22.125 --> 01:19:22.666
You know what I mean?

650
01:19:22.958 --> 01:19:25.125
Yeah, but what they think it's the code

651
01:19:25.125 --> 01:19:26.791
ends up taking space and you have no

652
01:19:26.791 --> 01:19:28.750
idea, you write code, it

653
01:19:28.750 --> 01:19:30.041
compiles on into a state machine.

654
01:19:30.041 --> 01:19:31.000
The size of the state machine is

655
01:19:31.000 --> 01:19:33.333
completely independent of your will.

656
01:19:33.333 --> 01:19:34.708
Like it's so easy to change

657
01:19:34.708 --> 01:19:35.916
the control flow slightly.

658
01:19:36.458 --> 01:19:38.500
And then instead of having, let's say two

659
01:19:38.500 --> 01:19:41.333
variants of an enum occupy the same

660
01:19:41.333 --> 01:19:41.958
memory space cause

661
01:19:41.958 --> 01:19:42.666
there's a discriminant.

662
01:19:42.666 --> 01:19:43.375
There's very little

663
01:19:43.375 --> 01:19:45.458
optimization in future.

664
01:19:46.083 --> 01:19:47.458
Yeah, that is a big problem.

665
01:19:47.458 --> 01:19:49.208
Small changes can result in big changes

666
01:19:49.208 --> 01:19:50.416
in the size of the future.

667
01:19:50.416 --> 01:19:51.333
And it's really hard to predict.

668
01:19:51.333 --> 01:19:52.208
And it's really easy to get in those

669
01:19:52.208 --> 01:19:53.708
situations where the stack is blowing up

670
01:19:53.708 --> 01:19:55.458
and you have to go on a hunting trip to

671
01:19:55.458 --> 01:19:56.500
figure out where it comes from.

672
01:19:56.750 --> 01:19:58.125
And that happens not just to beginners.

673
01:19:58.333 --> 01:19:59.250
It's like, oh, don't do that.

674
01:19:59.250 --> 01:20:00.083
Just be careful about this.

675
01:20:00.125 --> 01:20:01.125
Which by the way, it's

676
01:20:01.125 --> 01:20:02.791
kind of antithetic to Rust.

677
01:20:02.791 --> 01:20:04.375
Rust is all about the compiler is not

678
01:20:04.375 --> 01:20:05.291
gonna let you get in trouble.

679
01:20:05.291 --> 01:20:06.041
So you don't have to worry.

680
01:20:06.333 --> 01:20:07.791
It's not like you have to follow this set

681
01:20:07.791 --> 01:20:09.541
of rules or else your

682
01:20:09.541 --> 01:20:10.416
dog's gonna get eaten.

683
01:20:10.416 --> 01:20:11.875
That's C, C++, Go, whatever.

684
01:20:12.625 --> 01:20:14.000
Rust is about guiding you and everything.

685
01:20:14.291 --> 01:20:16.666
Okay, this brings me to software is nice

686
01:20:16.666 --> 01:20:19.291
in theory, but in practice it's being

687
01:20:19.291 --> 01:20:21.541
funded by capitalism.

688
01:20:21.916 --> 01:20:22.791
This is the capitalism

689
01:20:22.791 --> 01:20:23.708
moment of the podcast.

690
01:20:24.000 --> 01:20:24.958
Everybody take a shot.

691
01:20:25.333 --> 01:20:26.083
Here's what happened.

692
01:20:27.708 --> 01:20:28.458
Async functionality

693
01:20:28.458 --> 01:20:30.666
is built on generators.

694
01:20:31.208 --> 01:20:32.625
And generators let you write functions

695
01:20:32.625 --> 01:20:34.416
that can yield values.

696
01:20:35.291 --> 01:20:37.333
You are familiar with them if you write

697
01:20:37.333 --> 01:20:38.750
Ruby code, for example, you write a

698
01:20:38.750 --> 01:20:40.375
function and then you can return, but you

699
01:20:40.375 --> 01:20:41.500
can also just yield a value.

700
01:20:41.791 --> 01:20:43.416
So you can do iterators with that.

701
01:20:43.416 --> 01:20:44.458
That's one way of doing iterators.

702
01:20:44.458 --> 01:20:46.375
You write a function that can yield one,

703
01:20:46.375 --> 01:20:47.583
two, three, four, or five and you're

704
01:20:47.583 --> 01:20:48.916
iterating over all the numbers.

705
01:20:49.541 --> 01:20:50.291
Rust doesn't do that.

706
01:20:50.291 --> 01:20:52.000
Rust has you have a type that implements

707
01:20:52.000 --> 01:20:53.958
a trade that you can call a function on

708
01:20:53.958 --> 01:20:55.208
and then it returns with a value.

709
01:20:55.250 --> 01:20:56.333
And you keep calling a

710
01:20:56.333 --> 01:20:57.791
function to return more values.

711
01:20:57.791 --> 01:20:58.958
It doesn't have this yield thing, but

712
01:20:58.958 --> 01:21:00.625
there are generators in Rust.

713
01:21:00.791 --> 01:21:02.166
They're just permanent and stable.

714
01:21:02.458 --> 01:21:03.750
They haven't been stabilized at all.

715
01:21:04.125 --> 01:21:05.458
Whereas async, which is built on top of

716
01:21:05.458 --> 01:21:07.458
generators has been stabilized.

717
01:21:07.958 --> 01:21:08.875
Why is that?

718
01:21:08.875 --> 01:21:10.791
Because there are companies with a lot of

719
01:21:10.791 --> 01:21:12.750
money who really want to be able to write

720
01:21:12.750 --> 01:21:14.625
async code and not enough company with

721
01:21:14.625 --> 01:21:15.708
not enough money who want

722
01:21:15.708 --> 01:21:16.958
to be able to use generators.

723
01:21:17.208 --> 01:21:18.791
I want to be able to use generators, but

724
01:21:18.791 --> 01:21:20.791
I can't bankroll half of the Rust

725
01:21:20.791 --> 01:21:21.833
foundation by myself.

726
01:21:22.250 --> 01:21:22.833
I wish I could.

727
01:21:23.583 --> 01:21:25.166
So really you're not

728
01:21:25.166 --> 01:21:26.541
asking for async James.

729
01:21:26.541 --> 01:21:27.625
You're asking for generators.

730
01:21:28.083 --> 01:21:29.208
And that's what I want too.

731
01:21:29.208 --> 01:21:31.166
Cause you don't really, the async part is

732
01:21:31.166 --> 01:21:33.000
kind of not necessarily relevant because

733
01:21:33.000 --> 01:21:34.458
another argument I was going to throw at

734
01:21:34.458 --> 01:21:35.458
you and I'm going to let you respond.

735
01:21:36.125 --> 01:21:37.125
I'm going to let you finish, but

736
01:21:37.125 --> 01:21:38.833
sometimes you don't

737
01:21:38.833 --> 01:21:39.916
want to pull in async.

738
01:21:39.916 --> 01:21:40.666
Sometimes all you want

739
01:21:40.666 --> 01:21:42.916
is a nice small CLI tool.

740
01:21:42.916 --> 01:21:44.208
And I've defended Rust async forever.

741
01:21:44.208 --> 01:21:46.208
So I'm really enjoying playing the other

742
01:21:46.208 --> 01:21:49.333
part today, but sometimes you just want

743
01:21:49.333 --> 01:21:52.833
something that grabs some webpage and I

744
01:21:52.833 --> 01:21:54.791
don't know parses the CSS or whatever.

745
01:21:54.791 --> 01:21:55.833
You don't want to bring

746
01:21:55.833 --> 01:21:56.833
in Tokyo and everything.

747
01:21:56.833 --> 01:21:57.958
You just want some

748
01:21:57.958 --> 01:21:59.416
bytes from the network.

749
01:22:00.083 --> 01:22:01.041
It's fine for you to

750
01:22:01.041 --> 01:22:02.083
do blocking syscalls.

751
01:22:02.083 --> 01:22:02.458
You're not doing a

752
01:22:02.458 --> 01:22:03.208
high performance server.

753
01:22:03.875 --> 01:22:05.375
People have a point that is true.

754
01:22:06.000 --> 01:22:07.625
And so if you write everything as async

755
01:22:07.625 --> 01:22:10.875
code, you can technically have actually

756
01:22:10.875 --> 01:22:12.375
synchronous code that implements async

757
01:22:12.375 --> 01:22:14.000
and if you can pretend that it's async

758
01:22:14.000 --> 01:22:15.291
but actually it blocks and

759
01:22:15.291 --> 01:22:16.458
it's going to mostly work.

760
01:22:17.125 --> 01:22:19.625
But as soon as you call something from

761
01:22:19.625 --> 01:22:22.208
Tokyo that is actually asynchronous, the

762
01:22:22.208 --> 01:22:24.458
compiler will not warn you about that.

763
01:22:24.458 --> 01:22:26.041
It will just fail at runtime and it's

764
01:22:26.041 --> 01:22:26.791
still going to bring in

765
01:22:26.791 --> 01:22:27.458
a bunch of dependencies.

766
01:22:27.750 --> 01:22:29.458
There's still no good answer to writing

767
01:22:29.458 --> 01:22:31.125
code that will work both in an

768
01:22:31.125 --> 01:22:31.958
asynchronous context

769
01:22:32.416 --> 01:22:33.375
and a synchronous context.

770
01:22:33.791 --> 01:22:35.208
And the sense IO approach is kind of the

771
01:22:35.208 --> 01:22:36.458
only way to do it right now.

772
01:22:37.083 --> 01:22:40.458
So you make a lot of really good points.

773
01:22:40.791 --> 01:22:42.083
The, the, the, the, the.

774
01:22:42.375 --> 01:22:43.458
We can take it one at a time.

775
01:22:43.458 --> 01:22:44.250
I know I said a lot.

776
01:22:44.250 --> 01:22:44.541
I'm sorry.

777
01:22:45.250 --> 01:22:46.208
No, no, no, it's okay.

778
01:22:46.375 --> 01:22:47.458
It's where do you

779
01:22:47.458 --> 01:22:48.416
start peeling the onion?

780
01:22:48.750 --> 01:22:49.833
Am I the onion in the metaphor?

781
01:22:50.333 --> 01:22:51.166
The onion is ours.

782
01:22:51.791 --> 01:22:53.000
It's emotional right now.

783
01:22:53.000 --> 01:22:53.958
We have an onion to go.

784
01:22:54.041 --> 01:22:55.000
Definitely like I see,

785
01:22:55.000 --> 01:22:56.250
I understand the desire.

786
01:22:56.541 --> 01:22:58.083
It's nice to write blocking code.

787
01:22:58.750 --> 01:23:00.291
It's especially like in terms of learning

788
01:23:00.291 --> 01:23:02.750
curve, there are deficiencies in a lot of

789
01:23:02.750 --> 01:23:05.125
things and it does require some extra

790
01:23:05.125 --> 01:23:06.708
learning and it's, it's sort of like the

791
01:23:06.708 --> 01:23:08.541
transition from like not Rust to Rust.

792
01:23:09.083 --> 01:23:10.583
You kind of get that transition again

793
01:23:10.583 --> 01:23:11.875
with Rust to async Rust.

794
01:23:11.875 --> 01:23:13.375
And I think it's oversold a lot.

795
01:23:13.375 --> 01:23:15.166
Like I'm kind of stepping carefully here

796
01:23:15.166 --> 01:23:17.166
because there's a lot of, you know,

797
01:23:17.166 --> 01:23:18.375
people go on the internet and they copy

798
01:23:18.375 --> 01:23:20.333
and paste old arguments even when those

799
01:23:20.333 --> 01:23:21.250
old arguments aren't

800
01:23:21.250 --> 01:23:22.250
necessarily true anymore.

801
01:23:22.708 --> 01:23:24.625
Async has made a lot of improvements and

802
01:23:24.625 --> 01:23:25.875
I think the learning materials and the

803
01:23:25.875 --> 01:23:27.500
tooling and the compiler have come a long

804
01:23:27.500 --> 01:23:29.125
way and there's still, you know,

805
01:23:29.125 --> 01:23:30.458
improvement to be had where we're at the

806
01:23:30.458 --> 01:23:31.041
standard of where

807
01:23:31.041 --> 01:23:32.333
we'd probably like to be.

808
01:23:32.583 --> 01:23:34.250
But also there's a lot of people copying

809
01:23:34.250 --> 01:23:36.208
and pasting arguments from five years ago

810
01:23:36.208 --> 01:23:38.208
and it's very tiring to people who are

811
01:23:38.208 --> 01:23:39.791
working on those improvements or

812
01:23:39.791 --> 01:23:41.416
libraries and things like that, where

813
01:23:41.416 --> 01:23:42.583
people are just, you're like, you don't

814
01:23:42.583 --> 01:23:44.125
know, you're just memeing right now.

815
01:23:44.416 --> 01:23:45.958
And that's frustrating.

816
01:23:46.166 --> 01:23:47.500
So part of it, that's part of why I'm

817
01:23:47.500 --> 01:23:48.166
dancing around this.

818
01:23:48.416 --> 01:23:50.000
The other one is it is just a different

819
01:23:50.000 --> 01:23:51.541
beast and I will agree with it that it is

820
01:23:51.541 --> 01:23:53.333
a different beast, but it allows for some

821
01:23:53.333 --> 01:23:56.208
very cool things like boats has good, a

822
01:23:56.208 --> 01:23:58.125
thousand good ways of describing this,

823
01:23:58.125 --> 01:24:00.291
but just being able to throw things like,

824
01:24:00.291 --> 01:24:01.791
hey, I want to slap a timeout on this and

825
01:24:01.791 --> 01:24:04.708
call dot timeout and seed controller, or

826
01:24:04.708 --> 01:24:06.666
I want to be able to concurrently run

827
01:24:06.666 --> 01:24:08.166
these and race them against each other

828
01:24:08.166 --> 01:24:10.416
and those kinds of things where it's the

829
01:24:10.416 --> 01:24:13.458
intratask concurrency, doing it for high

830
01:24:13.458 --> 01:24:16.250
performances is a reason, but it's not

831
01:24:16.250 --> 01:24:17.833
the only reason why you would use async.

832
01:24:18.291 --> 01:24:19.708
And there will be in the show notes a

833
01:24:19.708 --> 01:24:22.458
link to boats is post about intratask

834
01:24:22.458 --> 01:24:24.000
concurrency and why futures matter.

835
01:24:24.416 --> 01:24:24.625
Yeah.

836
01:24:24.750 --> 01:24:25.666
Because Amanda is the best.

837
01:24:25.958 --> 01:24:27.333
And there are things where like Tokyo

838
01:24:27.333 --> 01:24:28.833
doesn't have to be this huge dependency.

839
01:24:29.041 --> 01:24:30.375
Like it can, you can turn off a lot of

840
01:24:30.375 --> 01:24:31.375
features and you can do those.

841
01:24:31.375 --> 01:24:33.291
And yes, it is a little setup to do, but

842
01:24:33.291 --> 01:24:36.125
I have my favorite setup of Tokyo in my

843
01:24:36.125 --> 01:24:37.958
command buffer where I do, I hit control

844
01:24:37.958 --> 01:24:40.291
R cargo add Tokyo and it adds the

845
01:24:40.291 --> 01:24:41.708
features that I want to the project that

846
01:24:41.708 --> 01:24:43.583
I want and it's pretty quick to set up.

847
01:24:44.041 --> 01:24:45.500
But I mean, okay.

848
01:24:45.708 --> 01:24:48.333
So first off, I just want to say, I don't

849
01:24:48.333 --> 01:24:49.958
even have to argue with you, even though

850
01:24:49.958 --> 01:24:51.416
that's kind of what we're doing for fun.

851
01:24:51.416 --> 01:24:52.541
Just remember that we're

852
01:24:52.541 --> 01:24:53.458
friendly towards each other.

853
01:24:53.458 --> 01:24:54.208
We're not actually fighting.

854
01:24:54.708 --> 01:24:54.916
Okay.

855
01:24:55.041 --> 01:24:55.791
Don't do this at home, but

856
01:24:55.791 --> 01:24:56.250
we're not actually fighting.

857
01:24:56.250 --> 01:24:57.541
We both probably mostly agree on all of

858
01:24:57.541 --> 01:24:58.333
these points, but it's

859
01:24:58.333 --> 01:25:00.333
interesting to dance around.

860
01:25:00.375 --> 01:25:01.708
But I think I don't have to argue with

861
01:25:01.708 --> 01:25:02.958
you because I can just wait two years and

862
01:25:02.958 --> 01:25:04.041
one of two things will happen.

863
01:25:04.041 --> 01:25:06.833
One, you will feel the pain of your

864
01:25:06.833 --> 01:25:09.041
growing application with async code and

865
01:25:09.041 --> 01:25:11.250
figure out that it's not just beginners.

866
01:25:11.458 --> 01:25:13.250
It's not just four years ago.

867
01:25:13.250 --> 01:25:14.291
It is like current Ross

868
01:25:14.291 --> 01:25:15.791
that has very real problems.

869
01:25:15.791 --> 01:25:16.791
And then you will see

870
01:25:16.791 --> 01:25:17.583
that I'm actually right.

871
01:25:17.625 --> 01:25:19.750
Or the compiler will get so much better

872
01:25:19.958 --> 01:25:21.416
that it will make me wrong.

873
01:25:21.958 --> 01:25:23.291
And in either case, I will be happy

874
01:25:23.291 --> 01:25:24.416
because I'll be either right

875
01:25:24.416 --> 01:25:25.875
or the world will be better.

876
01:25:26.166 --> 01:25:27.000
So I went either way.

877
01:25:27.458 --> 01:25:29.625
I think the thing that is frustrating me

878
01:25:29.625 --> 01:25:31.458
the most right now is that most of my

879
01:25:31.458 --> 01:25:34.791
responses to this are that it requires

880
01:25:34.791 --> 01:25:37.916
attention to how you design your systems.

881
01:25:38.125 --> 01:25:39.958
Like one of the things that I said at the

882
01:25:39.958 --> 01:25:42.041
last talk I gave was, sometimes the

883
01:25:42.041 --> 01:25:43.791
problem with a good tool is that you use

884
01:25:43.791 --> 01:25:45.958
it too far beyond what it should be used

885
01:25:45.958 --> 01:25:47.291
because it's so pleasant to use.

886
01:25:47.583 --> 01:25:49.333
And I think async can do that where you

887
01:25:49.333 --> 01:25:52.375
do still have to think, I don't totally

888
01:25:52.375 --> 01:25:53.916
buy the thing of async is

889
01:25:53.916 --> 01:25:55.125
just like blocking code.

890
01:25:55.125 --> 01:25:55.958
Like it's straight line,

891
01:25:55.958 --> 01:25:56.708
you don't have to think about.

892
01:25:56.958 --> 01:25:58.958
I do think from a systems perspective,

893
01:25:58.958 --> 01:26:00.958
you have to think about what your code is

894
01:26:00.958 --> 01:26:03.000
doing, how you architect it, where the

895
01:26:03.000 --> 01:26:04.666
data is stored, where the data is going,

896
01:26:05.041 --> 01:26:05.708
where you draw the

897
01:26:05.708 --> 01:26:06.833
lines of things like that.

898
01:26:06.833 --> 01:26:07.666
And I think that's like a

899
01:26:07.666 --> 01:26:09.208
systems design question.

900
01:26:09.625 --> 01:26:11.833
And I don't think you are well-served by

901
01:26:11.833 --> 01:26:13.375
pretending that blocking code and async

902
01:26:13.375 --> 01:26:14.375
code are the same,

903
01:26:14.375 --> 01:26:15.583
because I don't think they are.

904
01:26:15.958 --> 01:26:17.583
They're very similar and it's nice that

905
01:26:17.583 --> 01:26:18.791
you can do that, but I think that's sort

906
01:26:18.791 --> 01:26:20.291
of a misfeature of that.

907
01:26:20.500 --> 01:26:21.958
But it is one of those things that I've

908
01:26:21.958 --> 01:26:24.708
been doing, you know, async on desktop

909
01:26:24.708 --> 01:26:26.291
for maybe two or three years for

910
01:26:26.291 --> 01:26:28.208
relatively different sized applications

911
01:26:28.208 --> 01:26:30.333
and async on embedded for maybe four

912
01:26:30.333 --> 01:26:31.250
years or something like that.

913
01:26:31.250 --> 01:26:32.333
And I really did have a

914
01:26:32.333 --> 01:26:33.291
learning curve of that.

915
01:26:33.541 --> 01:26:35.125
But I think that's the same kind of thing

916
01:26:35.125 --> 01:26:37.250
in desktop Rust is like you're saying

917
01:26:37.250 --> 01:26:38.916
with recursion, you can blow your stack

918
01:26:38.916 --> 01:26:40.125
and recursion very easily,

919
01:26:40.583 --> 01:26:41.666
and you'll have to learn that.

920
01:26:41.666 --> 01:26:43.625
Or you have to learn that you need to

921
01:26:43.625 --> 01:26:46.000
lock stdio before you print, or otherwise

922
01:26:46.000 --> 01:26:47.416
all of your benchmarks are very silly.

923
01:26:47.708 --> 01:26:49.958
Or there are definitely like systemic

924
01:26:49.958 --> 01:26:51.458
things that you need to learn.

925
01:26:51.666 --> 01:26:54.083
And I do think that they're higher for

926
01:26:54.083 --> 01:26:56.541
async, but I think it's-- I don't know.

927
01:26:56.541 --> 01:26:58.458
I don't like that my answers get good,

928
01:26:58.458 --> 01:26:59.666
because that's not a good answer and it's

929
01:26:59.666 --> 01:27:00.958
not really a scalable answer.

930
01:27:00.958 --> 01:27:02.166
And I disagree.

931
01:27:02.458 --> 01:27:04.416
I disagree with you, James, and that's

932
01:27:04.416 --> 01:27:05.125
beautiful, because

933
01:27:05.125 --> 01:27:06.375
that makes a good podcast.

934
01:27:06.750 --> 01:27:08.666
Because I don't think it's very honest,

935
01:27:08.666 --> 01:27:10.333
because I think if we're adding async

936
01:27:10.333 --> 01:27:12.000
functions and we're telling everyone

937
01:27:12.000 --> 01:27:13.125
they're exactly like synchronous

938
01:27:13.125 --> 01:27:14.000
functions, except you

939
01:27:14.958 --> 01:27:16.083
sometimes have to know how to run.

940
01:27:16.666 --> 01:27:18.875
But the goal, with each addition of

941
01:27:18.875 --> 01:27:20.666
features, was to be OK, so that thing

942
01:27:20.666 --> 01:27:22.000
that used to not be possible with async

943
01:27:22.000 --> 01:27:23.541
code is now possible with async code.

944
01:27:23.541 --> 01:27:25.458
There's a clear trend to making you be

945
01:27:25.458 --> 01:27:26.833
able to do everything you can do with

946
01:27:26.833 --> 01:27:28.583
synchronous code also do

947
01:27:28.583 --> 01:27:29.875
with asynchronous code.

948
01:27:30.333 --> 01:27:31.875
So clearly the aim is for you

949
01:27:31.875 --> 01:27:33.625
to not have to worry about it.

950
01:27:33.625 --> 01:27:34.291
The fact that you can't

951
01:27:34.291 --> 01:27:35.708
do recursion is a problem.

952
01:27:36.416 --> 01:27:37.833
There's a bunch of new things that were

953
01:27:37.833 --> 01:27:39.666
added recently that lets

954
01:27:39.666 --> 01:27:41.916
you do lending iterators.

955
01:27:41.916 --> 01:27:42.541
What did we have recently?

956
01:27:42.875 --> 01:27:43.500
We had Gatsk.

957
01:27:44.208 --> 01:27:44.958
Async closures.

958
01:27:45.541 --> 01:27:47.000
Those things made sense.

959
01:27:47.458 --> 01:27:48.041
Everybody thought that

960
01:27:48.041 --> 01:27:49.708
it wasn't a big invention.

961
01:27:50.125 --> 01:27:51.166
Everybody wanted them.

962
01:27:51.583 --> 01:27:53.208
They were just hard to implement in the

963
01:27:53.208 --> 01:27:55.166
compiler, because it's not

964
01:27:55.166 --> 01:27:56.500
a trivial transform at all.

965
01:27:56.500 --> 01:27:57.333
And there's this

966
01:27:57.333 --> 01:27:58.583
borrow checking involved.

967
01:27:58.666 --> 01:28:00.416
It's really complicated when you get into

968
01:28:00.416 --> 01:28:01.583
the details of how it's implemented.

969
01:28:01.833 --> 01:28:02.958
But everything made sense.

970
01:28:03.291 --> 01:28:03.958
From the moment you were

971
01:28:03.958 --> 01:28:05.625
like, OK, we can make this async.

972
01:28:05.625 --> 01:28:07.625
We can make an await point actually

973
01:28:07.625 --> 01:28:10.791
return and then come back to the exact

974
01:28:10.791 --> 01:28:11.625
same state in the function.

975
01:28:12.250 --> 01:28:13.958
The whole universe of possibilities of

976
01:28:13.958 --> 01:28:14.500
what we could do with

977
01:28:14.500 --> 01:28:16.333
async Rust was already drawn.

978
01:28:16.833 --> 01:28:17.916
And the fact that some of

979
01:28:17.916 --> 01:28:19.333
it is currently problematic.

980
01:28:19.583 --> 01:28:20.041
You can't recurse.

981
01:28:20.541 --> 01:28:22.166
Sometimes the features get

982
01:28:22.166 --> 01:28:23.208
too big and the stack blows up.

983
01:28:23.208 --> 01:28:24.250
You have to debug that.

984
01:28:24.250 --> 01:28:25.291
It's a compiler bug.

985
01:28:25.750 --> 01:28:26.958
It's not-- people are being unreasonable

986
01:28:26.958 --> 01:28:28.500
and asking too much of async Rust.

987
01:28:28.500 --> 01:28:29.958
It's like, this should be fixed.

988
01:28:29.958 --> 01:28:31.708
But because we live in the real world

989
01:28:31.708 --> 01:28:33.083
with limited resources and limited

990
01:28:33.083 --> 01:28:36.208
funding, it's good enough that the

991
01:28:36.208 --> 01:28:38.916
biggest users of async Rust are kind of

992
01:28:38.916 --> 01:28:40.583
OK with where it's at.

993
01:28:40.625 --> 01:28:42.333
And things are making slow progress.

994
01:28:42.333 --> 01:28:43.291
But there's no big rush

995
01:28:43.291 --> 01:28:44.875
because you can already do so much.

996
01:28:44.875 --> 01:28:46.375
Like you say, if you just like sometimes

997
01:28:46.375 --> 01:28:48.041
you run into corner cases and you just

998
01:28:48.041 --> 01:28:49.000
kind of work around them.

999
01:28:49.583 --> 01:28:50.458
But as far as I'm

1000
01:28:50.458 --> 01:28:51.416
concerned, it's a compiler bug.

1001
01:28:51.416 --> 01:28:55.083
It's just like the last x% are the

1002
01:28:55.083 --> 01:28:57.250
hardest because some of them involve

1003
01:28:57.250 --> 01:28:58.791
fundamental changes to the compiler.

1004
01:28:59.291 --> 01:28:59.750
Yeah.

1005
01:28:59.750 --> 01:29:00.958
I don't entirely disagree.

1006
01:29:00.958 --> 01:29:02.125
And I do think a lot of

1007
01:29:02.125 --> 01:29:02.958
those should be better.

1008
01:29:02.958 --> 01:29:03.958
I think-- I don't know.

1009
01:29:04.166 --> 01:29:06.625
Some of them are given more-- or they

1010
01:29:06.625 --> 01:29:07.250
seem like more of a

1011
01:29:07.250 --> 01:29:08.083
problem than they are.

1012
01:29:08.083 --> 01:29:08.625
Well, I don't know.

1013
01:29:08.625 --> 01:29:09.958
I think you just got lucky and you just

1014
01:29:10.041 --> 01:29:11.750
didn't run into too many of those yet.

1015
01:29:11.958 --> 01:29:12.625
I think we should check

1016
01:29:12.625 --> 01:29:13.958
in with you in six months.

1017
01:29:14.166 --> 01:29:15.458
I mean, I'm happy to.

1018
01:29:15.666 --> 01:29:17.166
But I mean, Postation has been

1019
01:29:17.166 --> 01:29:18.958
exceedingly pleasant to develop.

1020
01:29:18.958 --> 01:29:21.833
And even though my database is a blocking

1021
01:29:21.833 --> 01:29:23.500
database-- so I'm using Fyall as my

1022
01:29:23.500 --> 01:29:24.916
database and Fyall is blocking.

1023
01:29:25.333 --> 01:29:28.041
But I mean, there are ways to develop

1024
01:29:28.041 --> 01:29:29.375
that where it becomes not

1025
01:29:29.375 --> 01:29:30.458
particularly challenging.

1026
01:29:30.541 --> 01:29:32.125
Or it is blocking, but it's a

1027
01:29:32.125 --> 01:29:33.083
transactional database.

1028
01:29:33.291 --> 01:29:34.625
And my queries aren't large.

1029
01:29:34.625 --> 01:29:36.375
And I'm not recursing over those.

1030
01:29:36.375 --> 01:29:37.708
Most of my blocking queries are

1031
01:29:37.708 --> 01:29:39.916
insertions only and things like that.

1032
01:29:40.708 --> 01:29:42.000
I think you're in the honeymoon period.

1033
01:29:42.375 --> 01:29:44.083
And you're trying to-- I just have to

1034
01:29:44.083 --> 01:29:46.041
disagree with people who run into

1035
01:29:46.041 --> 01:29:48.083
problems just don't know enough or they

1036
01:29:48.083 --> 01:29:49.666
had older Rust versions.

1037
01:29:50.083 --> 01:29:51.000
I just disagree with that.

1038
01:29:51.791 --> 01:29:53.583
I guess the point that I'm really trying

1039
01:29:53.583 --> 01:29:56.416
to make is that Sanzio forces you to

1040
01:29:56.416 --> 01:29:58.833
disregard all of the benefits of async

1041
01:29:58.833 --> 01:30:01.625
for the cost of compatibility.

1042
01:30:02.041 --> 01:30:03.291
And it's one of those challenging things.

1043
01:30:03.291 --> 01:30:04.916
Because when it comes to making sure that

1044
01:30:04.916 --> 01:30:07.208
your state machines are clear and correct

1045
01:30:07.208 --> 01:30:09.666
and things like that, it's way easier to

1046
01:30:09.666 --> 01:30:12.416
lose things in the diff of a very large

1047
01:30:12.416 --> 01:30:13.625
set of match statements

1048
01:30:13.625 --> 01:30:15.083
rather than linear code.

1049
01:30:15.416 --> 01:30:15.875
But generators.

1050
01:30:17.041 --> 01:30:18.500
It's not the answer you expected.

1051
01:30:18.791 --> 01:30:20.125
But I want you to take a minute.

1052
01:30:20.375 --> 01:30:21.333
No, I'm very familiar with generators.

1053
01:30:21.833 --> 01:30:22.458
Think about it.

1054
01:30:22.458 --> 01:30:23.958
And I do think there are some cases where

1055
01:30:23.958 --> 01:30:25.625
they absolutely would be the thing that

1056
01:30:25.625 --> 01:30:26.500
you want, like being

1057
01:30:26.500 --> 01:30:27.916
able to have possible--

1058
01:30:27.916 --> 01:30:29.041
Because your main argument is it sucks

1059
01:30:29.041 --> 01:30:30.333
the right state machines in

1060
01:30:30.333 --> 01:30:32.000
Rust, which is absolutely true.

1061
01:30:32.000 --> 01:30:32.958
I've written a bunch.

1062
01:30:33.208 --> 01:30:33.791
I know that.

1063
01:30:34.125 --> 01:30:34.833
You just do macros.

1064
01:30:35.166 --> 01:30:35.583
It is, but I prefer protocols.

1065
01:30:35.875 --> 01:30:36.791
So I'm very heavy in

1066
01:30:36.791 --> 01:30:37.791
protocol stuff right now.

1067
01:30:37.833 --> 01:30:41.166
You do really want to say, I want to send

1068
01:30:41.166 --> 01:30:42.375
something and await the result.

1069
01:30:42.541 --> 01:30:44.125
And I want to timeout, or I

1070
01:30:44.125 --> 01:30:45.500
want to receive the result.

1071
01:30:45.916 --> 01:30:49.625
And if-- or I want to basically mux on a

1072
01:30:49.625 --> 01:30:52.125
timeout occurs, a wrong message comes in,

1073
01:30:52.125 --> 01:30:54.750
a correct message comes in, or a giant

1074
01:30:54.750 --> 01:30:56.875
cancellation flag, or some external

1075
01:30:56.875 --> 01:30:57.500
signal has been

1076
01:30:57.500 --> 01:30:58.500
received and things like that.

1077
01:30:58.791 --> 01:31:00.541
And you really do want to be able to say,

1078
01:31:00.541 --> 01:31:02.875
OK, I'm going to receive.await, and then

1079
01:31:02.875 --> 01:31:03.833
I'm going to do a select

1080
01:31:03.833 --> 01:31:05.916
statement on three items.

1081
01:31:05.958 --> 01:31:08.041
And I think I'd agree with you in that

1082
01:31:08.041 --> 01:31:10.708
you could cover a fairly large subset, or

1083
01:31:10.708 --> 01:31:11.625
Sanzio could be made

1084
01:31:11.625 --> 01:31:12.791
much better with generators.

1085
01:31:13.458 --> 01:31:15.083
I would definitely agree with you on

1086
01:31:15.083 --> 01:31:15.958
that, in that you could

1087
01:31:15.958 --> 01:31:17.458
boil your state down to that.

1088
01:31:17.458 --> 01:31:19.250
But I guess what I'm saying is you can

1089
01:31:19.250 --> 01:31:22.000
get a lot of the benefit by having good

1090
01:31:22.000 --> 01:31:24.000
abstractions for things like that, and

1091
01:31:24.000 --> 01:31:26.083
that sometimes existing abstractions are

1092
01:31:26.083 --> 01:31:28.000
not great, and they force you into

1093
01:31:28.000 --> 01:31:29.250
corners that end up

1094
01:31:29.250 --> 01:31:30.458
making things more challenging.

1095
01:31:30.958 --> 01:31:32.416
Whether Async can improve or not, I

1096
01:31:32.416 --> 01:31:33.583
think, I'll agree with you.

1097
01:31:33.750 --> 01:31:34.541
I absolutely can.

1098
01:31:35.291 --> 01:31:37.416
But also that I think there is some level

1099
01:31:37.416 --> 01:31:39.000
of people are more scared

1100
01:31:39.000 --> 01:31:40.375
than the actual level there.

1101
01:31:40.708 --> 01:31:41.458
But again, maybe I just

1102
01:31:41.458 --> 01:31:42.916
haven't seen the right horrors yet.

1103
01:31:42.916 --> 01:31:44.166
The thing that I'm really getting at is

1104
01:31:44.166 --> 01:31:45.750
that I've seen a glimpse of something

1105
01:31:45.750 --> 01:31:47.750
that can be really pleasant in Async, and

1106
01:31:47.750 --> 01:31:49.375
writing protocol design, particularly

1107
01:31:49.375 --> 01:31:50.958
designing my own protocol from scratch

1108
01:31:51.291 --> 01:31:53.666
with Async Rust in mind to begin with,

1109
01:31:54.041 --> 01:31:55.750
and designing data structures around

1110
01:31:55.750 --> 01:31:58.791
that, and designing interactions with the

1111
01:31:58.791 --> 01:32:00.708
understanding of, hey, I know I'm going

1112
01:32:00.708 --> 01:32:03.291
to need a timeout or error or success and

1113
01:32:03.291 --> 01:32:06.041
being able to really natively encode that

1114
01:32:06.041 --> 01:32:07.958
as Async logic has been

1115
01:32:07.958 --> 01:32:08.958
tremendously pleasant.

1116
01:32:09.208 --> 01:32:10.791
And just thinking about how I would do

1117
01:32:10.791 --> 01:32:12.791
all that, if I had to turn everything

1118
01:32:12.791 --> 01:32:15.375
inside out to do Sans I.O., is one of

1119
01:32:15.375 --> 01:32:16.750
those really challenging things to me,

1120
01:32:16.750 --> 01:32:18.250
because I don't think it

1121
01:32:18.250 --> 01:32:19.541
would be nearly as pleasant.

1122
01:32:19.875 --> 01:32:21.750
And maybe this is the benefit of

1123
01:32:21.750 --> 01:32:23.958
designing something simple from scratch

1124
01:32:23.958 --> 01:32:26.541
with Async in mind to begin with, rather

1125
01:32:26.541 --> 01:32:28.708
than something that was encoded 20 years

1126
01:32:28.708 --> 01:32:31.500
ago from an RFC that has so many edge

1127
01:32:31.500 --> 01:32:33.000
cases and performance

1128
01:32:33.000 --> 01:32:34.375
impacts and things like that.

1129
01:32:34.791 --> 01:32:36.166
I think there's some hesitation to be

1130
01:32:36.166 --> 01:32:38.875
made instead of always going with Sans

1131
01:32:38.875 --> 01:32:40.125
I.O., because I think there is some

1132
01:32:40.125 --> 01:32:41.666
really interesting and clever and

1133
01:32:41.666 --> 01:32:43.250
pleasant, and really things that make

1134
01:32:43.250 --> 01:32:45.250
your code easier to read and more robust

1135
01:32:46.125 --> 01:32:47.875
if you address them as Async challenges

1136
01:32:47.875 --> 01:32:50.166
to begin with, instead of always sort of

1137
01:32:50.166 --> 01:32:53.166
landing on Sans I.O., even though it is a

1138
01:32:53.166 --> 01:32:55.166
very good tool in very specific cases.

1139
01:32:56.125 --> 01:32:57.458
Now that I'm done playing Devil's

1140
01:32:57.458 --> 01:32:59.125
Advocate, I will agree with you that,

1141
01:32:59.125 --> 01:33:01.000
one, it's not that bad

1142
01:33:01.000 --> 01:33:02.000
to write Async Rust code.

1143
01:33:02.041 --> 01:33:03.166
I've been writing

1144
01:33:03.166 --> 01:33:04.666
that for three years now.

1145
01:33:05.166 --> 01:33:08.083
So another very interesting read you can

1146
01:33:08.083 --> 01:33:09.583
have that is going to be in the show

1147
01:33:09.583 --> 01:33:12.583
notes is an article from the maintainer

1148
01:33:12.583 --> 01:33:16.125
of Cargo Next Test, Rain, who explains

1149
01:33:16.125 --> 01:33:19.333
why Cargo Next Test, how Cargo Next Test

1150
01:33:19.333 --> 01:33:22.000
uses Async and how it would be so hard to

1151
01:33:22.000 --> 01:33:24.583
do that using synchronous syscalls, it

1152
01:33:24.583 --> 01:33:25.125
would not be possible.

1153
01:33:25.375 --> 01:33:28.166
So the Next Test uses Tokyo very, very

1154
01:33:28.166 --> 01:33:29.500
efficiently, not

1155
01:33:29.500 --> 01:33:31.708
efficiently, it's great effect.

1156
01:33:31.958 --> 01:33:32.375
Effectively.

1157
01:33:34.333 --> 01:33:38.500
Finally, I wanna say that my, if you give

1158
01:33:38.500 --> 01:33:41.958
up the idea of having nice, light,

1159
01:33:41.958 --> 01:33:44.166
synchronous binaries, and you're all in

1160
01:33:44.166 --> 01:33:46.041
Async land, you've just kind of accepted

1161
01:33:46.041 --> 01:33:47.541
you're gonna have some sort of runtime,

1162
01:33:48.041 --> 01:33:49.916
then I think I would be fine if we all

1163
01:33:49.916 --> 01:33:52.750
standardized on an IOU ring compatible

1164
01:33:52.750 --> 01:33:55.958
abstraction because if you have that, you

1165
01:33:55.958 --> 01:33:58.208
can implement, you can implement that

1166
01:33:58.208 --> 01:33:59.916
interface efficiently on top of something

1167
01:33:59.916 --> 01:34:00.625
like Tokyo, but you

1168
01:34:00.625 --> 01:34:01.458
cannot do the reverse.

1169
01:34:02.041 --> 01:34:02.750
So one of them is strictly

1170
01:34:02.750 --> 01:34:04.083
more flexible than the other.

1171
01:34:05.083 --> 01:34:08.125
So I'm just really sad that Tokyo, like

1172
01:34:08.125 --> 01:34:09.875
the current Async retrades in the Rust

1173
01:34:09.875 --> 01:34:11.875
ecosystem are the de facto standard

1174
01:34:11.875 --> 01:34:12.708
because you cannot do

1175
01:34:12.708 --> 01:34:13.333
your ring with them.

1176
01:34:13.791 --> 01:34:16.125
So if we could standardize on that, then

1177
01:34:16.125 --> 01:34:17.791
we'd notice, or if we have a frame based

1178
01:34:17.791 --> 01:34:19.291
interface, like you're doing with

1179
01:34:19.291 --> 01:34:21.208
PostgreSQL, then that's fine too, because

1180
01:34:21.208 --> 01:34:22.333
it's also flexible enough.

1181
01:34:22.416 --> 01:34:23.958
I think people should be less afraid to

1182
01:34:23.958 --> 01:34:25.125
define their own interfaces.

1183
01:34:25.416 --> 01:34:26.541
I think there's something very powerful

1184
01:34:26.541 --> 01:34:29.458
of going, look, portability is fine, and

1185
01:34:29.458 --> 01:34:31.166
if people want to polyfill portability

1186
01:34:31.166 --> 01:34:32.750
onto this, but there's something to be

1187
01:34:32.750 --> 01:34:35.250
said about defining exactly the interface

1188
01:34:35.250 --> 01:34:37.875
you actually want and to use that.

1189
01:34:37.875 --> 01:34:39.375
Because I think that's one of the things

1190
01:34:39.375 --> 01:34:40.583
that I've done in my projects, and I

1191
01:34:40.583 --> 01:34:43.125
found there's a time for portability and

1192
01:34:43.125 --> 01:34:44.416
there's a time for being specific.

1193
01:34:44.958 --> 01:34:46.666
And I think getting that right, I think

1194
01:34:46.666 --> 01:34:48.125
goes a really long way.

1195
01:34:48.125 --> 01:34:49.916
Because like I said, if I can say frames

1196
01:34:49.916 --> 01:34:51.416
or frames, it doesn't matter whether it's

1197
01:34:51.416 --> 01:34:54.458
IOU ring or blocking IO, well, you

1198
01:34:54.458 --> 01:34:56.333
probably couldn't use blocking IO, but it

1199
01:34:56.333 --> 01:34:57.583
doesn't really matter how it gets there.

1200
01:34:57.583 --> 01:34:58.458
I say, that's your problem.

1201
01:34:58.500 --> 01:35:00.208
I'm saying what I need, and you're

1202
01:35:00.208 --> 01:35:01.583
telling me how you want to do it, which

1203
01:35:01.583 --> 01:35:03.500
gives a lot of customization back to the

1204
01:35:03.500 --> 01:35:05.750
integrator, which I think it helps a lot

1205
01:35:05.750 --> 01:35:06.541
of these challenges.

1206
01:35:06.916 --> 01:35:08.791
My mind immediately goes to Tokyo Rust

1207
01:35:08.791 --> 01:35:11.500
LS, which is a very leaky abstraction,

1208
01:35:11.958 --> 01:35:14.541
because TLS is not just the TCP sockets.

1209
01:35:15.041 --> 01:35:17.875
There's a side, what is it called?

1210
01:35:17.875 --> 01:35:18.708
There's events, there's

1211
01:35:18.708 --> 01:35:19.791
alerts that can happen.

1212
01:35:20.208 --> 01:35:21.500
You can know when the

1213
01:35:21.500 --> 01:35:22.500
keys are being rotated.

1214
01:35:22.791 --> 01:35:24.208
You can know where there's some sort of

1215
01:35:24.208 --> 01:35:25.041
exception or whatever.

1216
01:35:25.375 --> 01:35:26.208
And that's not part of

1217
01:35:26.208 --> 01:35:27.083
the async rate interface.

1218
01:35:27.666 --> 01:35:29.500
So on Linux, you have a file descriptor,

1219
01:35:29.500 --> 01:35:30.000
and then you have

1220
01:35:30.000 --> 01:35:31.541
some way to get to that.

1221
01:35:31.541 --> 01:35:33.083
I think it's called ancillary data.

1222
01:35:33.083 --> 01:35:34.041
I don't know exactly.

1223
01:35:34.791 --> 01:35:35.541
But essentially, it's not

1224
01:35:35.541 --> 01:35:37.750
just bytes go in, bytes come out.

1225
01:35:38.208 --> 01:35:40.500
There's control data, there's things on

1226
01:35:40.500 --> 01:35:42.666
the side, and that's completely lost in

1227
01:35:42.666 --> 01:35:44.791
the Tokyo Rust LS abstraction and other

1228
01:35:44.791 --> 01:35:45.875
Rust LS abstractions.

1229
01:35:46.458 --> 01:35:48.541
But it's not in the Rust LS crate, which

1230
01:35:48.541 --> 01:35:49.750
does implement the protocol

1231
01:35:49.750 --> 01:35:51.666
in some form of sense IOUA.

1232
01:35:51.916 --> 01:35:54.166
So yeah, I would agree with you there.

1233
01:35:54.583 --> 01:35:55.083
Well, then here's to

1234
01:35:55.083 --> 01:35:55.875
the honeymoon period.

1235
01:35:56.291 --> 01:35:56.833
(Laughing)

1236
01:35:57.458 --> 01:35:58.541
And we'll check back on

1237
01:35:58.541 --> 01:36:00.250
you in six to 12 months.

1238
01:36:00.416 --> 01:36:01.375
Yeah, we'll do the follow-up.

1239
01:36:01.375 --> 01:36:01.958
I think that'll be good.

1240
01:36:01.958 --> 01:36:02.458
Season three.

1241
01:36:02.708 --> 01:36:03.250
We will.

1242
01:36:03.500 --> 01:36:05.166
Beautiful, that was a cool ending.

1243
01:36:06.458 --> 01:36:06.958
(Laughing)

1244
01:36:07.625 --> 01:36:09.375
Also long fucking honeymoon, man.

1245
01:36:09.416 --> 01:36:09.666
Cheers.

1246
01:36:10.833 --> 01:36:14.291
(Upbeat Music)

1247
01:36:19.041 --> 01:36:20.791
This episode is sponsored by Depot, the

1248
01:36:20.791 --> 01:36:22.375
build acceleration platform that's on a

1249
01:36:22.375 --> 01:36:24.375
mission to make all builds near instant.

1250
01:36:24.666 --> 01:36:25.833
If you're tired of watching your builds

1251
01:36:25.958 --> 01:36:27.291
and GitHub actions crawl like the modern

1252
01:36:27.291 --> 01:36:29.208
day equivalent of paint drying, give

1253
01:36:29.208 --> 01:36:31.041
Depot's GitHub actions runners a try.

1254
01:36:31.416 --> 01:36:33.083
They're up to 10X faster with unlimited

1255
01:36:33.083 --> 01:36:35.291
concurrency, faster caching, support for

1256
01:36:35.291 --> 01:36:37.083
Linux, macOS, and Windows, and they plug

1257
01:36:37.083 --> 01:36:38.916
right into other Depot optimizations like

1258
01:36:38.916 --> 01:36:40.583
accelerated container image builds and

1259
01:36:40.583 --> 01:36:41.791
remote caching for Bazel,

1260
01:36:42.083 --> 01:36:43.791
TurboRepo, Gradle, and more.

1261
01:36:44.125 --> 01:36:45.500
Depot was built by developers who were

1262
01:36:45.500 --> 01:36:46.958
tired of wasting time waiting on builds

1263
01:36:46.958 --> 01:36:47.625
instead of shipping.

1264
01:36:47.958 --> 01:36:49.375
It's made for teams that wanna move

1265
01:36:49.375 --> 01:36:50.458
faster and stay focused

1266
01:36:50.458 --> 01:36:51.708
on what actually matters.

1267
01:36:52.000 --> 01:36:53.541
That's why companies like Posthog use

1268
01:36:53.541 --> 01:36:55.416
Depot to cut build times from over three

1269
01:36:55.416 --> 01:36:57.458
hours to just three minutes, saving tens

1270
01:36:57.458 --> 01:36:59.083
of thousands of build hours every week.

1271
01:36:59.375 --> 01:37:00.916
Start your free seven-day trial at

1272
01:37:00.916 --> 01:37:02.583
depot.dev and let them know we sent you.

1273
01:37:03.958 --> 01:37:06.583
(Upbeat Music)
