I have a function f
with a signature:
f(x, y, cache::Union{T1, T2})
where cache
will be mutated (modified) when it’s of type T1
and not mutated when it’s of type T2
. The type of cache
is determined by the combinations of the types of x
and y
. Furthermore, the body (specific lines of code) of f
does not change for different types of cache
as f
just passes cache
to an inner function, fCore
. So whether cache
gets mutated is not “really” determined by f
, but by cache
itself.
Additionally, I would prefer not to split f
into f1!(x, y, cache::T1)
and f2(x, y, cache::T2)
because f
is used multiple times in a larger wrapper function h
in which x
and y
do not compose a small finite number of type combinations. I think it’s too much of a hassle to manually write h
with different versions of f
in terms of f1!
and f2
in its body, while the other parts are nearly identical.
So, after this somewhat convoluted introduction, my question is, should I redefine f
’s signature to be something like f!(cache::Union{T1, T2}, x, y)
?
It seems that there isn’t an apparent naming convention for a function when the mutability of an argument is directly dependent on itself rather than the function.
On the one hand, I can simply append !
to the end of the function’s name. Such a choice is under the assumption that as long as it CAN mutate the argument, it should be marked with !
. On the other hand, we also have base functions like map
, which does not have !
at the end but can indirectly mutate its arguments due to the lower-order function evaluated inside it, just like the relation between f
and fCore
in my case. To demonstrate what I meant by “indirectly”, here is an example (on Julia 1.11.2):
julia> unexpectedMutate! = x -> x .+= 1
#1 (generic function with 1 method)
julia> v = [[1], [2], [3]]
3-element Vector{Vector{Int64}}:
[1]
[2]
[3]
julia> map(unexpectedMutate!, v);
julia> v
3-element Vector{Vector{Int64}}:
[2]
[3]
[4]
If we think marking the argument name instead of the function name is a better solution for this type of edge case, I would love to see a special symbol dedicated to the arguments that will be (potentially) mutated, like how !
is used for a function. However, a naive solution of appending !
to the name of an optional argument currently (Julia 1.11.2) is an invalid syntax:
julia> foo1(a!=1) = (a!) + 1
ERROR: syntax: "(a != 1)" is not a valid function argument name around
Nevertheless, I’m interested in other people’s opinions on this edge case. Thank you!!