3

I am new to Fortran and I am trying on the common block. My code is simple

program main
    implicit double precision (p)
    real * 8 :: x, y
    common /yvalue/ y
    x = 3d0
    y = 3d0
    print *, power(x)
end program main

function power(x)
    implicit none
    real * 8 :: power
    real * 8 :: x, y
    common /yvalue/ y
    power = x ** y
end function power

It works but if I comment out the second line, which implicitly declares variables starting with p to be double precision, the compiler complains the following

Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))

I do get the point that the return value power is by default a single precision variable, but why declaring power as double precision in the function is not enough? And why writing real * 8 power in main would not work either?

zyy
  • 1,271
  • 15
  • 25
  • 4
    Explicitly declaring `power` to be `real*8` in the main works for me. Since you are learning Fortran I would advise you to steer well clear of "features" like `COMMON`, implicit delarations and `real*8`. – RussF Nov 22 '18 at 06:09
  • 4
    Note real*8 is not part of standard Fortran, has never been part of standard Fortran, and if that is what you are being talught I worry about the quality of the rest of the teaching - especially if it is covering common and implicit typing as well, things that shouldn't have been used for 25 years. Learn instead about Fortran's kind mechansim – Ian Bush Nov 22 '18 at 06:52
  • 3
    To reinforce what @RussF has already advised: if you are new to Fortran don't learn about common blocks. Your first contact with them should come when you start to modify old codes. – High Performance Mark Nov 22 '18 at 08:21
  • 1
    Mixing real data type widths between caller and callee "worked" for a long time on 387 architecture and may still do so in non-sse mode with common 32-bit compilers, as the value would be returned and consumed from the same 387 stack register, and some compilers didn't check this. With an explicit interface (as advised below), a single declaration seen by both caller and callee could do the job. The undeclared type mixing is unlikely to "work" for the function arguments and cannot work for COMMON. – tim18 Nov 22 '18 at 10:29
  • @HighPerformanceMark Yes, that is exactly what I am doing, I am learning from some old code. – zyy Nov 22 '18 at 12:57
  • 1
    Old codes are NOT a good place to learn Fortran, unless you have a one-off task to modify some legacy thing and move on to a different language. – Vladimir F Героям слава Nov 24 '18 at 11:06

2 Answers2

4

As stated in the comments simply declaring the function in not only its own scope but also the scope that it is called will solve your problem. However I also want to discourage you from using common, implicit typing, and the completely non-standard real*8. As such here is a version of your program in a more modern dialect

ian@eris:~/work/stackoverflow$ cat power.f90
Program power_program
  Implicit None
  Integer, Parameter :: wp = Selected_real_kind( 14, 70 )
  Real( wp ) :: x, y
  x = 3.0_wp
  y = 3.0_wp
  ! Return type and kind of the function power in scope 
  ! due to the implicit interface
  Write( *, '( 3( a, 1x, f0.6, 1x ) )' ) &
       'x =', x, 'y = ', y, 'x**y = ', power( x, y )
Contains
  Pure Function power( x, y ) Result( r )
    Real( wp ) :: r
    Real( wp ), Intent( In ) :: x
    Real( wp ), Intent( In ) :: y
    r = x ** y
  End Function power
End Program power_program
ian@eris:~/work/stackoverflow$ gfortran -std=f2003 -Wall -Wextra -O power.f90
ian@eris:~/work/stackoverflow$ ./a.out
x = 3.000000 y =  3.000000 x**y =  27.000000
ian@eris:~/work/stackoverflow$ 
Ian Bush
  • 6,996
  • 1
  • 21
  • 27
4

When a procedure (function or subroutine) that you are trying to invoke in your code lays outside the body of your program and also is not part of any module, it's named an external function (or subroutine).

Fortran is a statically-typed language, so the types of all variables and functions must be known at compile-time. So, if you want to reference an external function in your program, there must be a way for the program to know its return type. You have 3 (bad) options for this, and I'll list them, starting from the worst:


  1. WORST: Rely on an implicit-typing rule that happens to match the return type of the external function with the type associated with its identifier in the caller (as you did in your sample).

Why you shouldn't do that? Because it is cancer. It makes the meaning of the code obscure, you can't know what this name reference to. It may even look just like an array variable in some circumstances, instead of a function. Also, the compiler doesn't check argument conformance in this case, so if you don't have specific compiler options turned on, the code will fail at runtime, or worse, will give wrong results. Moreover, implicit-typing is very very rarely useful these days, most of the time it's an ask for trouble. Always use implicit none!

As you noted, by the default rules of implicit-typing, any variable with a name starting with p will be default real type (in your compiler, it is real(4)). As you declared the function result as real*8, that your compiler interpret as real(8) (see final note), the error arises.


  1. BAD: Declare the function's name and type in the caller's specification area.

You'd do that just like you'd declare a variable, like this:

program main
implicit none
real*8 :: x, y, power

By the way, the attribute external may be applied to external procedures like yours. More than giving some properties to the procedure (can be passed as an actual argument, disambiguation from intrinsic procedures), it would make the origin of the identifier clearer.

program main
implicit none
real*8 :: x, y, power
external :: power

Why you shouldn't do that? There is no argument checking by the compiler either. This severely limits your options for communicating to external functions: the arguments cannot be assumed-shape, assumed-rank, polymorphic, parameterized, coarray, or be declared on the callee side as allocatable, optional, pointer, target, asynchronous, volatile or value; the return type cannot be an array, or pointer, or allocatable; the function cannot be passed as argument, be elemental and, if pure, can't be used in such contexts. And the reason for all this is the lack of an explicit interface.


  1. ACCEPTABLE: Specify an interface for your external function in the caller.

Like this:

program main
implicit none
interface
  real*8 function power(y)
    real*8 :: y
  end function
end interface

This way, the compiler is able to know all details of declaration and all the restrictions I mentioned won't apply. Total freedom and code clarity!

Why you shouldn't do that? Because there is a better way, that is using modules! Well, it's totally ok to do this in contexts were you can't go for modules, e.g. when working with already existent large old code. The downside is that, you have almost the same code in two different places, and they must always match.


Bonus: BETTER: Use modules.

program main
  use :: aux_module
  implicit none
  real*8 :: x, y
  common /yvalue/ y
  x = 3d0
  y = 3d0
  print *, power(x)
end

module aux_module
  implicit none
contains
  function power(x)
    real*8 :: power
    real*8 :: x, y
    common /yvalue/ y
    power = x ** y
  end
end

Why you should definitely do that? Because with modules, interfaces are automatically and implicitly available (less code duplication, no restrictions); modules can be recompiled separately and updated without breaking code. Also, you can declare shared variables in the scope of the module and avoid using common declarations. An even better version of your code would be:

program main
  use aux_module
  implicit none
  real*8 :: x
  x = 3d0
  y = 3d0
  print *, power(x)
end

module aux_module
  implicit none
    real*8 :: y
contains
  function power(x)
    real*8 :: power
    real*8 :: x
    power = x ** y
  end
end

There is even the option to include your functions directly into your program, after contains. This is recommended only if you don't plan to reuse this function in other program units. @IanBush's answer covers this case.

Final note: take a look on this answer to see why the syntax real*8 is non-standard and should be avoided.

Rodrigo Rodrigues
  • 7,545
  • 1
  • 24
  • 36
  • I had this weird problem of `no such file or directory` when compiling your code with `module`. The problem is solved after I move the module you defined up to the front of `main`. How could I make this module usable even if I define it after `main`? – zyy Nov 22 '18 at 15:26
  • 1
    you can have them in separate files and order them for compile, manually or through a makefile. Or, you can compile the modules separately and only link the module-objects when compiling the main program – Rodrigo Rodrigues Nov 23 '18 at 00:15
  • @zzy strictly speaking you can't. The module must be compiled first, before the main program. You can do that by moving it before the main or by compiling it first in a different file. – Vladimir F Героям слава Nov 24 '18 at 11:09