I am trying create a new symbol that represents a field b in a struct called A, e.g.
Symbol(“A.”,“b”)
This gives Symbol(“A.b”),
but I want :A.b, whereas
Symbol(“A”,“b”)
gives :Ab
It looks like I cannot compose a new Symbol when a point is present in the arguments of Symbol.
Can someone help me?
julia> :($(Symbol("A")).$(Symbol("b")))
:(A.b)
It seems the word you are looking for is “expression” instead of “symbol”.
1 Like
Thanks Kristoffer, that helps.
However, in my code, I still get an error which is perhaps something of different nature. My code looks like this:
Module bla
**export foo
function foo(B::MyType)
** var1 = “b = 10”. #I get this from a data file**
** var2 = Meta.parse(string(“B.”,var1). #creating “B.b = 10”**
** expr1 = Meta.parse(var2)**
** eval(expr1). #evaluate expr1**
end
end
Output when I run my code with (note that the mutable struct MyType is exported from another module and is known)
using bla
B = MyType()
foo(B)
ERROR: LoadError: UndefVarError: B not defined.
If I replace the line eval(expr1) with B.b=10 in the module bla there is no error message. B.b just refers to the value 10.
What is there I don’t understand? Thanks a lot!
Please see PSA: how to quote code with backticks.
That eval
operates on global scope. From what you have shown so far there is no need for any of this parse
+ eval
stuff, just do something like:
mutable struct MyType
a::Int
b::Int
end
function foo!(B::MyType)
var1 = "b = 10" # from data file
sym, val = strip.(split(var1, "="))
setproperty!(B, Symbol(sym), parse(Int, val))
end
with the result
julia> B = MyType(1, 2)
MyType(1, 2)
julia> foo!(B)
10
julia> B # B.b has been changed
MyType(1, 10)
Thanks a lot, this is higher Julia language that I did not know of. I come from the Fortran world where you have a limited number of commands.
There is still one thing I cannot solve. The type of sym differs (I read many var1’s from a data file), but I cannot do parse(typeof(Symbol(sym)), val) because sym is a field in B. How to tackle this?
You can lookup the fieldtype in MyType
and parse it as that
mutable struct MyType
a::Int
b::Float64
end
function foo!(B::MyType)
vars = ["a = 10"
"b = 2.0"] # from data file
for line in vars
var, val = strip.(split(line, "="))
sym = Symbol(var)
T = fieldtype(MyType, sym)
setproperty!(B, sym, parse(T, val))
end
end
julia> B = MyType(1, 2.0)
MyType(1, 2.0)
julia> foo!(B)
julia> B
MyType(10, 2.0)
The question here is, what subset of the full Julia language do you want to support. If it is the full Julia language then obviously you are going to need a Julia parser at some point, but if you just want to set some numbers and strings, invoking the Julia parser is overkill and can lead to security problems.
Hi Kristoffer,
Thanks! It works flawlessly, except for the fields that have an array:
a = 10 #this is a single value
b = [1,2,3] # an array
Thus, var = “b” and val = “[1,2,3]”. Parsing, however, goes wrong here. You cannot do something like parse(Array{Float64},val). Sorry for asking you, but I am (seems now) very unexperienced in Julia. It is very hard to get good info on internet.
This is related to my question of what subset of Julia you want to support for the RHS of the assignment. Is JSON enough? Then you could add the JSON package with
import Pkg
Pkg.add("JSON")
and use something like
using JSON
mutable struct MyType
a::Int
b::Float64
c::Vector{Int}
name::String
end
function foo!(B::MyType)
vars = ["a = 10",
"b = 2.0",
"c = [1, 2, 3]",
"name = \"John\""] # from data file
for line in vars
var, val = strip.(split(line, "="))
setproperty!(B, Symbol(var), JSON.parse(val))
end
end
julia> B = MyType(1, 2.0, [0, 0, 0], "");
julia> foo!(B);
julia> B
MyType(10, 2.0, [1, 2, 3], "John")
2 Likes
Hi Kristoffer,
This solutions works perfectly. Thanks a lot for your prompt help!!!
Martin