# Order-agnostic dispatch

**URL:** <https://discourse.julialang.org/t/order-agnostic-dispatch/138932>\
**Category:** General Usage\
**Created:** [August 19, 2026, 1:02pm UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932 "2026-08-19T13:02:21Z")\
**Posts on this page:** 8\
**Page:** 2

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 22, 2026, 1:15am UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/22 "2026-08-22T01:15:51Z")

</div>

Nobody should quote me on this, but I think the pairwise or canonical-to-pairwise ordering takes care of the combinations interference issue.

---

<div class="post-metadata">

**Author:** ![wheeheee](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wheeheee/32/36663_2.png) [@wheeheee](https://discourse.julialang.org/u/wheeheee)\
**Post date:** [August 22, 2026, 2:23am UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/23 "2026-08-22T02:23:59Z")

</div>

IMO, the easiest resolution is for OP to give up on not wanting to have to write `_f`’s arguments in canonical order, whatever they choose that to be.

---

<div class="post-metadata">

**Author:** ![philipky](https://avatars.discourse-cdn.com/v4/letter/p/4da419/32.png) [@philipky](https://discourse.julialang.org/u/philipky)\
**Post date:** [August 22, 2026, 4:11am UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/24 "2026-08-22T04:11:53Z")

</div>

Hi, I’m new here and just stumbled upon this thread.  
I come from the dotnet world so the solution that popped up in my head is more OOP like.  
But if you don’t care too much about elegance and is willing to push some error into runtime, you can consider using something like a builder. I’ve never written julia code (I’m just a lurker) so hopefully what I write makes sense.

```julia-auto
struct Builder
  a::TypeA
  b::TypeB
  ...
end

function _setA(builder::Builder, a)
function _setB(builder::Builder, b)
...
function run(builder::Builder) = f(a, b, ...) #throw if arguments are not set :(

```

Not clever or elegant, but at least you will get to control argument order until you find a more elegant solution. Feel free to correct me if this doesn’t work with type inference.

---

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [August 22, 2026, 10:43am UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/25 "2026-08-22T10:43:48Z")

</div>

[GitHub - Beforerr/PermuteArgs.jl: Generate multiple method definitions allowing arbitrary argument order based on types · GitHub](https://github.com/Beforerr/PermuteArgs.jl) may be of interest. I developed it for working with formula and it is general enough.

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [August 22, 2026, 9:38pm UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/26 "2026-08-22T21:38:21Z")

</div>

Cool, neat package! It seems like you implemented the method generator approach (n! scaling), so no canonical ordering? Any idea of the compilation overhead?

---

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [August 22, 2026, 10:55pm UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/27 "2026-08-22T22:55:36Z")

</div>

Yes. macro does a literal permutations(1:length(args)) and evals one concrete method per permutation so no @generated, no canonical order trick. I think JIT compilation is lazy so unused permutations are free until called (For Definition-time, noticeable at n=6 (720); n≥7 (5040+) would likely be painful or impractical.)

---

<div class="post-metadata">

**Author:** ![Beforerr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/beforerr/32/212045_2.png) [@Beforerr](https://discourse.julialang.org/u/Beforerr)\
**Post date:** [August 23, 2026, 12:03am UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/28 "2026-08-23T00:03:41Z")

</div>

A lazy option for macro has been added. So now we can have constant definition time.

---

<div class="post-metadata">

**Author:** ![arik](https://avatars.discourse-cdn.com/v4/letter/a/c4cdca/32.png) [@arik](https://discourse.julialang.org/u/arik)\
**Post date:** [August 24, 2026, 9:53pm UTC](https://discourse.julialang.org/t/order-agnostic-dispatch/138932/29 "2026-08-24T21:53:00Z")

</div>

I might be late to the party, but have you considered making a method with typed keyword arguments and then mapping your positional arguments onto these keywords?

```julia-auto
struct A x :: Int end
struct B x :: Int end
struct C x :: Int end

foo(;a::A, b::B, c::C) = begin #= your implementation here =# (a, b, c) end

foo(a::A, args...; kwargs...) = foo(args...; a, kwargs...)
foo(b::B, args...; kwargs...) = foo(args...; b, kwargs...)
foo(c::C, args...; kwargs...) = foo(args...; c, kwargs...)

println(foo(B(1), A(2), C(3)))
 # -> (A(2), B(1), C(3))
 
println(foo(C(1), B(2), A(3)))
 # -> (A(3), B(2), C(1))

 println(foo |> methods |> length) # -> 4

```

Pros: Only linear amount of methods, somewhat simple (compared to some other suggestions)  
Cons: Some boilerplate, each type in the signature must be unique (otherwise the problem becomes somewhat ill posed anyways).

If you do this regularly you could macroify the boilerplate away of course.

Edit: I could not sleep and ended up writing said macro myself. Hope it helps.

```julia-auto
using MacroTools

macro orderless_dispatch(fndef::Expr)
# this macro deserves better error handling and generalization to other syntactic 
# forms of function definition, but its a start
	@capture fndef function fnname_(args__) body_ end
	escargs = esc.(args)
	escbody = esc(body)
	escname = esc(fnname)

	mappingmethod(e) = begin
		@capture(e, arg_ :: T_) || throw("all arguments need to be typed")
		:($escname($(esc(arg)) :: $(esc(T)), args...; kwargs...) = $escname(args...; $(esc(arg)), kwargs...))
	end

	return quote
		function $escname(;$(escargs...)) $escbody end
		$((mappingmethod(arg) for arg in args)...)
	end
end

struct A x :: Int end
struct B x :: Int end
struct C x :: Int end
struct D x :: Int end

@orderless_dispatch function foo(a::A, b::B, c::C, d::D); (a, b, c, d) end

println(foo(D(1), C(2), A(3), B(4)))

```

[Previous page](https://discourse.julialang.org/t/order-agnostic-dispatch/138932.md?page=1)
