Only one Fortran compiler can cope with this usage -- most crashOn what grounds?
hard with internal errors -- but I contend that it's conforming
usage.
module m
contains
function foo()
procedure(bar), pointer :: foo
foo => bar
call foo ! <-- CALL of a function
end function
subroutine bar
print *, 'in bar'
end subroutine
end module
program demoSounds fishy, at least...
use m
procedure(bar), pointer :: p
p => foo()
call p
end
Only one Fortran compiler can cope with this usage -- most crash
hard with internal errors -- but I contend that it's conforming
usage.
module m
contains
function foo()
procedure(bar), pointer :: foo
foo => bar
call foo ! <-- CALL of a function
end function
subroutine bar
print *, 'in bar'
end subroutine
end module
program demo
use m
procedure(bar), pointer :: p
p => foo()
call p
end
Only one Fortran compiler can cope with this usage -- most crash
hard with internal errors -- but I contend that it's conforming
usage.
On what grounds?
Within the body of the function FOO, the name FOO refers to its
result variable. The result variable in this case is a procedure pointer
to a subroutine. A CALL statement's procedure designator is
allowed to be a procedure pointer.
Only one Fortran compiler can cope with this usage -- most crash hard with internal errors -- but I contend that it's conforming usage.
Within the body of the function FOO, the name FOO refers to its result variable. The result variable in this case is a procedure pointer to a subroutine. A CALL statement's procedure designator is allowed to be a procedure pointer.
Only one Fortran compiler can cope with this usage -- most crash hard with internal errors -- but I contend that it's conforming usage. ..
Only one Fortran compiler can cope with this usage -- most crash hard with internal errors -- but I contend that it's conforming usage.
module m
contains
function foo()
procedure(bar), pointer :: foo
foo => bar
call foo ! <-- CALL of a function
end function
subroutine bar
print *, 'in bar'
end subroutine
end module
program demo
use m
procedure(bar), pointer :: p
p => foo()
call p
end
On 5/18/2022 12:07 PM, pmk wrote:
Within the body of the function FOO, the name FOO refers to its result variable. The result variable in this case is a procedure pointer to a subroutine. A CALL statement's procedure designator is allowed to be a procedure pointer.
I agree with this.
It works if the result is explicitly specified like by Vipul
(FortranFan), or if the function is defined as recursive. Then gfortran
and Nagfor can compile, Nagfor even the original code with the -f2018
flag (using the Fortran 2018 standard where every function is recursive).
I think the gremlin lies in the procedure pointer assignment 10.2.2.4.
These are all procedures in the same module so the interfaces are explicit (as is required by the pointer-ness and the procedure-ness).
Since the interfaces are explicit, agreement is required of the characteristics.
The characteristics include whether it is a subroutine or a function 15.3.1. qed
.. if the function is defined as recursive. Then gfortran
and Nagfor can compile, Nagfor even the original code with the -f2018
flag (using the Fortran 2018 standard where every function is recursive). ..
..
And I'll respectfully disagree.
I think the gremlin lies in the procedure pointer assignment 10.2.2.4.
These are all procedures in the same module so the interfaces are explicit (as is required by the pointer-ness and the procedure-ness).
Since the interfaces are explicit, agreement is required of the characteristics.
The characteristics include whether it is a subroutine or a function 15.3.1. qed
(I'm reading 22-007r1) ..
On Thursday, May 19, 2022 at 9:08:54 AM UTC-7, Dan Nagle wrote:
I think the gremlin lies in the procedure pointer assignment 10.2.2.4.
These are all procedures in the same module so the interfaces are explicit (as is required by the pointer-ness and the procedure-ness).
Since the interfaces are explicit, agreement is required of the characteristics.
The characteristics include whether it is a subroutine or a function 15.3.1.
qed
The procedure pointer is assigned to the same procedure used to define its interface.
..
The function statement declares foo to be a function.
The explicit interface for bar declares bar to be a subroutine.
Hence, the mismatch...
The function statement declares foo to be a function.
The explicit interface for bar declares bar to be a subroutine.
Hence, the mismatch.
The function statement declares foo to be a function.
The explicit interface for bar declares bar to be a subroutine.
Hence, the mismatch.
Does that explain why my program doesn't work?
No, your code has genuine mismatch in the scope of your `trythis` subprogram.
but still it won't compile with gfortran.
If you have a Fortran 2018 compiler, here's a variant of your code the processor
should accept: with "gfortran", you can replace the "generic" statement with an INTERFACE block.
Does that explain why my program doesn't work?
but still it won't compile with gfortran.
On Thursday, May 19, 2022 at 3:25:14 PM UTC-4, Dan Nagle wrote:
..
The function statement declares foo to be a function.
The explicit interface for bar declares bar to be a subroutine.
Hence, the mismatch...
That is not the case.
See R1532 and note what is said about function statement versus execution-part and J3/22-007r1, page 336, lines 27 thru' 29.
On Thursday, May 19, 2022 at 12:25:14 PM UTC-7, Dan Nagle wrote:
The function statement declares foo to be a function.
The explicit interface for bar declares bar to be a subroutine.
Hence, the mismatch.
I think you're saying that a function returning a procedure pointer can only return a pointer to a function, but not a pointer to a subroutine.
That turns out to not be the case.
..and
And at line 25 the function result variable has all the characteristics of the function. ..
..
If you write a result-name in foo,
and you use a local variable with the subroutine characteristic in bar.
Only one Fortran compiler can cope with this usage -- most crash hard with internal errors -- but I contend that it's conforming usage..
module m
contains
function foo()
procedure(bar), pointer :: foo
foo => bar
call foo ! <-- CALL of a function
end function
subroutine bar
print *, 'in bar'
end subroutine
end module
program demo
use m
procedure(bar), pointer :: p
p => foo()
call p
end
On Friday, May 20, 2022 at 12:00:28 PM UTC-4, Dan Nagle wrote:
..and
And at line 25 the function result variable has all the characteristics of the function. ..
On Friday, May 20, 2022 at 12:05:53 PM UTC-4, Dan Nagle wrote:
..
If you write a result-name in foo,
and you use a local variable with the subroutine characteristic in bar.
@Dan Nagle,
I fail to see how your first point, "the function result variable has all the characteristics of the function" of any relevance to the original post.
A
function can *indeed* have a function-result that is a procedure pointer to a subroutine, there are no doubts it. The following is a conforming program:
module m
contains
function foo() result(r)
procedure(bar), pointer :: r
r => bar
end function
subroutine bar
print *, 'in bar'
end subroutine
end module
The question implied by OP is
1. If RESULT clause does NOT appear and
2. There is a reference to the function-name in the execution-part of the function,
what does the standard and the compilers have to "say" about that?
Well with the code in the original post, it conforms.
The compilers appear to "fall over" at the line "CALL foo" only because the function-name itself is FOO.
But the standard makes it clear, "If RESULT does not appear, the name of the function result is function-name and all occurrences of the function name in execution-part statements in its scope are references to the function result."
Thus "CALL foo" does not involved a reference to the function-name per the standard, instead it is a reference to a procedure pointer associated with `bar`. One can see it as though the "offending" line were `CALL bar` and there is nothing non-conformant when viewed as such.
Thus "CALL foo" does not involved a reference to the function-name per the >> standard, instead it is a reference to a procedure pointer associated with >> `bar`. One can see it as though the "offending" line were `CALL bar` and
there is nothing non-conformant when viewed as such.
Not so. C1525 disagrees. The name appearing in a call statement must designate
a subroutine.
foo is the name of a function (whose value is a pointer to
subroutine).
Again, this can be cured by using a local variable to hold the value
returned from the function foo, the which can then be called.
The theme is that one must distinguish the function-ness of foo
from the subroutine-ness of foo's result value. An extra variable does the trick.
..
The relevance is that, once the function statement gives the name foo the function characteristic,
the declaration of the local result variable cannot change it. The declaration can set other
attributes, but cannot change whether a name refers to an entity that is a function or a subroutine.
That is determined by whether the name appears in a function statement
or a subroutine statement.
On 5/21/22 10:26 AM, Dan Nagle wrote:
[...]
Thus "CALL foo" does not involved a reference to the function-name per the
standard, instead it is a reference to a procedure pointer associated with
`bar`. One can see it as though the "offending" line were `CALL bar` and there is nothing non-conformant when viewed as such.
Not so. C1525 disagrees. The name appearing in a call statement must designate
a subroutine.
In that call statement, foo is a procedure pointer to a subroutine, so
does that not qualify as designating a subroutine?
foo is the name of a function (whose value is a pointer to
subroutine).
Without the result() clause, foo is the value of the function within the function body, which is a pointer to a procedure. A procedure pointer
can point to either subroutines or functions, without restriction. There
are not separate pointers for functions and for subroutines, they all
share the same type declaration.
Furthermore, after the pointer assignment, it would be illegal to
reference foo as a function within the body of the function. It is
REQUIRED to reference it only as a subroutine and with the interface
that is consistent with that of the target subroutine.
Again, this can be cured by using a local variable to hold the value returned from the function foo, the which can then be called.
The result() clause was added to the language in order to allow direct recursion to the function from within the body of the function. Of
course, the recursive attribute is required, either explicitly (f90) or implicitly (f2003), in this case. After result(r) is added, then any references to foo are to the function, while references to r are to the value. It is even allowed to do indirect recursion without the result() clause, it is only direct recursion from foo to itself that requires the result() clause. However, in this example, there is no recursion
involved anywhere, direct nor indirect. If recursion is not involved
then it seems like result() should not be necessary.
Without result(), there is no ambiguity that within the body of the
function that references to foo are references to the value.
The theme is that one must distinguish the function-ness of foo
from the subroutine-ness of foo's result value. An extra variable does the trick.
Those two "-ness" are already distinguished. Without the result(), all references to foo within the body are to its value. With the result()
clause, all references to foo are recursive references to the function itself. It follows that since no recursive references to foo are
invoked, then result() is unnecessary. It is like declaring a variable
and then not referencing it. Of course, in this case, that might not be
a bad idea for human readers of the code, but it seems unnecessary for
the compiler which knows all of this because there is no ambiguity in
the language in this respect.
$.02 -Ron Shepard
The function result variable inherits all the characteristics
of the function name.
The statement declaring foo to be a pointer to subroutine
is invalid because it attempts to change the characteristics of foo.
The function statement declares two characteristics of foo:
1. foo is a function, and
2. foo has no arguments.
result was also added to allow the function value to be an array.
(This is one reason why result variables inherit all characteristics
of the function name- you want the array to have the correct shape.)
Without result(), there is no ambiguity that within the body of the
function that references to foo are references to the value.
The theme is that one must distinguish the function-ness of foo
from the subroutine-ness of foo's result value. An extra variable does the >>> trick.
Those two "-ness" are already distinguished.
The ambiguity is that you want some references to foo to be a function,
and some references to foo to be a subroutine.
Whether foo is a function or a subroutine is a characteristic
that cannot change.
foo is a function because it is the name in a function statement.
The type of foo is irrelevant.
foo is not a subroutine because its name does not appear in a subroutine statement.
Attempting to do so by setting the type of the result is not conforming.
Within the body of the function, and without the result() clause,
references to foo are to the result value, not recursive references to
the function. This is the same as if it were say, an integer function. References within the body would be to the integer value, not recursive references to the function with no arguments. Here is another example of this, which I think is conforming:
program func
write(*,*) foo(3)
contains
function foo(n)
integer :: foo(2) ! return an integer array.
integer, intent(in) :: n
foo(1) = -n
foo(2) = n
return
end function foo
end program func
Note that there is no result() clause. The result of the function is an integer array, so result() is not necessary simply to declare an array
valued function. Also, within the function body, the references to
foo(1) and foo(2) are to the elements of the integer array, they are not recursive references to the function with its single integer argument.
It's kind of mind-bending to think about the function foo and the
result variable foo as different things with the same name in
the seminal example of this thread, but different things can indeed
have the same name. If you google my name the first thing it comes
up with is some pervert from the West Coast. Another thing about
names with which we are all familiar: https://en.wikipedia.org/wiki/Haddocks%27_Eyes
On 5/22/2022 1:44 PM, James Van Buskirk wrote:
<--SNIP-->
It's kind of mind-bending to think about the function foo and the
result variable foo as different things with the same name in
the seminal example of this thread, but different things can indeed
have the same name. If you google my name the first thing it comes
up with is some pervert from the West Coast. Another thing about
names with which we are all familiar: https://en.wikipedia.org/wiki/Haddocks%27_Eyes
Not only the same name, as James writes, but sometimes we use the same notation but with different meanings.
Indeed, having multiple purposes/meanings of parentheses -- to hold a sequence of subprogram arguments, and also to hold subscripts -- is the
cause of so many complicated and confusing rules. Had we used the
notation of other programming languages, "foo(n)" would be a function invocation and "foo[n]" would be the n-th or (n+1)th element of array
"foo".
<-SNIP->
On 5/22/22 10:22 AM, Dan Nagle wrote:
[...]
The function result variable inherits all the characteristics
of the function name.
Your claim would seem to apply to both cases, with and without the
result() clause. Yet you have already stated that it doesn't, that it
only applies to the case without the result() clause.
Or are you claiming that with result(r), the entity r is not the result variable? Or that the entity r does not inherit all the characteristics
of foo, the function name.
Either way, it seems like a contradiction to the above statement?
The statement declaring foo to be a pointer to subroutine
is invalid because it attempts to change the characteristics of foo.
Yet, with the result() clause you claim that the same thing is allowed.
Isn't this inconsistent with your above argument?
Here is another example of
this, which I think is conforming:
program func
write(*,*) foo(3)
contains
function foo(n)
integer :: foo(2) ! return an integer array.
integer, intent(in) :: n
foo(1) = -n
foo(2) = n
return
end function foo
end program func
Note that there is no result() clause. The result of the function is an integer array, so result() is not necessary simply to declare an array
valued function. Also, within the function body, the references to
foo(1) and foo(2) are to the elements of the integer array, they are not recursive references to the function with its single integer argument.
Is this small program conforming?
[...]
result was also added to allow the function value to be an array.
The example above shows that result() is not required for this purpose.
(This is one reason why result variables inherit all characteristics
of the function name- you want the array to have the correct shape.)
See the above example which contradicts this statement.
There is no ambiguity. Without the result() clause, all references to
foo within the function body are to its value as an integer array in the above example, and to a procedure pointer in the example being discussed.
Whether foo is a function or a subroutine is a characteristic
that cannot change.
foo is a function, and its value is a procedure pointer.
foo is a function because it is the name in a function statement.
The type of foo is irrelevant.
This statement is not consistent with the above example. There foo is a function, and the type of its value is an integer array. References such
as foo(1) within the body of the function are to the integer array, not recursive references to the function.
Only one Fortran compiler can cope with this usage -- most crash hard with internal errors -- but I contend that it's conforming usage.
module m
contains
function foo()
procedure(bar), pointer :: foo
foo => bar
call foo ! <-- CALL of a function
end function
subroutine bar
print *, 'in bar'
end subroutine
end module
program demo
use m
procedure(bar), pointer :: p
p => foo()
call p
end
This case is confusing, I'll admit. I note that NAG Fortran 7.1 rejects
it, complaining of a recursive reference to FOO. I'm going to run this
by the committee and see what they think. (I'll also report the ICE to
Intel, though not before I get an answer as to what it is supposed to do.)
..
This case is confusing, I'll admit. I note that NAG Fortran 7.1 rejects
it, complaining of a recursive reference to FOO. I'm going to run this
by the committee and see what they think.
This case is confusing, I'll admit. I note that NAG Fortran 7.1 rejects
it, complaining of a recursive reference to FOO. I'm going to run this
by the committee and see what they think. (I'll also report the ICE to
Intel, though not before I get an answer as to what it is supposed to do.)
On 5/23/2022 7:29 PM, Steve Lionel wrote:
This case is confusing, I'll admit. I note that NAG Fortran 7.1 rejects it, complaining of a recursive reference to FOO. I'm going to run thisMalcolm Cohen (NAG Fortran, standard editor) said, "There is no doubt
by the committee and see what they think. (I'll also report the ICE to Intel, though not before I get an answer as to what it is supposed to do.)
that within FOO, FOO is the eponymous result name, not the name of the subprogram. This is similar to functions returning arrays – within an array function F with no RESULT clause, F(I,J) is an array element of
the result, not a recursive self-reference."
--
Steve Lionel
..
Malcolm Cohen (NAG Fortran, standard editor) said, "There is no doubt
that within FOO, FOO is the eponymous result name, not the name of the subprogram. This is similar to functions returning arrays – within an array function F with no RESULT clause, F(I,J) is an array element of
the result, not a recursive self-reference." ..
If we were to accept Dan's position that the FUNCTION statement causes
the function result to be a function, a function such as:
function BAZ ()
REAL :: BAZ
BAZ = 3.0
end function BAZ
would be invalid, since you can't assign 3.0 to a function.
Thank you for the follow-up, that is very useful to know. I wonder whether NAG Fortran team will open up a support incident on this.
In that case, the comment by PMK in the code fragment in the leading post:
call foo ! <-- CALL of a function
is incorrect, and perhaps misleading.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 159 |
Nodes: | 16 (0 / 16) |
Uptime: | 98:03:21 |
Calls: | 3,209 |
Files: | 10,563 |
Messages: | 3,009,574 |