# Optional positional arguments must occur at end

**URL:** <https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051>\
**Category:** Internals & Design\
**Created:** [April 5, 2022, 2:22pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051 "2022-04-05T14:22:31Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jean\_Michel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jean_michel/32/8282_2.png) [@Jean\_Michel](https://discourse.julialang.org/u/Jean_Michel)\
**Post date:** [April 5, 2022, 2:22pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/1 "2022-04-05T14:22:31Z")

</div>

It seems to me that wanting optional arguments not at end needs unnecessary contortions in Julia.  
Here is a typical example:

```julia
julia> test(io::IO=stdout,x)=print(io,x)
ERROR: syntax: optional positional arguments must occur at end around REPL[13]:1
Stacktrace:
 [1] top-level scope
   @ REPL[13]:1

```

one needs to write two methods

```julia
julia> test(io::IO,x)=print(io,x)
test (generic function with 1 method)

julia> test(x)=print(stdout,x)
test (generic function with 2 methods)

```

why does not Julia generate in all cases the two methods, and let ambiguities happen or not happen?

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 5, 2022, 2:40pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/2 "2022-04-05T14:40:08Z")

</div>

You could have optional positional parameters only at the start too, but then it is just a style consideration (i.e., you gain nothing but changing the order of the parameters). If you have optional positional parameters at both sides of a non-optional positional parameter then all cases are ambiguous except by: providing only the non-optional parameters and providing all parameters (optional and non-optional). Not really useful.

---

<div class="post-metadata">

**Author:** ![Jean\_Michel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jean_michel/32/8282_2.png) [@Jean\_Michel](https://discourse.julialang.org/u/Jean_Michel)\
**Post date:** [April 5, 2022, 5:50pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/3 "2022-04-05T17:50:11Z")

</div>

You did not get my point. All cases are ambiguous without type information. But why not let Julia dispatching act. My case above is not ambiguous.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [April 5, 2022, 7:50pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/4 "2022-04-05T19:50:34Z")

</div>

**[Off-topic]**

> [@Jean\_Michel](#):
>
> You did not get my point.

Suggested wording for a generous contributor trying to help:  
_Thank you, but perhaps I’m not making myself clear._

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 5, 2022, 7:56pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/5 "2022-04-05T19:56:53Z")

</div>

It’s certainly possible but it does tend to generate a lot of methods and makes it really easy to generate ambiguities. Let’s think it through. The natural rule seems to be that an optional positional argument that comes before a required positional argument works like this:

```julia
f(a=1, b=2, c) = ...

# means

f(a, b, c) = ...
f(b, c) = f(1, b, c)
f(c) = f(1, 2, c)

```

That seems ok. So what’s the problem? The problem comes when this feature is combined with trailing optional positional arguments. And if you can do one or the other, it’s only a matter of time before someone asks for the two together. Say we allow that and someone writes this definition:

```julia
f(a=1, b=2, c, d=4, e=5) = ...

```

What would that seemingly simple definition mean? Let’s spell it out:

```julia
f(a, b, c, d, e) = ...

# omitting 1 argument
f(a, b, c, d) = f(a, b, c, d, 5)
f(b, c, d, e) = f(1, b, c, d, e)

# omitting 2 arguments
f(a, b, c) = f(a, b, c, 4, 5)
f(b, c, d) = f(1, b, c, d, 5)
f(c, d, e) = f(1, 2, c, d, e)

# omitting 3 arguments
f(b, c) = f(1, b, c, 4, 5)
f(c, d) = f(1, 2, c, d, 5)

# omitting 4 arguments
f(c) = f(1, 2, c, 4, 5)

```

As you point out, this could be made unambiguous if the arguments are typed in such a way that all of these signatures can be distinguished. But holy moly that seems hard to enforce. We could just not enforce it, of course. After all we don’t prevent ambiguities between different methods. But it’s one thing to allow people to write ambiguous methods with separate bodies, it’s another thing for a method to be so heavily ambiguous with _itself_! This really seemingly simple method definition has seven ambiguous methods and only two unambiguous ones.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [April 5, 2022, 8:06pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/6 "2022-04-05T20:06:08Z")

</div>

One thing I do think is that it’d maybe be nice if we could have **either** prefix optional arguments **or** trailing optional arguments, especially since patterns like

```julia
F(f=identity, v)
f(io=stdio, v)

```

are so common. Of course, this also makes footguns if the programmer themselves write

```julia
F(f=identity, x, y) = ...
F(f, x, y=x) = ...

```

but I also think this is less problematic than the case where they’re allowed to write

```julia
F(f=identity, x, y=x)

```

so it may be worth the convenience as it’s quite annoying to have to constantly write

```julia
F(x) = F(identity, x)
F(f, x) = ...

```

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 5, 2022, 8:14pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/7 "2022-04-05T20:14:45Z")

</div>

That might be fine if each method definition could only have optional leading or trailing positional arguments but not both.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [April 5, 2022, 8:15pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/8 "2022-04-05T20:15:48Z")

</div>

Yeah, that’s what I meant by

> [@Mason](#):
>
> One thing I do think is that it’d maybe be nice if we could have **either** prefix optional arguments **or** trailing optional arguments,

I guess I should have said “xor” 😆

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 5, 2022, 9:00pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/9 "2022-04-05T21:00:22Z")

</div>

> [@Mason](#):
>
> so it may be worth the convenience as it’s quite annoying to have to constantly write
> 
> ```julia
> F(x) = F(identity, x)
> F(f, x) = ...
> 
> ```

This is the sign of a spoiled developer (or maybe greedy 😉)

Because I always thought it was _awsome_ that I could write stuff like that 😀

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 6, 2022, 7:04pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/10 "2022-04-06T19:04:55Z")

</div>

Actually, here’s an interesting idea. We _can_ actually check a set of signatures for ambiguities at definition time. So we could make it an error to write a method definition that is ambiguous with itself. Currently it’s impossible to write such a method, so this would be non-breaking. That would make the `f(a=1, b=2, c, d=4, e=5) = ...` method definition illegal. But it would allow something like this:

```julia
F(f=identity, s::String, n::Integer=0) = ...

```

This definition would expand to:

```julia
F(f, s::String, n::Integer) = ...
F(f, s::String) = F(f, s, 0)
F(s::String, n::Integer) = F(identity, s, n)
F(s::String) = F(identity, s, 0)

```

Since that set of method signatures isn’t ambiguous, it’s fine. This might actually make it _easier_ to avoid accidental method ambiguities since if you can write the signature with a single method then you’d get an error if it’s ambiguous.

\<aside\>

We used to emit a warning at method definition time for method ambiguities, back in Julias 0.1-0.3 (IIRC). But this was a huge drag because it was common when multiple packages extended the same generic function (often from Base), for method ambiguities to arise between these extensions. Something like this:

```julia
# in Base
f(a::AbstractA, b::AbstractB) = # generic logic

# in PackageX
f(a::SpecificA, b::AbstractB) = # specialization on A

# in PackageY
f(a::AbstractA, b:: SpecificB) = # specialization on B

```

Now you have an ambiguity if someone calls `f(a::SpecificA, b::SpecificB)`. So loading packages commonly lead to screenfuls of ambiguity warnings, which just made everything seem janky and broken. Of course, if someone does call the ambiguous method, we don’t know what to do, so we throw an error. But it’s fairly common that this intersection method doesn’t make much sense and never gets called, in which case leaving it ambiguous is just fine. Anywho, that’s why we changed method ambiguities from definition-time warnings into runtime errors.

\</aside\>

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 6, 2022, 7:15pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/11 "2022-04-06T19:15:11Z")

</div>

One possible/probable indirect effect of this new feature is making even more common to add unnecessary type annotation to the parameters of methods. I do not like this possible outcome very much.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [April 6, 2022, 7:18pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/12 "2022-04-06T19:18:16Z")

</div>

If you need the type annotation then the API you wanted—and could already write out with multiple methods—was actually ambiguous, which is worse. You only need to restrict types enough to avoid ambiguity, which one should do anyway.

---

<div class="post-metadata">

**Author:** ![Jean\_Michel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jean_michel/32/8282_2.png) [@Jean\_Michel](https://discourse.julialang.org/u/Jean_Michel)\
**Post date:** [April 6, 2022, 9:46pm UTC](https://discourse.julialang.org/t/optional-positional-arguments-must-occur-at-end/79051/13 "2022-04-06T21:46:52Z")

</div>

Thank you very much for your answer. I think this was exactly my idea (which I did not make so clear).
