Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User defined constructor for Fortran derived type instance

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:

  1. generic interface with the same name as the derived type they're supposed to construct, see link above;

  2. 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
    
  3. 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.

like image 595
Chang Avatar asked Oct 04 '17 17:10

Chang


People also ask

What is a derived type Fortran?

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.

What is derived type?

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.

What is type in Fortran?

The type statement specifies the data type of items in the list, optionally specifies array dimensions, and initializes with values.


1 Answers

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.)
like image 174
Vladimir F Героям слава Avatar answered Dec 09 '22 22:12

Vladimir F Героям слава