|
Prev: Good book on FORTRAN OT
Next: branch prediction?
From: James Van Buskirk on 12 Apr 2008 14:50 "James Van Buskirk" <not_valid(a)comcast.net> wrote in message news:bpqdnfvMtKe7VGLanZ2dnUVZ_tuonZ2d(a)comcast.com... I have heard that it's bad manners to follow-up to your own post but I was hoping in vain that someone else would correct my errors. > I'm not sure that I catch the meaning of this paragraph. After all, it's > commonplace to have a fixed-rank specific procedure that has the same > generic name as the corresponding elemental procedure. That feature is > there because it may be desirable to write out a highly-optimized > procedure for a given rank, but also to hedge ones bets by providing an > elemental procedure that would otherwise cover the optimize case. I still think it's correct up to here. > In > reading 12.4.4.1 of N1601.pdf: > "(1) If the reference is consistent with a nonelemental reference to one > of the specific interfaces of a generic interface that has that name and > either is in the scoping unit in which the reference appears or is made > accessible by a USE statement in the scoping unit, the reference is to > the specific procedtre in the interface block that provides that > interface. The rules in 16.2.3 ensure that there can be at most one > such specific procedure. > (2) If (1) does not apply, if the reference is consistent with an > elemental reference to one of the specific interfaces of a generic > interface that has that name and either is in the scoping unit in which > the reference appears or is made accessible by a USE statement in the > scoping unit, the reference is to the specific elemental procedure in > the interface block that provides that interface. The rules in 16.2.3 > ensure that there can be at most one such specific elemental procedure." > This is saying that nonelemental procedures trump elemental ones. The > compiler is supposed to compare all the nonelemental procedures first > and use one of those if it matches, and only if no nonelemental > procedure works, then shuffle through the list of elemental procedures > to see if one of them works. I didn't notice in the above that the standard isn't really saying this. There are two ways this way of thinking conflicts with the standard: 1) The standard says that nonelemental REFERENCES trump elemental REFERENCES. A reference to an elemental procedure with all scalar actual arguments is not an elemental reference, see N1601.pdf, section 12.4.2: "A reference to an elemental function (12.7) is an elemental reference if one or more actual arguments are arrays and all array arguments have the same shape." Similar verbiage exists in section 12.4.3 for subroutines. 2) The standard does not say that elemental references always trump nonelemental references. Host-associated names go to the back of the bus in such a way that they can be blocked by other names. Thanks to Bob Corbett who pointed this out with clarity in http://groups.google.com/group/comp.lang.fortran/msg/3ca1c4732c6909e6 > If elemental procedures conflicted with > elemental procedures in the fashion suggested, why would there be a > need to separate parts (1) and (2) above instead of just making them > into one big part (1) where no distinction was made between elemental > and nonelemental procedures? > Here is an example: > C:\gfortran\clf\cos_test>ifort /stand:f03 ex1.f90 > pure function enisoc(x) > --------------------^ > ex1.f90(28) : Error: This name does not have a type, and must have an > explicit t > ype. [ENICOS] > print *, enicos(1.0) > ------------^ > compilation aborted for ex1.f90 (code 1) And now in my example I misspelled ENISOC. Just shows how a bad choice of variable names can make a program unreadable and untypable. Fixing up my example: C:\gfortran\clf\cos_test>type ex1a.f90 module cos_mod implicit none interface enisoc module procedure element, enisoc end interface enisoc contains pure function enisoc(x) real, intent(in) :: x real enisoc enisoc = 2 end function enisoc elemental function element(x) real, intent(in) :: x real element element = cos(x) end function element end module cos_mod program main use cos_mod implicit none real fun external fun print *, enisoc(0.0) print *, enisoc([0.0]) print *, fun(enisoc, 0.0) end program main function fun(f,x) implicit none real fun real f real x fun = f(x) end function fun C:\gfortran\clf\cos_test>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran -std=f20 03 ex1a.f90 -oex1a ex1a.f90:4.38: module procedure element, enisoc 1 Error: Ambiguous interfaces 'enisoc' and 'element' in generic interface 'enisoc' at (1) ex1a.f90:23.14: use cos_mod 1 Fatal Error: Can't open module file 'cos_mod.mod' for reading at (1): No such fi le or directory x86_64-pc-mingw32-gfortran: Internal error: Aborted (program f951) Please submit a full bug report. See <http://gcc.gnu.org/bugs.html> for instructions. C:\gfortran\clf\cos_test>ifort /stand:f03 ex1a.f90 Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1 Build 20061104 Copyright (C) 1985-2006 Intel Corporation. All rights reserved. ex1a.f90(7) : Warning: The type/rank/keyword signature for this specific procedu re matches another specific procedure that shares the same generic-name. [ENIS OC] pure function enisoc(x) --------------------^ Microsoft (R) Incremental Linker Version 8.00.40310.39 Copyright (C) Microsoft Corporation. All rights reserved. -out:ex1a.exe -subsystem:console ex1a.obj C:\gfortran\clf\cos_test>ex1a 2.000000 1.000000 2.000000 So gfortran rejects it and ifort accepts it. Which is right? Well, according to the literal words of the standard I think they both are. As stated above, although procedures that accept array arguments can override elemental procedures, procedures that have only scalar arguments can't because a conflicting reference to the elemental proceedure would not be an elemental reference. Quirk of the standard as I see it, but it's what the standard says. Thus gfortran rejects it and ifort accepts it with a warning and does perform the override as desired. ifort should insert the keywords "QUIRK IN STANDARD" in their warning message, though :) Now for a fixed-up version of this example that does perform the override as in Note 12.34: C:\gfortran\clf\cos_test>type ex1b.f90 module cos_mod implicit none interface enisoc module procedure element, enisoc end interface enisoc contains pure function enisoc(x) real, intent(in) :: x(:) real enisoc(size(x)) enisoc = 2 end function enisoc elemental function element(x) real, intent(in) :: x real element element = cos(x) end function element end module cos_mod program main use cos_mod implicit none ! real fun ! gfortran should reject if this line uncommented interface function fun(f,x) implicit none interface pure function f(x) real, intent(in) :: x(:) real f(size(x)) end function f end interface real x(:) ! real fun(size(f(x))) ! ICE with ifort if this line in force real fun(size(x)) ! ifort handles this OK end function fun end interface print *, enisoc(0.0) print *, enisoc([0.0]) print *, fun(enisoc, [0.0]) end program main function fun(f,x) implicit none interface pure function f(x) real, intent(in) :: x(:) real f(size(x)) end function f end interface real x(:) real fun(size(f(x))) fun = f(x) end function fun C:\gfortran\clf\cos_test>c:\gcc_equation\bin\x86_64-pc-mingw32-gfortran -std=f20 03 ex1b.f90 -oex1b C:\gfortran\clf\cos_test>ex1b 1.00000000 2.0000000 2.0000000 C:\gfortran\clf\cos_test>ifort /stand:f03 ex1b.f90 Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1 Build 20061104 Copyright (C) 1985-2006 Intel Corporation. All rights reserved. Microsoft (R) Incremental Linker Version 8.00.40310.39 Copyright (C) Microsoft Corporation. All rights reserved. -out:ex1b.exe -subsystem:console ex1b.obj C:\gfortran\clf\cos_test>ex1b 1.000000 2.000000 2.000000 So the example works, and even better it exposes a couple of errors in gfortran and ifort as noted in the comments. Now I think I begin to understand what the thread is about: a name can refer to multiple things, such as a generic name, a specific procedure name, and an intrinsic procedure name, and the standard permits names of perhaps unrelated things to block host-associated names in a perhaps quirky, nonintuitive and surprising fashion. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end |