When a function has an alternate entry, is it necessary to set the return value for the entry name, or will the primary name always work if the alternate name is not set? For example,
INTEGER FUNCTION MYFUNC( ARG )
INTEGER ARG
INTEGER MYFUNC2
C ... do something here...
GOTO 100
ENTRY MYFUNC2( ARG )
C ... do something else here
100 CONTINUE
MYFUNC = <some value>
C .. is the next line needed, of can it be omitted?
myfunc2 = myfunc
RETURN
END
Citing the Fortran 2008 Standard, Cl. 12.6.2.6 ENTRY statement:
[...]
3 If the ENTRY statement is in a function subprogram, an additional
function is defined by that subprogram. The name of the function is
entry-name and the name of its result variable is result-name or is
entry-name if no result-name is provided.
[...]
If the characteristics of the result of the
function named in the ENTRY statement are the same as the
characteristics of the result of the function named in the FUNCTION
statement, their result variables identify the same variable, although
their names need not be the same. Otherwise, they are storage
associated and shall all be nonpointer, nonallocatable scalars that
are default integer, default real, double precision real, default
complex, or default logical.
The way I read the highlighted passage is that the line
myfunc2 = myfunc
is indeed not required since MYFUNC and MYFUNC2 are both scalar integers of the same kind.
Since no result is specified with either the function statement nor the entry statement, the function name becomes result-name. This is specified in Cl. 12.6.2.2 Function subprogram
[...]
4 If RESULT appears, the name of the result variable of the function
is result-name and all occurrences of the function name in
execution-part statements in its scope refer to the function itself.
If RESULT does not appear, the name of the result variable is
function-name and all occurrences of the function name in
execution-part statements in its scope are references to the result
variable. [...]
Related
I am trying to the assign value to a variable at the time of declaration and use that variable to declare the dimensions of some arrays as follows,
type (typ_A), intent (in) :: str_A
integer, parameter ::
x val_4 = (str_A%val_1 + str_A%val_2),
x val_5 = str_A%val_3
integer :: array_1(str_A%val_1, str_A%val_2), array_2(val_4, val_5)
In this code, the array_1 is declared properly with the expected sizes but the array_2 is not declared. Also, I am getting errors like "This symbol must be a defined parameter, an enumerator, or an argument of an inquiry function that evaluates to a compile-time constant."
Note - I can straight away use the expression of val_4 to declare array_2, but sometimes, the expression (str_A%val_1 + str_A%val_2 + ....) is very large and have to use it to define multiple arrays. Hence, for better readability and less number of lines, I want to put it in a variable (val_4 in this case)
A Fortran parameter must be computable at compile time, as the error message hints, and str_A%val_1 etc are not known at compile time.
You can't use a variable directly for this, but you can create a nested argument:
subroutine x (str_A)
type(whatever),intent(in)::str_A
call x_2 (str_A, str_A%val_1 + str_A%val_2)
contains
subroutine x_2 (str_A, mydim)
type(whatever),intent(in)::str_A
integer::mydim
integer:: ary1(mydim), ary2(mydim), ary3(mydim)
...
end subroutine x_2
end subroutine x
or if you can put at least the type and a helper function in a containing module you can do:
module t
type whatever ...
contains
pure function mydim(str_A)
integer::mydim
type(whatever),intent(in)::str_A
mydim = str_A%val_1 + str_A%val_2
end function mydim
subroutine y (str_A)
type(whatever),intent(in)::str_A
integer:: ary1(mydim(str_A)), ary2(mydim(str_A)), ary3(mydim(str_A))
...
end subroutine y
end module t
Added since you may not have considered/realized it:
Alternatively you could simply use ALLOCATABLE arrays instead; those can be allocated (not declared) with bounds computed by any runtime expression, including a local variable.
The answer of #dave_thompson_085 already answers the root for your problem.
A Fortran parameter must be computable at compile time
There are four possibilities to achieve the behaviour you want:
If you use the block statement you create a local, nested scope where you can declare new variables. You can then declare arrays that use runtime variables outside of the block for their shapes.
integer :: n
n = compute_at_runtime()
block
integer :: M(n)
! do something with M
end block
! M does not exist anymore
As #dave_thompson_085 also put it in his answer, you can use contained procedures with a local nested scope, to declare array with runtime variables that exist outside of the procedure.
Or you use allocatable for dynamic memory and automatic destruction/deallocation.
Or you use pointer for dynamic memory, but then you have to manually cleanup.
Consider the following class structure, which involves three separate modules:
!----------------------- in file a.f
module parent_body_mod
type :: face
class(parent_body), pointer :: bPtr
end type
type, abstract :: parent_body
integer i
type(face) :: f
end type
end module parent_body_mod
!------------------------ in file b.f
module body_mod
use parent_body_mod
type, extends(parent_body) :: body
end type
interface body
procedure :: new_body
end interface
contains
function new_body() result(b)
type(body), target :: b
b%i = 123
b%f%bPtr => b
end function
end module body_mod
!--------------------------- in file c.f
module body_group_mod
use body_mod
type :: body_group
type(body), allocatable :: b
end type
interface body_group
procedure :: new_body_group
end interface
contains
function new_body_group() result(bg)
type(body_group) :: bg
allocate(bg%b)
bg%b = body()
end function
end module body_group_mod
!------------------- The main program
use body_group_mod
type(body_group) :: my_bg
my_bg = body_group()
print *, my_bg%b%f%bPtr%i
end
!--------------------------------------
The expected output is 123, whereas the actual output is something random. The code is compiled using ifort version 18.0.1. Note that the same issue doesn't happen when using "body" class itself, i.e. the following works just fine:
type(body), allocatable :: my_b
allocate(my_b)
my_b = body()
print *, my_b%f%bPtr%i ! This produces 123 as expected.
Any help is appreciated.
The code is non conforming.
Pointers associated with unsaved local variables of a procedure become undefined when the execution of the procedure completes (F2008 16.5.2.5 (5)). The function result b in function new_body is considered such a local variable (F2008 1.3.154.1), hence the pointer component b%f%bPtr becomes undefined after the function call.
Function results are a little special compare to other local unsaved variables, in that their value is available longer than the variable exists - see F2008 Note 12.41 for some discussion.
Another way of thinking of the problems is that with the statement bg%b = body(), the body on the left hand side is a different object from the body on the right hand side. The assignment just copies the value of the right hand side object - once that assignment is complete, the right hand side object ceases to exist. Nowhere is there code to say that when the value of a body object is transferred - the pointer component needs to be updated to reference the left hand side variable being assigned to. Also note that the left hand side bg%b does not have the TARGET attribute - so there is no way that a pointer can be validly associated with it anyway.
In Fortran, there are two standard ways to return a result from a function. The first one is by assigning the return value of the function to the function name.
function foo()
integer :: foo
foo = 10
end function foo
The second form, standardized in Fortran 90 is through a "result" variable.
function foo result(res)
integer :: res
res = 10
end function foo
Calling either form of the function returns the value 10. My question is, what was the rationale of the Fortran 90 committee for introducing result variables? Were they standardizing a common practice? Or were they allowing programs to be more modular by not tying the function name to a function result. For example, in the second version of foo(), the name of the function foo() could be changed to bar() and the function would still work as expected when called.
However, I may be wrong. Does anyone know what the actual rationale was for introducing result variables?
Introduced at the same time as the result was recursion. Before we get to how a recursive function comes about, some clarification on what a result variable is.
The function result is always returned through a result variable, whether result is used or not.1 With result the result variable has the name specified, and without it the result variable has the same name as the function. In this latter case use of the name is a reference to the result variable and not the function.
So, if the function foo has result variable foo then we can't do direct recursion:
recursive function foo(n)
foo = foo(n-1) ! Oh dear
end function
result comes about so that we can have
recursive function foo(n) result(res)
res = foo(n-1) ! Yay
end function
[1] Well, this is true up until Fortran 2008, when the definition of variable changed. For modern Fortran use instead the term function result.
While going through some allegro tutorials I found an odd call.
int al_init();
The function al_init() initializes allegro so that the allegro functions can be used. What is with the int al_init(); line? If I change this line of the code to exclude int it works the same, but if I take out the line altogether it does not work. What is this line doing? The only thing I can imagine is that it creates an integer and assigns it the return value of the al_init() function, with that likely being -1 for failure and 0 for success etc. But if that is what this is doing, then how can you even check the return value?
In C/C++ there are function declarations and function definitions:
Declarations look like these:
int a_function();
void another_function();
double yet_another_function();
Explanation:
The identifier before the function name (e.g. int, void, double) describes the type of value returned by the function.
If you do not specify one, it defaults to int (which is why it works when you remove int from int al_init(), but not when you remove the declaration altogether)
void means it's not supposed to return a value (even though technically it can, but that's for rarer cases)
Definitions look like these:
int a_function() {
std::cout << "hello world!";
int x = 1;
int y = 2;
return (x + y);
}
Notice the difference:
Declarations end with ;
Definitions are followed by a block of code enclosed by braces: { and }, but no ;!
In some cases, you do not need to declare a function. If it's at a point in the code where the definition has already been seen, the definition can substitute for the declaration (this leads us to the next point...)
The purpose of declaration is to tell the program that, for example, there is a function named a_function, it expects no arguments, and it returns a value of type int.
Are you sure you aren't looking at the function declaration?
According to C's syntactic rules, a prototype is defined as:
<return-type> function-name (param1, param2, ..);
And a function call is defined as:
function-name(param1, param2,...);. So its obviously defining a function prototype and NOT calling the function.
C89 and previous rules were:
With the above rule, another rule was:
For implicit integer return type, the prototype was suppose to be defined outside of any executable function code. If it was inside of a function, it would be called a function-call and not function-prototype-definition.
That aside, lets start with the question:
While going through some allegro tutorials I found an odd call. int
al_init();
That's incorrect, it looks like a function prototype or declaration
The function al_init() initializes allegro so that the allegro
functions can be used. What is with the int al_init(); line? If I
change this line of the code to exclude int it works the same, but if
I take out the line altogether it does not work.
What does not work? Stops to compile? That would be obvious because it will not be able to find al_init() function. Also the reason it works without the "int" is because its implicitly assumed to return an integer.
What is this line doing?
Its telling the compiler that al_init() library function is defined elsewhere, typically in a .lib or .a or .dll, and you would want to use it in your program.
The only thing I can imagine is that it creates an integer and assigns
it the return value of the al_init() function,
Absolutely incorrect interpretation of code, it does not create any integer, nor assigns any value to it.
with that likely being -1 for failure and 0 for success etc. But if
that is what this is doing, then how can you even check the return
value?
Since you want to know what that function returned, you could do this while an actual call to al_init():
int retval = al_init();
printf("al_init() returned %d",retval);
Whenever I define a function say funct(n), then can I assign value of n to a different variable such as m so that I can compare value of n which changes within the function with the initial value of m. Further, since I have nested and sometimes independent other functions, is there a way to make the m variable universal?
What I did is:
fun funct(n)= let val m=n in if (condition) then...
Further, here funct calls funct1 and funct1 calls funct2. The error message reads
Error: unbound variable or constructor: m
for funct2
Error: unbound variable or constructor: funct1
for funct1
Error: unbound variable or constructor: funct1
for funct
I suppose the single correction of m would solve the wholse cascade of errors.
You can access any identifier from scopes which are deeper than the one the identifer has been defined in. E.g.
fun funct(n) =
let fun funct1(x, y, z) = if n < 1 then ...
...
In this example, funct1 has access to n, which has been defined in an outer scope (namely as a parameter of funct).
Be careful though, in functional languages like ML, identifiers have a different meaning from those in imperative languages like C. In your example, n and m are not variables, meaning the values denoted by the identifiers will not change. You can only redefine the identifiers; however, code that uses an identifier before its redefinition will always refer to the original value of that identifier.