Is the presence attribute 'inherited' to components of derived data structures? The standard says, a dummy argument is not present, if the corresponding actual argument is not present. But I am not sure, how this applies to components of derived data types as in the following example:
program test
implicit none
type some_type
integer :: acomponent
end type some_type
type(some_type) :: testval
testval%acomponent = 42
call outer()
call outer(testval)
contains
subroutine outer(me)
type(some_type), optional :: me
call inner(me%acomponent)
end subroutine outer
subroutine inner(simple)
integer, optional :: simple
if (present(simple)) then
write(*,*) 'simple present:', simple
else
write(*,*) 'simple not present...'
end if
end subroutine inner
end program test
The above example compiles and runs fine with gfortran-5, but is it standard conformant? Somehow, I can't figure it out by looking at the standard.
The example code is not conforming.
The relevant part of the Fortran 2008 standard is in 12.5.2.12p3 (5) - "A designator with it [an optional dummy argument that is not present] as the base object and with one or more subobject selectors shall not be supplied as an actual argument."
The component reference in me%acomponent is a subobject selector. Similarly, if me was an array, an array subscript of any form would also be a subobject selector.
Related
Is it possible to extend a class and overload one of its procedure with one with a different interface?
I would like to create multiple type (say tensor1, tensor2, ...) extending a base class tensor , all implementing a method sub whose arguments depend on the subclass.
Consider the following code:
module tensor_class
implicit none
private
public :: tensor_Type
type, abstract :: tensor_Type
Contains
procedure,pass(self) :: sub
end type
Contains
subroutine sub(self,other)
class(tensor_Type),intent(inout) :: self
integer :: other
write(*,*) 'sub is not implemented in the main class'
end subroutine
end module tensor_class
module tensor1_mod
use tensor_class
type, extends(tensor_type) :: tensor1
real,dimension(2) :: val
Contains
procedure, pass(self) :: sub
end type tensor1
Contains
subroutine sub(self,other)
class(tensor1),intent(inout) :: self
real,dimension(2),intent(in) :: other
self%val = self%val + 2.0 * other
end subroutine
end module
module tensor
use tensor1_mod
end module
program testTensor
use tensor
implicit none
class(tensor_type),allocatable :: t
type(tensor1) :: t1
real,dimension(2) :: v1 = [1.0,-2.3]
integer :: i
t1 = tensor1(v1)
t = tensor1(v1)
call t1%sub(i)
call t%sub(i)
end program
Neither Intel Fortran (19.1.1.216 20200306) nor gfortran (9.3.0) will compile it. The Intel compiler prints the following error message
tensorMin.F90(25): error #8383: The dummy arguments of an overriding and overridden binding that correspond by position must have the same characteristics, except for the type of the passed object dummy arguments. [SUB]
and gfortran
>tensorMin.F90:25:15:
25 | procedure, pass(self) :: sub
| 1
Error: Argument mismatch for the overriding procedure 'sub' at (1): Type mismatch in argument 'other' (REAL(4)/INTEGER(4))
I cannot declare sub as deferred in tensor_class, if I want to be able to create multiple subclasses and have sub take different type of arguments in each class (say real, dimension(2) in tensor1, real, dimension(2,2) in tensor2 etc).
Upon reading of the Fortran 2008 standard section 4.5.7.3, it seems that the name and number of arguments in sub need to match, but the standard does not seem to say anything about the type of the arguments.
Am I missing something? Is there a way other than creating a class containing all possible arguments of sub?
The Fortran standard does require the argument types to match.
Except for the passed-object dummy arguments the standard says that the dummy arguments which correspond shall have the same characteristics. (This the Intel Fortran error message states.) The type of a dummy argument is one characteristic (of many) of that argument.
You can look in to polymorphic arguments (as in your comment) or at generic bindings.
I got troubles with this common:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
& REDVAR,MOCDER(2)
COMMON /REDCO1/ CTEXT
C
type(double_st) :: DPREC
INTEGER :: NITMA,INDIC,NBERR,NCAR,KMOTLU,REDVAR,MOCDER
CHARACTER(72) :: CTEXT
CHARACTER(4) :: CTEXT4
C
EQUIVALENCE (CTEXT,CTEXT4)
The double_st derived type is:
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
Trying to compile some code including this common, I get:
ifort:
./REDCOM.INC(1): error #6005: A derived type object in a COMMON block shall not have default initialization [DPREC]
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
----------------------^
gfortran:
REDCOM.INC:1.27:
Included at m_abaq4.f:90:
COMMON /REDCOM/ DPREC,NITMA,INDIC,NBERR,NCAR,KMOTLU,
1
Error: Derived type variable 'dprec' in COMMON at (1) may not have default initializer
Being not very familiar with Fortran, I don't understand what the problem is, or how to solve it (I tried googling with no success). If I use a REAL(8) instead of a double_st, everything works fine.
Could someone help me on this?
From the line
integer :: acc = -1
strip off the trailing
= -1
to leave
integer :: acc
recompile, and see what happens. The error message suggests that a program can't initialise a derived type component and use variables of that derived type in common statements. 'Initialize' is used in the Fortran standards to mean, precisely, the setting of a variable (or element) 's value in its declaration.
In my (draft) version of the Fortran 2008 standard constraint 506 on rule 503 prohibits initialization of components of variables of derived type used in common blocks. This prohibition doesn't seem to apply to initialization of variables of intrinsic types, hence the compiler's acceptance of the code when the variable is of type real(8).
As for using derived types in common blocks, that's mixed-paradigm programming if ever there was such a thing !
I'm saying much the same as in High Performance Mark's answer, but hopefully with a little more elaboration. After that answer's edit I actually diverge a little.
Having the type declaration
type double_st
sequence
real(kind(0.d0)) :: x,y,z
integer :: acc = -1
end type double_st
involves default initialization. That's the acc=1 part: see Fortran 2008 4.5.4.6. It isn't just the component that is default initialized but the whole type.
There is a constraint (C5105, in 5.7.2.1) which says that
If a common-block-object is of a derived type, the type shall have the BIND attribute or the SEQUENCE attribute and it shall have no default initialization.
This is what the compilers complain about. Using a real(kind(0d0)) (or real(8)) doesn't violate this constraint. Intrinsic types (such as that real) cannot have default initialization, but they can have explicit initialization (such as real :: hello = 1.). There are some restrictions on the use of an explicitly initialized object (such as C506 mentioned in the other answer), but the question isn't clear enough on that point for me to comment further.
I have multiple subroutines with a parameter p which is an array of explicit size like
subroutine foo(p)
integer,dimension(2),intent(in) ::p
end subroutine foo
subroutine bar(p)
integer,dimension(3),intent(in) ::p
end subroutine bar
I'd like to call these two functions through an indirect call, but could not find a way to declare an interface that matches both foo and bar signature...
Using an assumed array size in the interface for example does not work:
subroutine indirect(f,p)
integer,dimension(*),intent(in):p
interface
subroutine f(p)
integer,dimension(*),intent(in) :: p
end subroutine f
end interface
call f(p)
end subroutine indirect
When I invoke foo or bar thru indirect, the compiler (gfortran 4.9.2) complains about shape mismatch for first argument p of f...
integer,dimension(2) :: pfoo
integer,dimension(3) :: pbar
pfoo = (/ 0,1 /)
pbar = (/ 1,2,3 /)
call foo(pfoo) ! direct call is OK
call bar(pbar)
call indirect(foo,pfoo) ! compiler complains about foo signature
call indirect(bar,pbar) ! same for bar...
Compiler error is something like:
Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'p'
Of course, I could modify foo and bar signature to use assumed array size (*) instead of fixed array size, but
it's like I'm loosing some information just for making the compiler
happy without adding any kind of security
foo and bar are not my code and I'd rather not change them...
I've found a workaround, but it consist of writing an assumed size wrapper for each subroutine foo and bar
call indirect(foo_wrapper,pfoo) ! compiler complains about foo signature
call indirect(bar_wrapper,pbar) ! same for bar...
subroutine foo_wrapper(p)
integer,dimension(*),intent(in) ::p
call foo(p)
end subroutine foo_wrapper
subroutine bar_wrapper(p)
integer,dimension(*),intent(in) ::p
call bar(p)
end subroutine bar_wrapper
or eventually, replacing all assumed size by deferred size in indirect and wrapper, so as to give a chance to runtime checks, also works, but that's not the point...
The point is, since I have many such foo/bar isn't there a way to declare the interface properly (I mean without wrappers or other artefacts).
I couldn't decipher the standard (I used http://www.j3-fortran.org/doc/year/10/10-007.pdf - I presume it's around 12.5.2.9 Actual arguments associated with dummy procedure entities §2), so I don't know if it's a limitation of gfortran. Right now i haven't any other compiler available, but I'd like to know if some other compiler would compile (intel? - I'm on windows 7 64 bits).
I'll look at whether gfortran is correct to complain and, regardless, what options there are to work around the complaint. References are to Fortran 2008.
12.5.2.9 is indeed important.
If the interface of a dummy procedure is explicit, its characteristics as a procedure (12.3.1) shall be the same as those of its effective argument, except that [inapplicable things]
f in indirect is a dummy procedure with an explicit interface (through the interface block; 12.4.2.1). Looking at the reference 12.3.1 we see
The characteristics of a procedure are .. , the characteristics of its dummy arguments, ..
foo, bar and f are all procedures with a single dummy argument (all called p, by coincidence). So, if foo wants to be the effective argument associated with f then foo's p must match the characteristics of f's p. Each p is a dummy data object, so 12.3.2.2 becomes relevant:
The characteristics of a dummy data object are its type, its type parameters (if any), its shape, ... If a shape, size, or type parameter is assumed or deferred, it is a characteristic.
We have that the type and type parameters match. However, p in f has its size assumed. p in foo does not have this matching characteristic. It is, then, not allowed to associate foo with f in the call to indirect. The same holds for bar.
This requirement for matching characteristics of the dummy data objects to have the same shape also leads naturally to another conclusion: foo and bar don't have matching characteristics as procedures. For a third procedure to match both the shape characteristic must be ignored.
Using a wrapper subroutine is possible, but I'd also think about whether I could change the various subroutines to take assumed-shape arguments. This is much better than assumed-size. But, as you say, I'd also be reluctant to change that code.
For the subroutines foo and bar as you have them, there is another available option. Nothing about those subroutines requires a caller to have an explicit interface for them available (12.4.2.2). So, in indirect you could just scrap the interface block: the rules about matching are much more relaxed (other parts of 12.5.2.9). For other procedures this may not be possible, though.
All that said, ifort appears to happily compile and run the code as you have it...
Why do the names of arguments in overriding procedures need to match those of the abstract interface?
I understand that clearly the TYPE, INTENT, etc of such arguments are required to match the interface, but why should the compiler care what I call my variables?
In the following, I've defined a simple abstract utility class containing a single deferred procedure EVAL that takes a double precision argument.
!------------------------------------- an abstract utility class !
type, abstract :: func_1d
contains
procedure(interface_1d),deferred :: eval
end type func_1d
!-------------------------------------------- interface for eval !
abstract interface
function interface_1d(this,data) result(rval)
import :: func_1d
class(func_1d), intent(inout) :: this
real*8 , intent(in) :: data
real*8 :: rval
end function interface_1d
end interface
Defining an overriding class and an implementation for EVAL:
type, extends(func_1d) :: foo
contains
procedure, pass :: eval => eval_foo
end type foo
function eval_foo(this,another_variable_name) result(rval)
implicit none
class(foo), intent(inout) :: this
real*8, intent(in) :: another_variable_name
real*8 :: rval
!! etc
end function eval_foo
I get the following error from gfortran:
Error: Dummy argument 'another_variable_name' of 'eval' at (1) should be named 'data'
as to match the corresponding argument of the overridden procedure
If I instead substitute DATA for ANOTHER_VARIABLE_NAME everything compiles and runs as expected.
But this seems silly to me. I want to be able to inherit from FUNC_1D multiple times, and under various circumstances and being forced to call my variables DATA every time seems ridiculous.
I don't understand why the compiler should be interested in more than the TYPE and INTENT of the arguments?
Elaborating on High Performance Mark's comment
I don't know but I suspect that it may be down to Fortran's argument keyword capabilities, which mean that you can call your function like this fun_1d(data=the_data,this=that), that is you can name the arguments in the call rather than rely on position matching.
consider the following
type, extends(func_1d) :: foo
contains
procedure, pass :: eval => eval_foo
end type foo
type, extends(func_1d) :: bar
contains
procedure, pass :: eval => eval_bar
end type bar
with appropriate procedure definitions with interfaces
real*8 function eval_foo(this,foo_var)
class(foo), intent(inout) :: this
real*8, intent(in) :: foo_var
end function
real*8 function eval_bar(this,bar_var)
class(bar), intent(inout) :: this
real*8, intent(in) :: bar_var
end function
then later
class(func_1d), allocatable :: baz
allocate (foo_or_bar :: baz) ! For one of the types foo, bar
which, if any, makes sense with an argument keyword?
print*, baz%eval(data=s)
print*, baz%eval(foo_var=s)
print*, baz%eval(bar_var=s)
[There are cases where this would be much more pronounced, especially with optional dummy arguments.]
The standard requires that you keep the same dummy argument names (very likely to avoid the issue above). See 12.4.1 ISO/IEC 1539-1:2010:
12.4.1 Interface and abstract interface
The interface of a procedure determines the forms of reference through which it may be invoked. The procedure’s
interface consists of its name, binding label, generic identifiers, characteristics, and the names of its dummy
arguments. The characteristics and binding label of a procedure are fixed, but the remainder of the interface may
differ in differing contexts, except that for a separate module procedure body (12.6.2.5), the dummy argument
names and whether it is recursive shall be the same as in its corresponding separate interface body (12.4.3.2).
This states that separate procedures using the same interface shall have the same dummy argument names as the interface. This is further strengthened by 4.5.7.3:
The overriding and overridden type-bound procedures shall satisfy the following conditions.
- [...]
- Dummy arguments that correspond by position shall have the same names and characteristics, except for the type of the passed-object dummy arguments.
I am using fortran for a while, but I didn't check the implicit cast issue when using subroutines in fortran.
For example
subroutine printa(a)
double precision :: a
...
endsubroutine printa
When I called the subroutine
call printa(1)
I saw error #6633: The type of the actual argument differs from the type of the dummy argument. [1]
I know it is because I use an integer instead of a double precision as an input parameter. But I just realized that there is no implicit cast when using subroutines.
If I want a subroutine which handles integer and double precision data, it seems I have to define 2 subroutines for doing these things. Is there a way to make the implicit cast happen (just like the function calling in c)? Or there is another way to make it?
Thanks.
It is fundamental in Fortran that reals (including different precisions) and integers are different and that you need different subroutines to handle them. If you want the convenience of having a single call, similar to Fortran intrinsics such as sin which are implicitly several different functions, you can write the several different procedures and then create a generic interface to select between them. Fortran will then select the correct actual procedure based on the actual arguments, to match the dummy arguments. Here is an example that does it by rank of the array argument: how to write wrapper for 'allocate'. It can also be done, as you wish, by type of the argument.
You can overload a subroutine name so that when the "wrong" type of argument is supplied it is converted to right type and used to call the subroutine, as shown below.
module foo
implicit none
interface printa
module procedure print_int,print_real
end interface printa
contains
!
subroutine print_real(x)
real, intent(in) :: x
print*,"number is ",x
end subroutine print_real
!
subroutine print_int(i)
integer, intent(in) :: i
call print_real(real(i))
end subroutine print_int
!
end module foo
program main
use foo, only: printa
implicit none
call printa(1)
call printa(1.0)
end program main
Output:
number is 1.
number is 1.