@@ -180,13 +180,18 @@ Test Passed
180
180
181
181
## Toplevel code and world age
182
182
183
- Some code is more complicated and requires special handling: code that defines new `struct`s,
184
- new methods, or new modules . In such cases, calling `finish_and_return!` on a frame that
183
+ Code that defines new `struct`s, new methods, or new modules is a bit more complicated
184
+ and requires special handling . In such cases, calling `finish_and_return!` on a frame that
185
185
defines these new objects and then calls them can trigger a
186
186
[world age error](https://docs.julialang.org/en/latest/manual/methods/#Redefining-Methods-1),
187
187
in which the method is considered to be too new to be run by the currently compiled code.
188
+ While one can resolve this by using `Base.invokelatest`, we'd have to use that strategy
189
+ throughout the entire package. This would cause a major reduction in performance.
190
+ To resolve this issue without leading to performance problems, care is required to
191
+ return to "top level" after defining such objects. This leads to altered syntax for executing
192
+ such expressions.
188
193
189
- In such cases care is required to return to "top level" before continuing. Here's a demonstration:
194
+ Here's a demonstration of the problem :
190
195
191
196
``` julia
192
197
ex = :(map (x-> x^ 2 , [1 , 2 , 3 ]))
@@ -195,7 +200,7 @@ julia> JuliaInterpreter.finish_and_return!(JuliaStackFrame[], frame)
195
200
ERROR: this frame needs to be run a top level
196
201
```
197
202
198
- The reason becomes clearer if we examine `frame` or look directly at the lowered code:
203
+ The reason for this error becomes clearer if we examine `frame` or look directly at the lowered code:
199
204
200
205
``` julia
201
206
julia> Meta. lower (Main, ex)
@@ -223,10 +228,11 @@ end)))
223
228
))))
224
229
```
225
230
226
- All of the code before `%7` is devoted to defining the anonymous function `x->x^2`: it creates a new "anonymous type"
227
- (here written as `##17#18`), and then defines a call function for this type, equivalent to `(##17#18)(x) = x^2`.
231
+ All of the code before the `%7` line is devoted to defining the anonymous function `x->x^2`:
232
+ it creates a new "anonymous type" (here written as `##17#18`), and then defines a "call
233
+ function" for this type, equivalent to `(##17#18)(x) = x^2`.
228
234
229
- The easy way to fix this is to simply add a flag :
235
+ In some cases one can fix this simply by indicating that we want to run this frame at top level :
230
236
231
237
``` julia
232
238
julia> JuliaInterpreter. finish_and_return! (JuliaStackFrame[], frame, true )
@@ -236,7 +242,8 @@ julia> JuliaInterpreter.finish_and_return!(JuliaStackFrame[], frame, true)
236
242
9
237
243
```
238
244
239
- Here's a more fine-grained look at what's happening under the hood:
245
+ Here's a more fine-grained look at what's happening under the hood (and a robust strategy
246
+ for more complex situations where there may be nested calls of new methods):
240
247
241
248
``` julia
242
249
modexs, _ = JuliaInterpreter. prepare_toplevel (Main, ex)
@@ -255,15 +262,6 @@ Then, each frame is executed until it finishes defining a new method, then retur
255
262
The return to top level causes an update in the world age.
256
263
If the frame hasn't been finished yet (if the return value wasn't `nothing`),
257
264
this continues executing where it left off.
258
- You can extract the return value with
259
-
260
- ``` julia
261
- julia> JuliaInterpreter. get_return (frames[end ])
262
- 3 - element Array{Int64,1 }:
263
- 1
264
- 4
265
- 9
266
- ```
267
265
268
266
(Incidentally, `JuliaInterpreter.enter_call(map, x->x^2, [1, 2, 3])` works fine on its own,
269
267
because the anonymous function is defined by the caller---you'll see that the created frame
0 commit comments