Right way to put code into a function?

I am writing a simulation code where there is an “input.toml” file which contains the initialization parameters (20 to 30 parameters) for the simulation. It works fine if I keep the code in the main where the variables stay global. I tried to wrap it in a function for sake of organizing and readability:

using TOML

function parser()

    println("PARSING input parameters from 'input.toml' file")
    input_parameters = TOML.parsefile("input.toml")
    println()

    blob_width = input_parameters["Initial parameters"]["blob_width"]

end

parser()

println("blob_width = $(blob_width)")

my input.toml file looks like this:

["Initial parameters"]
blob_width = 2.0

and i get the following error

ERROR: LoadError: UndefVarError: `input_parameters` not defined in `Main`

What is the Julia way to do this correctly for organizing & readability?

Use function arguments to pass things into the function (e.g. the name of the TOML file), and use function return values (or less commonly mutate the arguments) to pass information out of the function. Don’t use global variables, in general.

This is not really about Julia per se. It’s basic to the concept of a “function” in any programming language, and being reluctant to use global variables is standard software-engineering practice.

The error means exactly what it says — you never defined this variable. Presumably you meant to call input_parameters = TOML.parsefile("somefile.toml")

Note that none of the confusion here is really specific to parsing, so I’ve edited the post title.

4 Likes

Okay. I tried to do what you suggested, but I think I am doing something wrong, I am still facing the same error

ERROR: LoadError: UndefVarError: blob_width not defined in Main

using TOML

input_parameters = TOML.parsefile("input.toml")

function parser(dictionary)
    println("PARSING input parameters from the dictionary")
    blob_width = dictionary["Initial parameters"]["blob_width"]
    return blob_width
end

parser(input_parameters)
println(blob_width)

What am I doing wrong?

The objective is to use the parsed parameters throughout the code in various functions. Doesn’t that justify Global variables?
Another concern I have is that it becomes messy to return 30 parameters. Is there a better way?

You need blob_width = parser(input_parameters) in order to assign the return value to a variable.

I would recommend reading some tutorial material on the “function” concept in programming, such as this chapter from Think Julia. (Or similar material from any programming language; this is not specific to Julia.)

Combine them into a data structure.

3 Likes

If a function returns 2 to 10 parameters you can return a tuple:

julia> function test()
           a=1
           b=2
           c=3
           return a,b,c
       end
test (generic function with 1 method)

julia> a, b, c = test()
(1, 2, 3)

julia> a
1

julia> b
2

julia> c
3

Also worth reading for newbies: Working with Julia projects | Julia programming notes

1 Like

Personally, I would let the parser function return all interesting input parameters in a NamedTuple, e.g.:

using TOML

function parser(filename)

    println("PARSING input parameters from '$filename' file")
    input_parameters = TOML.parsefile(filename)
    println()

    (; blob_width = input_parameters["Initial parameters"]["blob_width"],
        blob_height = input_parameters["Initial parameters"]["blob_height"])

end

iparams = parser("input.toml")

println("blob_width = $(iparams.blob_width)")
println("blob_height = $(iparams.blob_height)")

So that all input parameters are collected in one variable (iparams in this case). If you really want to have each input variable in its own variable, this can still be done (using the same parser function as above):

blob_width, blob_height = parser("input.toml")

println("blob_width = $(blob_width)")
println("blob_height = $(blob_height)")
1 Like

Thanks, that’s what I was looking for

1 Like