Skip to content

Commit 1e248e1

Browse files
Kenoararslannickrobinson251
authored
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 d7cd271 commit 1e248e1

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
@@ -265,7 +265,7 @@ support libraries, etc. In these cases it can be useful to prevent unwanted
265265
method invalidation and recompilation latency, and to prevent the user from
266266
breaking supporting infrastructure by mistake.
267267
268-
The current world age can be queried using [`Base.get_world_counter()`](@ref)
268+
The global world age can be queried using [`Base.get_world_counter()`](@ref)
269269
and stored for later use within the lifetime of the current Julia session, or
270270
when serializing and reloading the system image.
271271

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
@@ -322,6 +322,68 @@ Here, Julia cannot decide which `f` you are referring to, so you have to make a
322322

323323
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).
324324

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

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

0 commit comments

Comments
 (0)