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.