Best way to create/assign variables based on strings


#1

Hi all

Which would be best way to create/assign variables based on strings. Assuming I have this:

string = “AA”
string = get(“https://get.some.unknown.very.short.string”)

would like to do the following

AA = 1
new_variable_named_on_that_yet_unknown_short_string = 1

Thank you!


#2

Sorry not answering your question, but consider using JSON.jl.


#3

Use a dictionary: http://docs.julialang.org/en/stable/stdlib/collections/#Base.Dict


#4

If this is in global scope. Use eval. If this is local scope, it’s impossible and won’t be possible. Use a Dict with String as keys to hold the value instead.


#5

Here is the code, but this is not the best practice:

julia> string = "AA"
"AA"

julia> value = 1
1

julia> eval(parse("$string=$value"))
1

julia> AA
1

julia> 

#6

Even if you want to use eval. DO NOT USE parse.

Do @eval $(Symbol(string)) = $value or @eval $(Symbol(string)) = value.


#7

Thank you for all the answers.

[quote=“yuyichao, post:4, topic:3001, full:true”]
If this is in global scope. Use eval. If this is local scope, it’s impossible and won’t be possible. Use a Dict with String as keys to hold the value instead.
[/quote]
Found a “solution” in local scope by widening the field of permissible functions. In my setting “AA” and “BB” represent those short-strings yet to be fetched
var1 = "AA"
var2 = "BB"

but on the contrary, x and y are known at coding time

x = 2.0
y = rand(2,2)

An ugly solution may be:

function crazymeta(file)
open(file, "w") do f
write(f,"$var1 = x\n$var2 = y")
end
include("$file")
return AA * BB
end

CC = crazymeta("whatever.jl")
print("$CC")

Now AA = 2.0, BB and CC are naturally 2x2 Array{Float64,2}. Would it possible to do something like this print/include trick, but with all steps in memory and reasonably fast?


#8

Well you could use include_string, but include operates at global scope.
In your example, AA and BB will be defined as global variables.
In this case, probably best to go with @yuyichao’s suggestion and use @eval.


#9

A better way to write this is

var1 = "AA"
var2 = "BB"
@eval $(Symbol(var1)) = x
@eval $(Symbol(var2)) = x
CC = AA * BB
print(CC)

but again, this is not usually the best way to go about things. What are you trying to do? By that I mean your actual goal, for which this metaprogramming may likely not be the best solution for.


#10

I agree that using a Dict is better in most cases. However, by defining a macro it is certainly not impossible to create variables in local scope only. I posted one possible solution in another thread. Or did I misunderstand what you meant?


#11

No it’s impossible to create a variable in local scope from runtime value. You can of course use a macro to translate @m "b" into b = 1 but it’s impossible to make var = "b"; @m var behave like b = 1.


#12

In another word, if there’s a way to do this (create local variable from runtime value), it’s a semantic bug that needs to be fixed.


#13

I see. I should have read the original post more carefullly instead of jumping all over my example in the other thread. Thanks for clarifying!


#14

Note that the macro is very unlikely the right solution in the other thread either. It essentially let you spell variable syntax slight differently, like writing "a" = 1 instead of a = 1, which might be cool if you really like quoting but I don’t think that’s what the OP asked about in either thread.


#15

Sorry for nagging, but there is obviously something I still don’t understand. The macro in the other thread seems to work (the function creates a random runtime value and the macro creates a variable with that value in the local scope). Here’s the code:

macro localvariable(s::AbstractString, v::Any)
	s = Symbol(s)
	esc(:($s = $v))
end

function newtest()
    c = rand()  
    @localvariable("b", c)
    println("b in function = $b")
end

newtest()
isdefined(:b) && println("global b = $b")
nothing

Output:

b in function = 0.8428874752942634

What am I missing?


#16

What you are missing is that the macro isn’t useful other than making it possible to do things like

It does NOT create a variable whose name is determined at runtime, merely changing how you spell assignments. Also, it’s missing esc.


#17

I have a use case for which I could probably use strings as variable names. I want to construct a graph with some vertices. Since I want to create them iteratively, I use a for loop here but this doesn’t work as expected.

for i = 1:max_nodes
  @eval $(Symbol("V$i")) = ExVertex(i, "V$i")
end

So, I switched back to your primary suggestion of using Dictionaries. So far, they work fine.


vertices = Dict("V$i" => ExVertex(i, "V$i") for i=1:max_nodes)