This is my second question related to Fortran (I use C++, so forgive me my way of thinking).
I want to use OOP, to say, derived type in Fortran whenever appropriate. In C++, you can use user defined constructor such as https://msdn.microsoft.com/en-us/library/s16xw1a8.aspx
Here in Fortran, things are different. The first thing I tried is from here: https://www.ibm.com/developerworks/community/blogs/b10932b4-0edd-4e61-89f2-6e478ccba9aa/entry/object_oriented_fortran_user_defined_constructors2?lang=en
Link is broken, so I pasted it here:
module m
!...
interface base
module procedure new_base
end interface
contains
!...
function new_base(I)
integer, intent(in) :: I
type(base) new_base
allocate(new_base%data(I))
new_base%data = I
end function
!...
end module
The interface above defines a user-defined constructor for type base. It is used in a similar way to a structure constructor. It can even take argument keywords.
Then I found some other ways to do it. Here I listed a few approaches seemly to work but I only tested the first and second:
generic interface with the same name as the derived type they're supposed to construct, see link above;
use type-bound procedure (This is not even a "traditional" constructor)
MODULE mymod
TYPE mytype
Private
INTEGER :: x
CONTAINS
PROCEDURE, PASS :: init
END TYPE
CONTAINS
SUBROUTINE init(this, i)
CLASS(mytype), INTENT(OUT) :: this
INTEGER, INTENT(IN) :: i
write(*,*) this%x
IF(i > 0) THEN
this%x = 1
ELSE
this%x = 2
END IF
write(*,*) this%x
END SUBROUTINE init
END
PROGRAM test
USE mymod
TYPE(mytype) :: y
CALL y%init(1)
END PROGRAM
use Static Constructors or Structure Constructors (http://www.lahey.com/docs/lfenthelp/NLMOvUsInvConst.htm) But it appears that this is NOT for general Fortran http://www.lahey.com/docs/lfenthelp/NLMGSWhatIs.htm
So I haven't understood well enough what is most preferred and flexible approach to initialize/construct a derived type in practice, especially when I use nested derived type in development. I hope I can organize this topic with some help.
As discussed previously in Variables, there are five built-in data types in Fortran. A derived type is a special form of data type that can encapsulate other built-in types as well as other derived types. It could be considered equivalent to struct in the C and C++ programming languages.
A derived type is formed by using one or more basic types in combination. Using derived types, an infinite variety of new types can be formed. The array and structure types are collectively called the aggregate types. Note that the aggregate types do not include union types, but a union may contain an aggregate member.
The type statement specifies the data type of items in the list, optionally specifies array dimensions, and initializes with values.
OK, so I will assume you read well the answers at How to override a structure constructor in fortran and I will answer your problem raised in the comment. There is not enough place in the comment to answer that.
You can also make constructors in Fortran which accept variable number of arguments.
It is even possible with the default structure constructors which every derived type has by default. If you default-initialize a component, it is optional in the constructor. The same holds for allocatable and pointer components.
For type
type t1
integer :: i = 1
integer, pointer :: ip => null()
integer, allocatable :: ap
end type
you can call the default constructor just as
instance = t1()
and it is perfectly legal, i
will be 1, ip
will point to null
and ap
will not be allocated.
Or you can call it as
instance = t1(ap=5)
and the ap
component will be allocated and set to 5 and the other components will be left default.
You can achieve similar stuff with user defined constructors just by making the arguments optional
.
function t1_user(ap, i) result(res)
type(t1) :: res
integer, allocatable :: ap !this argument MUST be passed,
! it does not have to be allocated
integer, optional :: i ! this argument is optional
if (present(i)) then
...
end if
end function
any type-bound procedure can of-course also have optional arguments.
As for the nested types, that is really best done with constructors as functions, no matter if they are default or user defined:
type inner
real :: x, y
end type
type outer
type(inner), allocatable :: in
real :: z
end type
instance1 = outer(inner(1., 2.), 3.)
instance2 = outer(z=4.)
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