5
$\begingroup$

What are the pros and cons of allowing users to define functions with the same name as built-in functions?

For example, defining:

max(a, b) {
    if a > b return a;
    else return b;
}

as a repeat of the already existing max() function in some languages.

Or defining:

min(a, b) {
    if a > b return b;
    else return a;
}

as a repeat of min().

What are the pros and cons of letting users define functions like the ones listed above?

$\endgroup$
4
  • 1
    $\begingroup$ Relevant Meta discussion: languagedesign.meta.stackexchange.com/questions/370/… $\endgroup$ Jun 20, 2023 at 4:22
  • 2
    $\begingroup$ Why has the question been downvoted? It seems to be reasonable. $\endgroup$ Jun 20, 2023 at 4:22
  • $\begingroup$ To be pedantic, I'd define min using the < test. E.g I can think of objects where a>b and a<b can both be true. $\endgroup$ Jul 16, 2023 at 1:59
  • $\begingroup$ Is this question only for languages without namespaces/packages (for standard library functions, at least)? $\endgroup$
    – gidds
    Jul 17, 2023 at 17:01

4 Answers 4

14
$\begingroup$

Pro: New builtins won't break old programs.

Perhaps the programmer wrote that max() function because the builtin was not available in a previous version of the programming language. If the language does not allow user functions to shadow builtins, then if the language introduces a new builtin it may break old programs that were already using that name.

$\endgroup$
1
  • $\begingroup$ If a language has a means of indicating "the programmer is aware that a built-in with the same name as this function may exist, and if it does it would be equally acceptable to call the built-in or this function", such a feature may allow programs to be written in ways that can benefit from new language functions when available (perhaps operating more efficiently than user-written code could), but still work on older implementations that lack them (employing user-written functions as a fall-back). $\endgroup$
    – supercat
    Jul 17, 2023 at 17:06
5
$\begingroup$

One fundamental consideration is whether the user function will override the builtin, the builtin will override the user function, or there will be no conflict. And perhaps what happens depends on context.

Consider a user defined div(a,b) that returns a divided by b while handling the b=0 case. There are also companion functions: tim(a,b), plu(a,b), and min(a,b).
What should happen with this new definition of min?

Or functions could invoke actions by specific dogs: rover(a,b), fido(a,b), and max(a,b).

Is it okay to unintentionally redefine a builtin that does something completely different?

Or is it okay to intentionally redefine a builtin to help with debugging or statistical analysis?


I remember running into a problem in C, where I added for(index=0;… and got compiler errors. It turned out that previously someone had helpfully put #define index strchr into a header file, in anticipation of the renaming of the function in the C standard.

And in the other direction, I once wrote a library that intercepts calls to all the section 2 functions that take filenames. For example, my open(…) would check the filename to see if it began with "host:" and if so it would establish a connection with the other computer (where accounts with the same userid were guaranteed to be the same person). Otherwise it would call .open(), with a leading ".", to get the standard function from libc. With that, anyone could reload their own programs using my library, and they would instantly get access to the remote filename mechanism, with no changes to their own code.

This leading dot convention was provided by the writers of libc in order both to allow functions to be overridden (e.g. open could be redefined as ++call_count_open; return .open(args)), and to prevent new definitions from affecting the libc library, which made all internal calls with the leading dot.


The important point here is that whatever the language does, it needs to be well defined and advertised.

$\endgroup$
4
$\begingroup$

Con: code becomes less readable

Reading code, one has to look up the definitions of user-defined function, whereas build-in functionality has a constant meaning. If you allow overwriting built-in names, the reader must suspect that every built-in name has been overwritten, and must look all these up, either manually or with the help of an IDE.

$\endgroup$
1
$\begingroup$

The programmer may not be aware that some system function has been called and not a user-defined one. Even if the user-define function has a priority, this may depend on some import or header statement missing.

This is usually addressed by marking the built-in functions the way user defined functions should never be marked (__function, JFunction, std::function and the like), even when it makes the code more cluttered. For instance, C++ has many functions with quite common names (tie, pair, map) that can be easily re-invented. In some cases the code may actually compile by some chance, creating bugs that take time to find. While in old Java AWT there was a Button, in the later Swing this has been changed to JButton.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .