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

```
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

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

or

```
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?

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

Liso
January 7, 2018, 7:56pm
3
What about this trick?

```
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:

```
f(x::Int, y) = 0
g(x::Int, y) = 0
fg(1,1) # -> (0, 0)
fg(1.,1) # -> ("stack", "overflow")
```

1 Like

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

```
@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
```

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

```
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.

1 Like