When I have a somewhat complex datatype, I often end up constructing it by
assigning values to local variables, then constructing a value of the
datatype in one go at the end, like "x,y=1,2; Foo(x,y)". When there are
many fields, Haskell's RecordWildcards idea is convenient: there you can
say "Foo{..}", which is equivalent to "Foo(x,y)", where x, y are local
variables. You can also decompose structures the same way: "Foo {..} = v"
is equivalent to "x, y = v.x, v.y" (not haskell syntax). The order of
variables is always correct, and the result is more readable, so long as
you know what the field names are.
So in julia, it would be convenient to have macros that allow you to
construct a type from local variables, and that allow you to inject a
type's fields into the local environment, just like pattern matching with
record wildcards in haskell, like so:
macro make(typename)
> datatype = eval(typename)
> @assert isa(datatype, DataType)
> fields = names(datatype)
> esc(Expr(:call, typename, fields...))
> end
> macro inject(typename, varname)
> datatype = eval(typename)
> @assert isa(datatype, DataType)
> fields = names(datatype)
> esc(Expr(:block, map(f -> :($f = $varname.$f), fields)...))
> end
An example would be
type Foo; x; y; end
> x = 1
> y = 2
> var = @make Foo
> var2 = Foo(3, 4)
> @inject Foo var2
@show x, y
Any thoughts? The use of "eval" is slightly ugly, but the macro needs to
know the field names of a type when it is expanded, and it cannot be a
function because it needs to use local variables.
This is not so good for accessing fields of an external julia library,
because you don't really know which fields are present there, but it's
convenient when you have control over the fields yourself.
Also, how can I get a macro to evaluate an expression in the context of its
caller? Otherwise, the "eval(typename)" is incorrect, and I don't want to
call it as "eval(:(@inject $Foo varfoo))". The type declaration should (I
think) already be known when the macro is expanded.