Skip to content

Commit 9e323a5

Browse files
Kenoararslannickrobinson251
authored andcommitted
Add manual chapter on world age and binding partition (#58253)
Co-authored-by: Alex Arslan <ararslan@comcast.net> Co-authored-by: Nick Robinson <npr251@gmail.com>
1 parent 191fc25 commit 9e323a5

File tree

4 files changed

+360
-68
lines changed

4 files changed

+360
-68
lines changed

base/Base_compiler.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ support libraries, etc. In these cases it can be useful to prevent unwanted
258258
method invalidation and recompilation latency, and to prevent the user from
259259
breaking supporting infrastructure by mistake.
260260
261-
The current world age can be queried using [`Base.get_world_counter()`](@ref)
261+
The global world age can be queried using [`Base.get_world_counter()`](@ref)
262262
and stored for later use within the lifetime of the current Julia session, or
263263
when serializing and reloading the system image.
264264

doc/src/manual/methods.md

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -578,73 +578,8 @@ However, future calls to `tryeval` will continue to see the definition of `newfu
578578

579579
You may want to try this for yourself to see how it works.
580580

581-
The implementation of this behavior is a "world age counter".
582-
This monotonically increasing value tracks each method definition operation.
583-
This allows describing "the set of method definitions visible to a given runtime environment"
584-
as a single number, or "world age".
585-
It also allows comparing the methods available in two worlds just by comparing their ordinal value.
586-
In the example above, we see that the "current world" (in which the method `newfun` exists),
587-
is one greater than the task-local "runtime world" that was fixed when the execution of `tryeval` started.
588-
589-
Sometimes it is necessary to get around this (for example, if you are implementing the above REPL).
590-
Fortunately, there is an easy solution: call the function using [`Base.invokelatest`](@ref) or
591-
the macro version [`Base.@invokelatest`](@ref):
592-
593-
```jldoctest
594-
julia> function tryeval2()
595-
@eval newfun2() = 2
596-
@invokelatest newfun2()
597-
end
598-
tryeval2 (generic function with 1 method)
599-
600-
julia> tryeval2()
601-
2
602-
```
603-
604-
Finally, let's take a look at some more complex examples where this rule comes into play.
605-
Define a function `f(x)`, which initially has one method:
606-
607-
```jldoctest redefinemethod
608-
julia> f(x) = "original definition"
609-
f (generic function with 1 method)
610-
```
611-
612-
Start some other operations that use `f(x)`:
613-
614-
```jldoctest redefinemethod
615-
julia> g(x) = f(x)
616-
g (generic function with 1 method)
617-
618-
julia> t = @async f(wait()); yield();
619-
```
620-
621-
Now we add some new methods to `f(x)`:
622-
623-
```jldoctest redefinemethod
624-
julia> f(x::Int) = "definition for Int"
625-
f (generic function with 2 methods)
626-
627-
julia> f(x::Type{Int}) = "definition for Type{Int}"
628-
f (generic function with 3 methods)
629-
```
630-
631-
Compare how these results differ:
632-
633-
```jldoctest redefinemethod
634-
julia> f(1)
635-
"definition for Int"
636-
637-
julia> g(1)
638-
"definition for Int"
639-
640-
julia> fetch(schedule(t, 1))
641-
"original definition"
642-
643-
julia> t = @async f(wait()); yield();
644-
645-
julia> fetch(schedule(t, 1))
646-
"definition for Int"
647-
```
581+
The implementation of this behavior is a "world age counter", which is further described in the [Worldage](@ref man-worldage)
582+
manual chapter.
648583

649584
## Design Patterns with Parametric Methods
650585

doc/src/manual/modules.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,68 @@ Here, Julia cannot decide which `f` you are referring to, so you have to make a
316316

317317
3. When the names in question *do* share a meaning, it is common for one module to import it from another, or have a lightweight “base” package with the sole function of defining an interface like this, which can be used by other packages. It is conventional to have such package names end in `...Base` (which has nothing to do with Julia's `Base` module).
318318

319+
### Precedence order of definitions
320+
321+
There are in general four kinds of binding definitions:
322+
1. Those provided via implicit import through `using M`
323+
2. Those provided via explicit import (e.g. `using M: x`, `import M: x`)
324+
3. Those declared implicitly as global (via `global x` without type specification)
325+
4. Those declared explicitly using definition syntax (`const`, `global x::T`, `struct`, etc.)
326+
327+
Syntactically, we divide these into three precedence levels (from weakest to strongest)
328+
1. Implicit imports
329+
2. Implicit declarations
330+
3. Explicit declarations and imports
331+
332+
In general, we permit replacement of weaker bindings by stronger ones:
333+
334+
```julia-repl
335+
julia> module M1; const x = 1; export x; end
336+
Main.M1
337+
338+
julia> using .M1
339+
340+
julia> x # Implicit import from M1
341+
1
342+
343+
julia> begin; f() = (global x; x = 1) end
344+
345+
julia> x # Implicit declaration
346+
ERROR: UndefVarError: `x` not defined in `Main`
347+
Suggestion: add an appropriate import or assignment. This global was declared but not assigned.
348+
349+
julia> const x = 2 # Explicit declaration
350+
2
351+
```
352+
353+
However, within the explicit precedence level, replacement is syntactically disallowed:
354+
```julia-repl
355+
julia> module M1; const x = 1; export x; end
356+
Main.M1
357+
358+
julia> import .M1: x
359+
360+
julia> const x = 2
361+
ERROR: cannot declare Main.x constant; it was already declared as an import
362+
Stacktrace:
363+
[1] top-level scope
364+
@ REPL[3]:1
365+
```
366+
367+
or ignored:
368+
369+
```julia-repl
370+
julia> const y = 2
371+
2
372+
373+
julia> import .M1: x as y
374+
WARNING: import of M1.x into Main conflicts with an existing identifier; ignored.
375+
```
376+
377+
The resolution of an implicit binding depends on the set of all `using`'d modules visible
378+
in the current world age. See [the manual chapter on world age](@ref man-worldage) for more
379+
details.
380+
319381
### Default top-level definitions and bare modules
320382

321383
Modules automatically contain `using Core`, `using Base`, and definitions of the [`eval`](@ref)

0 commit comments

Comments
 (0)