Return the variable name as a String

Hi,
Is it possible to define a function, structure, macro or whatever to get sth like this:

julia> a = somefunc()
“a”

where the string contains the variable name ? I would like a way to print the variable name without writing it twice (once for the declaration and once for the string).

no, the right hand side of = can’t see what’s left to it. Because the right-hand side has to be “evaluated” first, and the return value is bonded to left-hand side (variable name)

what you’re looking for is @show:

julia> a = 2.03;

julia> @show a;
a = 2.03

EDIT: This answer is obsolete after OP updated the question to include

I would like a way to print the variable name without writing it twice (once for the declaration and once for the string).

@jling gave the correct answer above.


I feel like your syntax is a bit off.

Maybe you want to do something like

julia> macro stringify(ex)
           return esc(string(ex))
       end
@stringify (macro with 1 method)

julia> name_a = @stringify a
"a"

But the question is, why not just write

julia> name_a = "a"

in the first place?

Thank you for your answers.

Because I have plenty of parameters to play with, and I would like a way to access their names as Strings without writing for each parameter

name(very_long_parameter_name)=“very_long_parameter_name”

You can get all “names” defined in a module with names(module_name).

julia> x = 3
3

julia> y = 5
5

julia> names(Main)
7-element Vector{Symbol}:
 :Base
 :Core
 :InteractiveUtils
 :Main
 :ans
 :x
 :y

Also, see the VSCode Workspace for that same information.
image

However, that is only going to work for global variables which should generally be avoided (unless they are const). I suggest instead you put all your parameters into a NamedTuple (or a Dictionary if you don’t know all of the parameters ahead of time) and work with that instead.

julia> parameters = (a=1, b="hello")
(a = 1, b = "hello")

julia> keys(parameters)
(:a, :b)

julia> string.(keys(parameters))
("a", "b")

Named Tuples are faster to use than Dictionaries but the names will be stored as Symbol rather than String. Dictionaries can use strings directly as keys and you can add to them after creation.

julia> params = Dict("c" => 8.8)
Dict{String, Float64} with 1 entry:
  "c" => 8.8

julia> params["d"] = 10
10

julia> params
Dict{String, Float64} with 2 entries:
  "c" => 8.8
  "d" => 10.0

julia> keys(params)
KeySet for a Dict{String, Float64} with 2 entries. Keys:
  "c"
  "d"
1 Like

Hi @geo1093 , this may be a possible different solution.

  1. Store variables names (as strings) in a vector, or any other variable, (so you write them only once):
names = ["A", "B"]
  1. Define a function to create a variable from a string and assign a value to it (example from Lee Phillips’s book “Practical Julia”):
mkvar(s, v) = eval(:($(Symbol(s)) = $v))
  1. Use the mkvar() function with the strings stored in variable names:
mkvar(names[1], 1:3)
# which produce the variable `A` as with the command:
A = 1:3
  1. For the reverse (reading the values stored in the variables given the variables names specified as strings), define the function:
readvar(s) = eval(:($(Symbol(s))))
  1. Use function readvar() with the strings stored in names to read the values in the corresponding variables;:
readvar(names[1])
1 Like

A macro is what you want I think. For example, I used one in Napari.jl to the stringify the expression of the image I’m trying to show while also passing it.

julia> macro namekw(expr)
           ( isa(expr,Expr) && expr.head == :call ) ||
               error("@namekw must be used on a method call.")
           push!( expr.args, Expr( :kw, :name, string(expr.args[2]) ) )
           esc( expr )
       end
@namekw (macro with 1 method)

julia> f(args...; kwargs...) = args, kwargs
f (generic function with 1 method)

julia> f(a)
((5,), Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}())

julia> @namekw f(a)
((5,), Base.Pairs(:name => "a"))

More succintly

julia> g(x; name=nothing) = x, name
g (generic function with 1 method)

julia> @namekw g(a)
(5, "a")

julia> value, variable = @namekw g(a)
(5, "a")

julia> value
5

julia> variable
"a"

Nested collections may also help avoid such long variable names. Accessing the variables directly with dot syntax isn’t any shorter (e.g. parameters.files.schedule), but collections can make it easier to pass only relevant variables to functions.

julia> function list_employees(employees)
           for name in values(employees)
               println(name)
           end
       end
list_employees (generic function with 1 method)

julia> parameters = (
           files = (
               schedule = "Documents/schedule.xlsx",
               output = "Documents/out.txt",
           ),
           employees = (
               CEO = "John",
               manager = "Barb",
               cashier = "Fred",
           ),
           minimum_wage = 7.50,
       )
(files = (schedule = "Documents/schedule.xlsx", output = "Documents/out.txt"), employees = (CEO = "John", manager = "Barb", cashier = "Fred"), minimum_wage = 7.5)

julia> list_employees(parameters.employees)
John
Barb
Fred

It is also common to rename a variable to something shorter at the top of a function where the context is more clear and then do the real work with those shorter names.

function update_schedule(parameters)
    schedule = parameters.files.schedule
    cashier = parameters.employees.cashier
    # do stuff
end