# Breaking circularity in fallback methods

**URL:** <https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219>\
**Category:** General Usage\
**Tags:** question\
**Created:** [January 7, 2018, 3:13pm UTC](https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219 "2018-01-07T15:13:39Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [January 7, 2018, 3:13pm UTC](https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219/1 "2018-01-07T15:13:39Z")

</div>

I have two functions `f(x, y)` and `g(x, y)`. For some types of `x`, it may be advantageous to reuse components of calculations when both are needed, for some other types this is not the case. On the other hand, sometimes I just need `f` or `g`.

I could define

```julia
fg(x, y) = f(x,y), g(x, y)
f(x, y) = fg(x,y)[1]
g(x, y) = fg(x,y)[2]

```

as fallback methods, and then either define

```julia
fg(x::SomeType, y) = ...

```

or

```julia
f(x::SomeOtherType, y) = ...
g(x::SomeOtherType, y) = ...

```

The problem is that if I have a missing method, I get a `StackOverflowError`. Is there a way to avoid this, and break the circularity when I don’t have the right methods?

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [January 7, 2018, 3:42pm UTC](https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219/2 "2018-01-07T15:42:53Z")

</div>

I’ve been battling this a lot recently, I hope you can get a good way for handling that!

---

<div class="post-metadata">

**Author:** ![Liso](https://avatars.discourse-cdn.com/v4/letter/l/898d66/32.png) [@Liso](https://discourse.julialang.org/u/Liso)\
**Post date:** [January 7, 2018, 7:56pm UTC](https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219/3 "2018-01-07T19:56:07Z")

</div>

What about this trick?

```julia
fg(x, y, undef=false) = if undef "stack","overflow" else f(x,y), g(x, y) end;

f(x, y, undef=true) = fg(x,y,undef)[1]
g(x, y, undef=true) = fg(x,y,undef)[2]

```

You could overwrite without `undef` argument:

```julia
f(x::Int, y) = 0
g(x::Int, y) = 0

fg(1,1) # -> (0, 0)
fg(1.,1) # -> ("stack", "overflow")

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [January 8, 2018, 9:55am UTC](https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219/4 "2018-01-08T09:55:46Z")

</div>

This works, but AFAICT has a costly method table lookup. Can this be optimized away somehow?

```julia
@inline function fallback(fun, x::T) where T
    if which(fun, Tuple{T}) ≡ which(fun, Tuple{Any})
        error("no fallback method `$fun` for `$T`")
    else
        fun(x)
    end
end

f(x) = fallback(fg, x)[1]

g(x) = fallback(fg, x)[2]

fg(x) = fallback(f, x), fallback(g, x)

f(x::Float64) = x + 1

g(x::Float64) = zero(x)

fg(x::Int) = x^2, 2*x

```

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [January 8, 2018, 4:25pm UTC](https://discourse.julialang.org/t/breaking-circularity-in-fallback-methods/8219/5 "2018-01-08T16:25:37Z")

</div>

The costly method lookup is just from type instability. Change it to

```julia
function fg(x, y, undef=false)
    undef && error("You must define either `fg` or `f` and/or `g` for inputs ", x, " and ", y)
    f(x, y), g(x, y)
end

```

and the performance hit should go away.
