Why are there multiple ways of defining functions?

I’ve always found it weird that you can define the same function in different ways. Is there a specific reason for this?

function f(x)
    real :: x
    real :: f
    f = 2*x
end function f

function f2(x) result(y)
    real :: x
    real :: y
    y = 2*x
end function

real(8) function f3(x)
    real :: x
    f3 = 2*x
end function f3
2 Likes

I always thought of these as three different ways to declare a function result. The second form allows defining the result with a shorter name. The third form allows declaring the type of the result on the function statement. I use the forms 2+3 combined when possible.

For three truly different ways to define a function, check out JavaScript.

You’ve missed the fourth variant:

real function f4(x) result(y)
    real :: x
    y = 2*x
end function f4
2 Likes

The 2nd form has been introduced in the F90 standard (I think), and can be convenient in case of a long function name. Also, it allows to change the function name if needed, without having to change anything in the source code of the function. This is an optional feature that you are free to use or not.

Between the 1st and 3rd form I’m not sure, but I suspect that they also correspond to different revisions of the standard. But for backward compatibility reasons, the older one has been kept.

I generally stick to forms 1 and 2 because it leaves everything consistent given that forms 3 and 4 are not feasible in some cases. I.e.

function foo(x) result(y)
  real, intent(in) :: x
  real, allocatable :: y(:)
  ...
end function

cannot be written as

real, allocatable, dimension(:) function foo(x) result(y)
  real, intent(in) :: x
end function
2 Likes

Language evolution!

The second way you show is what I prefer and recommend.

1 Like

OP and others can also wonder there are a few other possibilities given the certain same-named statement and attribute options:

real function foo(x)
   real, intent(in) :: x
   allocatable :: foo
   dimension :: foo(:)
  ..
end function

and

real function foo(x) result(y)
   real, intent(in) :: x
   allocatable :: y
   dimension :: y(:)
   ..
end function

Fortran is “funny that way”!

The reason for the result clause was to allow recursion. Within the body, the direct recursive references to f() are different from the result being computed y. However, as others have mentioned the result clause also can be used for other reasons.

In fortran, it has been possible to declare the result either on the function statement or along with the other variables going back to f66. In this case, it is mostly a matter of taste. Sometimes you want the declarations after the implicit statement, to stress that the return type is consistent with the other arguments, sometimes you want it on the function declaration line to make it look special, perhaps even distinct from the argument types. In modern fortran, there are other reasons for choosing where to declare the return type, such as when the function result depends on the type, kind, rank, size, etc. of one or more of the arguments or of some global variable.

My preference is type “3” where the function type/kind is clearly described at the front of the function definition.

My recall from pre F77 days is that the function value should be the last statement execued before return. Is this still the case, or was it a (cdc or prime) manufacturer requirement for setting registers ?