Creating a new Symbol from two strings with a point

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