My IDE is Visual Studio 2010 with integrated Intel Fortran compiler. The version of compiler is: Intel Parallel Studio XE 2011.
I am not experienced programer in Fortran so I need a little help about using optional argument in public procedure from derived type. This is my example code:
MODULE DERIVED_TYPE
TYPE , PUBLIC :: SOME_TYPE
INTEGER , PRIVATE :: V_INT
CONTAINS
PROCEDURE , PUBLIC :: CALL_V_INT => CALL_DATA_V_INT
PROCEDURE , PUBLIC :: TAKE_V_INT => TAKE_DATA_V_INT
END TYPE SOME_TYPE
PRIVATE :: CALL_DATA_V_INT
PRIVATE :: TAKE_DATA_V_INT
CONTAINS
! PUBLIC PROCEDURES
SUBROUTINE CALL_DATA_V_INT( THIS , IA , IB , IC )
CLASS( SOME_TYPE ) :: THIS
INTEGER , INTENT( IN ) :: IA , IC
INTEGER , INTENT( IN ) , OPTIONAL :: IB
IF( .NOT. PRESENT( IB ) ) THEN
THIS%V_INT = IA + IC
ELSE
THIS%V_INT = IA + IB + IC
END IF
END SUBROUTINE CALL_DATA_V_INT
FUNCTION TAKE_DATA_V_INT ( THIS ) RESULT( RES )
CLASS( SOME_TYPE ) :: THIS
INTEGER :: RES
RES = THIS%V_INT
END FUNCTION TAKE_DATA_V_INT
END MODULE DERIVED_TYPE
PROGRAM OPTIONAL_ARG
USE , NON_INTRINSIC :: DERIVED_TYPE
IMPLICIT NONE
INTEGER :: I
INTEGER , PARAMETER :: N = 3
CLASS( SOME_TYPE ) , POINTER :: P_SOME_TYPE
TYPE( SOME_TYPE ) , DIMENSION( N ) , TARGET :: ARR_V_INT
DO I = 1 , N
P_SOME_TYPE => ARR_V_INT( I )
CALL P_SOME_TYPE%CALL_V_INT( I , 5 )
WRITE( * , * ) P_SOME_TYPE%TAKE_V_INT()
END DO
END PROGRAM OPTIONAL_ARG
At the end of compiling proces i got this kind of message in build window:
Missing actual argument for argument 'ic'
What is wrong with this example?
I also try to move optional argument to latest position in argument list and in that case there is no error message.
Can I get detail explanation for optional argument position in argument list?
You should normally try to put optional arguments at the end of the argument list. What happens when you do call such as
subroutine sub (a, b, c)
real :: a, c
real, optional :: b
...
call sub(1.,2.)
is that the compiler must assume that the 1. is for a and the 2. is for b. Then the argument for c is missing.
Instead one can use named arguments after the missing optional one
call sub(1, c=2.)
So in your case you could do
CALL P_SOME_TYPE%CALL_V_INT( I , IC = 5 )
if you don't want to have the optional IB at the end of the argument list.
Related
I have a module which defines a Type, with its methods, plus some other Type-unrelated methods as well.
module TypeDef
type, public :: T
...
contains
...
procedure type_proc
end type
...
contains !module
subroutine type_proc( this, ... )
class(T), target :: this
...
call gen_proc( arg_1, arg_n-1, this, arg_n+1 )
...
end subroutine type_proc
...
subroutine gen_proc( arg_1, ..., arg_n-1, tv, arg_n+1 )
! this is a general module routine.
! NOT type related
implicit none
...
class(T), pointer, intent(in) :: tv
...
if ( cond ) tv%member = 0
...
end subroutine gen_proc
end module
At a given point, I call, from a variable type(T), public :: var its member method type_proc(), which at its interior calls a general module procedure gen_proc(). In there, for some conditions, I may need to change some member(s) of the ACTUAL object calling the method's tree (i.e. var). To do so, I pass this as a constant pointer to call gen_proc() to have its address passed at the function call, and access its members.
But, I get the error as described.
Same if I pass it by reference and not as a const pointer.
I cannot see if I do something mistakenly. Here Intel Fortran error #6633: The type of the actual argument differs from the type of the dummy argument there's something similar, but there, the call happens in a different program unit.
EDIT 2:
Ok, this compiled and run as expected..
module test
type, public :: T
real, allocatable :: m1(:)
real, allocatable :: m2(:)
integer :: may_change
contains
procedure :: t_proc
procedure :: all_t
end type
private :: all_t
contains
subroutine t_proc( this, n )
implicit none
class(T), target :: this
integer, intent(in) :: n
call this%all_t( n )
call gen_proc( n, this%m1, this%m2, this )
end subroutine t_proc
subroutine all_t( this, n )
implicit none
class(T) :: this
integer, intent(in) :: n
allocate( this%m1( n ) )
allocate( this%m2( n ) )
end subroutine
subroutine gen_proc( n, m1, m2, Tt )
implicit none
integer, intent(in) :: n
real, intent(in) :: m1(n), m2(n)
class(T), intent(in), pointer :: Tt
if ( .true. ) Tt%may_change = 1
print *, ' may change = ', Tt%may_change
end subroutine gen_proc
end module test
module varmod
use test
type(T), public :: var
end module varmod
program main
use varmod, only: var
implicit none
integer, parameter :: n = 2
var%may_change = 0
call var%t_proc( n )
end program main
So, even more than before, I don't know what could be wrong on the actual code...
I was using operator overloading for a vector class
interface operator(+)
module procedure :: vec_add_sv !< scalar + vector
module procedure :: vec_add_vs !< vector + scalar
module procedure :: vec_add_vv !< vector + vector
end interface operator(+)
:
:
function vec_add_sv( s, v1 ) result( v2 )
type(Vector) :: v2
real(dp), intent(in) :: s
type(Vector), intent(in) :: v1
integer :: i, n
n = v1%size()
call v2%resize(n)
do i=1,n
V2%q(i) = s + V1%q(i)
end do
end function vec_add_sv
:
:
v2 = s + v1
works just fine. However when I implemented:
interface assignment(=)
module procedure vector_assign
end interface assignment(=)
and put write statements in both the function vec_add_sv and the subroutine vector_assign I noticed that when I used
vec2 = scalar + vector
it called both the vec_add_sv function and the vector_assign subroutine. This indicates that the vec_add_sv function created a temporary vector for its return and then passed that temporary to the vector_assign subroutine. The result is that I am looping through my vector elements twice.
Is there a way to implement binary operators with out creating temporary storage?
I recognize that a temporary is needed if you do something like A = B + ( C * D ) then (C * D) crates a temporary that is used in B + temp.
But if I am just doing a single operation A = B + C
I would like something equivalent to
interface add
subroutine vec_add( A, B, C )
type(vector), intent(out) :: A
type(vector), intent(in) :: B
type(vector), intent(in) :: C
end subroutine vec_add
end interface add
interface operator(+) requires the module procedure to be a function not a subroutine
I have a Vector derived type
Type :: Vector
Real (Real32), Allocatable :: r32(:)
Real (Real64), Allocatable :: r64(:)
Real (Real128), Allocatable :: r128(:)
Contains
Procedure :: set => vector_set, &
vector_tutvc, &
vector_vctvc
If I call the subroutine as in (a) I get everything working
correctly, however when using (b) I am getting
Error: Rank mismatch in argument 'u' at (1) (scalar and rank-1)
(a) Call vcr % vector_tutvc (r)
(b) Call vcr % set (r)
Here are more details
Subroutine vector_set (t, u, v, w)
Class (Vector), Intent(InOut) :: t
Class (*), Intent (In) :: u
Class (*), Intent (In), Optional :: v, w
Subroutine vector_tutvc (u, tu)
Class (Vector), Intent(InOut) :: u
Class (*), Intent (In) :: tu(:)
Here is code for test program
Type (Vector) :: vcr
Real (Real32), Allocatable :: r(:)
r = [ &
1.0000000, 0.9999965, 0.9999931, 0.9999896, 0.9999862, &
0.9999829, 0.9999796, 0.9999763, 0.9999731, 0.9999699, &
0.9999668, 0.9999637, 0.9999607 &
]
Call vcr % set (r)
In the type-bound procedure declaration
procedure :: binding => procedure
the type-bound procedure procedure has the binding name binding.
From your mention of overloading and your choice of indentation, it seems like you expect the statement
Procedure :: set => vector_set, &
vector_tutvc, &
vector_vctvc
to be such that the binding name set is generic, referring to each of those procedures. In fact, the statement above is the same as
Procedure :: set => vector_set, &
vector_tutvc => vector_tutvc, &
vector_vctvc => vector_vctvc
To establish overloading, you need to use a generic binding, such as
Procedure :: vector_set, vector_tutvc,vector_vctvc
Generic :: set => vector_set, vector_tutvc, vector_vctvc
module type_Vector
use, intrinsic :: iso_fortran_env, only: &
sp => REAL32, &
dp => REAL64, &
qp => REAL128
! Explicit typing only
implicit none
! Everything is private unless stated otherwise
private
public :: Vector
! Declare derived data type
type, public :: Vector
real (sp), allocatable :: r32(:)
real (dp), allocatable :: r64(:)
real (qp), allocatable :: r128(:)
contains
procedure, private :: vector_set
procedure, private :: vector_tutvc
generic, public :: set => &
vector_set, &
vector_tutvc
end type Vector
contains
subroutine vector_set(this, u, v, w)
class (Vector), intent(in out) :: this
class (*), intent (in) :: u
class (*), optional, intent (in) :: v
class (*), optional, intent (in) :: w
end subroutine vector_set
subroutine vector_tutvc(this, tu)
class (Vector), intent (in out) :: this
class (*), intent (in) :: tu(:)
end subroutine vector_tutvc
end module type_Vector
program main
use, intrinsic :: iso_fortran_env, only: &
sp => REAL32, &
stdout => OUTPUT_UNIT, &
compiler_version, &
compiler_options
use type_Vector, only: &
Vector
! Explicit typing only
implicit none
type (Vector) :: vcr
real (sp), allocatable :: r(:)
r = [ &
1.0000000_sp, 0.9999965_sp, 0.9999931_sp, 0.9999896_sp, 0.9999862_sp, &
0.9999829_sp, 0.9999796_sp, 0.9999763_sp, 0.9999731_sp, 0.9999699_sp, &
0.9999668_sp, 0.9999637_sp, 0.9999607_sp &
]
call vcr%set(r)
write( stdout, '(/4A/)' ) 'This file was compiled by ', &
compiler_version(), ' using the options ', &
compiler_options()
end program main
set is now a generic type-bound procedure.
This file was compiled by GCC version 5.3.1 20160528 using the options -mtune=generic -march=x86-64 -O3 -std=f2008ts
I'm not familiar with Fortran. And here is a generic interface with some subroutines. gfortran 4.8 complains that:
Ambiguous interfaces 'sortic4' and 'sortic' in generic interface 'sorti' at (1)
INTERFACE SORTI
SUBROUTINE SORTIC( N, IND, TBLC )
INTEGER , INTENT(IN ) :: N
INTEGER , INTENT(INOUT) :: IND( N )
CHARACTER*(*), INTENT(IN ) :: TBLC( * )
END SUBROUTINE SORTIC
SUBROUTINE SORTIC4( N, IND, TBLC )
INTEGER , INTENT(IN ) :: N
INTEGER , INTENT(INOUT) :: IND( N )
CHARACTER*(*), INTENT(IN ) :: TBLC( * )
END SUBROUTINE SORTIC4
SUBROUTINE SORTIC8( N, IND, TBLC )
INTEGER(8) , INTENT(IN ) :: N
INTEGER(8) , INTENT(INOUT) :: IND( N )
CHARACTER*(*), INTENT(IN ) :: TBLC( * )
END SUBROUTINE SORTIC8
SUBROUTINE SORTI1( N, IND, TBL1 )
INTEGER, INTENT(IN ) :: N
INTEGER, INTENT(INOUT) :: IND( N )
INTEGER, INTENT(IN ) :: TBL1( * )
END SUBROUTINE SORTI1
....
END INTERFACE
The code comes from the ioapi3.1 library, m3utilio.f: http://www.baronams.com/products/ioapi/index.html
What is wrong?
You first two subroutines (SORTIC and SORTIC4) have exactly the same types, kinds and dimensions (ranks) of dummy arguments. The TKR resolution thus cannot difference between them, they are ambiguous. They must differ in some of these attributes to be usable in generic interface.
The second and the third one differ in their kinds, this is OK. (Default integer and integer(8), kind 8 is not portable, but is most often distinct from the default one.) The first and the second one are the same.
I looked in the source code of the library. I conclude, that this generic interface does not conform to the Fortran 90 and later standards. Therefore I would start with changing it to a regular interface block just for the explicit interface, i.e., delete the name SORTI after the word interface, and call the individual subroutines directly.
I'm binding Fortran code with a C dll, and I would like to have a Fortran array inter-operable with C. I currently have the following subroutine to bind the Fortran array with a C double*:
SUBROUTINE Pack_Inputs( Input , In_X )
TYPE( InputType ) , INTENT(INOUT) :: Input
REAL(KIND=C_DOUBLE) , ALLOCATABLE , TARGET , INTENT(INOUT) :: In_X(:)
IF ( .NOT. ALLOCATED(In_X) ) ALLOCATE( In_X (Input%Xlen) )
DO i = 1,Input%C_obj%Xlen
In_X(i) = Input%X(i)
END DO
Input%C_obj%X = C_LOC(In_X)
END SUBROUTINE Pack_Inputs
However, what I don't like about the current code is that I am constantly allocating memory, and having to unpack the array when the C dll is entered (partly driven by my reluctance to use the SAVE attribute on In_X(:)). I would rather much declare In_X once, inside a Fortran derived type. This leads to the motivation for this post. In this derived type:
USE , INSTRINSIC :: ISO_C_BINDING
TYPE , PUBLIC :: InputType
TYPE(InputType_C) :: C_obj
REAL(KIND=C_DOUBLE) , ALLOCATABLE , TARGET :: In_X(:)
REAL , DIMENSION(:) , ALLOCATABLE :: X
REAL , DIMENSION(:) , ALLOCATABLE :: Y
REAL , DIMENSION(:) , ALLOCATABLE :: Z
INTEGER , DIMENSION(:) , ALLOCATABLE :: index
INTEGER :: Xlen
INTEGER :: Ylen
INTEGER :: Zlen
INTEGER :: indexlen
END TYPE InputType
I get the error:
REAL(KIND=C_DOUBLE) , ALLOCATABLE , TARGET :: In_X(:)
1
Error: Attribute at (1) is not allowed in a TYPE definition
Is there a way to eliminate this error?
I have encountered this problem before, and the solution that worked for me was to to declare the component as POINTER instead of ALLOCATABLE, TARGET. I am not sure whether the Fortran standard does not support it, or this feature is just not implemented by the compilers. I was using ifort v12.0.2.137.
Would this be an acceptable solution for you? You would then be able to use it as pointer target.
TYPE , PUBLIC :: InputType
TYPE(InputType_C) :: C_obj
REAL(KIND=C_DOUBLE),DIMENSION(:),POINTER :: In_X => NULL()
REAL , DIMENSION(:) , ALLOCATABLE :: X
REAL , DIMENSION(:) , ALLOCATABLE :: Y
REAL , DIMENSION(:) , ALLOCATABLE :: Z
INTEGER , DIMENSION(:) , ALLOCATABLE :: index
INTEGER :: Xlen
INTEGER :: Ylen
INTEGER :: Zlen
INTEGER :: indexlen
END TYPE InputType
Then, you can associate the In_X pointer with target data:
In_X(1:Input%C_obj%Xlen) => Input%X(1:Input%C_obj%Xlen)
Note that Input%X will need to have a TARGET attribute as well.