Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Fortran associate construct

DataScientist
Valued Contributor I
3,379 Views

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)?

 

 

0 Kudos
12 Replies
FortranFan
Honored Contributor III
3,360 Views

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.

IanH
Honored Contributor III
3,354 Views

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.

DataScientist
Valued Contributor I
3,350 Views

thanks @FortranFan , @IanH .

You are right, this is a runtime segfault rather than a compiler error.

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,272 Views

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).

Jim Dempsey

DataScientist
Valued Contributor I
3,258 Views

"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.

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,247 Views

Macro expansion is handled by FPP (Fortran PreProcessor).

Add the -fpp switch, then you can use #include "yourPreProcessorInclude"

*** note

#include "foo" ! available with -fpp
INCLUDE "foo" !~ standard Fortran

behave differently

INCLUDE lives for the duration of the current scope

#include "..."

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).

Jim Dempsey

Steve_Lionel
Honored Contributor III
3,236 Views

Indeed, ASSOCIATE is NOT a macro! Jim explained it correctly.

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,217 Views

FWIW

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

 

Or

#define FOO TraceFOO

...

! Fortran code
CALL FOO(A,B,C)

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.

Jim Dempsey

0 Kudos
DataScientist
Valued Contributor I
3,034 Views

Thank you @jimdempseyatthecove , @Steve_Lionel 

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.

 

0 Kudos
Steve_Lionel
Honored Contributor III
3,030 Views

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.

0 Kudos
DataScientist
Valued Contributor I
2,986 Views

macros are indeed like sins the majority abhor, yet a majority also commit out of sight.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,849 Views

>>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.

Jim Dempsey

0 Kudos
Reply