Questions about statement functions

Fast question. I just got to read a code where a function was defined as in the following example:

program fexps
  implicit none
  real :: fexp, x
  fexp(x) = exp(x+1)
  print'(":: exp(x)  = ",g0)', exp(3.0)
  print'(":: fexp(x) = ",g0)', fexp(2.0)
end program fexps

I just got a bit shock because, as far as I can remember, is the first time I see this and I think I haven’t read this in any book I’ve read on Fortran. I would always go to define the function as function fexp ....

  1. Can anyone explain what is happening here behind the scenes (pointer associations, etc.)?
  2. Would that work with other user-defined function?
  3. How much would you recommend to use this approach, or would you encourage people to avoid it and why?
1 Like

It took me a bit of time to realise that you are not dealing with a brandnew and undocumented feature here, but with an old feature that has been known to cause trouble: statement functions. Internal functions are the newer and safer and much more capable replacements. Basically, such a statement function consists of a single statement like the one you showed. It could also be:

fexp(x,delta) = exp(x + delta)

(or any variation on that theme)

1 Like

Great! Thanks a lot @Arjen. Forgot to mention that I’ve partially read the books… Now I see in my reference book (Moder Fortran Explained, Metcalf, Reid, Cohen) in section B.1.5 that it appears as an obsolescent feature in the Fortran 95 standard.

So do we agree that it’s something to be avoided?

1 Like

Well, I definitely agree. It is rather compact, that is the attractive bit, but it has caused confusion in the past to both human beings and compilers. You would be far better off with a proper internal function. Or something defined in a separate module :wink: .

2 Likes

I agree. I really prefer and like to define a local functions within the scoping unit after the contains statement. But yeah, quite attractive because of its simplicity.

1 Like

In the F77 era, when there were no smartphones and, incidentally, no internal or module functions, the statement functions were quite useful. Containing just a single expression as their definition, could be treated as an obvious hint to the compiler to inline them in the code. Probably could have been still such a hint, if not made obsolescent.

1 Like

Statement functions have been obsolescent in the standard for some time now. Enabling standards conformance diagnostics would pick that up.

2 Likes

I was just pondering if statement functions could be resurrected in some other form like this:

module test
    use iso_fortran_env, only: wp => real64 
    implicit none
    contains 
    real(wp), function :: fexp(real(wp),intent(in) :: x, real(wp),intent(in) :: delta) = exp(x + delta)
    !...etc...
end module test

I see the advantage of having a way to define simple functions with one-liners. Just an idea.

1 Like

A CONTAIN’ed function should work as well as statement functions, with the ability to better define the argument list.

Defining the arguments that appear in an existing statement function can be confusing. I now prefer contained functions for their clarity of variable definition.

The more confusing (annoying?) issue with both is the scope of the defined function and also the scope of variables referenced in either function type.

Many years ago, I did like statement functions as I thought they had a more efficient argument list implementation, but these impressions are hard to justify.

1 Like

This was the topic of a separate recent discussion. It is not always possible to replace a statement function with an internal procedure because the nesting levels of internal procedures is limited by the standard. Specifically, a program, a module procedure, or an external procedure can have internal procedures, but internal procedures themselves cannot have internal procedures. However, Internal procedures can have statement functions, so sometimes that is the only choice for that kind of self-contained functionality. Internal functions have many advantages over statement functions, but their use, in particular as a replacement for a statement function, is artificially limited by the standard.

@RonShepard , in that “separate recent discussion” you failed to prove this: you were the one who made the questionable claim, “It is not always possible to replace a statement function with an internal procedure,” but you couldn’t furnish an example supporting that claim and then deflected the discussion to another situation but which too was questionable.

You should read through that discussion again, I certainly did provide an example. I even included the compiler error reports when the internal procedure nesting was too deep.

As for the claim in general, read my post above where I explain how an internal procedure cannot itself have internal procedures due to the current language restrictions. That is a statement of fact, not opinion.

For the more general question about whether eliminating that restriction in the language would be a good idea, I think it is worth discussing. I suggest that the discussion be continued there rather than here however. Otherwise, the useful information posted there would need to be repeated here.

Here’s that thread.

You did not provide any example that supports your claim, “It is not always possible to replace a statement function with an internal procedure because of the nesting levels of internal procedures is limited by the standard.”

Such an example would be along the following lines: 1) here’s a standard-conforming code which makes use of statement functions, and 2) any reasonable attempt to refactor the code in 1) to (an) internal procedure(s) is not viable because the Fortran standard does not allow an internal procedure to host another internal procedure.

@RonShepard - seriously, pay attention to this - you didn’t even remotely come close to showing such an example involving any issues with the refactoring of statement functions. That you feel it will be valuable for the language to consider permitting internal procedures to host internal procedures is ok, please propose it as such some place, preferably at the J3 Fortran GitHub site.

But the fact is the semantics around statement functions in the standard is limited and its semantics hardly suggests any nesting as supported by the standard. So then your attempt to make an use case out of statement functions for nesting of internal procedures isn’t likely going to get you far. Try to read between the lines in this paper. Unless you can find a strong sponsor who can drive even weak proposals through, almost all the proposals with Fortran are DOA. Thus you need extremely strong and convincing use cases with proposals, but here with the proposal on the nesting of internal procedures, I don’t even see you make an attempt at a strong case.

As a matter of fact, that is exactly what I demonstrated. As for your weasel words “reasonable attempt”, I would say that there are indeed many workarounds for this limitation of the standard. We’ve all been using them for 30 years, and this was clearly stated in my previous posts. But these are workarounds, and it is only a matter of opinion whether or not these are “reasonable attempts” at refactoring the codes in order to overcome the limitation in the current fortran standard.

As a matter of fact, I demonstrated the internal procedure nesting limit, including compiler error messages. As a matter of opinion, you claim that there are workarounds for this limitation that are reasonable attempts at refactoring the codes. I presented facts, you presented opinions. I think we can just agree to disagree on this matter at this point.

No, all you showed was a case like this:

   .
   real, parameter :: a = 1.0, b = 2.0, c = 3.0
   real :: f
   f(x) = ((a * x + b) * x) + c
   .

Such a statement function does not require nested internal procedures.

But then you “manufactured” a rather specific use case with an argument, “Then you realize that sub() is only used in that one program, so it is better off being an internal procedure than an external or a module procedure, so you refactor it as … But now when you compile, the first error you see is …”.

That your use case then becomes a situation where something “… is only used in that one program, so it is better off being an internal procedure than an external or a module procedure” is so marginal to be of little to no relevance.

But again, if you think otherwise, please do propose the feature and see how far you can go with it, perhaps you will succeed in pushing it through particularly given my comments here and in that thread, you may convince the standard-bearers to drop their instinct and go with the “the opposite theory”!!

And that case demonstrated the point exactly. It is a situation where if you try to change the statement function into an internal procedure, it produces an error at compile time. That compile error is correct because the current language limits do not allow an internal procedure to be nested within an internal procedure.

As I said above, it is probably best for us to simply agree to disagree. I think every reader of this thread sees what is the point, despite your mischaracterizations of both my posted code and of my intent to clearly demonstrate the feature with a small example.

This has nothing to do with an insensible “agreeing to disagree” and especially not with me, I’m here now probably"cancelled" any next moment!

The point is about putting together good use cases for Fortran proposals. A massive issue with Fortran is inadequate effort on use cases because of which half-baked or nonsensical stuff like two (!) enumeration type facilities - both poor - get added by voting members of J3 Fortran committee whereas many other suggestions, some of which might really help practitioners, are treated as dead-on-arrival by the same committee.

The notion that a use case is one’s “preference” to contain an internal procedure in a main program rather than it be a module procedure and further that this procedure needs to contain another procedure instead of consuming another internal procedure of the same host and therefore the language standard should be changed to allow nesting of internal procedures is so feeble it’ll.be humorous to see this proposed as such and considered by the bearers, after all some of them have even included a subsection in their books with trivial conveniences in their title, thus there is precedence!!

Or work harder for more better use cases.