# Why is accessing a typed global different from dereferencing a const Ref

**URL:** <https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992>\
**Category:** Internals & Design\
**Tags:** typed-globals\
**Created:** [August 20, 2023, 12:57am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992 "2023-08-20T00:57:06Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 20, 2023, 12:57am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/1 "2023-08-20T00:57:06Z")

</div>

I had expected these to be implemented the same way, just loading a value of the specified type from a memory address, but it appears that the typed global needs 2 different loads. Why is that? Doesn’t seem to be a performance difference, `@btime` and `@benchmark` vary around the same figures…

```julia
julia> const x = Ref(1.5)
Base.RefValue{Float64}(1.5)

julia> getx() = x[]
getx (generic function with 1 method)

julia> y::Float64 = 1.5
1.5

julia> gety() = y
gety (generic function with 1 method)

julia> @code_llvm getx()
; @ REPL[20]:1 within `getx`
define double @julia_getx_225() #0 {
top:
; ┌ @ refvalue.jl:56 within `getindex`
; │┌ @ Base.jl:38 within `getproperty`
    %0 = load double, double* inttoptr (i64 140382054219008 to double*), align 256
; └└
  ret double %0
}

julia> @code_llvm gety()
; @ REPL[21]:1 within `gety`
define double @julia_gety_227() #0 {
top:
  %0 = load atomic double*, double**inttoptr (i64 140382044328152 to double**) unordered, align 8
  %1 = load double, double* %0, align 8
  ret double %1
}

```

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [August 20, 2023, 1:21am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/2 "2023-08-20T01:21:30Z")

</div>

Typed globals are thread-safe so the first load is a lock. When the lock isn’t contended they both should be pretty fast.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 20, 2023, 1:39am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/3 "2023-08-20T01:39:42Z")

</div>

Is that why `setx(v) = x[] = v` and `sety(v) = global y = v` are much more different, too? In that case `sety` does seem slower.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [August 20, 2023, 1:41am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/4 "2023-08-20T01:41:12Z")

</div>

exactly.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 20, 2023, 1:43am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/5 "2023-08-20T01:43:22Z")

</div>

I had not expected the locking, didn’t run across this in any writings about typed globals. I wonder why performance was sacrificed for this feature, it’s not like local variables and untyped globals are thread-safe.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [August 20, 2023, 2:19am UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/6 "2023-08-20T02:19:04Z")

</div>

I’m pretty sure untyped globals are type safe.

---

<div class="post-metadata">

**Author:** ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)\
**Post date:** [August 20, 2023, 12:21pm UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/8 "2023-08-20T12:21:21Z")

</div>

> [@Oscar\_Smith](#):
>
> Typed globals are thread-safe so the first load is a lock.

I was excited at first and wrote about how happy I am about having thread-safe typed globals.

However, after running the following experiment, this doesn’t seem to be the case:

```julia
toggle::Bool = false
counter::Int = 0

function switch()
    global toggle
    global counter
    toggle = !toggle
    counter += 1
end

for _ in 1:1001
    Threads.@spawn switch()
end

# 12 threads: counter < 1001 (usually < 920) and ~50% true/false for toggle

```

Am I missing something?

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [August 20, 2023, 12:35pm UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/9 "2023-08-20T12:35:58Z")

</div>

They are thread safe in the sense that no two threads can write simultaneously. They are however not data race free, i.e. you can still have other different threads reading/writing in an interleaved/noncoordinated manner.

This distinction is mostly relevant for bigger structs that contain multiple objects - the thread safety of globals means that you won’t ever get a mix of two objects from different threads (so no one thread achieves a “partial write”), you’ll always end up with the whole object of some thread.

---

<div class="post-metadata">

**Author:** ![algunion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/algunion/32/51630_2.png) [@algunion](https://discourse.julialang.org/u/algunion)\
**Post date:** [August 20, 2023, 12:44pm UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/10 "2023-08-20T12:44:50Z")

</div>

Thanks for the explanation. I didn’t make the distinction (e.g., in my mind expressing that there is thread safety implies that you can safely update the value from different threads).

But I get it now.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [August 20, 2023, 11:29pm UTC](https://discourse.julialang.org/t/why-is-accessing-a-typed-global-different-from-dereferencing-a-const-ref/102992/11 "2023-08-20T23:29:58Z")

</div>

There is no locking going on here, thread safety only comes from the atomic reads. The difference lays in the way global bindings are implemented:

When assigning a value to a binding, a separate box is allocated for each new value and a module’s binding table then contains a pointer to that box. This adds an extra layer of indirection compared to constant refs, which always refer to the same location in memory so their memory address can be inlined in codegen.

This is potentially fixable by adding special handling for concretely typed globals, but that will require some careful thought. Fixing this is not a very high priority at the moment since code this performance sensitive should generally not be accessing global state anyways
