WebDev
WebDev

Reputation: 1381

How to instantiate a struct in Julia where I have the struct name in a string variable?

The name of the struct to instantiate will be passed by the caller to my program. Then I would need to instantiate the corresponding struct for the same for further processing.

For example, if the struct is defined like this

struct A end

and I have a function defined as

function load(struct_name::AbstractString)
    if struct_name == "A"
        return A()
    elseif struct_name == "B"
        return B()
    elseif ..... # and so on
    end
end

it will work. But is there a more direct way like return struct_name() instead of having n number of if else statements? I see that Julia supports reflection. How can that be used to support the above use case?

Upvotes: 2

Views: 1571

Answers (3)

HarmonicaMuse
HarmonicaMuse

Reputation: 7893

You could use a macro instead:

julia> module Load
       export @load

       macro load(struct_name::Symbol)
           return :($(esc(struct_name))())
       end

       end
Main.Load

julia> using Main.Load: @load

julia> struct A end

julia> struct B end

julia> @load A
A()

julia> @macroexpand @load B
:(B())

julia> @load C
ERROR: UndefVarError: C not defined
Stacktrace:
 [1] top-level scope at none:0

Upvotes: 1

Evgeny
Evgeny

Reputation: 4571

An example of dictionary-based dispatch. Dict("a" => A, "b" => B)[tag] selects a constructor, and () calls it.

struct A end
struct B end

function dispatch(tag)
   return Dict("a" => A, "b" => B)[tag]()
end

@assert dispatch("a") == A()

If you care about default values to handle unexpected parameter, for example dispatch('zzz'), you can make recourse to get().

As a side note about risks of eval() there is a small collection of powerful warning references in a neighboring Python question. In short, eval() is a big security hole and a 'smell' (warning sign) for a questionable design of a program.

Upvotes: 1

Bogumił Kamiński
Bogumił Kamiński

Reputation: 69949

I would recommend not doing it in production code, but you can do the following:

function load(struct_name::AbstractString)
    invoke(eval(Symbol(struct_name)),Tuple{})
end

strut_name via eval will get resolved in the global scope of the module.

It is safer to use a dictionary as @EPo suggested.

Upvotes: 3

Related Questions