# Naming positional arguments at call site

**URL:** <https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526>\
**Category:** Internals & Design\
**Created:** [September 4, 2023, 7:07pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526 "2023-09-04T19:07:20Z")\
**Posts on this page:** 20\
**Page:** 2

<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:** [September 4, 2023, 8:07pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/22 "2023-09-04T20:07:36Z")

</div>

> [@ParadaCarleton](#):
>
> Then, we would have to replace positional arguments for every function in Julia with keyword arguments.

Absolutely not. This would be only for those who actually want this sort of abomination in their code.

---

<div class="post-metadata">

**Author:** ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)\
**Post date:** [September 4, 2023, 8:09pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/23 "2023-09-04T20:09:33Z")

</div>

> [@DNF](#):
>
> Absolutely not. This would be only for those who actually want this sort of abomination in their code.

It’s your proposal, not mine. I want to give users that choice; you’re saying we should make keyword arguments faster and then use them to replace positional arguments.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [September 4, 2023, 8:10pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/24 "2023-09-04T20:10:50Z")

</div>

> [@ParadaCarleton](#):
>
> It seems like Julia devs still haven’t learned the lessons of TensorFlow. TensorFlow/Keras blew a 4-year lead to PyTorch because PyTorch was slightly more readable, despite TensorFlow being orders of magnitude faster under some circumstances.

…

I’m pretty confident there are more differences between the libraries than just “PyTorch is slightly more readable”

> This is one of the top 3 or 4 complaints about the issue that I hear people bring up

they’ll get over it. this is one of those complaints that’s mostly just fear of the unfamiliar than an actual issue with the language. I would categorize it with all those who call Julia doomed because of 1-based indexing

---

<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:** [September 4, 2023, 8:10pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/25 "2023-09-04T20:10:52Z")

</div>

> [@ParadaCarleton](#):
>
> I want to give users that choice;

Your suggestion implies forcing everyone to make their variable names part of the API. It’s incredibly intrusive and messy.

Variable names are internal implementation details, they should not be leaked like that, that’s what keywords are for.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [September 4, 2023, 8:12pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/26 "2023-09-04T20:12:12Z")

</div>

Turing and other packages where this makes sense can (and in some cases should) set up something like

```julia
function sample(; # keyword args only
    rng=Random.default_rng(),
    logdensity,
    sampler,
    N_or_isdone,
    kwargs...,
)
   return sample(rng, logdensity, sample, N_or_isdone; kwargs...)
end

```

This can certainly make high-level functions easier to use, and produce more readable code, but it can also come at a performance cost, and doesn’t generally fit with arbitrary functions or interfaces.

If the developers of Turing don’t want to support such an API, I wouldn’t think it unreasonable for you to make such a definition e.g., at the top of a Jupyter notebook. Strictly speaking, it’s type piracy, but there’s nothing wrong with defining your own convenience functions in a local environment.

---

<div class="post-metadata">

**Author:** ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)\
**Post date:** [September 4, 2023, 8:19pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/27 "2023-09-04T20:19:51Z")

</div>

> [@adienes](#):
>
> I’m pretty confident there are more differences between the libraries than just “PyTorch is slightly more readable”

Not particularly. People liked PyTorch because eager mode was more intuitive and produced readable error messages, and also because it was more readable than TensorFlow. These are the main reasons any ML developer will give if you ask them why they switched.

> [@adienes](#):
>
> they’ll get over it.

It’s been 3 years since I learned Julia and if it weren’t for the package manager I’d go back to Python for this feature alone. I like it when my models are readable and I can check them for bugs.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [September 4, 2023, 8:29pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/28 "2023-09-04T20:29:49Z")

</div>

> [@ParadaCarleton](#):
>
> It’s been 3 years since I learned Julia and if it weren’t for the package manager I’d go back to Python for this feature alone

You can easily implement your own [keyword-only wrappers](https://discourse.julialang.org/t/what-steps-should-the-julia-community-take-to-bring-julia-to-the-next-level-of-popularity/101389/634) to get exactly the behavior you want. If you’re worried about it being type piracy, or don’t want to define it over and over again in every notebook, put it in a separate package.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [September 4, 2023, 8:35pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/29 "2023-09-04T20:35:57Z")

</div>

> [@goerz](#):
>
> This can certainly make high-level functions easier to use, and produce more readable code, but it can also come at a performance cost, and doesn’t generally fit with arbitrary functions or interfaces.
> 
> If the developers of Turing don’t want to support such an API, I wouldn’t think it unreasonable for you to make such a definition e.g., at the top of a Jupyter notebook. Strictly speaking, it’s type piracy, but there’s nothing wrong with defining your own convenience functions in a local environment.

The high level automated solver interface is the funniest thing. I never use it. The other devs never use it. In fact, many of the devs dislike it because it naturally has a bit of overhead (and some type instability due to how it currently chooses the algorithm, etc.)

But,

every time I talk to random users, it’s the best feature. DifferentialEquations.jl, just call `solve(prob)`, so much easier than learning `ode45` and `ode15s` and trying to learn what stiff is. And when I see “semi-power users” choose algorithms, they often choose a worse one than the default algorithm.

I almost got rid of it in like 2018 because it was too suboptimal in my mind. But it’s more optimal than what most people would do, so it’s a killer feature 🤷.

---

<div class="post-metadata">

**Author:** ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)\
**Post date:** [September 4, 2023, 8:41pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/30 "2023-09-04T20:41:28Z")

</div>

How can I give a million likes to this 😅

Chris for BDFL 2024

---

<div class="post-metadata">

**Author:** ![GregVernon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gregvernon/32/5611_2.png) [@GregVernon](https://discourse.julialang.org/u/GregVernon)\
**Post date:** [September 4, 2023, 8:41pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/31 "2023-09-04T20:41:41Z")

</div>

Excuse my naivete, but I had assumed that the “Julian” approach to something like you’ve described as being to simply add type to the positional argument:

```julia
function LinearAlgebra.eigvals( A::Hamiltonian )
   # content
end

function LinearAlgebra.eigvals( A::Liouvillian )
   # content
end

```

I hadn’t even considered that it was possible to overwrite a positional argument’s “name” in a Julia method. I can accept that my desire might require a Julia 2.0, and thus will never happen, but it is slightly disappointing to me that _that_ functionality was preferred over allowing `LinearAlgebra( A=stiff_matrix )` usage. I’m sure there’s _way more_ functionalities and capabilities that are enabled other than just this single tradeoff, but if it was simply “one or the other” then it seems more natural to follow the form common in mathematical writing:

> A generalized eigenvalue problem (second sense) is the problem of finding a (nonzero) vector \mathbf {v} that obeys
> 
> \mathbf{A} \mathbf {v} = \lambda \mathbf {B} \mathbf {v} ,
> 
> where \mathbf{A} is a sparse positive-definite matrix and \mathbf{B} is a sparse diagonal matrix

\mathbf{A} might in fact be a stiffness matrix (or an assembly operator), and \mathbf{B} a mass matrix (operator), but the equation (function) isn’t fundamentally different if you wrote it \mathbf{K} \mathbf {d} = \lambda \mathbf {M} \mathbf {d}. In my worldview the information about the structure \mathbf{A} and \mathbf{B} are should be communicated in the type (i.e., `where _ is a ...`), not in the variable name.

All that being said, I view this more as a “nice-to-have” rather than a “blocker”, I just use comments in my code to get around readability issues when I see them:

```julia
# Solve Aϕ=λBϕ, where A = stiff_matrix, B = mass_matrix
Arpack.eigs( stiff_matrix, mass_matrix; nev=1, which=:SR, sigma=1.0)[0]

```

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [September 4, 2023, 8:50pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/32 "2023-09-04T20:50:35Z")

</div>

> [@ParadaCarleton](#):
>
> `sample(Xoshiro(0), NUTS(), model)`

It seems obvious what’s going on in this case. Is there another example of where named arguments would help?

---

<div class="post-metadata">

**Author:** ![xiaoxi](https://avatars.discourse-cdn.com/v4/letter/x/a9adbd/32.png) [@xiaoxi](https://discourse.julialang.org/u/xiaoxi)\
**Post date:** [September 4, 2023, 8:52pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/33 "2023-09-04T20:52:10Z")

</div>

> [@What steps should the Julia community take to bring Julia to the next level of popularity?](https://discourse.julialang.org/t/what-steps-should-the-julia-community-take-to-bring-julia-to-the-next-level-of-popularity/101389/637):
>
> The philosophy should be: **whatever is best for the inexperienced user for the 90% use case**

The Julia community could also adopt Plasma’s motto: “Simple by default, powerful when needed.”

> **[KDE Plasma 5.10, Simple by Default, Powerful when Needed](https://kde.org/announcements/plasma/5/5.10.0/)**
>
> KDE Ships Plasma 5.10.

---

<div class="post-metadata">

**Author:** ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)\
**Post date:** [September 4, 2023, 8:56pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/34 "2023-09-04T20:56:07Z")

</div>

Well actually the problem is that has a 50/50 shot at being the wrong order for `NUTS()` and `model` (I can never remember which comes first)

---

<div class="post-metadata">

**Author:** ![GregVernon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gregvernon/32/5611_2.png) [@GregVernon](https://discourse.julialang.org/u/GregVernon)\
**Post date:** [September 4, 2023, 8:59pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/35 "2023-09-04T20:59:14Z")

</div>

I mean, as someone who didn’t write @ParadaCarleton’s code, when I saw

```julia
sample(rng=Xoshiro(0), sampler=NUTS(), model=my_loglikelihood)

```

I _immediately_ was able to read what he wrote:

“Ok, so use `Xoshiro(0)` as the random number generator, `NUTS()` is the sampler, and use `my_loglikelihood` as the model.”

If instead see:

```julia
sample(Xoshiro(0), NUTS(), my_loglikelihood )

```

Then I need to do the following:

1. Search Google (or my repo) to find the package(s) contain `sample()` method so I can then
2. Read the API reference doc for `sample()` to see what the arguments are
  - Of course, if I’m somewhere with no / poor internet connection and the docs are online, then I’m stuck.

The first example is just _so_ much easier for me to read.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [September 4, 2023, 9:02pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/36 "2023-09-04T21:02:33Z")

</div>

I don’t think anybody is disputing the potential value of designing an API to make heavy use of keyword arguments

however, that goal has (almost) nothing to do with the specific design proposal, of making positional arguments named.

I would conjecture that for nearly all functions that would benefit from a kwarg-only API, the extra overhead of a single function call (and defining `foo(; kwargs...) = foo(values(kwargs)...)`) is completely negligible

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [September 4, 2023, 9:04pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/37 "2023-09-04T21:04:21Z")

</div>

You mean the case when you’re writing it rather than reading it?

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [September 4, 2023, 9:06pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/38 "2023-09-04T21:06:47Z")

</div>

Tangentially also Python has found it valuable to have the option to specify positional-only arguments: [PEP 570 – Python Positional-Only Parameters | peps.python.org](https://peps.python.org/pep-0570/)

---

<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:** [September 4, 2023, 9:18pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/39 "2023-09-04T21:18:51Z")

</div>

> [@What steps should the Julia community take to bring Julia to the next level of popularity?](https://discourse.julialang.org/t/what-steps-should-the-julia-community-take-to-bring-julia-to-the-next-level-of-popularity/101389/604):
>
> The inability to use positional arguments with keywords

> [@ParadaCarleton](#):
>
> The compiler could handle it easily (see KeywordCalls.jl, which gives 0-cost keyword dispatch). The fact that keywords force runtime dispatch is because of a heuristic in the Julia compiler

I’ve tackled this before (and so have a lot of other much smarter people), and no, using keywords to specify positional arguments out of order really relies on a function having 1 method for each unique set of names. Simple example:

```julia
foo(a::Int, b::Float64) = a+b
foo(b::Float64, a::Int) = b-a
@keywordedpositional foo(b=1.5, a=2) # ambiguity error

```

KeywordCalls.jl doesn’t do an error in such a case, it uses the position of the keywords, which defeats the purpose of using keywords to shuffle positional arguments and adds an undesired layer of complexity to dispatch (`f(::Int, ::Int)` type signature not enough, needs additional keywords to determine which 1 of 2 methods).

```julia
# Adapting front page example to have >1 method for arguments (a,b)
using KeywordCalls
f(nt::NamedTuple{(:b, :a)}) = println("Calling f(b = ", nt.b,",a = ", nt.a, ")")
f(nt::NamedTuple{(:a, :b)}) = println("Calling f(a = ", nt.a,",b = ", nt.b, ")")
@kwcall f(b,a) # writing f(a, b) makes no difference here
#^ but if only 1 method exists, the order should match that method

f(a=1,b=2) # Calling f(a = 1,b = 2)
f(b=2,a=1) # Calling f(b = 2,a = 1)

```

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [September 4, 2023, 9:36pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/40 "2023-09-04T21:36:05Z")

</div>

Was also just thinking about that. E.g., R matches unnamed arguments by position, but named ones by name:

```plaintext
f <- function(x, y = 1) { ... }
# Can be called as
f(1.0) # same as f(x = 1.0, y = 1)
f(y = 2, 3) # same as f(x = 3, y = 2)
f(y = 2, x = 1) # same as f(x = 1, y = 2)

```

Arguably, this can become a bit confusing when mixing positional and named arguments arbitrarily. On the other hand, it raises the following question for Julia:

```julia
julia> (; a = 1.0, b = 2) |> typeof
NamedTuple{(:a, :b), Tuple{Float64, Int64}}

julia> (; b = 2, a = 1.0) |> typeof
NamedTuple{(:b, :a), Tuple{Int64, Float64}}

```

Should this actually be the same type (and value for that matter)?, I.e., should `(; b = 2, a = 1.0) == (; a = 1.0, b = 2)` be true?

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [September 4, 2023, 9:36pm UTC](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526/41 "2023-09-04T21:36:46Z")

</div>

> [@bertschi](#):
>
> should `(; b = 2, a = 1.0) == (; a = 1.0, b = 2)` be true?

no, but the associated function calls with those NT as kwargs should be equivalent

[Previous page](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526.md?page=1)

[Next page](https://discourse.julialang.org/t/naming-positional-arguments-at-call-site/103526.md?page=3)
