Function, constants, globals

I wanted to have a function:

function test()
    const global x = 1
end

Obviously it does not work. Is there a workaround that would make it feasible to declare constant globals from function?

I want to have some sort of ‘function’ that I would later save with JLD2 so I could reload the parameters later on. If there’s some other way I could do it let me know.
Or is there some other way?

Not sure I get what you want, but maybe you can do something like

function make_constant()
   ... # assign the value you need to `c`
   return c
end

const c = make_constant()

In my code it looks like that:

function test()
   "Definition of x1"
    const global x1 = 1
   "Definition of x2"
    const global x2 = 1
# many more
   "Definition of xk_1"
    const global xk_1 = 1
   "Definition of xk"
    const global xk = 1

end

What you propose is quite inefficient from perspective of a user

Right now I have a script that defines constants. I just want to remake it into something ‘portable’

The way you should do this is with a NamedTuple or struct (mutable or otherwise) or, if you really need the ability to add or remove constants, a global constant Dict.

5 Likes

From your description, it seems you would want something like:

julia> using Parameters

julia> @with_kw struct MyConsts
          x = 1
          y = 2
       end
MyConsts

julia> const myconsts = MyConsts()
MyConsts
  x: Int64 1
  y: Int64 2


julia> myconsts.x
1


Yet, probably if you explain better what exactly do you want to achieve, you can get better alternatives.

1 Like

Sorry for my naif question to the forum. What is wrong with saving a large quantity of constants in a separate *.jl file?

# mycontants.jl file
const e = 2.7182818284
const γ = 0.5772156649
# etc...

and then collect them via code inclusion:

include("myconstants.jl");
julia> e
2.7182818284
julia> γ
0.5772156649

Well, it depends, why are you not using a Module with these global variables inside?

If you just want to use include this file in the REPL there is no problem.

1 Like

Functions are not meant to modify global scopes, but macros can:

macro makeglobal()
    quote
        const global x=1
    end
end

And then you call @makeglobal. (Side note: you can also define the macro in another module; it gets evaluated in the caller’s scope.)

I think this is closer to the OP’s request, although less tidy than other suggestions already given.

1 Like

TLDR: if your constants aren’t really constant, don’t tell julia they are.


It is not only less tidy, it is also not nearly as flexible, and can also be dangerous if it isn’t understood properly. People sometimes assume you can just do :

const a = 10
# define some functions that "capture" `a` and run them
# later I want to change a and rerun my code, so I run:
a = 11
# rerun my functions from before

But you can’t. If the value of a was captured in any functions that have now been compiled, changing a without also redefining those functions will lead to the wrong result. This is why the following warning is issued at the REPL when you do this:

WARNING: redefinition of constant a. This may fail, cause incorrect answers, or produce other errors.

Basically, global constants should be treated as global constants, and the fact that julia lets you change them (as long as their type doesn’t change) can be misleading if you don’t understand that.

So in that case, if you take care to follow the rules (which is already a hassle), you’re subjecting yourself to a lot of unnecessary redefinition and recompilation. So if the constants aren’t literally meant to be constant, put them into something mutable or temporary.

You will see this same advice issued pretty often on here, as this is a common question :slight_smile:

5 Likes

There’s nothing wrong with this at all! It could be convenient to wrap these in a module, but there is nothing problematic about doing exactly this in your own code.

The OP sounded like the constants will change. I.e.

sounds like different parameters could be saved and loaded (otherwise presumably they would stick to their current setup, and it sounded like they were outgrowing it.)

By the way, math constants are available through Base.MathConstants, in case you didn’t already know:

julia> Base.MathConstants.γ
γ = 0.5772156649015...
2 Likes

Perhaps we can help showing exactly what this means:

julia> module Const
          a = 3.
          b = 4.
          export a, b
       end
Main.Const

julia> using .Const   # be aware of the dot

julia> a
3.0

julia> b
4.0

julia> a = 3
ERROR: cannot assign a value to variable Const.a from module Main
Stacktrace:
 [1] top-level scope at REPL[7]:1

6 Likes

For this simple case of defining global constants, could someone explain for Julia beginners like me, the benefits of including a separate file containing a module wrapping all the constants, versus simple code inclusion? Thank you.

Not many, but one advantage would be that you can optionally choose not to import all constants:

julia> module Const
          a = 3.
          b = 4.
          export a, b
       end
Main.Const

julia> using .Const: a 

julia> a
3.0

julia> b
ERROR: UndefVarError: b not defined

But I think we should warn that if a code depends on the definition of a lot constants, probably they should be included in a struct or other data structure and passed as parameters to the functions that will use them.

3 Likes

In this case, you could just do:

function test()
    @eval const x = 1
end
2 Likes

That’s what I needed, thank you!

In the end my code looks like that:

function test()

  @eval begin

      "Definition of x1"
       const global x1 = 1
      "Definition of x2"
       const global x2 = 1
      # many more
      "Definition of xk_1"
       const global xk_1 = 1
      "Definition of xk"
       const global xk = 1
   
   end

end

My constants do not change.
I have a solver for some class of problems. Part of each problem are parameters. They repeat in many parts of problem definition. Thus I wanted to make use of constants to speed up calculations. Solved problem is saved with JLD2.jl so I could access it later (in different workspace) but until now I could not restore parameters as they were stored in a script.
If I changed parameters (changed problem) old setting was gone. I need function literally for a purpose of saving it.

(You do not need the global here, since eval always evaluates in global scope)

1 Like

This is a typical scenario. The most portable solutions involve storing the parameters in a struct and/or passing the model function as a parameter to the solver using closures, while the model function receives as input parameters the constants in a data structure.

Having the parameters of each model in a struct also allows very easy saving of the model data, for example using JSON.

2 Likes

It’s not empirical model but theoretical.
Won’t const be faster than NaamedTuple?