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.
Related
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. [...]
Consider the following FORTRAN program:
program functiontest
implicit none
real :: x, square
print *, "Enter a number to square"
read (*,*) x
print *, square(x)
end program functiontest
real function square(x)
real :: x
square = x * x
end function square
Why do I need to declare square to be real inside program functiontest? Haven't I already declared it a real function in its definition?
Why did the authors of FORTRAN make this design decision?
No, actually in your example you haven't declared it a real function inside the program, but it's an external function to the program. If you defined your function inside the program, as follows, or put it in a module and used it, you wouldn't have to specify it's a real function twice.
program functiontest
implicit none
real :: x
print *, "Enter a number to square"
read (*,*) x
print *, square(x)
contains
real function square(x)
real :: x
square = x * x
end function square
end program functiontest
As for why it also works the way you wrote it, it is for backwards compatibility with Fortran 77.
Put the function in a module and use the module, as shown below. Then you don't need to declare the function in the main program.
module foo
contains
real function square(x)
real :: x
square = x * x
end function square
end module foo
program functiontest
use foo
implicit none
real :: x
print *, "Enter a number to square"
read (*,*) x
print *, square(x)
end program functiontest
The square inside the function is a variable, and is not the function name. Since it is a variable, it must be declared with the right type.
I think you need to declare the type in functionlist because "in general" compiler doesn't know the type of "square". Consider a case that you have function "square" defined in a separate file, i.e. "square.f", and functionlist in another file "functionlist.f". In that case you need to compile each of those files separately and create two object file, i.e. square.o and functionlist.o. In this scenario, compiler has no clue about the "square" type, when compiling for "functionlist.o", unless you explicitly define it.
So you might ask why compiler needs to know the type of square in the first place. The answer, I think, is related to memory allocation, casting the type (e.g. when you are assigning the results to a real*8), ....
Note that, this is also common in C. There, you either need to define the prototype (in foo.h), in which the type of square is declared, or place all the functions in a file such that compiler "sees" square first.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is the return type part of the function signature?
Following up on a related but tangential question ( How to disambiguate function templates that differ only by return type? ), I would like to ask a question related to the fact that the return type of a function is not considered to be part of the signature of a function.
Consider the following code:
#include <iostream>
int foo()
{
return 0;
}
int main()
{
long n = static_cast<long(&)()>(foo)(); // Error: incorrect return type
int p = static_cast<int(&)()>(foo)(); // Compiles just fine
}
The line of code noted above results in a compilation error, because the return type of the function type to which foo is being cast does not match the return type of the function foo.
But I thought the return type of a function does not play a role in the signature of the function!
According to a certain line of thinking, since the function signature long(&)() matches the signature of foo, the cast of foo to a function of this type should succeed.
However, the cast does not succeed. Where does the reasoning go wrong? If the cast cannot fail due to the function signature, then why does the cast fail?
You're correct that the return type doesn't form part the signature of the function.
However, it does form part of the type of the function, and you're not allowed to convert pointers to incompatible function types.
The return type is part of the type, although not used for overload resolution. It is important not to confuse the terms. Basically, the type includes arguments and return value, but during overload resolution, the return type is not considered. The type of the function or function pointer is a contract between the caller and the callee, and they must fully agree on the terms.
From a practical point of view, consider what would happen if what you suggest was allowed. Imagine a calling convention in which the caller reserves space and passes a pointer to that space to the function, the function will then construct in that location the returned object (this is actually a very common calling convention). Consider now that you were allowed to perform the cast you proposed and the following use case
static_assert(sizeof(T1)<sizeof(T2));
T2 f();
T1 (*p)() = &f;
p(); // call
Now when the compiler is processing p() it reserves space somewhere, and given the type of the function it needs to reserve sizeof(T1). It then calls the function, which ends up calling f which writes sizeof(T2) bytes into the location causing an overflow.
Even if the sizes matched, the code would be problematic. Consider T1==int and T2==float in a platform where sizeof(int)==sizeof(float). While the code above would not cause a buffer overrun, the bitpattern stored in the location of the return type would be that of a float, not that of an int.
The return type of a function is not part of the signature, but the signature isn't what the compiler needs to know in order to correctly call the function referred to by a function pointer or reference.
As well as the parameters, the compiler needs to know the return type, so that it can make space for the return value on the stack, or read the return value from the correct register(s), or whatever the calling convention demands in a given implementation.
That is why the return type is part of the type of the function -- so that the type tells the compiler what it needs to know at compile time in order to emit code to call the function.
the function signature long(&)() matches the signature of foo
long(&)() isn't a function signature, it's a type. foo(void) is a (representation of a) function signature. It includes the name and parameters. But you never need to specify a function signature in C++ code (well, perhaps as a string passed to dlsym or similar). The definitive representation of a function signature is the mangled name of the function in a given implementation. The mangling scheme isn't standard, it's up to the implementation (although if different implementations want to call into each other's libraries then they must use the same scheme, so the OS might specify one).
The return type of a function is considered part of its signature (and of its type). However, it is allowed to assign function pointers to variables with different return types if the return types are "covariant".
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);
I have a code.
class A
{
public:
int foo(int i)
{
return i;
}
};
int foo(int i)
{
return i;
}
int (A::*ptrFoo)(int) = NULL;
int (*_foo)(int) = NULL;
int main()
{
ptrFoo = &A::foo;
_foo = foo;
(*_foo)++++++++++++++(10); //This dont compile...
A a;
(a.*ptrFoo)+++++++++++++++++(10); //This compiles ????
}
please tell me what it is ?? a undefined behavior or what ??? I compiled it in VS2008.Strangely the last line of code compiles successfully.
Neither expression should compile: in C++, you cannot perform arithmetic on a pointer to a function or member function, or on a function type or member function. The two expressions in your program attempt to perform arithmetic on a function and on a member function, respectively.
If your compiler accepts the second expression, it is due to a bug in the compiler.
First note that pointer to functions are different with pointer to member functions.
Your first example is a pointer to an ordinary function. It contains the real memory address of the function. When you dereference it ((*_foo)) you get the function itself, and arithmetic operations including ++ on a function (function pointer) are meaningless.
The second one is another story, pointers to member functions of classes do not carry the address of the function in memory. Actually how compiler manages member functions is implementation-specific. A pointer to a member function may contain some address or maybe some compiler-specific information. Arithmetic on this type is also meaningless.
Therefore we don't know what the value of (a.*ptrFoo) ever is, but in your case MSVC2008 managed to compiler it, either because of a bug or by design.
By the way, GCC does not compile any of the two statements and threw errors on both.
The above is true whether you put even number of +'s or odd numbers; we are doing arithmetic anyway. (If there are an odd number of +'s then there is no function call, as in your second example you are incrementing the function 8 times then the last remaining + adds 10 to the result. Again, this doesn't matter: we are trying to change a function/member function pointer.)