Your problem lies probably in the use of eval rather than Meta.parse (which, incidentally, you could probably replace by Symbol in this case). The problem is that eval evaluates an expression within the context of a module. If everything was defined in the same module, you wouldn’t have any problem:
julia> struct Foo end
julia> gettype(s::String) = Meta.parse(s) |> eval
gettype (generic function with 1 method)
julia> gettype("Int")
Int64
julia> gettype("Foo")
Foo
In your case however, since your JSONPointer constructor is in a separate package (and therefore a separate module), the type symbol is evalled in the context of the JSONPointer module, where type Foo does not exist. Hence the error:
julia> module MyModule
gettype(s::String) = Meta.parse(s) |> eval
end
Main.MyModule
# Still works because `Int` is defined both in Main and MyModule
# (and refers to the same thing, which could not be the case!)
julia> MyModule.gettype("Int")
Int64
# Does not work because Foo is unknown in the context of MyModule
julia> MyModule.gettype("Foo")
ERROR: UndefVarError: Foo not defined
One way you could circumvent the problem would be to add an argument providing the module in which type names have to be evaluated:
julia> module MyModule2
gettype(s::String, mod=@__MODULE__) = Symbol(s) |> mod.eval
end
Main.MyModule2
# No absolute need to provide a module here
# (but it would probably be better anyway)
julia> MyModule2.gettype("Int")
Int64
# Same as above
julia> MyModule2.gettype("Foo")
ERROR: UndefVarError: Foo not defined
# Foo is known in the context of the calling module
julia> MyModule2.gettype("Foo", @__MODULE__)
Foo
For this type of reasons, using eval is sometimes considered “bad style”. I personally don’t know any way avoiding it in this case; hopefully someone more knowledgeable will chime in and propose a better solution…
Providing a module is most likely not the correct solution.
The fundamental issue is that the a name is not enough to uniquely qualify an object (including types). A name needs to be combined with a name space to look up into.
Unless you have some specific use case that will always require the user to import all the needed types into the same namespace (which is basically not needed for anything else in the language) and unless the string is not meant to transfer generic information, you should not pass in the module separately.
If the string is used basically as code to pass local information, then you should not use string. You should pass in the information directly. If you are only using it to construct an object more easily, you can use a macro.
Otherwise you should encode the fully qualified name in the string.
If you are asking what’s the difference between what I said and what you are suggesting, I’m saying that what’s missing is not a module for the function, it’s missing from the string.
Also something that I forgot to say, this is the simplest case to avoid eval, you are just accessing module member and you should just do that instead of eval. What you need is getfield or getproperty.
You could use Meta.parse and then a little bit of logic to do this.
Its a question as to what module you should be using.
To be preperly explict about the type in this case you should be using its originating module-- Base.
But if you want what ever is in scope then @__MODULE__
or if in repl and saving chacacters Main