While searching on the internet I found almost every programming language said implement your own factorial function, rather than giving built-in function for it. Some of stackoverflow answers mention that it is too easy to implement that is why they leave it to programmers. However, then the question arise, why the language designer can code and implement very complex function in built in library, but not the easy factorial why?
-
4$\begingroup$ Most programming languages don't have most functions. For example, most programming languages don't have a "hello world" function. Why not? Because you can easily make it yourself. $\endgroup$– user253751May 13, 2022 at 14:18
-
$\begingroup$ because programmers need to learn how to implement recursion ;o) $\endgroup$– Dikran MarsupialMay 13, 2022 at 21:34
3 Answers
Most programming languages don't have any built-in functions and such additional functions are provided by "standard library" of sorts. This answer addresses why factorial is unlikely to be found in "standard library" either.
Factorial is a function that is very rarely used in general purpose code (outside of basic recursion exercises) and requires extreme care when used. So general-purpose "standard" library (included or merged with a language) does not benefit much with providing one.
Specific concerns:
- for majority of languages that have fixed-size integer values there is extremely small range of input values that are acceptable (1-14 for 32-bit integers) - having table for such a small range is preferable when it actually needed. This is quite different for majority of other common functions that have much large usable range of input values (something like "+" would work safely for up to INT_MAX/2 values).
- it is very impractical to be defined in non-integer types as values are very quickly go out of precision range and become estimates. Each program needs to assess how to handle such losses and one generic implementation (usually unintentionally hiding exact details) become mostly useless.
- for languages that allow unbounded integer types it grows far too quickly to be safe to use in general code anyway - performance is almost unpredictable and memory usage would grow too quickly. Again, calling for every specific case to pick specialized implementations and possibly calling for alternative approaches altogether.
- in many cases (i.e. Taylor series) code naturally computes
n!
in the process avoiding O(n) cost of computation for each iteration or the actual result needs only part of the factorial (C(n,k)). Such cases likely occur in specialized applications that would use a library specific to the domain rather than generic one lessening need for factorial to be in the standard library.
First of all, keep in mind that "language", "implementation" and "standard library" are separate concepts. Languages are implementation blueprints that may not prescribe a standard library.
Factorial is built-in to standard implementations of Julia, R and Python (at the time of writing), which makes sense because these are mathematics-oriented, high-level languages. For the audience of these languages, it's a common task that should be easy. The expectation/flavor of these languages is "import solution", rather than "write it yourself".
As far as I know, there's nothing in the Python language specification requiring implementations to have a math
module, and whether that math
module must have a factorial
method. The creators/maintainers of CPython (the reference implementation of Python) thought it'd be a good idea to include math
and math.factorial
though, and it's a pretty safe bet that most other implementations will follow suit, because it's a function that fits well with Python's "batteries mostly included" philosophy.
On the other hand, C has no such factorial function because it'd just be extra bloat. It's not a common task in the language. The flavor of C is low-level and bare-bones. C is a substrate to build up from, opting-in to necessary functionality. It hearkens from an era when every byte of space mattered (we're talking a few megabytes for the whole system). For embedded or system engineers, a huge standard library filled with things they're not using would only get in the way of their goals. There's no need to buy a car if you just want a chair to sit in. The Go language follows a similar philosophy: we'll give you just the primitives, you write the abstractions you need (or install a package).
Adding more stuff to a programming language specification itself and/or an implementation of that specification takes maintainence work, so it's not free lunch even when it does align. Taking the car analogy further, putting computers in every part of the car sounds great until there's a chip shortage or people figure out how to hack them, and it turns out to be a huge design liability. Sometimes less is more.
Based on this, we can infer that which functionality is built into the standard library and which isn't is pretty much a judgment call. Do language or implementation designers/maintainers find it important for the goals of the language? Then include it. If not, don't. Sometimes, it's unclear and maintainers and designers disagree about what should be included and what shouldn't. If something is included, is it a built-in (no import) or included but require import?
In Python, factorial
is not a built-in likely because it isn't common enough to warrant core functionality and makes the most sense tucked in the math
module. This is a design decision that can evolve: reduce
was removed as a built-in and relegated to a standard library module (functools) because the creator of Python wanted to de-emphasize functional programming and avoid overuse.
I should also say that whether a function is easy to write or not is probably seldom much of a factor in whether it's included. It's a question of anticipating needs relative to costs.
If you want a language that magically does "all the things" (especially math things), Wolfram Alpha comes to mind.
Let's take C as an example The programming language C was created without any built in functions. This was a very deliberate choice.
When you create a helper such as a factorial function you are placing flag in the ground that says "this is how things are done". That may seem great at the moment of inception, but may greatly diminish the future of the language. It may rob future developers of the ability improve the logic of a tool due to the need to maintain legacy code.
User interface is another reason that most modern languages lack built in functions. When you create a UI function, you are tying the language to the platform it was designed on.
Functions are left to the developer to maintain the utility of the language.
-
$\begingroup$ Based on this argument, how would you explain the countless other functions that most language standard libraries do contain then? $\endgroup$ May 13, 2022 at 19:41
-
1$\begingroup$ @EdwinDalorzo they are worth the backward compatibility cost, but factorial isn't (the gamma function might be ;o) $\endgroup$ May 13, 2022 at 21:33
-
$\begingroup$ @Edwin Dalorzo the explanation is is the term “standard library” they are not part of the language specification. They are a group of tools that were developed after the fact that have been implemented on every platform. $\endgroup$ May 15, 2022 at 5:50
-
$\begingroup$ I don’t think the question was why the factorial function is not in the language specification, but why is it not defined somewhere where the language puts its built-in functions. For example, why doesn’t Java have a
factorial
function defined in its JDK API? Unless we have designed a specific language, most answers will be opinionated. My take is the factorial function is simply not useful enough in those languages, that’s all. $\endgroup$ May 15, 2022 at 10:45 -
$\begingroup$ @Edwin Dalorzo Ageed. Others did a good, in depth analysis of why factorial itself would be a bad choice for inclusion in a language or even a standard library. I simply felt it important to point out that at their core, most languages try to leave the door open to innovation rather than defining specifics. $\endgroup$ May 16, 2022 at 12:15