Then the following works as expected, yielding an instance of M.T:
eval(:(M.T()))
Using the type indirectly also works, yielding again an instance of M.T:
stype = M.T
eval(:($stype()))
However, dumping the expression for indirect approach:
dump(:($stype()))
Expr
head: Symbol call
args: Array{Any}((1,))
1: M.T <: Any
typ: Any
it becomes obvious that it incorporated the entire type into expression tree. Comparing to the direct way:
dump(:(M.T()))
Expr
head: Symbol call
args: Array{Any}((1,))
1: Expr
head: Symbol .
args: Array{Any}((2,))
1: Symbol M
2: QuoteNode
value: Symbol T
typ: Any
typ: Any
And here we got a well-formed expression tree.
Question: how to achieve the same effect (a well-formed expression tree) using the indirect approach, through the stype variable?
But there is no easy way to achieve the exact correspondence between the trees? For my purposes the behavior of the :(M.T()) is more desirable than that of :($stype()), but I need to use the dynamically supplied stype::DataType variable.
It’s unclear what do you want with :(M.T()) since it’s not really well defined. Or there’s basically no robust way to construct a expression with only symbols that can reliably refer to the right object in all evaluation context.
Thank you for the answer, I don’t want anything with :(M.T()), I do want to (and need to) use :($stype()). The code you pointed me at only shows how to get the name of the current module. Is there any function which allows to get the module in which a type is defined? In this case I can construct Symbol-only expression manually, this seems to be the only way.
There’s nothing wrong with inserting literal objects into expressions, like :($stype) or :($M.stype). I do it all the time. Why do you want to avoid it? If you construct :(ModuleName.type), you’ll have problems in places where ModuleName is not imported, or when it’s shadowed by a local variable.
@cstjean I was surprised actually that it works at all, and thought that this is not a correct way of doing this.
So what happens to this literal object when
expression is evaluated? Literal objects are just inserted in right places, while others constructed from symbolic representations? In this case the expression acts as a closure, allowing to insert objects from elsewhere?
expression is converted to a string (if you want some generated code to stay as a physical file)?
@mauro3 thanks for the tip, this indeed will allow to express a DataType in symbolic form. Btw, how to find out things like this (that DataType has a field name)? Documentation explorer yielded nothing about DataType and its internals, fieldnames() returns fields of the DataType itself.
That works exactly as you would expect. In fact, it simplifies the compiler’s job, since it knows exactly what object is there, instead of having to look it up. It’s just a pointer to an object - there’s no memory issue.
If you just want to print it, it kinda works, but obviously if you want to eval/parse that code, you’re likely to have problems with some objects (types are probably fine?). You could also try JLD.jl/JLD2.jl instead of printing it.