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