# Correct way to declare global constant in modules

**URL:** https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234
**Category:** General Usage
**Tags:** constants
**Created:** [April 8, 2018, 8:02pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234 "2018-04-08T20:02:11Z")
**Posts on this page:** 16
**Page:** 1

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 8, 2018, 8:02pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/1 "2018-04-08T20:02:11Z")

</div>

Hi guys,

I have a module with a lot of global constants. Those are related to physical quantities, like Earth gravitational parameter. These are declared as:

```julia
const R0 = 6378137.0

```

I was analyzing the type-stability of my code and `@code_warntype` is marking every expression that uses those constants as `Core.Box`.

This seems to have impact on performance. I know that I can pass those constants as arguments, but it is not advisable because there are many of them.

Any ideas how can I fix this?

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [April 8, 2018, 8:04pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/2 "2018-04-08T20:04:58Z")

</div>

That shouldn’t happen if you declare them as `const`. Can you provide a minimal example?

---

<div class="post-metadata">

### Author: ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)
#### Post date: [April 8, 2018, 9:55pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/3 "2018-04-08T21:55:56Z")

</div>

Maybe it is because the radius of the Earth is not really constant? 😉

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 8, 2018, 10:07pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/4 "2018-04-08T22:07:04Z")

</div>

Hi @tkoolen,

Sorry, it took a while to create a minimal working code that reproduces the problem. See the following module:

```julia
VERSION >= v"0.4.0-dev+6521" && __precompile__ ()

module TestConst

export test

# Earth Equatorial radius [m].
const R0 = 6378137.0

# Standard gravitational parameter for Earth [m^3/s^2].
const m0 = 3.986004418e14

function test(n::Number, e::Number)
    # Check if the arguments are valid.
    if (n <= 0)
        throw(ArgumentError("The angular velocity must be greater than 0."))
    end

    if !( 0. <= e < 1. )
        throw(ArgumentError("The eccentricity must be within the interval 0 <= e < 1."))
    end

    # Auxiliary variables.
    sqrt_m0 = sqrt(m0)
    sqrt_e2 = sqrt(1-e^2)

    # Auxiliary constant to compute the functions.
    K1 = 3.0*R0^2*sqrt_m0/(4.0*(1-e^2)^2)

    # Declare the functions that must solved for 0.
    f1(a, i) = ne + 2.0*K1*a^(-3.5)*cos(i)
end

end

```

If I run `@code_warntype test(1,1)`, then I get:

```julia
Variables:
  #self# <optimized out>
  n::Int64
  e::Int64
  sqrt_m0::Float64
  sqrt_e2 <optimized out>
  K1::Core.Box
  f1::TestConst.#f1#1
  #temp#::Bool
  fy::Float64
  fx::Float64

```

What is interesting though is that if I remove the exceptions, then I get:

```julia
Variables:
  #self# <optimized out>
  n <optimized out>
  e::Int64
  sqrt_m0::Float64
  sqrt_e2 <optimized out>
  K1::Any
  f1::TestConst.#f1#1{_} where _

```

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 8, 2018, 10:07pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/5 "2018-04-08T22:07:41Z")

</div>

Good point! 🙂 Should have thought about it earlier!

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 8, 2018, 10:13pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/6 "2018-04-08T22:13:54Z")

</div>

Guys,

The problem is not related with the global constants, but with the internal `K1`. This other code reproduces the problem as well:

```julia
VERSION >= v"0.4.0-dev+6521" && __precompile__ ()

module TestConst

export test

function test(n::Number, e::Number)
    # Check if the arguments are valid.
    if (n <= 0)
        throw(ArgumentError("The angular velocity must be greater than 0."))
    end

    # Auxiliary constant to compute the functions.
    K1 = 3.0

    # Declare the functions that must solved for 0.
    f1(a, i) = K1
end

end

```

Notice that, if I remove the exceptions, then everything is fine:

```julia
Variables:
  #self# <optimized out>
  n <optimized out>
  e <optimized out>
  K1 <optimized out>
  f1::TestConst.#f1#1{Float64}

```

Am I missing something?

---

<div class="post-metadata">

### Author: ![NickNack](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nicknack/32/1792_2.png) [@NickNack](https://discourse.julialang.org/u/NickNack)
#### Post date: [April 8, 2018, 10:29pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/7 "2018-04-08T22:29:23Z")

</div>

> [@Ronis\_BR](#):
>
> Am I missing something?

No. I have the same problem with constants that are used in functions and have concluded that this is due to the closure bug [#15276](https://github.com/JuliaLang/julia/issues/15276), the single most annoying remaining issue in Julia (in my opinion). If this and absolutely nothing else were miraculously fixed in 1.0 then the release would be marked a success in my book.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 8, 2018, 10:30pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/8 "2018-04-08T22:30:32Z")

</div>

Hi @NickNack,

Yes, it indeed seems a similar problem! I think I will have to wait then 🙂

Thanks!

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [April 8, 2018, 10:34pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/9 "2018-04-08T22:34:52Z")

</div>

> [@Ronis\_BR](#):
>
> The problem is not related with the global constants, but with the internal K1. This other code reproduces the problem as well:

No, there isn’t a problem here. Read the whole code, not just the header:

```julia
Variables:
  #self# <optimized out>
  n::Int64
  e <optimized out>
  K1::Core.Box
  f1::#f1#15

Body:
  begin
      K1::Core.Box = $(Expr(:new, :(Core.Box)))
      NewvarNode(:(f1::#f1#15))
      unless (Base.sle_int)(n::Int64, 0)::Bool goto 6 # lin
e 139:
      (Main.throw)($(Expr(:new, :(Base.ArgumentError), "The
 angular velocity must be greater than 0.")))::Union{}
      6: # line 143:
      (Core.setfield!)(K1::Core.Box, :contents, 3.0)::Float
64 # line 146:
      f1::#f1#15 = $(Expr(:new, :(Main.#f1#15), :(K1)))
      return f1::#f1#15
  end::#f1#15

```

`Core.Box` doesn’t mean that there’s a type instability. It just means the variable gets boxed, here because it might not be needed depending on if there’s an exception or not. But its result is not type-unstable. In fact,

```julia
(Core.setfield!)(K1::Core.Box, :contents, 3.0)::Float64 # line 146:

```

this line says that it knows that the contents will be `Float64`, so all of the types in the AST are inferred and everything is fine.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 8, 2018, 10:49pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/10 "2018-04-08T22:49:45Z")

</div>

Hi @ChrisRackauckas

Sorry, it is a part of a bigger code and I maybe misunderstood the real problem. See this other code:

```julia
VERSION >= v"0.4.0-dev+6521" && __precompile__ ()

module TestConst

export test

# Earth Equatorial radius [m].
const R0 = 6378137.0

# Standard gravitational parameter for Earth [m^3/s^2].
const m0 = 3.986004418e14

# Perturbation terms based on EGM-08 standard gravitational model [1, pp. 1039].
const J2 = 1.08262617385222e-3

# Earth's orbit mean motion [rad/s]
const ne = (360.0/365.2421897)*pi/180/86400

function test(n::Number, e::Number)
    # Check if the arguments are valid.
    if (n <= 0)
        throw(ArgumentError("The angular velocity must be greater than 0."))
    end

    if !( 0. <= e < 1. )
        throw(ArgumentError("The eccentricity must be within the interval 0 <= e < 1."))
    end

    # Auxiliary variables.
    sqrt_m0 = sqrt(m0)
    sqrt_e2 = sqrt(1-e^2)

    # Auxiliary constant to compute the functions.
    K1 = 3.0*R0^2*J2*sqrt_m0/(4.0*(1-e^2)^2)

    # Declare the functions that must solved for 0.
    f1(a, i) = ne + 2.0*K1*a^(-3.5)*cos(i)

    a_k::Float64 = (m0/n^2)^(1/3)
    i_k::Float64 = acos( -ne*a_k^(3.5)/(2*K1) )

    f1(a_k, i_k)
end

end

```

In this case, it is not correcting guessing the return value:

```julia
return $(Expr(:invoke, MethodInstance for (::TestConst.#f1#1)(::Float64, ::Float64), :(f1), SSAValue(1), :(i_k)))
  end::Any

```

On the other hand, if I remove `K1` from the function `f(a,i)`, then it works:

```julia
return $(Expr(:invoke, MethodInstance for (::TestConst.#f1#1)(::Float64, ::Float64), :(f1), SSAValue(0), SSAValue(1)))
  end::Float64

```

**NOTE** : I know that I can always do `K1::Float64`, but I want to avoid that.

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [April 9, 2018, 12:07am UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/11 "2018-04-09T00:07:57Z")

</div>

The code is type-stable in the sense that the output type is inferred correctly, but there’s still a performance issue here: the code in [this post](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/6) allocates with the `if` statement in place, while it doesn’t without that `if` statement. ~~I think that @NickNack’s assessment ([performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276)) is correct, especially given that the [`let` block workaround](https://github.com/JuliaLang/julia/issues/15276#issuecomment-297596373) fixes the performance problem:~~

Edit: I’m no longer convinced that it’s [performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/15276), as the `let` block trick doesn’t work.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 9, 2018, 1:10am UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/12 "2018-04-09T01:10:33Z")

</div>

Should I do something? Comment on this bug perhaps?

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [April 9, 2018, 1:43am UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/13 "2018-04-09T01:43:44Z")

</div>

I’d give it a minute, maybe someone who knows more about the internals of Julia will stop by this post.

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [April 9, 2018, 1:58am UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/14 "2018-04-09T01:58:38Z")

</div>

Actually, I didn’t apply the `let` block trick correctly previously. The following doesn’t exhibit the performance problem:

```julia
module TestConst

export test

function test(n::Number, e::Number)
    # Check if the arguments are valid.
    if (n <= 0)
        throw(ArgumentError("The angular velocity must be greater than 0."))
    end

    # Auxiliary constant to compute the functions.
    K1 = 3.0

    # Declare the functions that must solved for 0.
    f1 = let K1 = K1
        (a, i) -> K1
    end
end

end

```

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [April 9, 2018, 3:22am UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/15 "2018-04-09T03:22:27Z")

</div>

This isn’t the basic 15276 because a much fancier optimization is required. Naively, the inner function `f` is visible and could be called throughout the outer test function—before or after `K0` is defined. In order to correctly implement that, `K0` must be boxed so that it’s state can be either unassigned or assigned. The compiler would have to prove that `f` cannot be called before `K0` defined in order to know that it doesn’t need to do any boxing here. It’s possible but quite tricky. You could try moving the definition of `K0` before the error checks or putting the main computation into a separate function body that is called after the checks are done. It’s also worth filing an issue about this situation since we would ideally like to handle it efficiently.

---

<div class="post-metadata">

### Author: ![Ronis\_BR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ronis_br/32/50999_2.png) [@Ronis\_BR](https://discourse.julialang.org/u/Ronis_BR)
#### Post date: [April 9, 2018, 2:17pm UTC](https://discourse.julialang.org/t/correct-way-to-declare-global-constant-in-modules/10234/16 "2018-04-09T14:17:42Z")

</div>

Hi guys,

First of all, thanks for the help. As per @StefanKarpinski advice, I opened a issue in gitbhub: [Variable type is not inferred correctly if an `if` statement is added · Issue #26752 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/26752)

Sorry about the technical description and title of the issue, I really do not have the necessary technical background to do any better 🙂

> [@StefanKarpinski](#):
>
> You could try moving the definition of K0 before the error checks or putting the main computation into a separate function body that is called after the checks are done.

You are right! If I put `K1` before the `if`, then the problem is gone!
