I find that cases like this are easier to handle by constructing the expression directly. You can construct any Julia expression by directly building an Expr(), and you can find out how a particular expression is built using dump(). For example:
julia> dump(:(a, b))
Expr
head: Symbol tuple
args: Array{Any}((2,))
1: Symbol a
2: Symbol b
We can infer from that dump() output that we can construct a tuple expression like so:
julia> Expr(:tuple, :a, :b)
:((a, b))
Or to construct a tuple expression from arbitrarily many other expressions, we can do:
julia> Expr(:tuple, ex...)
:((x + y, x - y))
By the way, I should mention that you actually don’t need a @generated function in the case you posted originally. A @generated function is necessary when you want the generated code to depend on the types of the input arguments, but your code doesn’t actually depend on the types of x or y.
Instead, you can just use @eval to construct the function right away:
julia> @eval function f(x, y)
($(ex[1]), $(ex[2]))
end
f (generic function with 1 method)
julia> f(1, 2)
(3, -1)
or, using the splatting syntax:
julia> @eval function f(x, y)
$(Expr(:tuple, ex...))
end
f (generic function with 1 method)
julia> f(1, 2)
(3, -1)