The following code does not compile, which implies it is likely not standard conforming. But I wonder why such an association would not be allowed. Are there any issues or problems with a dynamic association like the following example?
program hello type :: try_type integer :: n end type try_type type(try_type) :: try(10) integer :: i associate(n => try(i)%n) do i = 1, 10 n = i end do end associate do i = 1, 10 write(*,*) try(i)%n end do end program Hello
Also, in general, should one expect a lower performance due to association than simply defining a new variable (and updating the values assignments where necessary)?
Note the standard allows the following:
program hello type :: try_type integer :: n end type try_type type(try_type) :: try(10) integer :: i do i = 1, 10 associate(n => try(i)%n) n = i end associate end do do i = 1, 10 write(*,*) try(i)%n end do end program Hello
The standard or a reference text such as Modern Fortran Explained can point you to the rules involving object definition that make the code in the original post non-conformant.
As to performance, as with many cases, it "depends"! On the code constructs as well as the compiler implementation. There are situations involving data copy of large arrays where ASSOCIATE can really help with an optimizing compiler.
An associate construct associates a name for use in the following block of source code, with a particular thing, where that thing is a variable or value. That association is established at the time the associate statement is executed, and it does not change during execution of the rest of the construct.
(In the example code, the designator that ... well, designates ... the thing that the name `n` is to be associated with requires the value of the variable i. i is undefined, so you cannot sensibly work out what is being designated by the designator. This is definitely non-conforming, but I'd expect it to result in a runtime issue, rather than compile time.)
There's perhaps the expectation in the example code that the associate statement defines a piece of source that can then be substituted in place for the associate name inside the block, and that substituted source is then evaluated in the context of its appearance (like a text substitution macro). That's not how it works, and that would be inconsistent with the behaviour of designators in other aspects of the language. If you have a procedure defined and invoked as per the following:
subroutine s(n) integer :: n real :: array(n) ... n = 10 ... end subroutine s ... call s(5)
the size of `array` is specified when the procedure is invoked by the value passed for `n`, it does not change later on during the execution of the procedure when the value of `n` is redefined.
FWIW I am assuming the your were assuming that the ASSOCIATE was behaving like a statement function. Though in your case it wouldn't be feasible to use a statement function as you would need it to return a reference .and. syntactically be placed on the lhs.
Whereas ASSOCIATE behaves like a reference that is evaluated at the point of the ASSOCIATE. Think of it as creating a new DUMMY variable (as if it were an argument on a CALL, but using the internal state of the variables procedure).
"reference that is evaluated at the point of the ASSOCIATE", that's the key point. Still, I think it would be good if the associate construct had an additional optional argument like MACRO = .TRUE. that would enforce a macro substitution instead of creating a pointer to the selector.
Macro expansion is handled by FPP (Fortran PreProcessor).
Add the -fpp switch, then you can use #include "yourPreProcessorInclude"
#include "foo" ! available with -fpp
INCLUDE "foo" !~ standard Fortran
INCLUDE lives for the duration of the current scope
Any macros defined within there live past the current scope.
So... be careful, or you will get what you ask for (possibly where you don't want expansions).
I've used fpp quite effectively to aid in the migration of code and to introduce instrumentation.
For instance, fpp macros are case sensitive, Fortran is case insensitive.
#define Continue CALL TakeSnapShot()
! Fortran code
Continue ! noop w/o fpp, snapshot w fpp
#define FOO TraceFOO
! Fortran code
Note, in the above case, without editing the source code, the (selected) subroutine calls are redirected. In this example to a tracing/logging subroutine, in other cases to a different "new and improved" method.
I understand that ASSOCIATE is not a MACRO expansion. However, in many instances, I suspect a MACRO expansion would suffice. Is ifort currently smart enough to realize this and avoid creating a pointer? The performance hit is likely not noticeable in many use cases, but likely not always. and in those rare cases, the user is left to choose between ugly code and a potential performance hit. If this is hard for the compiler to predict from the code, perhaps adding an optional argument to ASSOCIATE to aid the compiler (to simply do a MACRO expansion) could resolve the problem. Is this a viable proposal to present to the committee? The necessity and significance of such an optional argument for ASSOCIATE are, in my opinion, perhaps comparable to the optional CONTIGUOUS attribute for assumed-shape dummy arguments.
The committee has expressly disdained macros. The standard did have an optional preprocessor, but it was widely ignored and removed from the standard.
ASSOCIATE effectively creates a new variable, with some, but not all, of the properties of the selector. Others in this thread have given you some alternatives. As for performance, I would not expect a noticeable difference in most cases.
>>Is ifort currently smart enough to realize this and avoid creating a pointer?
Excepting for scalar value arguments and module/common statically allocated arrays, pointers (aka references) are always used.
The compiler(s) today is(are) quite good at common sub-expression elimination, lifting loop invariant code, etc... that the use of ASSOCIATE is not necessarily of a performance preference, but rather of increasing code reading clarity and/or elimination of typographical errors.
This said, I have experience that "increasing code reading clarity" also enabled the compiler to generate more optimal code. This is not that the associated reference is inherently more optimal, but rather it reduces the complexity to the compiler optimization with respect to tracking common sub-expressions and their elimination/reduction.