How about to simplify the factorial function name?

Recently I found it quite complicated to call the function factorial(). I feel it too long for such a function that is so frequently used in some situations. Can we make it simpler? Like !(n) (I found that the operator ! does not have a method for ::Integer), for example.

Iā€™ve never found the argument about length of functions/commands compelling, in any language. If you get tired of typing itā€™s probably a sign you need better tooling (for example some more help from your IDE), but bending a language because you donā€™t want to type to more is never a good idea.

13 Likes

If you have some factorial-heavy code you can introduce an alias yourself.

julia> const ! = factorial
factorial (generic function with 7 methods)

julia> !(5)
120

For performance reasons itā€™s important to use const.

7 Likes

Does this hide ! as negation? If so, everywhere?

3 Likes

Just in your code. :slight_smile:

Well, I guess thatā€™s a little heavy-handed. In your own code itā€™s probably a better idea to commit some type piracy with

Base.:!(x::Int) = factorial(x)

but on the whole it would be advisable to alias it to something truly private.

2 Likes

And then again it is debatable whether !(5) is truly more readable than factorial(5), especially in a language where ! usually means boolean negation

10 Likes

If you have a high factorial density in your code I think itā€™s an arguable improvement but since it definitely means something different from negation it will never be considered for Base.

If you really want to commit a crime, with this

julia> Base.:(*)(n::Int, ::typeof(Base.:(!))) = factorial(n)

julia> 5(!)
120

at least you get the order right (although you need too many parentheses) :stuck_out_tongue_winking_eye: But again, donā€™t do it!

6 Likes

Thanks. It wouldnā€™t ever happen in my code. I was just curious how much potential damage it would cause.

You can just do

julia> !5
120

:smiley:

1 Like

[I think actually `5!` could be made to do this, as in with Unitful.jl, but Iā€™m not sure.]

You can get this with one letter, and readable in a way, i.e. using the correct functional form with the related gamma function:

julia> Ī“(6)  # Yes, you still have to type \Gamma<TAB>
120

after defining:

julia> const Ī“(x::Integer) = factorial(x-1)
Ī“ (generic function with 2 methods)

The gamma function is there:

Iā€™m not going to propose adding const Ī“(x::Number) = gamma(x) there (which gives Float64), I suppose the Greek letters were considered too valuable to also claim one of them.

2 Likes

Hm. Maybe:

julia> struct Factorial end

julia> const _! = Factorial()
Factorial()

julia> Base.:*(n::Integer, ::Factorial) = factorial(n)

julia> 5_!
120

?

8 Likes

It doesnā€™t parse:

julia> 5!
ERROR: syntax: extra token "!" after end of expression
Stacktrace:
 [1] top-level scope
   @ none:1

I like it.

julia> struct Factorial end
julia> const ā¢ = Factorial()
julia> Base.:*(n::Integer, ::Factorial) = factorial(n)
julia> 5ā¢
120

:slight_smile:

9 Likes

Thatā€™s very clever but isnā€™t Base.* supposed to be for a function that behaves like multiplication?

Not really much danger in abusing it here for nice juxtaposition notation

Or const ā— = Factorial(), which can be typed by \:exclamation:<tab>. :wink:

Honestly, though, Iā€™m a bit curious about what kind of code makes such heavy use of factorial that a shortcut is worth it.

(A common mistake is calling factorial when evaluating series formulas. See also this tutorial.)

6 Likes

Mineā€™s the ā€˜fat-torialā€™ā€¦ :grinning:

3 Likes

Sometimes you want to optimize for performance and or numerical accuracy. Other times you know that doesnā€™t matter in your case and you just want to write pretty code

1 Like