Is pointing to a target dummy argument safe after return?

I would say that is not a special combination at all, it is one of the typical use cases for pointer assignments. More specifically, you want to make a series of pointer assignments, but the logic is complicated to determine the upper and lower bounds and so on. So you isolate that logic within a subroutine rather than repeating it numerous times in the calling program.

This is what I said above. This is a typical use case for pointer assignments, it is not an unusual case at all.

As far as passing in a non pointer argument and having it associate with a pointer dummy argument, I know that is allowed, and I know it is a short cut for the intent(in), target combination. I still have not decided if I would ever declare arguments that way. It feels unnatural and obscure to me.

There is no “intent(in), target combination” that has any particular relevance per the standard semantics.

IMO, it is absolutely natrual, as it is a beautiful generalization of what you usually do when you associate a pointer with a target. This way, the association of the pointer with the target is done automatically by the compiler (and you can associate further poitners with the associated one…)

real, target :: array(5)
real, pointer :: array_ptr(:)

array_ptr => array   # Associates a pointer with a target

versus

real, target :: array(5)
real, pointer :: array_ptr(:)

call associate_ptr(array_ptr, array) 
   ! the call automatically associates a ptr with a target
[..]
subroutine associate_ptr(array_ptr, array)
  real, pointer, intent(out) :: array_ptr(:)
  real, pointer, intent(in) :: array(:)

 # note: array is already a ptr by automatic association
 array_ptr => array
end subroutine

I don’t see a big semantic difference between the two approaches. However, by using the pointer attribute, the call is robust and is warranted to yield a valid array_ptr after the subroutine finished (or you get a compile time error otherwise). If you use the target attribute for array in the subroutine instead, you/the subroutine must hope for the callers mercy, not to have forgotten the target attribute for the passed argument array, as otherwise array_ptr would be invalid (and currently no production compiler I know gives you any compile-time warnings/errors).

1 Like

Note the term pedantic mode; also what @certik with LFortran refer to “strict” mode.

Thinking even more pedantically or constraining oneself further with some strict rules when in comes to code design toward the kind of use cases that drive questions like in the original post here is a safer way to proceed.

An aspect of such strictness can be to

  • Avoid altogether a dummy argument with the POINTER attribute that is also not intent(in).

Basically it means to strive for code designs that do not require and make use of “getter” procedures of the type such as foo in the original post.

There are two ways that I disagree with this characterization. First, the usual way to associate a pointer with a target is something like:

real, target :: a(N,N)
real, pointer :: apt(:,:) 
...
apt => a

That is, you have the target, you have the pointer, and you assign directly from one to the other.

You are instead suggesting that the “natural” way is something like

temp => a
apt => temp

where the temp pointer acts as an intermediate. That does not seem natural to me.

The second observation is the way the dummy argument is declared. In what I consider the natural way, the declaration is

real, intent(in), target :: a(:,:)

This reflects correctly my intentions for that dummy argument, namely that is is not changed within the subroutine and that it is a target that can be used in a pointer assignment statement. If I were to make a program mistake, say a(1,1)=newvalue, the compiler would tell me, probably at compile time, and I would fix it immediately. Your suggestion

real, intent(in), pointer :: a(:,:)

says instead that the pointer characteristics cannot be modified, but the array itself (i.e. the target of the declared pointer) can be modified. Those characteristics are not faithful to my intentions. Indeed, if I were to make a mistake and type, a(1,1)=newvalue, the compiler would not tell me that I had done so, it would allow me to shoot myself in the foot and then spend time later trying to find the error.

All of that seems unnatural and like a gimmick to me. I don’t know if I would ever use the pointer declaration shortcut for those reasons. I am still inclined to make the correct declarations so that the compiler, and humans reading the code, can see my intentions clearly.

Well, that is not even cold comfort because the standard readily allows for the target to be redefined via an object with the pointer attribute that has that target.

As to all this being “unnatural” and a “gimmick”, well that has to do with development backgrounds. OP has not explained the use case for a dummy argument pointer with an intent other than in (like the parameter p in foo).

But with other comments on this thread (@aradi can correct as needed), I suspect the motivation is developing what is viewed by authors as more general purpose libraries with the use of OO methodologies where a “container” type holding some data that is consumed by users via some getter methods that return objects with pointers to parts or whole of said “data”.

As I commented upthread, my suggestion will be to avoid such getter methods i.e., avoid altogether a dummy argument with the POINTER attribute that is also not intent(in). With modern Fortran, as things stand, further thought is often required with alternate approaches in libraries that are safe, or at least less vulnerable for the library customers. Unfortunately there is no one approach that will serve all, YMMV will apply.

Yes, this is true, but it just demonstrates that the language does not protect me from shooting myself in the foot in every possible way. However, that is not a good argument for avoiding also the parts of the language that do successfully prevent me from making those mistakes.

The intent(in), target declaration prevents me from making certain mistakes, and it does so at compile time, which is the best time to detect errors. The intent(in), pointer declaration allows those mistakes, without warning, either at compile time or at run time.

@RonShepard That’s a very good essence, thanks. Funny enough, if I could formulate so concise, I would have written almost exactly the same summary for my line of arguments :smile:

The intent(in),pointer declaration prevents me from making certain mistakes, and it does so at compile time, which is the best time to detect errors. The intent(in), target declaration allows those mistakes, without warning, either at compile time or (often also) at run time.

Your approach prefers to avoid changing a value by mistake without the compiler warning you. On the other hand, you allow for the mistake of forgetting the target attribute for the passed argument (or of passing a vector subscripted array) and obtaining an invalid pointer as a consequence without a compile time warning (at least with current production compilers).

I prefer to avoid the mistake of obtaining an invalid pointer (which can cause indeterministic segfaults and other hard to debug symptoms), but concede the unintended change of a variable within a routine. I find latter easier to track down. Additionally, once you allow a pointer to point to an object, you basically give up the access control for this object anyway, as pointer-constantness does not exist in Fortran (yet).

So, at the end, this is a matter of taste choice with both approaches having some pros and cons, I guess.

I agree with all of this. It might be nice if the compilers were required to warn the programmer that such an error has occurred. I think in some cases, the compiler can see that an error has occurred, but there are also cases where the compiler cannot see the chain of pointer assignments or argument associations that result in the final error.

With the intent(in), target declaration, the compiler does have a lot of information to catch errors at compile time. If that argument is modified in a direct way, say on the left hand side of an assignment, then it is of course easy for the compiler to see the error. But also, there are many indirect ways that the compiler can catch errors. An example of this is when that argument is used as an actual argument that is associated with an intent(out) or intent(inout) dummy argument. As @FortranFan points out, you can trick the compiler into modifying that argument by modifying it in indirect ways, such as through pointer assignments. I consider that a fault of the fortran language itself, but it is one that is difficult to fix without also restricting legitimate uses of pointers. Pointers in fortran are dangerous in this way, just as they are in a practical sense in other languages. That is why I avoid them as much as possible (e.g. using allocatables instead).

In the other declaration case, intent(in), pointer, it is no longer a semantic error to modify that argument, so it is impossible for the compiler to catch any errors related to such a modification. But, as you point out, it is now possible to catch some errors related to copy-in argument association. I consider this also a shortcoming of the language itself. If there were a way to tell the compiler that neither the pointer nor its targets can be modified within a procedure, then the compiler could catch both types of errors at compile time, making the use of pointers a little safer.

I think this has been an interesting discussion.