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

Access to PROTECTED variable outside original module using dedicated subroutines

Windyman
Beginner
512 Views

Hello,

On my Windows 7 64 bit PC I am using Intel(R) Visual Fortran Composer XE 2011 Integration for Microsoft Visual Studio* 2008, 12.0.3470.2008.

I have a large piece of inherited code that uses different modules containing objects with the PROTECTED attribute. For read and write access to these objects outside the module that it is defined in, get and set routines have been defined in the relevant module. INTERFACE statements have been defined to access these routines from outside these modules. Attached is an example of this set-up in a simple project.

Recently I have upgraded to Intel® Parallel Studio XE 2016 Update 1 Composer Edition for Fortran Windows* Integration for Microsoft Visual Studio* 2013, Version 16.0.0058.12. The compiler now throws an error compiling the same project:

Error 1 error #7993: A use associated object that has the PROTECTED attribute shall not appear as an actual argument if the associated dummy argument has the INTENT(OUT) or INTENT(INOUT) attribute. [MYDATA] .\test\main.f90 15

So it appears that for the new compiler I am not anymore able to modify the object from outside the module that it is defined in, even not through dedicated functions. Since this construction is used throughout this large piece of code, I was hoping that somebody has a bright idea towards resolving this issue? A simple way out is off course removing the PROTECTED attribute, but maybe there is a more neat way of doing this?

Best regards,

Koen

0 Kudos
4 Replies
mecej4
Honored Contributor III
512 Views

I think that your example code is a good illustration of situations in which unspecified intent is not the same as INTENT(IN OUT). Try compiling after removing the INTENT clause in line-36 of module.f90.

0 Kudos
Steven_L_Intel1
Employee
512 Views

The newer compiler is properly enforcing the rules of the standard.  The standard says:

C551 A nonpointer object that has the PROTECTED attribute and is accessed by use association shall not appear in a variable definition context (16.6.7) or as the data-target or proc-target in a pointer-assignment-stmt.

16.6.7 (Variable definition context) says:

The following are the contexts in which the variable implies such definition or undefinition of the variable:
...
(12) an actual argument in a reference to a procedure with an explicit interface if the corresponding dummy argument has INTENT(OUT) or INTENT(INOUT).

Your code's use of the "set procedures" is incorrect - you're not supposed (nor allowed) to pass in the use-associated protected variable to the procedure that will set it. The way you're supposed to do this is have a "Set_MyData" routine that references the variable locally (through host association), not pass it in as an argument.

While mecej4 is correct that removing INTENT will allow the code to compile, it is just "papering over" the design error, in my view.

 

0 Kudos
FortranFan
Honored Contributor II
512 Views

@Koen,

To me, this falls into one of those object-oriented, information-hiding related design issues.  There is a lot of literature on good design involving such concepts with various languages (not just Fortran) and if you may want to study them to get a better grip on the reasoning and rationale behind those concepts.  You may want to ask yourself why the PROTECTED module variable of MyData need be present as actual argument at all; does it not appear superfluous in your main program?  Also, if the setter/getter methods are intended to be used really in conjunction with a PROTECTED module variable, then why would they need a dummy argument of DataType at all?  If you look at your module_test design in line per concepts put forth in computer science literature for OO paradigm, you may find several improved design options  that are supported by standard Fortran.  The idiom, "many ways to skin a cat", is apt for what you're trying to do:

module m

   use, intrinsic :: iso_c_binding

   implicit none

   private

   type, public :: dt_t
      private
      real :: factor
   contains
      private
      procedure, pass(this), public :: set => set_factor_dt_t
   end type dt_t

   type(dt_t), protected, public :: MyData

   enum, bind(c)
      enumerator :: FACTOR = 1
      !.. other options elided
   end enum

   public :: FACTOR

contains

   subroutine set_factor_dt_t(this, InpKey, ValFactor)

      class(dt_t), intent(inout) :: this
      integer(kind=kind(factor)) :: InpKey
      real, intent(in)           :: ValFactor

      select case (InpKey)
         case ( FACTOR )
            this%factor = ValFactor
      end select
      !
   end subroutine set_factor_dt_t

end module m
program p

   use m, only : MyData, FACTOR

   implicit none

   real :: answer

   answer = 1.0

   call MyData%set(FACTOR, answer)

   stop

end program p

 

0 Kudos
Windyman
Beginner
512 Views

Thank you all for your replies, sorry for my late response as I have not found time yet to look at this issue. Anyhow I will do this in the coming months using your suggestions.

 

0 Kudos
Reply