Fortran: class in abstract interface [duplicate] - oop

This question already has answers here:
Why is the type not accessible?
(2 answers)
Closed 6 years ago.
Using cygwin64 on Windows this program won't compile:
program test
implicit none
!define my type
type myType
real::foo
integer::bar
end type myType
!define an operator for this type
interface operator (>)
logical function compare(a,b)
type(myType),intent(in) :: a,b
compare = a%foo>b%foo
end function compare
end interface operator (>)
!simple example of operator usage
type(myType) :: tfoo, tbar
tfoo = card(1.,2); tbar = card(3.,4)
print*, tfoo>tbar
end program test
gfortran (only argument is "std=f2008") tells me:
type(myType),intent(in) :: a,b
1
Error: Derived type ‘mytype’ at (1) is being used before it is defined
which is confusing to me, since the type is defined right before the operator. I'm relatively new to Fortran, so this example code might have some more errors.
The same problem occurred here, but encapsulating myType in a separate module did not resolve the issue.

There are several issues with your code, but this particular error is because myType is in the host scope, but not in the interface block. The solution is to either place the derived type in a separate module as suggested in the linked thread, or import the derived type from the host scoping unit:
interface operator (>)
logical function compare(a,b)
import myType
type(myType),intent(in) :: a,b
end function compare
end interface operator (>)
This is described in the Fortran 2008 Standard, Cl. 12.4.3.3 "IMPORT statement":
1 The IMPORT statement specifies that the named entities from the host scoping unit are accessible in the interface
body by host association. An entity that is imported in this manner and is defined in the host scoping unit shall be
explicitly declared prior to the interface body.
An interface block may not have executable statements included - so the assignment you have there is not valid. Furthermore, card is not defined in your code.

Related

Defining and invoking a constructor in Fortran

I can't figure out how I define a simple constructor for a class. What I want to do is allocate an array in mytype and later populate it in the main program.
What I have is this:
module types
implicit none
type mytype
real, allocatable :: someArray(:)
end type mytype
interface
module procedure :: init
end interface
contains
subroutine init(this)
class(mytype), intent(inout) :: this
allocate( this%someArray(5) )
end subroutine init
end module types
program test
use types
implicit none
type(mytype) :: array
call array%init
do i=1, 5
array%someArray(i) = real(i)
print *, array%someArray(i)
end do
end program test
When I compile I get the error
Error: MODULE PROCEDURE at (1) must be in a generic module interface
What does that mean? How can I define a generic module interface?
Thanks!
The language's model for a user provided constructor is a generic function with the same identifier as the type, that simply returns an object of the type. Beyond the ability to have a generic with the same name as a type, this is nothing special.
module types
implicit none
type mytype
real, allocatable :: someArray(:)
end type mytype
interface mytype
module procedure :: init
end interface
! init would typically be private.
contains
function init()
type(mytype) :: this
allocate( this%someArray(5) )
! Non-pointer function result must be defined.
this%someArray = 0
end function init
end module types
program test
use types
implicit none
type(mytype) :: x
x = mytype()
do i=1, 5
x%someArray(i) = real(i)
print *, x%someArray(i)
end do
end program test
(The example is somewhat pointless given other aspects of the language, such as parameterized types, array constructors, automatic allocation or even the out-of-the-box capability of the built-in structure constructors.)
The error message from the compiler perhaps means to reference a generic interface, as a procedure statement is only permitted in an interface block for a generic.
Specific type bound procedure references - things with the syntax object % binding - are generally used when you have a parent type that has a method with a particular signature (set of dummy arguments, bar the passed argument), and you want to override that method in extensions - i.e. invoke a different procedure that has the same signature. Constructors don't fit this - typically the information that needs to be passed to a constructor (i.e. the signature of the call) is type specific.

Fortran link modules for precision and global variable types

I am new to Fortran and trying to understand if the following is possible. My idea to structure the program is to declare the precision and variable types in one module. Then make use of those variables without declaring again the type in other modules or the main program.
module pre
implicit none
INTEGER, PARAMETER :: sp=SELECTED_REAL_KIND(6,37)
INTEGER, PARAMETER :: dp=SELECTED_REAL_KIND(15,307)
INTEGER, PARAMETER :: qp=SELECTED_REAL_KIND(33,4931)
REAL(dp), PARAMETER :: pi = 4.*ATAN(1.)
REAL(dp) :: H
REAL(dp) :: M
REAL(dp) :: KR
end module pre
Now I want to make use of all the variables in another module that contains one or more functions, such as:
module hon
use pre
implicit none
contains
function KE(H,M) result(KR)
KR = 2*PI/H/M
end function KE
end module hon
Then I use gfortran in this order:
gfortran -c mod_pre.f90
gfortran -c mod_hon.f90
Since 'module pre' is part of 'module hon' I compile in order, but gfortran shows an error.
With the code above I understand the variable types and parameters should have been included by USE; But the message I get from gfortran is that none of my variables have IMPLICIT type when I try to compile 'module hon'.
Could somebody clarify the problem or suggest a solution? I would like to avoid having my variables scattered in multiple modules.
Thanks!
In the function statement, the result(kr) says that the function result has name kr. This function result is not the same thing as the module variable kr. In particular, this function result makes inaccessible the module variable.
The function result is specific to the function itself and its properties must be declared within the function subprogram.
Similarly, the dummy arguments of the function, H and M, are distinct from the module variables and need to be declared in the function subprogram.
Beyond that, you perhaps have similar concerns to this other question.
To be clear, it isn't possible to say something like "all function results called kr and all dummy arguments called H or M have these characteristics". Each individual object must be given the properties.
However, although I don't recommend this, this is a situation where literal text inclusion (using a preprocessor or include file) could help you:
function ke(H, M) result (kr)
include 'resdummydecls'
...
end function
where the file has the declarations.

How to create and use array of type extensions in Fortran? [duplicate]

I am trying to use pointers to create links between objects. Using Fortran and here is the code piece:
module base_pars_module
type,abstract,public :: base_pars
end type
end module
module test_parameters_module
use base_pars_module
type, extends(base_pars) :: test_pars
contains
procedure :: whoami
end type
contains
function whoami(this) result(iostat)
class( test_pars) :: this
write(*,*) 'i am a derived type child of base_pars'
end type
end module
module base_mask_module
use base_pars module
type, abstract , public :: base_mask
class(base_pars),pointer :: parameters
end type
end module
module test_mask_module
use base_mask_module
implicit none
type, extends(base_mask) :: test_mask
end type
end module
program driver
type(test_pars) , target :: par_Test
type(test_mask) :: mask_test
iostat= par_test%whoami()
mask_test%parameters=>par_test
iostat=mask_test%parameters%whoami()
end program
parameters at base_mask_module is a pointer with base_pars class. I would like to use this pointer to refer par_test object which is test_pars type that extends base_pars type. So the pointer and the target has the same class. But when I compile this it gives an error:
driver.f90:17.37:
iostat=mask_test%parameters%whoami()
1
Error: 'whoami' at (1) is not a member of the 'base_pars' structure
Is it a bug or am i doing something wrong?
When you have polymorphism like this there are two things to consider about an object: its dynamic type and its declared type. The parameters component of test_mask (base_mask) is declared as
class(base_pars),pointer :: parameters
Such a component therefore has declared type base_pars.
Come the pointer assignment
mask_test%parameters=>par_test
mask_test%parameters has dynamic type the same as par_test: test_pars. It's of declared type base_pars, though, and it's the declared type that is important when we care about its components and bindings. base_pars indeed has no whoami.
You need, then, something which has declared type par_test. Without changing the definitions of the derived types you can do this with the select type construct.
select type (pars => mask_test%parameters)
class is (par_test)
iostat=pars%whoami() ! pars of declared type par_test associated with mask_test%parameters
end select
That said, things get pretty tedious quite quickly with this approach. Always using select type, distinguishing between numerous extending types, will be quite a bind. An alternative would be to ensure that the declared type base_pars has a binding whoami. Instead of changing the main program as above, we alter the module base_pars_module:
module base_par_modules
implicit none ! Encourage good practice
type,abstract,public :: base_pars
contains
procedure(whoami_if), deferred :: whoami
end type
interface
integer function whoami_if(this)
import base_pars ! Recall we're in a different scope from the module
class(base_pars) this
end function
end interface
end module
So, we've a deferred binding in base_pars that is later over-ridden by a binding in the extending type test_pars. mask_test%parameters%whoami() in the main program is then a valid and the function called is that offered by the dynamic type of parameters.
Both approaches here address the problem with the binding of the declared type of parameters. Which best suits your real-world problem depends on your overall design.
If you know that your hierarchy of types will all have enough in common with the base type (that is, all will offer a whoami binding) then it makes sense to go for this second approach. Use the first approach rather when you have odd special cases, which I'd suggest should be rare.

Extending derived types in separate module without changing the type's name

I can extend a program by adding a module file in which I extend originally defined derived types like e.g.:
module mod1
type type1
real :: x
end type
end module
module mod2
use mod1
type,extends(type1) :: type2
contains
procedure,pass :: g
end type
contains
function g(y,e)
class(type2), intent(in) :: y
real,intent(in) :: e
g=y%x+e
end function
end module
program test
use mod2
type(type2) :: a
a%x=3e0
write(*,*) a%g(5e0)
end program
But with this solution I need to change the declaration of 'a' (type1->type2) in the calling program, each time when I'm adding another module. So my question is if there is a way around this, i.e. I can add a type bound procedure to a derived type in another module without changing the original name of the type.
I totally understand that this might not work since I could then declare a variable and extend its type later, what sounds problematic for me. So, I thought about the deferred statement. But this isn't really what I want, since I first have to ad it to the original definition and second I need to provide an interface and thus need to know about the variables of the later coming function (here g) already. However, maybe someone has a nice solution for this.
All this is of course to bring more structure in the program, especially when I think about different people working on one program at the same time, such a possibility to split workpackages seems rather useful.
You can rename entities that are use associated by using the renaming capability of the USE statement.
MODULE m2
USE m1, chicken => type1
TYPE, EXTENDS(chicken) :: type1
...
type1 in module m2 is a different type to type1 in module m1.
You could also do this renaming in the USE statement in your main program, or via some intermediate module.
If both type1 names are accessible in another scope and you reference the name type1, then your compiler will complain.
If you use this trick and other programmers read your code, then they might complain.
To some extent submodules would help you, but they are implemented in the most widely used compilers. You could defer the implementation of the procedure to the submodule, but you would have to specify the interface anyway.
It isn't possible in any other way as far as I know.

Including a module more than once

Suppose I have a module which defines some basic constants such as
integer, parameter :: i8 = selected_int_kind(8)
If I include this in my main program and I also include a module which does some other things (call this module functions) but functions also uses constants, then am I essentially including constants twice in my main program?
If so, is this bad? Can it be dangerous at all to include a module too many times in a program?
No, it is fine to do this. All you are doing with the use statement is providing access to the variables and functions defined in your module via use association. It is not like declaring variables each time they are use'd (they are in fact redeclared however).
The only thing to be wary of are circular dependencies, where module A uses module B and module B uses module A. This is not allowed.
Edit: From Metcalf et al. Fortran 95/2003 explained, pg. 72:
A module may contain use statements that access other modules. It must not access itself directly or indirectly through a chain of use statements, for example a accessing b and b accessing a.
Whilst this quote doesn't directly answer your question, it reiterates that really the only thing you can't do is have a circular dependency. So the following is perfectly valid:
module one_def
implicit none
integer, parameter :: one=1
end module one_def
module two_def
use one_def, only : one
implicit none
integer, parameter :: two=one+one
end module two_def
program test
use one_def, only : one
use two_def, only : two
implicit none
print*, two == one+one ! This prints .True.
end program