Define function with multiple dispatch in terms of another function with same signatures

Say I have a function, call it q and it has multiple signatures:

q(a,b) 
q(b)
...

And I have the relationship that p = 1 - q

Is there a simpler way to define this other than to list out the same set of signatures?

I.e. not do the following

p(a,b) = 1 - q(a,b)
p(b) = 1 - q(b)
...

I tried just saying p = 1 - q but I get a MethodError: no method matching -(::Int64, ::typeof(q))

Also tried p() = 1 - q() but that’s just defining a function with no arguments, not passing along a variable set to q

can you try this?

q(args...) = 1-p(args...)

tell me if it works, i will need this in some point in the future

1 Like

Why not? That looks like the right way to do it. Ideally, you expose an interface via a small set of functions, so this should not be cumbersome.

But as @longemen3000 suggested,

@inline p(args...) = 1  - q(args...)

should work fine.

1 Like

Yea, I might end up still defining it that way. I was curious because I’m trying to build out ActuarialScience.jl and there’s a lot of functions that are useful to export that have the same “name” but different dispatch/signatures (e.g. life annuities) where often the different signatures really have a simpler relationship (like that in my original example.

Really just looking to build out my understanding of the different things I can do with Julia.

Question on your response though - in this case, what would @inline do?

See the documentation, eg ?@inline.

The other approach you could take is for the first signature of q, wrap a and b in a struct. Something like:

struct MyType
    a::SomeType
    b::SomeType
end

q(b) = ...
q(ab::MyType) = ...

p(x) = 1 - q(x)
1 Like

Reviving this topic, as now I’m refactoring to use keyword arguments in some cases, but the splat doesn’t work in this case:

q(a,b) = 0.1
q(b) = 0.2
q(a,b;c=2)  = 0.3
p(args...) = 1.0 - q(args...)
p(1,2) # 0.9
p(1) # 0.8
p(1,2,b=3) # function p does not accept keyword arguments

Out of curiosity, I tried to run these commands. For p(1,2) I get 0.7 instead of 0.9 once q(a,b;c=2) has been defined.

julia> q(a,b) = 0.1
q (generic function with 2 methods)

julia> q(b) = 0.2
q (generic function with 2 methods)

julia> q(a,b;c=2)  = 0.3
q (generic function with 2 methods)

julia> p(args...) = 1.0 - q(args...)
p (generic function with 1 method)

julia> p(1,2) # 0.9
0.7

julia> p(1) # 0.8
0.8

julia> p(1,2)
0.7

p(args...; kwargs...) = 1.0 - q(args...; kwargs...)
2 Likes

I still get p(1,2) as 0.7 even after doing this.

julia> q(a,b) = 0.1
q (generic function with 1 method)

julia> q(b) = 0.2
q (generic function with 2 methods)

julia> q(a,b;c=2)  = 0.3
q (generic function with 2 methods)

julia> p(args...;kwargs...) = 1.0 - q(args...;kwargs...)
p (generic function with 1 method)

julia> p(1,2)
0.7

julia> p(1,2,c=5)
0.7

q(a,b;c=2) = 0.3 overwrites q(a,b) = 0.1, so that’s to be expected. I was just responding to @Alec_Loudenback.

@tkoolen: Thanks I did understand the same behaviour but was curious to know if there is way out.

Nope, because keyword arguments do not participate in dispatch.

2 Likes