I’d prefer to write multiple outer constructors for structs, so that the user can provide what they have and let the constructor make whatever conversions are needed. Running the mwe:
Fraction(; numerator::Integer, denominator::Integer, name="") = Fraction(numerator, denominator, numerator/denominator, name)
Fraction(; value::Number, denominator::Integer, name="") = Fraction(value*denominator, denominator, value, name)
fa = Fraction(3,4,0.75,"three-quarters")
fb = Fraction(numerator=3,denominator=4,name="three-quarters")
fc = Fraction(value=0.75,denominator=4,name="three-quarters")
Main.ConstructorTest.Fraction(3, 4, 0.75, "three-quarters")
ERROR: LoadError: UndefKeywordError: keyword argument value not assigned
from fb’s creation. Despite using named arguments and unique argument types, the wrong constructor is called.
Have I made an error in defining the outer constructors or is this usage not intended/implemented?
Unfortunately keyword arguments do not participate in method dispatch, so you can’t have two different methods which differ only in what keywords they accept. In practice, whichever one you define last will just overwrite the one defined before it. There’s a note about this in the docs here:
Keyword arguments behave quite differently from ordinary positional arguments. In particular, they do not participate in method dispatch. Methods are dispatched based only on positional arguments, with keyword arguments processed after the matching method is identified.
One possible workaround is to create a single function with default values for all the keyword arguments and then check which ones are set inside that function:
function Fraction(; numerator=nothing, value=nothing, denominator, name="")
if numerator !== nothing
@assert value === nothing # can't set both
Fraction(numerator, denominator, numerator / denominator, name)
else if value !== nothing
Fraction(value * denominator, denominator, value, name)
@error "must set either numerator or value"
You may also be interested in Base.@kwdef and/or Parameters.jl, two tools that automate keyword argument constructors.