Base.factorial: Extending and overwriting functions in SpecialFunctions

The Base.factorial function supplies the following methods

julia> methods(factorial)
# 7 methods for generic function "factorial":
[1] factorial(n::UInt128) in Base at combinatorics.jl:26
[2] factorial(n::Int128) in Base at combinatorics.jl:25
[3] factorial(x::BigFloat) in Base.MPFR at mpfr.jl:639
[4] factorial(x::BigInt) in Base.GMP at gmp.jl:639
[5] factorial(n::Union{Int64, UInt64}) in Base at combinatorics.jl:27
[6] factorial(n::Union{Int16, Int32, Int8, UInt16, UInt32, UInt8}) in Base at combinatorics.jl:33
[7] factorial(n::Integer) in Base at intfuncs.jl:889

Currently that function is extended to x::Number using the gamma function within the SpecialFunctions module as such

# this trickery is needed while the deprecated method in Base exists
@static if !hasmethod(Base.factorial, Tuple{Number})
    import Base: factorial
end
factorial(x) = Base.factorial(x) # to make SpecialFunctions.factorial work unconditionally
factorial(x::Number) = gamma(x + 1) # fallback for x not Integer

It seems like that Base.factorial is deprecated according to the comments?

The problem arises now because the implementation Base.factorial(x::BigFloat) is checking that isinteger(x) which does not really make any sense. I’d like to extend it to any BigFloat by calling the gamma function.

Is it possible to extend Base.factorial in the following way:

  • for x::Integer call Base.factorial
  • else call SpecialFunctions.gamma
    • especially, overwrite Base.factorial(x::BigFloat)

I tried a straight forward implementation like such

# this trickery is needed while the deprecated method in Base exists
@static if !hasmethod(Base.factorial, Tuple{Number})
    import Base: factorial
end
factorial(x::Integer) = Base.factorial(x)   # to make SpecialFunctions.factorial work unconditionally
factorial(x::Number)  = gamma(x + 1)        # fallback for x not Integer

This approach throws the following error

julia> using SpecialFunctions
[ Info: Precompiling SpecialFunctions [276daf66-3868-5448-9aa4-cd146d93841b]
WARNING: Method definition factorial(Integer) in module Base at intfuncs.jl:889 overwritten in module SpecialFunctions at <HOME>/.julia/environments/SpecialFunctions-dev/dev/SpecialFunctions/src/gamma.jl:891.
  ** incremental compilation may be fatally broken for this module **

This in relation to issue #233.

1 Like

That is technically type piracy and should not be part of a solution. IMO in the long run, it would be best to move all methods either into or out of Base — piling hacks on hacks will continue to backfire.