I stumbled into a curious problem that seems like it surely must already been solved by someone before, maybe even somewhere in Base that I’m just not familar with. I figured I’d consult the brain-trust here to see if anyone had any good ideas.

# Problem

Say I’ve defined some set of types `A`

, `B`

, `C`

, etc and I want to define a binary/two-argument function `f`

that acts on these and is commutative (i.e. `f(x,y) == f(y,x)`

). There are a large number of possible combinations of argument types and many but not all of them will be implemented. I’m looking for an elegant way to implement this commutativity.

# Ideas

Here’s some thoughts I’ve had, but I’m very open to new ideas.

## Option 1

For every pair of argument types that I intend to implement, I could explicitly define two methods.

```
f(x::A, y::B) = ...
f(x::B, y::A) = f(y, x)
f(x::A, y::C) = ...
f(x::C, y::A) = f(y, x)
...
```

**Pro:** It works. Not overly complicated.

**Con:** It requires a second boilerplate method for every implemented method. I have to remember to add both every time I implement a new method. For a large number of possible types, this is a non-trivial number of additional method definitions.

Maybe this could be implemented with a macro?

```
@commutative f(x::A, y::B) = ...
@commutative f(x::A, y::C) = ...
...
```

## Option 2

I could define a single generic two-argument fallback method that reverses argument order.

```
f(x::A, y::B) = ...
f(x::A, y::C) = ...
f(x, y) = f(y, x)
```

**Pro:** Requires less boilerplate code.

**Con:** Generates a `StackOverflow`

if `f`

has not been implemented for this `(x,y)`

pair.

I considered adding a `hasmethod(f, typeof.(y, x))`

check or `applicable(f, y, x)`

in the fallback method with the hope that it would prevent recursion for unimplemented pairs, but this method definition itself would serve for `(::Any, ::Any)`

.