I am writing my first module in Julia. I have a function f
which will use a vector or range for some calculations. I would like to create a method of this function which will create a range using the range
function before proceeding with the calculations in order to provide some flexibility to the user.
I have written the following:
# Attempt 1
function f(x,start,stop;length=1001,step=0.1)
r=range(start,stop,length=length,step=step)
# do more stuff with x and r
end
# error: length and step don't agree
However, range
will accept only one of either step
or length
. It cannot take both unless they are defined in agreement. This leads me to want to define another function g
which will be called inside of f
. g
would call range
and have methods to account for the three possible scenarios.
length
when calling f
.step
when calling f
.length
nor step
when calling f
, so a default step
value is used.I'd rather not create more methods of f
to avoid copying #do more stuff with x and r
excessively. I would also like to avoid if
statements where possible to take advantage of multiple dispatch and be efficient. Although, I haven't come up with any solutions so far.
I cannot define multiple methods of g
with keyword arguments since the keyword arguments are optional.
# Attempt 2
function g(start,stop;length=1001)
r=range(start,stop,length=length)
end
function g(start,stop;step=0.1)
r=range(start,stop,step=step)
end
# error: the method definitions overlap
I also cannot convert the keyword arguments to regular arguments because I won't know which argument to pass.
# Attempt 3
function g(start,stop,length)
r=range(start,stop,length=length)
end
function g(start,stop,step)
r=range(start,stop,step=step)
end
function f(x,start,stop;length=1001,step=0.1)
r=g(start,stop,y)
end
# error: no way to determine y or to differentiate length from step when passed to g
The range
function uses nothing
for step
/length
when they are not specified, so the following should work for you:
function f(start, stop; step=nothing, length=nothing)
if step === length === nothing
step = 0.1 # default step
end
r = range(start, stop; step=step, length=length)
return r
end
Examples:
julia> f(1, 2; step=0.2)
1.0:0.2:2.0
julia> f(1, 2; length=3)
1.0:0.5:2.0
julia> f(1, 2) # default step
1.0:0.1:2.0
I'd rather not create more methods of f to avoid copying #do more stuff with x and r excessively
A somewhat common pattern is to move the core functionality to another function, say _f
, and have multiple entrypoints f
which constructs the correct arguments for _f
. Here is a sketch of that:
function f(x, y)
# construct arguments with x and y
args = ...
return _f(args...)
end
function f(x, y, z)
# construct arguments with x, y and z
args = ...
return _f(args...)
end
function _f(args...)
# core computation
end