Skip to content

vchuravy/ScopedValues.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ScopedValues.jl

Implement dynamically scoped values for Julia. This package was primarly inspired by ContextVariablesX.jl, it's corresponding pull-request to Julia base, and Java's JEPS446.

It has been submitted to Julia as a JULEP.

Usage

using ScopedValues

const svar = ScopedValue(1)

@show svar[]

# Enter a new dynamic scope and set value
with(svar => 2) do
    @show svar
end

# While a ScopedValue contents are constant
# You can store mutable values.
const svar_dict = ScopedValue(Dict())

# Important we are using `merge` to "unshare" the mutable values
# across the different views of the same scoped value.
with(svar_dict => merge(svar_dict[], Dict(:a => 10))) do
    @show svar_dict[][:a]
end

scoped values are inherited across tasks:

const LEVEL = ScopedValue(:GUEST)

function serve(request, response)
    level = isAdmin(request) ? :ADMIN : :GUEST
    with(LEVEL => level) do
        Threads.@spawn handle(request, respone)
    end
end

function open(connection::Database)
    level = LEVEL[]
    if level !== :ADMIN
        error("Access disallowed")
    end
    # ... open connection
end

function handle(request, response)
    open(Database(#=...=#))
    # ...
end

Usage with logging

Before Julia 1.11, this package implements scoped variables by using a special "payload" logger (just like ContextVariablesX.jl). Therefore, changing the logger from within a dynamic scope can clobber the scoped values. To avoid this, use

ScopedValues.with_logger

as a replacement for Logging.with_logger. Likewise, if you need to access the logger, use

ScopedValues.current_logger()

which will unwrap the special ScopedValues's "payload" logger to provide you with the actual logging-logger.

Note that there is no issue with setting a logger outside of the dynamic scope. For example, a common usage is to set the global logger at the start of the program (and to not change it mid-execution). In this case, there is no issue clash with ScopedValues.jl, and e.g. Logging.global_logger() may be used to set the logger. There is only concern when modifying or accessing the logger from within a dynamic scope provided by ScopedValues.jl (i.e. within a with block).

There is also no issue with logging to a logger (e.g. @info, etc), within a dynamic scope or elsewhere. ScopedValues "payload" logger will pass log messages through to the active logger.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages