Re: please try this program (generic resolution)
- From: "James Van Buskirk" <not_valid@xxxxxxxxxxx>
- Date: Sat, 12 Apr 2008 12:50:09 -0600
"James Van Buskirk" <not_valid@xxxxxxxxxxx> wrote in message
news:bpqdnfvMtKe7VGLanZ2dnUVZ_tuonZ2d@xxxxxxxxxxxxxx
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
.
- References:
- please try this program (generic resolution)
- From: robert . corbett
- Re: please try this program (generic resolution)
- From: Steve Lionel
- Re: please try this program (generic resolution)
- From: James Van Buskirk
- Re: please try this program (generic resolution)
- From: Steve Lionel
- Re: please try this program (generic resolution)
- From: James Van Buskirk
- please try this program (generic resolution)
- Prev by Date: Re: Reopening standard input/output
- Next by Date: Pause in program execution
- Previous by thread: Re: please try this program (generic resolution)
- Next by thread: Re: please try this program (generic resolution)
- Index(es):
Relevant Pages
|
Loading