# Best Practice: Default Values/Optional Arguments/Readable Code

**URL:** <https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226>\
**Category:** New to Julia\
**Created:** [May 15, 2019, 2:00am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226 "2019-05-15T02:00:39Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![taqtiqa-mark](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taqtiqa-mark/32/4383_2.png) [@taqtiqa-mark](https://discourse.julialang.org/u/taqtiqa-mark)\
**Post date:** [May 15, 2019, 2:00am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226/1 "2019-05-15T02:00:39Z")

</div>

Some time you want to have default values.  
Sometimes you want to be relaxed about the order parameters are handed in.  
Sometimes you just want to write readable code:

```julia
discount_rate()
discount_rate(;risk_category = 'AA+', years = 3, amount=$3,000,000, starting_date=20190312, )

```

The issue of default values in type constructors in Julia v1.x is still [wet paint](https://github.com/JuliaLang/julia/issues/10146), with the Parameters.jl alternative being available as a 3rd party package.

Of the two approaches available in Julia v1.x, each has drawbacks:

1. Positional Arguments with default values:
  - Extra function methods get defined automagically.
  - They can get overwritten out of sight/silently, just as automagically.
  - Result in a code base that is not understood (has behavior not covered by test cases while cov metrics might be green).

2. Keyword arguments:
  - Function methods don’t dispatch on keyword arguments.
  - Result in dispatch behavior changing ([issue #9489](https://github.com/JuliaLang/julia/issues/9498)).
  - Can also overwrite an existing default method silently.

Others have come this way before:

> [@Fun with kwargs methods](https://discourse.julialang.org/t/fun-with-kwargs-methods/15711):
>
> Consider julia\> bar(x, y) = x / y bar (generic function with 1 method) julia\> bar(x, y; c) = x + y + c bar (generic function with 1 method) julia\> bar(3,4,c=5) 12 julia\> bar(3,4) ERROR: UndefKeywordError: keyword argument c not assigned Stacktrace: [1] bar(::Int64, ::Int64) at ./REPL[2]:1 [2] top-level scope at none:0 However (restarting Julia): julia\> bar(x, y; c) = x + y + c bar (generic function with 1 method) julia\> bar(x, y) = x / y bar (generic function with 1 method) julia\> bar(…

> [@Default values for composite types in Julia](https://discourse.julialang.org/t/default-values-for-composite-types-in-julia/4479):
>
> In C++11, one can initialize the fields of a class to avoid boiler plate code. In Julia, I am currently typing every single combination of constructors in order to handle default values, for example: immutable GaussianVariogram{T\<:Real} sill::T range::T nugget::T end GaussianVariogram{T\<:Real}(s::T, r::T) = GaussianVariogram(s, r, zero(T)) GaussianVariogram() = GaussianVariogram(1.,1.) Is there a better mechanism for setting default values? Ideally, something like: immutable GaussianVar…

> <https://stackoverflow.com/questions/48734888/define-julia-functions-with-optional-positional-arguments>

> <https://stackoverflow.com/questions/48497821/status-of-default-initialisation-of-struct-fields>

> <https://stackoverflow.com/questions/26447854/named-arguments-without-natural-defaults-in-julia>

Using only Julia Base v1.x (i.e. not Parameters.jl):

What is the best practice or ‘habit’ to develop for using default values or writing readable code that will:

- preserve Julia’s performance
- avoid the other issues mentioned above
- likely cause the least pain between 1.0 and 2.0?

It might help to use an example(s) from the posts listed above.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [May 15, 2019, 3:08am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226/2 "2019-05-15T03:08:53Z")

</div>

I also wrote FieldDefaults.jl, mostly so you can easily view what the defaults are and use them outside of the constructor by defining methods that dispatch on type and fieldname.

Whatever the accepted method ends up being I think they need to be easily introspected, like `default(::Type{T}, ::Type{Val{:fieldname}})`, or at least `defaults(T)` and return a tuple.

---

<div class="post-metadata">

**Author:** ![taqtiqa-mark](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taqtiqa-mark/32/4383_2.png) [@taqtiqa-mark](https://discourse.julialang.org/u/taqtiqa-mark)\
**Post date:** [May 15, 2019, 5:35am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226/3 "2019-05-15T05:35:54Z")

</div>

This is more verbose, but it forces the default variable definition logic checks into the type inner constructor.

```julia
mutable struct RateVariables
    parameters::Dict{Symbol,Any}
    function RateVariables(p)
        # Enforce the default value if a parameter is missing
        category = get!(p, :risk_category, "AAA+") 
        horizon = get!(p,:years, 30)
        value = get!(p,:amount, 1000000)
        start = get!(p,:starting_date, 20190101)
        # Do anything else with the given & default values
        new(p) 
    end
end

# The all default values case
discount_rate(RateVariables(Dict()))

# Some parameters given:
# Note without {symbol, Any} passed to Dict you'll get a int -> string type conversion error when the
# string parameter is inserted
rv = RateVariables(Dict{Symbol,Any}( :years => 3, :amount=>1, :starting_date=>20000101))
discount_rate(rv)

```

Is it really so straightforward to say to a Julia newcomer:

If you want to use optional/default parameters, the simplest robust approach in Julia 1.x is to use a `Dict`, a `mutable struct` (aka type) and its inner constructor?

Appreciate any suggestions that are simpler.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [May 15, 2019, 6:35am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226/4 "2019-05-15T06:35:05Z")

</div>

I think I have avoided these problems by not allowing empty defaults, and adding only one method in the macro:

` T(; kwargs...)`

I’m not sure what that could overwrite silently, or how it would be overwritten by other methods accidentally, unless I am missing something.

---

<div class="post-metadata">

**Author:** ![taqtiqa-mark](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taqtiqa-mark/32/4383_2.png) [@taqtiqa-mark](https://discourse.julialang.org/u/taqtiqa-mark)\
**Post date:** [May 16, 2019, 2:23am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226/5 "2019-05-16T02:23:57Z")

</div>

Thanks for pointing out FieldDefaults.jl. I’ll look at to learn more Julia-fu.

Right now my costraint is to use std/base julia Packages

> [@Raf](#):
>
> I’m not sure what that could overwrite silently, or how it would be overwritten by other methods accidentally, unless I am missing something.

I was referring to the existing way Julia handles default/optional values using positional arguments and Keyword arguments - they stand on each other’s toes.

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [May 16, 2019, 4:05am UTC](https://discourse.julialang.org/t/best-practice-default-values-optional-arguments-readable-code/24226/6 "2019-05-16T04:05:48Z")

</div>

Sorry I wasn’t clear. I agree with you that those methods with optional fields are risky and complicated, thats why I avoided them - but it wasn’t really because I understood the problems you have layed out!

I also nearly always want` SomeParams()` to provide a completely functional default, so having fields without defaults is kind of irrelevent to me.

Edit : And no FieldDefaults.jl is definately not standard! the FieldMetadata.jl trick with field level traits for metadata storage is in the “weird things julia can do, but should it?” category, although I use it all day for basically everything…
