Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexport with, at_with, and ScopedValue from Base #53004

Merged
merged 6 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -653,11 +653,6 @@ export
sprint,
summary,

# ScopedValue
with,
@with,
ScopedValue,

# logging
@debug,
@info,
Expand Down
1 change: 1 addition & 0 deletions base/logging.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module CoreLogging

import Base: isless, +, -, convert, show
import Base: ScopedValue, with, @with

export
AbstractLogger,
Expand Down
8 changes: 4 additions & 4 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ end
tie_breaker_is_to_even(::MPFRRoundingMode) = true

const ROUNDING_MODE = Ref{MPFRRoundingMode}(MPFRRoundNearest)
const CURRENT_ROUNDING_MODE = ScopedValue{MPFRRoundingMode}()
const CURRENT_ROUNDING_MODE = Base.ScopedValue{MPFRRoundingMode}()
const DEFAULT_PRECISION = Ref{Clong}(256)
const CURRENT_PRECISION = ScopedValue{Clong}()
const CURRENT_PRECISION = Base.ScopedValue{Clong}()
# Basic type and initialization definitions

# Warning: the constants are MPFR implementation details from
Expand Down Expand Up @@ -162,7 +162,7 @@ significand_limb_count(x::BigFloat) = div(sizeof(x._d), sizeof(Limb), RoundToZer
rounding_raw(::Type{BigFloat}) = something(Base.ScopedValues.get(CURRENT_ROUNDING_MODE), ROUNDING_MODE[])
setrounding_raw(::Type{BigFloat}, r::MPFRRoundingMode) = ROUNDING_MODE[]=r
function setrounding_raw(f::Function, ::Type{BigFloat}, r::MPFRRoundingMode)
@with(CURRENT_ROUNDING_MODE => r, f())
Base.@with(CURRENT_ROUNDING_MODE => r, f())
end


Expand Down Expand Up @@ -1109,7 +1109,7 @@ Note: `nextfloat()`, `prevfloat()` do not use the precision mentioned by
The `base` keyword requires at least Julia 1.8.
"""
function setprecision(f::Function, ::Type{BigFloat}, prec::Integer; base::Integer=2)
@with(CURRENT_PRECISION => _convert_precision_from_base(prec, base), f())
Base.@with(CURRENT_PRECISION => _convert_precision_from_base(prec, base), f())
end

setprecision(f::Function, prec::Integer; base::Integer=2) = setprecision(f, BigFloat, prec; base)
Expand Down
2 changes: 2 additions & 0 deletions base/scopedvalues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Dynamic scopes are propagated across tasks.
# Examples

```jldoctest
julia> using Base.ScopedValues;

julia> const sval = ScopedValue(1);

julia> sval[]
Expand Down
25 changes: 22 additions & 3 deletions doc/src/base/scopedvalues.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ concurrently.
Scoped values were introduced in Julia 1.11. In Julia 1.8+ a compatible
implementation is available from the package ScopedValues.jl.

In its simplest form you can create a [`ScopedValue`](@ref) with a
default value and then use [`with`](@ref Base.with) or [`@with`](@ref) to
In its simplest form you can create a [`Base.ScopedValue`](@ref) with a
default value and then use [`Base.with`](@ref with) or [`Base.@with`](@ref) to
enter a new dynamic scope.

The new scope will inherit all values from the parent scope
Expand Down Expand Up @@ -54,6 +54,8 @@ f() # 1
Now using a `ScopedValue` we can use **dynamic** scoping.

```julia
using Base.ScopedValues

x = ScopedValue(1)
f() = @show x[]
with(x=>5) do
Expand All @@ -70,6 +72,8 @@ and you can set the value of multiple `ScopedValue`s with one call to `with`.


```julia
using Base.ScopedValues

const scoped_val = ScopedValue(1)
const scoped_val2 = ScopedValue(0)

Expand All @@ -94,6 +98,8 @@ Since `with` requires a closure or a function and creates another call-frame,
it can sometimes be beneficial to use the macro form.

```julia
using Base.ScopedValues

const STATE = ScopedValue{State}()
with_state(f, state::State) = @with(STATE => state, f())
```
Expand All @@ -106,7 +112,9 @@ The parent task and the two child tasks observe independent values of the
same scoped value at the same time.

```julia
using Base.ScopedValues
import Base.Threads: @spawn

const scoped_val = ScopedValue(1)
@sync begin
with(scoped_val => 2)
Expand All @@ -128,7 +136,9 @@ values. You might want to explicitly [unshare mutable state](@ref unshare_mutabl
when entering a new dynamic scope.

```julia
using Base.ScopedValues
import Base.Threads: @spawn

const sval_dict = ScopedValue(Dict())

# Example of using a mutable value wrongly
Expand Down Expand Up @@ -161,6 +171,8 @@ are not well suited for this kind of propagation; our only alternative would hav
been to thread a value through the entire call-chain.

```julia
using Base.ScopedValues

const LEVEL = ScopedValue(:GUEST)

function serve(request, response)
Expand Down Expand Up @@ -189,7 +201,9 @@ end
### [Unshare mutable state](@id unshare_mutable_state)

```julia
using Base.ScopedValues
import Base.Threads: @spawn

const sval_dict = ScopedValue(Dict())

# If you want to add new values to the dict, instead of replacing
Expand All @@ -210,6 +224,7 @@ be in (lexical) scope. This means most often you likely want to use scoped value
as constant globals.

```julia
using Base.ScopedValues
const sval = ScopedValue(1)
```

Expand All @@ -218,7 +233,9 @@ Indeed one can think of scoped values as hidden function arguments.
This does not preclude their use as non-globals.

```julia
using Base.ScopedValues
import Base.Threads: @spawn

function main()
role = ScopedValue(:client)

Expand All @@ -241,6 +258,8 @@ If you find yourself creating many `ScopedValue`'s for one given module,
it may be better to use a dedicated struct to hold them.

```julia
using Base.ScopedValues

Base.@kwdef struct Configuration
color::Bool = false
verbose::Bool = false
Expand All @@ -260,7 +279,7 @@ end
Base.ScopedValues.ScopedValue
Base.ScopedValues.with
Base.ScopedValues.@with
Base.isassigned(::ScopedValue)
Base.isassigned(::Base.ScopedValues.ScopedValue)
Base.ScopedValues.get
```

Expand Down
10 changes: 5 additions & 5 deletions test/scopedvalues.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license
import Base: ScopedValues
using Base.ScopedValues

@testset "errors" begin
@test ScopedValue{Float64}(1)[] == 1.0
Expand Down Expand Up @@ -67,13 +67,13 @@ import Base.Threads: @spawn
end

@testset "show" begin
@test sprint(show, ScopedValue{Int}()) == "ScopedValue{$Int}(undefined)"
@test sprint(show, sval) == "ScopedValue{$Int}(1)"
@test sprint(show, ScopedValue{Int}()) == "Base.ScopedValues.ScopedValue{$Int}(undefined)"
@test sprint(show, sval) == "Base.ScopedValues.ScopedValue{$Int}(1)"
@test sprint(show, Core.current_scope()) == "nothing"
with(sval => 2.0) do
@test sprint(show, sval) == "ScopedValue{$Int}(2)"
@test sprint(show, sval) == "Base.ScopedValues.ScopedValue{$Int}(2)"
objid = sprint(show, Base.objectid(sval))
@test sprint(show, Core.current_scope()) == "Base.ScopedValues.Scope(ScopedValue{$Int}@$objid => 2)"
@test sprint(show, Core.current_scope()) == "Base.ScopedValues.Scope(Base.ScopedValues.ScopedValue{$Int}@$objid => 2)"
end
end

Expand Down