• Mixing functions and subroutines in a combined generic interface

    From Peter Klausler US@21:1/5 to All on Tue Nov 8 09:16:31 2022
    Generic interfaces are constrained in some specific circumstances to contain all functions or all subroutines, but in general they can contain both. (There's language in the standard that pertains to the visibility of intrinsic procedures of the same
    name that depends on whether a generic interface contains a mixture or not, so it must be possible.)

    While it's probably not the best practice to explicitly define an interface that has a mixture of functions and subroutines, it's possible for such an interface to be created -- perhaps inadvertently -- when an interface is defined in multiple locations
    and merged together. For example:

    module m1
    interface generic
    module procedure func
    end interface
    contains
    integer function func(n)
    integer, intent(in) :: n
    func = n
    end function
    end module

    module m2
    interface generic
    module procedure subr
    end interface
    contains
    subroutine subr
    print *, 'ok'
    end subroutine
    end module

    program main
    use m1
    use m2
    call generic
    end

    Some compilers can handle this example, some can't, and complain that a mixed generic interface is not allowed. I think that those compilers are incorrect. If you disagree, please let me know why.

    Amusingly, if you delete the function's dummy argument from that example, *no* compiler can deal with it, since they apparently don't take the function/subroutine distinction into account when comparing specific procedures for distinguishability, only
    their dummy arguments. So I think I'm going to get to add another item to f18's documentation section on features that it supports that are standard but might as well not be.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Arjen Markus@21:1/5 to Peter Klausler US on Tue Nov 8 12:30:54 2022
    On Tuesday, November 8, 2022 at 6:16:33 PM UTC+1, Peter Klausler US wrote:
    Generic interfaces are constrained in some specific circumstances to contain all functions or all subroutines, but in general they can contain both. (There's language in the standard that pertains to the visibility of intrinsic procedures of the same
    name that depends on whether a generic interface contains a mixture or not, so it must be possible.)

    While it's probably not the best practice to explicitly define an interface that has a mixture of functions and subroutines, it's possible for such an interface to be created -- perhaps inadvertently -- when an interface is defined in multiple
    locations and merged together. For example:

    module m1
    interface generic
    module procedure func
    end interface
    contains
    integer function func(n)
    integer, intent(in) :: n
    func = n
    end function
    end module

    module m2
    interface generic
    module procedure subr
    end interface
    contains
    subroutine subr
    print *, 'ok'
    end subroutine
    end module

    program main
    use m1
    use m2
    call generic
    end

    Some compilers can handle this example, some can't, and complain that a mixed generic interface is not allowed. I think that those compilers are incorrect. If you disagree, please let me know why.

    Amusingly, if you delete the function's dummy argument from that example, *no* compiler can deal with it, since they apparently don't take the function/subroutine distinction into account when comparing specific procedures for distinguishability, only
    their dummy arguments. So I think I'm going to get to add another item to f18's documentation section on features that it supports that are standard but might as well not be.

    If you take away the argument from the function, then its interface is not distinguishable from the subroutine according to ifort. With the argument, it emits a warning, but builds the program.
    gfortran does not accept it on the grounds of it being a mixture, with or without the argument n.

    I do not know which one is right, but the mixups (pun not entirely intended) you sketch are unfortunate and possible. Renaming would solve it, but that is besides the point.

    Regards,

    Arjen

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to Arjen Markus on Thu Nov 10 21:42:08 2022
    Arjen Markus <arjen.markus895@gmail.com> schrieb:
    On Tuesday, November 8, 2022 at 6:16:33 PM UTC+1, Peter Klausler US wrote:
    Generic interfaces are constrained in some specific circumstances to contain all functions or all subroutines, but in general they can contain both. (There's language in the standard that pertains to the visibility of intrinsic procedures of the same
    name that depends on whether a generic interface contains a mixture or not, so it must be possible.)

    While it's probably not the best practice to explicitly define an interface that has a mixture of functions and subroutines, it's possible for such an interface to be created -- perhaps inadvertently -- when an interface is defined in multiple
    locations and merged together. For example:

    module m1
    interface generic
    module procedure func
    end interface
    contains
    integer function func(n)
    integer, intent(in) :: n
    func = n
    end function
    end module

    module m2
    interface generic
    module procedure subr
    end interface
    contains
    subroutine subr
    print *, 'ok'
    end subroutine
    end module

    program main
    use m1
    use m2
    call generic
    end

    Some compilers can handle this example, some can't, and complain that a mixed generic interface is not allowed. I think that those compilers are incorrect. If you disagree, please let me know why.

    Amusingly, if you delete the function's dummy argument from that example, *no* compiler can deal with it, since they apparently don't take the function/subroutine distinction into account when comparing specific procedures for distinguishability, only
    their dummy arguments. So I think I'm going to get to add another item to f18's documentation section on features that it supports that are standard but might as well not be.

    If you take away the argument from the function, then its interface is not distinguishable from the subroutine according to ifort. With the argument, it emits a warning, but builds the program.
    gfortran does not accept it on the grounds of it being a mixture, with or without the argument n.

    I do not know which one is right, but the mixups (pun not entirely intended) you sketch are unfortunate and possible. Renaming would solve it, but that is besides the point.

    I actually ran aross this some time ago.

    The key is 15.4.3.4.5 Restrictions on generic declarations, where there
    is a constraint:

    C1514 Within the scope of a generic name, each pair of procedures
    identified by that name shall both be subroutines or both be
    functions, and [...]

    I think this makes the code illegal, and not diagnosing it is a bug.

    Please feel free to disagree :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter Klausler US@21:1/5 to Thomas Koenig on Thu Nov 10 13:56:13 2022
    On Thursday, November 10, 2022 at 1:42:11 PM UTC-8, Thomas Koenig wrote:
    The key is 15.4.3.4.5 Restrictions on generic declarations, where there
    is a constraint:

    C1514 Within the scope of a generic name, each pair of procedures
    identified by that name shall both be subroutines or both be
    functions, and [...]

    I think this makes the code illegal, and not diagnosing it is a bug.

    Please feel free to disagree :-)

    I think that in my example above the "scope of the generic name" is one module or the other, but in the main program the generic name is being accessed via USE association and the main program is technically not in a (or the) scope of the generic name.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From FortranFan@21:1/5 to Peter Klausler US on Thu Nov 10 16:18:41 2022
    On Tuesday, November 8, 2022 at 12:16:33 PM UTC-5, Peter Klausler US wrote:

    Generic interfaces are constrained in some specific circumstances to contain all functions or all subroutines, but in general they can contain both. (There's language in the standard that pertains to the visibility of intrinsic procedures of the same
    name that depends on whether a generic interface contains a mixture or not, so it must be possible.)


    Re: "but in general they can contain both," from what I can understand from 18-007r1 document toward Fortran 2018, I do *not* think the semantics of the standard is such that "in general they can contain both" Sure the standard has following carve out
    but that does suggest any generality, in fact the section on "Restrictions on generic declarations" indicates the opposite:
    "Within the scope of a generic name that is the same as the generic name of an intrinsic procedure, the intrinsic procedure is not accessible by its generic name if the procedures in the interface and the intrinsic procedure are *not all functions or not
    all subroutines*. If a generic invocation is consistent with both a specific procedure from an interface and an accessible intrinsic procedure, it is the specific procedure from the interface that is referenced."
    (emphasis with asterisk is mine)


    While it's probably not the best practice to explicitly define an interface that has a mixture of functions and subroutines, it's possible for such an interface to be created -- perhaps inadvertently -- when an interface is defined in multiple
    locations and merged together. For example:


    I think the intended message by the OP with example is misleading. The example is *not* "explicitly define an interface that has a mixture of functions and subroutines, it's possible for such an interface to be created -- perhaps inadvertently -- when
    an interface is defined in multiple locations and merged together"

    Rather the example shows two different ultimate entities, both of which are generic interfaces named 'generic'. One ultimate entity is that for functions (func being one specific procedure in it) and the other for subroutines (subr being one specific
    procedure in this interface).

    I think the standard only permits the second of these two entities to be referenced in the scope containing the USE statement, meaning the following:

    A) consume the generic as a function, here note the order of USE statements program main
    use m2
    use m1
    print *, generic(42)
    end

    Or

    B) consume the generic as a subroutine, note the order of USE statements is opposite to that A)
    program main
    use m1
    use m2
    call generic
    end

    It will take me effort to decode the standardese and try to explain in plain English but I think this is tied to semantics with "An ultimate entity is a module entity that is not accessed by use association. An accessed entity shall not be associated
    with two or more ultimate entities unless its identifier is not used, or the ultimate entities are generic interfaces. Generic interfaces are handled as described in 15.4.3.4."

    I think this is also tied to how the standard permits extension of generic interfaces via USE statements, as in the following example:
    module m1
    interface generic
    module procedure func
    end interface
    contains
    integer function func(n)
    integer, intent(in) :: n
    func = n
    end function
    end module

    module m2
    interface generic
    module procedure func
    end interface
    contains
    real function func(n)
    real, intent(in) :: n
    func = n
    end function
    end module

    program main
    use m1
    use m2
    print *, generic(42)
    print *, generic(99.0)
    end

    .. So I think I'm going to get to add another item to f18's documentation section on features that it supports that are standard but might as well not be.

    Honestly I think the "f18 documentation" on "features that it supports that are standard but might as well not be" needs a thorough review by a subgroup in the J3 committee, say JoR or /DATA or the Editor. I think there are inaccuracies in that "f18
    documentation", the above comments by OP in the original post on generic interfaces will be one such if that were to get included. Until the f18 team (is it all at Nvidia?) can get it thoroughly reviewed and all corrections applied, ideally it will
    only be in the publicly available online with clearly stated disclaimers.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From FortranFan@21:1/5 to FortranFan on Thu Nov 10 16:20:21 2022
    On Thursday, November 10, 2022 at 7:18:43 PM UTC-5, FortranFan wrote:
    On Tuesday, November 8, 2022 at 12:16:33 PM UTC-5, Peter Klausler US wrote:

    Generic interfaces are constrained in some specific circumstances to contain all functions or all subroutines, but in general they can contain both. (There's language in the standard that pertains to the visibility of intrinsic procedures of the same
    name that depends on whether a generic interface contains a mixture or not, so it must be possible.)

    Re: "but in general they can contain both," from what I can understand from 18-007r1 document toward Fortran 2018, I do *not* think the semantics of the standard is such that "in general they can contain both" Sure the standard has following carve out
    but that does suggest any generality

    Oops, omitted a key word: I meant "that does not suggest any generality"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to Peter Klausler US on Fri Nov 11 22:21:34 2022
    Peter Klausler US <pklausler@nvidia.com> schrieb:
    On Thursday, November 10, 2022 at 1:42:11 PM UTC-8, Thomas Koenig wrote:
    The key is 15.4.3.4.5 Restrictions on generic declarations, where there
    is a constraint:

    C1514 Within the scope of a generic name, each pair of procedures
    identified by that name shall both be subroutines or both be
    functions, and [...]

    I think this makes the code illegal, and not diagnosing it is a bug.

    Please feel free to disagree :-)

    I think that in my example above the "scope of the generic name"
    is one module or the other, but in the main program the generic
    name is being accessed via USE association and the main program
    is technically not in a (or the) scope of the generic name.

    I disagree there. Both interfacs are accessed by use association
    in the main program, and thus are in its scope.

    At least this is how I interpret use association and 14.2.2.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter Klausler US@21:1/5 to Thomas Koenig on Fri Nov 11 18:02:37 2022
    On Friday, November 11, 2022 at 2:21:37 PM UTC-8, Thomas Koenig wrote:
    I disagree there. Both interfacs are accessed by use association
    in the main program, and thus are in its scope.

    At least this is how I interpret use association and 14.2.2.

    Thanks for the response. You're probably right. But since at least four compilers support this combination, so must I, and it's just a matter of determining how it should be documented.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to Peter Klausler US on Fri Nov 11 18:19:41 2022
    On Friday, November 11, 2022 at 6:02:39 PM UTC-8, Peter Klausler US wrote:

    (snip)

    Thanks for the response. You're probably right. But since at least four compilers support this combination, so must I, and it's just a matter
    of determining how it should be documented.

    Since compilers are allowed to support extensions, the fact that compilers support it doesn't tell you much.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From gah4@21:1/5 to Peter Klausler US on Fri Nov 11 19:05:58 2022
    On Tuesday, November 8, 2022 at 9:16:33 AM UTC-8, Peter Klausler US wrote:
    Generic interfaces are constrained in some specific circumstances to contain all functions or all subroutines, but in general they can contain both. (There's language in the standard that pertains to the visibility of intrinsic
    procedures of the same name that depends on whether a generic
    interface contains a mixture or not, so it must be possible.)

    I tried something like this some years ago, about Fortran 95 days:

    real x
    external sub, fun
    x=3
    call sf(sub,1,x)
    call sf(fun, 2,x)
    print *,x
    end
    subroutine sf(fs, i, x)
    integer i
    real x
    external fs
    if(i.eq.1) call fs(x)
    if(i.eq.2) x=fs(3.0)
    end
    subroutine sub(y)
    y=y+2
    end
    function fun(z)
    fun = z*z
    end

    This shows some of the surprising ways Fortran considers functions and subroutines.

    It won't compile this way, but will if you comment out either if statement.

    Note also that it never calls a function as a subroutine or subroutine as a function.

    It makes me suspect that Fortran also won't like mixing them as generics.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Thomas Koenig@21:1/5 to Peter Klausler US on Sat Nov 12 07:35:20 2022
    Peter Klausler US <pklausler@nvidia.com> schrieb:
    On Friday, November 11, 2022 at 2:21:37 PM UTC-8, Thomas Koenig wrote:
    I disagree there. Both interfacs are accessed by use association
    in the main program, and thus are in its scope.

    At least this is how I interpret use association and 14.2.2.

    Thanks for the response. You're probably right. But since at
    least four compilers support this combination, so must I, and it's
    just a matter of determining how it should be documented.

    It's a violation of a numbered constraint, and not diagnosing it
    is a bug in the compiler. See 4.2, conformance, clause 2:

    # A processor conforms to this document if:
    [...]

    # (3) it contains the capability to detect and report the use within
    # a submitted program unit of a form or relationship that is not
    # permitted by the numbered syntax rules or constraints, including
    # the deleted features described in Annex B;

    So, you can support it, and you can even hide the check behind
    some options, but unless you want a bug in the compiler, you need
    to be able to issue a diagnostic.

    As a matter of policy, I think all constraint violations should
    be errors by default, and if needed, options should be used
    to downgrade the error to a warning (which is still a diagnostic)
    or to quieten it entirely.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter Klausler US@21:1/5 to Thomas Koenig on Sat Nov 12 11:02:36 2022
    On Friday, November 11, 2022 at 11:35:23 PM UTC-8, Thomas Koenig wrote:
    So, you can support it, and you can even hide the check behind
    some options, but unless you want a bug in the compiler, you need
    to be able to issue a diagnostic.

    As a matter of policy, I think all constraint violations should
    be errors by default, and if needed, options should be used
    to downgrade the error to a warning (which is still a diagnostic)
    or to quieten it entirely.

    Thanks for the advice. I think a portability warning (optionally fatal but not by default) is sufficient in this case and in the best interest of users trying to port code to a new compiler. The extension is benign, unambiguous, useful, and well
    supported elsewhere. Were it dangerous, ambiguous, easy to avoid, or peculiar to a single compiler, things would be otherwise.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From FortranFan@21:1/5 to Peter Klausler US on Sat Nov 12 12:17:31 2022
    On Friday, November 11, 2022 at 9:02:39 PM UTC-5, Peter Klausler US wrote:

    On Friday, November 11, 2022 at 2:21:37 PM UTC-8, Thomas Koenig wrote:
    I disagree there. Both interfacs are accessed by use association
    in the main program, and thus are in its scope.

    At least this is how I interpret use association and 14.2.2.
    ..
    Thanks for the response. You're probably right. But since at least four compilers support this combination, so must I, and it's just a matter of determining how it should be documented.

    Re: ".. at least four compilers support this combination ..", I seriously doubt it.

    The code in the original post is not generic enough to fully illustrate the issue. With the modification below, both Intel Fortran (IFORT, IFX) and gfortran appear to conform to the standard and detect and report the issue of a generic interface in a
    scope where the procedures are not all functions nor all subroutines:

    module m1
    interface generic
    module procedure func
    end interface
    contains
    integer function func(n)
    integer, intent(in) :: n
    func = n
    end function
    end module

    module m2
    interface generic
    module procedure subr
    end interface
    contains
    subroutine subr
    print *, 'ok'
    end subroutine
    end module

    program main
    use m1
    use m2
    call generic
    print *, generic(42)
    end

    C:\temp>ifort /c /standard-semantics p.f90
    Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.7.0 Build 20220726_000000
    Copyright (C) 1985-2022 Intel Corporation. All rights reserved.

    p.f90(24): warning #6706: There is a mixture of specific functions and specific subroutines for one generic-spec. [SUBR]
    use m2
    -------^

    C:\temp>ifx /c /standard-semantics p.f90
    Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2022.2.0 Build 20220730
    Copyright (C) 1985-2022 Intel Corporation. All rights reserved.

    p.f90(24): warning #6706: There is a mixture of specific functions and specific subroutines for one generic-spec. [SUBR]
    use m2
    -------^

    C:\temp>gfortran -c p.f90
    p.f90:24:7:

    24 | use m2
    | 1
    Error: In generic interface 'generic' at (1) procedures must be either all SUBROUTINEs or all FUNCTIONs

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)