2

I'm fairly new to Fortran, and while going through some documentation it seems like both subroutines and functions can use the 3 types of parameter intent:

  • intent (in)
  • intent (out)
  • intent (inout)

But when trying to implement intent (inout) in a function something similar to the snippet shown below

function cell_blocked(row,col,ncb) result (ncb)
integer, intent(in) :: row,col
integer, intent(inout):: ncb

  if (row == col) then
    ncb = ncb + 1
  end if

end function cell_blocked

I get the following compiler error:

Symbol 'cell_blocked' at (1) has no IMPLICIT type

ncb is a counter that I would like to pass into the function and update given a condition and return the value.

If I try this with a subroutine I don't get any compiler errors, so I'm confused why the error while using a function

francescalus
  • 30,576
  • 16
  • 61
  • 96
coder
  • 53
  • 3
  • You have a couple of errors here: you cannot have a result `ncb` the same name if one if the arguments (the other `ncb`). When you remove the `result(ncb)` or give it another name, you must also declare the type of that result. – francescalus Jun 09 '22 at 18:22
  • Equally, you have a conceptual error about what functions do: you can have an `intent(inout)` argument (but you'll easily get into arguments about that), but you certainly need the function itself to return something explicitly a "result". You don't here (and arguably you should stick to using a subroutine). – francescalus Jun 09 '22 at 18:25
  • Hi @francescalus thanks for the help, could you elaborate a bit more, maybe Im not understanding correctly what intent(inout) is for. As I understand intent(inout) is exactly to have the same variable as argument and as result, so that it preserves the value coming in, but returns a new value. that is why I have the same name for argument and result. Regarding the second comment, isn't ncb my explicit "result", I have result(ncb) and in the body I assign it a new value to return – coder Jun 09 '22 at 18:40
  • I have added another question which hopefully clarifies what the "result" of a function means. However, to be slightly more specific: imagine a function `f` used like `y=f(x)`. Much like "cos(0)" has a result 1 this `f` has a particular result, independent of whatever changes are made to the argument `x`. Using` result` just means that the function result can be called something other than `f` when defining the function. – francescalus Jun 09 '22 at 18:52
  • I tried going through the links you added, but I'm still confused, I think its more a conceptual problem I have, rather than the specific compiler error. I understand we can either specify a "result" or just use the funciton name. In short I'd like my function to take in a counter (ncb) and return the same counter(ncb), which is why I thouth intent(inout) applies. Also I added 'result' and declared the variable type as an integer in the 3rd line of the function so I dont understand why it has no IMPLICIT type – coder Jun 09 '22 at 19:15
  • Maybe my issue is in understanding why you say my function doesn't have a particular result My understanding is that it does have a particular result, which is ncb regardles So it would return ncb if condition is not meet, and if condition is meet it returns ncb + 1 Is this not how Fortran is actually interpreting my function? – coder Jun 09 '22 at 19:19

1 Answers1

4

You are quite correct that each of the three intents (or using no intent) can be specified for any dummy argument of a function, just as they can for a subroutine.

However, the dummy arguments for a function are still quite distinct from the function result. The result(ncb) clause here is not saying "the argument ncb is the result of my function". Instead result(ncb) says "the result of the function is called ncb instead of cell_blocked".

You cannot give the function result the same name as one of the function's arguments. (You get an (unhelpful) compiler error saying that cell_blocked is not given an implicit type because the result clause is invalid, so the compiler is ignoring it and considering the function result to be called cell_blocked. A more helpful error message would include the fact that the result clause is itself invalid.)

The function result is a completely separate thing from any of the dummy arguments, and having a function result is what distinguishes a function from a subroutine. You may (whether it's advisable or not) change a dummy argument (intent(inout), intent(out) or no intent) independently of how you specify the result of the function.

Given the function

function f(a, b, c, d)
  integer, intent(in) :: a
  integer, intent(out) :: b
  integer, intent(inout) :: c
  integer :: d
  integer :: f  ! Function result unless there's a result clause
  ...
  f = ...
end function f

the function result is f and the function result is used in the expression in the right-hand side of the assignment

y = f(a, b, c, d)

The value of the function result is whatever was assigned to f by the end of the function's evaluation. Not one of the dummy arguments, however modified, is a "result".

In the function of the question (which is perhaps better left as a subroutine) we are failing to give the function's result a value. If we want the function's value to be either ncb or an incremented version of that we don't use an intent(inout) dummy to do that:

function cell_blocked(row,col,ncb)
integer, intent(in) :: row,col, ncb
integer :: cell_blocked

! One of many ways writing this logic
  if (row == col) then
    cell_blocked = ncb + 1
  else
    cell_blocked = ncb
  end if

end function cell_blocked

You may then write something like

ncb = cell_blocked(row, col, ncb)

but one then wonders whether a subroutine is what was wanted all along.

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • This was very helpfull! I think this specificlly I wasnt understanding "The result(ncb) clause here is not saying "the argument ncb is the result of my function". But with the further details I see now what you mean thanks a lot! – coder Jun 09 '22 at 20:03
  • In regards to the last remark, in Fortran one doesn't usually write something like this '''ncb = cell_blocked(row, col, ncb)'''? Or this cases where one needs to update a value are meant more for subroutines? – coder Jun 09 '22 at 20:09
  • It can make sense to write that, but if you're always going to update that third argument a subroutine would be more natural. A subroutine encodes the intention behind the code, where a function can be used much more generally such as in `ppp=cell_blocked(row, col, ncb)` or `print *, 154+cell_blocked(row, col, ncb)`. – francescalus Jun 09 '22 at 20:15