I am quite a beginner in OOP with Fortran and I am trying to write a program with procedures that deal with polymorphic variables as arguments. Although my original code is much more complicated (many procedures, several derived types etc), I could isolate a simple example of my problem, say: I have a procedure that copies a polymorphic variable and slightly modifies this copy.
I was able to successfully write my test program using a subroutine:
MODULE my_module
type :: my_type
real :: data
endtype my_type
type, extends(my_type) :: my_derived_type
end type my_derived_type
CONTAINS
subroutine sub_copy(old,new)
implicit none
class(my_type), intent(in) :: old
class(my_type), allocatable, intent(out) :: new
allocate(new, source = old)
new%data = new%data + 1
end subroutine sub_copy
END MODULE my_module
PROGRAM my_prog
use my_module
implicit none
type(my_derived_type) :: x
class(my_type), allocatable :: y
x%data = 1.0
call sub_copy(x,y)
print*,y%data
deallocate(y)
END PROGRAM my_prog
This performs nicely both regarding the expected result and the memory allocation/deallocation.
However, I have been fighting for days trying to make working a Fortran function that would do the same job.
It seems that a function defined in a similar way to the subroutine (see here after) cannot be used simply as
y = fun_copy(x)
and my gfortran compiler (v5.0.0) complains:
Error: Assignment to an allocatable polymorphic variable at (1) is not yet supported
I have read here and there that indeed such assignment is not supported by my compiler. Waiting for that, I have tried to work that around by defining my own assignment operator (=). The following code works:
MODULE my_module
type :: my_type
real :: data
endtype my_type
type, extends(my_type) :: my_derived_type
end type my_derived_type
interface assignment(=)
module procedure myassign
end interface
CONTAINS
function fun_copy(old) result(new)
implicit none
class(my_type), intent(in) :: old
class(my_type), allocatable :: new
allocate(new, source = old)
new%data = new%data + 1
end function fun_copy
subroutine myassign(new,old)
class(my_type), intent(in) :: old
class(my_type), allocatable, intent(out) :: new
allocate(new, source=old)
end subroutine
END MODULE my_module
PROGRAM my_prog
use my_module
implicit none
type(my_derived_type) :: x
class(my_type), allocatable :: y
x%data = 1.0
y = fun_copy(x)
print*,y%data
deallocate(y)
END PROGRAM my_prog
It works in the sense that indeed, a copy of x
is created as y
.
However, inspecting the memory budget of this simple test program (I use the Instrument software on OS X), it appears that some memory is not deallocated before the end of it.
I suspect that the copy function and the assignment subroutine both allocate memory and that I only free one occurrence, leaving one allocated.
As I intend to use such a routine a large number of times in a much more complicated code, I am really concerned about memory allocation/deallocation. Of course, I can use the subroutine version of the program, but if there is a way, I would prefer the function version.
Is there a way to deal with such a problem?
Have you tried using pointers?
module my_module
implicit none
type :: my_type
real :: data
contains
procedure :: sub_copy
procedure :: fun_copy_ptr
procedure :: fun_copy_alloc
procedure, pass (this) :: my_assign
generic :: assignment(=) => my_assign
end type my_type
type, extends(my_type) :: my_derived_type
end type my_derived_type
contains
subroutine sub_copy(this, new)
class(my_type), intent (in) :: this
class(my_type), allocatable, intent (out) :: new
allocate(new, source=this)
new%data = new%data + 1
end subroutine sub_copy
function fun_copy_alloc(this) result (new)
class(my_type), intent(in) :: this
class(my_type), allocatable :: new
allocate(new, source=this)
new%data = new%data + 1.0
end function fun_copy_alloc
function fun_copy_ptr(this) result (new)
class(my_type), intent(in) :: this
class(my_type), pointer :: new
allocate(new, source=this)
new%data = new%data + 1.0
end function fun_copy_ptr
subroutine my_assign(new, this)
class(my_type), intent(in) :: this
class(my_type), allocatable, intent(out) :: new
allocate(new, source=this)
end subroutine
end module my_module
program my_prog
use my_module, only: &
my_type, &
my_derived_type
implicit none
type(my_derived_type) :: x
class(my_type), allocatable :: y
class(my_type), pointer :: y_ptr => null()
x%data = 1.0
! Case 1
call x%sub_copy(y)
print *, y%data
deallocate(y)
! Case 2
y_ptr => x%fun_copy_ptr()
print *, y_ptr%data
deallocate(y_ptr)
! Case 3
allocate( y, source=x%fun_copy_alloc() )
print *, y%data
deallocate(y)
end program my_prog
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With