I have a string x
. I think that x
is a string representation of a type that is a subtype of Number
. For example, x
might take the value "Float64"
. I could check this using:
eval(parse(x)) <: Number
However, it is possible that x
contains something dangerous, like some variant on "rm(something_important)"
, so using eval
is a bad idea until I'm sure x
is safe.
Is there any way I can safely check whether x
is a string representation of a subtype of Number
?
(other than building an array of strings of all possible sub-types of Number
and comparing...)
The HDF5.jl package has to deal with this. It tackles it by parsing the string and then inspecting the result before
eval
ing it. If the parsed string is what it considers to be avalid_type_expression
then it knows that it should be safe to evaluate in theMain
namespace. This allows it to pickup custom types from the Main namespace that wouldn't be available from within abaremodule
.More details: After you parse an arbitrary string, you can inspect the returned object to see if it's "safe" to evaluate:
We want to ensure that we never
eval
an expression that could call arbitrary behaviors. Depending on how thoroughly you want to support the type syntax, your solution could be quite simple or it could be as complicated as the HDF5 solution I linked above. If you're just after simple, unparameterized types we can simplify things substantially:Note that anything more complicated than a symbol isn't allowed to be
eval
'ed. And aftereval
ing the expression, we check to ensure that the type is a Type and that it's a subtype ofNumber
. This will also allow custom subtypes ofNumber
in addition to the builtin ones, since we're evaluating it in theMain
namespace.Edit: This solution is not safe. Read the comments. I leave it because it is still instructive.
eval
optionally takes a module as its first argument.You could evaluate it in a bare module (
baremodule
), so the command doesn't have access to the standard library (then it cannot do much harm).