function factorial(n::Integer)
n < 0 && throw(DomainError(n, "`n` must be nonnegative."))
f::typeof(n*n) = 1
for i::typeof(n*n) = 2:n
f *= i
end
return f
end
Why typeof(n*n) instead of typeof(n)? This maybe a dumb question but I really don’t get it.
There are numbers who’s type is not closed under multiplication. This makes sure you get something of the right type. In practice, this will almost always just be typof(n) though.
If there is some strange implementation of Integer for which n*n is not closed under multiplication, why should (n*n)*n be? And why should 1 be of the same type as n*n?
Working with result types is actually one of the most irksome parts of Julia. Even restricting to <:Number, the interfaces are not formalized. So while it may be strange, making a <:Number type that is not closed under multiplication does not formally violate any contract.
While in this particular case, typeof(n) would be fine.
That said, I am curious where you got that code from, currently in Julia factorial uses a lookup table and looks very different.
I think the point is that you cannot know for certain that n*n will always have the same type as n, for example in types created by users. Therefore this is an extra safeguard. You want to make sure that things will work out, instead of relying on that it “seems to work in most cases.”
might be a better generic implementation? It won’t be type stable if n is not closed under multiplication, but assuming n and 1 can always be converted to typeof(n*n) is probably worse, as seen in the Unitful example. It is also not guaranteed that (n*n) * n can be converted to typeof(n*n), so typeof(n*n) seems rather arbitrary as output type.