I’ve been pointed toward the constraint C1514 (pg. 316 in J3/23-007r1)
Within the scope of a generic name, each pair of procedures identified by that name shall both be subroutines or both be functions, and … [rules for dummy arguments omitted]
although the rationale why this constraint was introduced in the first place is omitted.
The best reason I could think of myself is because adding free functions to a generic interface (also known as an overload set) usually comes with some expected behaviour (semantics). Permitting functions and subroutines to have the same generic name, could be surprising to the developer.
Quoting from C++ Software Design (pg. 60):
The problem is that it might not always be entirely clear what the expected behaviour is, especially for an overload set that is scattered across a big codebase. You might not know all the expectations and all the details. Thus sometimes, even if you’re aware of this problem and pay attention, you might still not do the “right” thing. This is what several people in the community are worried about: the unrestricted ability to add potentially LSP-violating functionality into an overload set. And as state before, it’s easy to do. Anyone, anywhere, can add free functions.
In the C++ Core Guidelines this is expressed as,
- C.162: Overload operations that are roughly equivalent
- C.163: Overload only for operations that are roughly equivalent.
In other words of K. Iglberger,
Whereas C.162 expresses the advantage of having the same name for semantically equivalent functions, C.163 expresses the problem of having the same name for semantically different functions.
I think the following line of reasoning goes both ways:
Imagine you are writing a cash register system for your newly opened craft beer pub. You set the display language so that local pub staff can use it:
cstr = setlocale(1, "el_US.utf8"//c_null_char)
One of your employees is an ale aficionado, so he writes a subroutine that allows registering beers into different categories:
interface setlocale
module procedure setlocale_sub
end interface
integer, parameter :: CATEGORY_ALE_IPA = 1
integer, parameter :: CATEGORY_ALE_BLONDE = 2
integer, parameter :: CATEGORY_ALE_AMBER = 3
contains
! Set the local ale (as in beer) of choice
subroutine setlocale_sub(category, ale_name)
integer(c_int) :: category
character(len=*) :: ale_name
end subroutine
so you register a few of them:
cstr = setlocale(1, "el_US.utf8"//c_null_char) ! The C function
! ...
! ...
category = CATEGORY_ALE_AMBER
call setlocale(category, "Olde Fortran Malt")
A few months later you need to extend the software, and you hire a young C programmer straight out of college. Naive as they come, the programmer assumes that the two setlocale
functions are the same, and starts wondering if the whole project is a practical joke… He resigns from the project the same afternoon.