# \[Julia usage\] Passing "complex" arguments to a function with default values

**URL:** <https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506>\
**Category:** New to Julia\
**Tags:** argument, function\
**Created:** [May 4, 2021, 8:19am UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506 "2021-05-04T08:19:33Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![erwanlecarpentier](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erwanlecarpentier/32/23448_2.png) [@erwanlecarpentier](https://discourse.julialang.org/u/erwanlecarpentier)\
**Post date:** [May 4, 2021, 8:19am UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506/1 "2021-05-04T08:19:33Z")

</div>

Hi!  
This is a quite general question on the correct way to pass arguments with default values in Julia. I am concerned about the facts that 1) my function’s signature could get quite unreadable if I have many arguments with “complex” default values 2) if my default values require several lines of code to initialize the argument, it may be hard to write it in the signature.

Here is an example where the argument `a` is what I mean by “complex”:

```julia
function foo(n::Int64; a::Array{Int64}=Array{Int64}(undef, n, 2*n))
    println(a) # Do whatever
end

n = 2
foo(n) # use default value
foo(n, a=Array{Int64}(undef, 3)) # use specific value

```

So in this example, i see two drawbacks:

1. if I have many “complex” arguments like `a`, it may get harder to read;
2. if my initialization of `a` would require several lines of code, then I believe I cannot use this syntax.

I see one alternative using `kwargs`:

```julia
function foo(n::Int64; kwargs...)
    kwargs_dict = Dict(kwargs)
    if haskey(kwargs_dict, :a)
        a = kwargs_dict[:a]
    else
        a = Array{Int64}(undef, n, 2*n) # default value of `a`
        # Notice that here, setting `a` to its default value could be done in several lines of code
    end
    println(a) # Do whatever
end

n = 2
foo(n) # use default value
foo(n, a=Array{Int64}(undef, 3)) # use specific value

```

Is this alternative a good solution in terms of code readability / performance (is parsing `kwargs` expensive?). Do you have suggestions?  
Thanks!

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 4, 2021, 9:36am UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506/2 "2021-05-04T09:36:28Z")

</div>

A few things:

1. Type annotation in function signatures do nothing in terms of code optimization, so they’re not necessary here.
2. `Array{Int64}` is an abstract type, since it’s missing the dimensionality. Use `Array{Int64, 2}` or equivalently `Matrix{Int64}` if you want a 2-dimensional array.
3. `foo(n; a=...)` is already using keyword arguments: The `;` in front of `a=` makes `a` into a keyword (in contrast to `n`, which is a positional argument).

Your `foo` could just as well be written like `foo(n, a=Matrix{Int64}(undef, n, 2*n)`.

If your function has multiple arguments with default values, the following is an option:

```julia
function foo(n, m, p;
      a=...,
      b=...,
      c=...)
   # function body
end

```

But if you find to require a lot of arguments that you pass around to a lot of functions, it’s usually a good idea to start thinking about putting them into a struct and passing that around instead.

Another option would be to create a `bar` function that only takes the required arguments (e.g. `n`), takes arbitrary default arguments as keyword arguments, constructs remaining ones and passes that into the fully fledged `foo` (which takes _no_ keyword arguments). In that case, you’d expose `bar` as your “public” interface.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [May 4, 2021, 12:01pm UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506/3 "2021-05-04T12:01:23Z")

</div>

It’s also possible to define helper functions to create your default values:

```julia
julia> default_a(n) = Matrix{Int64}(undef, n, 2*n);

julia> foo(n, a=default_a(n)) = (n, a);

julia> foo(2)
(2, [0 0 0 0; 0 0 0 0])

```

---

<div class="post-metadata">

**Author:** ![fredrikekre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fredrikekre/32/1688_2.png) [@fredrikekre](https://discourse.julialang.org/u/fredrikekre)\
**Post date:** [May 4, 2021, 2:23pm UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506/4 "2021-05-04T14:23:51Z")

</div>

A common pattern is to use `nothing` as “not specified”, for example

```julia
# function foo(n::Int64; a::Union{<:Array{Int64}, Nothing}=nothing)
function foo(n::Int64; a = nothing)
    if a === nothing
        a = Array{Int64}(undef, n, 2*n)
    end
    println(a) # Do whatever
end

```

---

<div class="post-metadata">

**Author:** ![erwanlecarpentier](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/erwanlecarpentier/32/23448_2.png) [@erwanlecarpentier](https://discourse.julialang.org/u/erwanlecarpentier)\
**Post date:** [May 4, 2021, 2:32pm UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506/5 "2021-05-04T14:32:42Z")

</div>

Lighter than using `kwargs` (which is desired in the simple example I gave) I guess? Thanks for the tip!

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [May 4, 2021, 2:51pm UTC](https://discourse.julialang.org/t/julia-usage-passing-complex-arguments-to-a-function-with-default-values/60506/6 "2021-05-04T14:51:17Z")

</div>

This is one clean alternative, I think:

```julia
julia> using Parameters

       @with_kw struct DefaultArgs
         a::Vector{Int} = zeros(Int,2)
         b::Int = 1
       end

       foo(n;args...) = foo(n,DefaultArgs(;args...))
       function foo(n,args::DefaultArgs) 
         @unpack a, b = args 
         n*b .* a
       end
foo (generic function with 2 methods)

julia> foo(2,a=[1,2])
2-element Vector{Int64}:
 2
 4

julia> foo(3,a=[1,2],b=5)
2-element Vector{Int64}:
 15
 30

```
