# Best practice for several alternative constructors

**URL:** <https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655>\
**Category:** New to Julia\
**Created:** [May 3, 2020, 8:29am UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655 "2020-05-03T08:29:06Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 3, 2020, 8:29am UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/1 "2020-05-03T08:29:06Z")

</div>

As a simplified example, suppose I have a type representing an axis-aligned ellipse defined by its major and minor axes:

```julia
struct Ellipse
    major::Float64
    minor::Float64
end

```

It makes sense to construct an ellipse from several different sets of parameters. My first thought was to implement something that allows the following usage:

```julia
Ellipse(major=2, minor=1)
Ellipse(semimajor=1, semiminor=0.5)
Ellipse(major=2, eccentricity=0.1)
Ellipse(major=2, focus=0.5)
...

```

However, this is impossible with separate methods: keywords do not participate in the dispatch. In principle it is possible to make one huge method with checks like

```julia
if kwargs[:major] != nothing && kwargs[:minor] != nothing
...

```

but it looks very error-prone: easy to miss a check or ignore a parameter by accident.

So my question is - what do you think is a reasonable interface in this case? How would you implement it?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 3, 2020, 8:44am UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/2 "2020-05-03T08:44:01Z")

</div>

You can take all kwargs in a single constructor, and check if they are just enough to determine the ellipse (and error for insufficient or overspecified information). See the implementation of `range`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 3, 2020, 9:57am UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/3 "2020-05-03T09:57:00Z")

</div>

Thanks for the pointer, didn’t see this approach before:

```julia
range(start; length=nothing, stop=nothing, step=nothing) = _range(start, step, stop, length)

_range(a::Real, ::Nothing, ::Nothing, len::Integer) = UnitRange{typeof(a)}(a, oftype(a, a+len-1))
# other well-formed implementations
# ...

_range(start, step, ::Nothing, ::Nothing) = # range(a, step=s)
    throw(ArgumentError("At least one of `length` or `stop` must be specified"))
# other errors
# ...

```

However, it looks really error-prone for more parameters: tracking the argument positions becomes more difficult, especially when you want to add or change one of the arguments.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 3, 2020, 12:49pm UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/4 "2020-05-03T12:49:30Z")

</div>

You are right, but I would argue that having a lot parameters which are optional/required in various combinations is a [code smell](https://en.wikipedia.org/wiki/Code_smell) in any case.

Eg I don’t know if the `Ellipse` is just a MWE, but if it isn’t, arguably having _both_ a major/minor and a semi-major/minor constructor may be overkill — after all, they are just a factor of 2 variation on the other one.

That said, you can do something like

```julia
Ellipse(; kwargs...) = _Ellipse((; kwargs...)) # make a NamedTuple

function _Ellipse(nt::Union{NamedTuple{(:major,:minor)},
                            NamedTuple{(:minor,:major)})
    Ellipse(nt.major, nt.minor)
end
# other methods like this

```

---

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [May 3, 2020, 1:52pm UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/5 "2020-05-03T13:52:45Z")

</div>

Echoing @Tamas_Papp suggestion to not overkill this, especially if you are just trying to provide convenience to your users as you might end up doing the opposite.

That said here are some other options I can think of:

1. Just define explicit methods for each valid combination, e.g. `ellipse_major_minor(2,1)`, but I’m sure you have considered this already.
2. Wrap the context of the numbers in a type OOP style, e.g. `Ellipse(Major(2), Minor(1)), Ellipse(SemiMajor(1), SemiMinor(0.5))`. If you don’t like the parantheses, make a macro which turns an expression like `@Ellipse Major=2 Minor=1` into the above.

Both options suffer a bit from needing arguments in order (as well as overengineering) and you most likely need more than one method and/or some transform-one-type-to-another set of methods.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 3, 2020, 2:30pm UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/6 "2020-05-03T14:30:39Z")

</div>

Thanks for all the suggestions! A nice one with `NamedTuple`s, not sure if it’s “free” regarding performance?

I think I’ll go with separate methods indeed, and put them inside a module so that usage looks like:

```julia
Ellipse.from_major_minor(2, 1)
Ellipse.from_major_eccentricity(2, 0.1)
...
# the struct itself is Ellipse.Ellipse

```

> [@Tamas\_Papp](#):
>
> I don’t know if the `Ellipse` is just a MWE

Yes, it was just an MWE. The actual case involves of a more complicated object with several widely-used parametrizations.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [May 3, 2020, 3:14pm UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/7 "2020-05-03T15:14:22Z")

</div>

> [@aplavin](#):
>
> A nice one with `NamedTuple` s, not sure if it’s “free” regarding performance?

Yes, it should be elided. I checked on 1.4 and 1.5.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [May 3, 2020, 6:21pm UTC](https://discourse.julialang.org/t/best-practice-for-several-alternative-constructors/38655/8 "2020-05-03T18:21:38Z")

</div>

There’s [https://github.com/simonbyrne/KeywordDispatch.jl](https://github.com/simonbyrne/KeywordDispatch.jl)
