fortran-wringer-tests icon indicating copy to clipboard operation
fortran-wringer-tests copied to clipboard

Passed-object dummy arguments

Open ivan-pi opened this issue 9 months ago • 2 comments

Consider the following module inspired by the multiple dispatch article on Wikipedia (https://en.wikipedia.org/wiki/Multiple_dispatch):

! c3.f90

module collisions

type, abstract :: SpaceObject
contains
   procedure(collide_sub), deferred :: collide
end type

abstract interface
   subroutine collide_sub(x,y)
      import SpaceObject
      class(SpaceObject) :: x,y
   end subroutine
end interface


type  :: Spaceship
contains
    private
    procedure, pass(x) :: p_collide_ss => collide_ss
    procedure, pass(x) :: p_collide_sa => collide_sa
    procedure, pass(y) :: p_collide_as => collide_as
    generic, public :: collide => p_collide_ss, p_collide_sa, p_collide_as
end type

type :: Asteroid
end type

interface collide
    module procedure collide_aa, collide_as, collide_sa, collide_ss
end interface

contains

subroutine collide_aa(x,y)
    class(Asteroid) :: x
    class(Asteroid) :: y
    print *, "a/a"
end subroutine
subroutine collide_as(x,y)
    class(Asteroid) :: x
    class(Spaceship) :: y
    print *, "a/s"
end subroutine
subroutine collide_sa(x,y)
    class(Spaceship) :: x
    class(Asteroid) :: y
    print *, "s/a"
end subroutine
subroutine collide_ss(x,y)
    class(Spaceship) :: x
    class(Spaceship) :: y
    print *, "s/s"
end subroutine

end module


program test

use collisions

type(Spaceship) :: s1, s2
type(Asteroid) :: a1, a2

print *, "using generic procedure"
call collide(a1,a2)
call collide(a1,s1)
call collide(s1,a1)
call collide(s1,s2)

print *, "using type-bound procedures"
call s1%collide(s2)
call s1%collide(x=a1)
call s1%collide(y=a1)
! call s1%collide(a1)
end program

The Fortran processors differ in their output:

$ gfortran-14 c3.f90 
c3.f90:24:33:

   24 |     generic, public :: collide => p_collide_ss, p_collide_sa, p_collide_as
      |                                 1
Error: 'collide_sa' and 'collide_as' for GENERIC 'collide' at (1) are ambiguous
$ ifort c3.f90 
$ ./a.out
 using generic procedure
 a/a
 a/s
 s/a
 s/s
 using type-bound procedures
 s/s
 a/s
 s/a
$ flang-new c3.f90 
error: Semantic errors in c3.f90
./c3.f90:24:24: error: Generic 'collide' may not have specific procedures 'p_collide_sa' and 'p_collide_as' as their interfaces are not distinguishable
      generic, public :: collide => p_collide_ss, p_collide_sa, p_collide_as
                         ^^^^^^^
./c3.f90:46:12: Procedure 'p_collide_sa' of type 'spaceship' is bound to 'collide_sa'
  subroutine collide_sa(x,y)
             ^^^^^^^^^^
./c3.f90:41:12: Procedure 'p_collide_as' of type 'spaceship' is bound to 'collide_as'
  subroutine collide_as(x,y)
             ^^^^^^^^^^
$ flang-new --version
Homebrew flang-new version 19.1.4
Target: x86_64-apple-darwin23.6.0
Thread model: posix
InstalledDir: /usr/local/Cellar/flang/19.1.4/libexec
Configuration file: /usr/local/Cellar/flang/19.1.4/libexec/flang.cfg
Configuration file: /usr/local/etc/clang/x86_64-apple-darwin23.cfg
> nagfor c3.f90 
NAG Fortran Compiler Release 7.2(Shin-Urayasu) Build 7203
Warning: c3.f90, line 40: Unused dummy variable X
Warning: c3.f90, line 40: Unused dummy variable Y
Warning: c3.f90, line 45: Unused dummy variable X
Warning: c3.f90, line 45: Unused dummy variable Y
Warning: c3.f90, line 50: Unused dummy variable X
Warning: c3.f90, line 50: Unused dummy variable Y
Warning: c3.f90, line 55: Unused dummy variable X
Warning: c3.f90, line 55: Unused dummy variable Y
[NAG Fortran Compiler normal termination, 8 warnings]
> ./a.out
 using generic procedure
 a/a
 a/s
 s/a
 s/s
 using type-bound procedures
 s/s
 a/s
 s/a

If we now uncomment the last line in c3.f90:

call s1%collide(a1)

we also trigger different behaviors:

$ ifort c3.f90 
c3.f90: error #5286: Ambiguous generic interface COLLIDE: previously declared specific procedure COLLISIONS::COLLIDE_SA is not distinguishable from this declaration. [COLLISIONS::COLLIDE_AS]
compilation aborted for c3.f90 (code 1)
> nagfor c3.f90 
NAG Fortran Compiler Release 7.2(Shin-Urayasu) Build 7203
Warning: c3.f90, line 40: Unused dummy variable X
Warning: c3.f90, line 40: Unused dummy variable Y
Warning: c3.f90, line 45: Unused dummy variable X
Warning: c3.f90, line 45: Unused dummy variable Y
Warning: c3.f90, line 50: Unused dummy variable X
Warning: c3.f90, line 50: Unused dummy variable Y
Warning: c3.f90, line 55: Unused dummy variable X
Warning: c3.f90, line 55: Unused dummy variable Y
[NAG Fortran Compiler normal termination, 8 warnings]
(base) di75yas@cm4login1:~/dispatch> ./a.out
 using generic procedure
 a/a
 a/s
 s/a
 s/s
 using type-bound procedures
 s/s
 a/s
 s/a
 a/s

ifort does not want to make an ambiguous choice. nagfor selects the method p_collide_as for whatever reason that may be.

ivan-pi avatar Mar 04 '25 15:03 ivan-pi

I suppose this could fall under a subcase of non-portability related to generic interface (https://github.com/klausler/fortran-wringer-tests/tree/main?tab=readme-ov-file#generic-interfaces).

In this example the combination of keyword arguments and types is needed to complete the analysis.

ivan-pi avatar Mar 04 '25 15:03 ivan-pi

The Fortran standard, to the extent that it matters, requires that the specific procedures of a generic interface be distinguishable according to rules that it lays out, whether any particular reference to the generic procedure turns out to be ambiguous or not. This was a really good idea in Fortran '90 since it allowed one to write a generic library API that one could be assured would never lead to an ambiguous reference in any client of the library. Because some compilers don't implement these checks, or don't do so correctly, I sometimes get bug reports from users complaining that their code compiles fine with $OTHER_COMPILER, or asking that ambiguity checking only be done on a per-call basis.

Unfortunately, the rules for distinguishing specific procedures were no longer perfect after F'2003 added polymorphism to the language. So a compiler still has to check for ambiguity on each reference anyway now.

klausler avatar Mar 04 '25 22:03 klausler