IterTools.jl provides an iterate method that does exatly this.
help?> iterated
…
iterated(f, x)
Iterate over successive applications of f, as in x, f(x), f(f(x)), f(f(f(x))), ...
…
julia> x_0, y_0 = 5, 10;
g1 = +;
g2 = -;
julia> using IterTools: iterated, nth
julia> nth(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 3)
(10, 20)
As the documentation says, the result is (an iterator over) (x, f(x), f(f(x)), …), which means (x_2, y_2) from the question would be f(f(x)) which is the third element - that's why the call to nth above passes 3 as the second argument.
An advantage of this method is that it returns an iterator that you can then treat like any other iterator. So if you instead want the results of all the first 5 stages of the process:
julia> using Base.Iterators: take
julia> take(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 5) |> collect
10-element Vector{Tuple{Int64, Int64}}:
(5, 10)
(15, -5)
(10, 20)
(30, -10)
(20, 40)
Or only want the recursion to continue while a condition is true:
julia> using Iterators: takewhile
julia> takewhile(((x, y),) -> x + y < 50,
iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0))) |> collect
4-element Vector{Tuple{Int64, Int64}}:
(5, 10)
(15, -5)
(10, 20)
(30, -10)