Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override a structure constructor in fortran

Is it currently possible to override the structure constructor in Fortran? I have seen proposed examples like this (such as in the Fortran 2003 spec):

module mymod

  type mytype
    integer :: x
    ! Other stuff
  end type

  interface mytype
    module procedure init_mytype
  end interface

contains
  type(mytype) function init_mytype(i)
    integer, intent(in) :: i
    if(i > 0) then
      init_mytype%x = 1
    else
      init_mytype%x = 2
    end if
  end function
end

program test
  use mymod
  type(mytype) :: x
  x = mytype(0)
end program

This basically generates a heap of errors due to redundant variable names (e.g. Error: DERIVED attribute of 'mytype' conflicts with PROCEDURE attribute at (1)). A verbatim copy of the fortran 2003 example generates similar errors. I've tried this in gfortran 4.4, ifort 10.1 and 11.1 and they all produce the same errors.

My question: is this just an unimplemented feature of fortran 2003? Or am I implementing this incorrectly?

Edit: I've come across a bug report and an announced patch to gfortran regarding this issue. However, I've tried using a November build of gcc46 with no luck and similar errors.

Edit 2: The above code appears to work using Intel Fortran 12.1.0.

like image 534
marshall.ward Avatar asked Nov 23 '10 23:11

marshall.ward


2 Answers

Is it currently possible to override the structure constructor in Fortran?

No. Anyway even using your approach is completely not about constructor overriding. The main reason is that structure constructor # OOP constructor. There is some similarity but this is just another idea.

You can not use your non-intrinsic function in initialization expression. You can use only constant, array or structure constructor, intrinsic functions, ... For more information take a look at 7.1.7 Initialization expression in Fortran 2003 draft.

Taking that fact into account I completely do not understand what is the real difference between

type(mytype) :: x
x = mytype(0)

and

type(mytype) :: x
x = init_mytype(0)

and what is the whole point of using INTERFACE block inside mymod MODULE.

Well, honestly speaking there is a difference, the huge one - the first way is misleading. This function is not the constructor (because there are no OOP constructors at all in Fortran), it is an initializer.


In mainstream OOP constructor is responsible for sequentially doing two things:

  1. Memory allocation.
  2. Member initialization.

Let's take a look at some examples of instantiating classes in different languages.

In Java:

MyType mt = new MyType(1);

a very important fact is hidden - the fact the object is actually a pointer to a varibale of a class type. The equivalent in C++ will be allocation on heap using:

MyType* mt = new MyType(1);

But in both languages one can see that two constructor duties are reflected even at syntax level. It consists of two parts: keyword new (allocation) and constructor name (initialization). In Objective-C syntax this fact is even more emphasized:

MyType* mt = [[MyType alloc] init:1];

Many times, however, you can see some other form of constructor invocation. In the case of allocation on stack C++ uses special (very poor) syntax construction

MyType mt(1);

which is actually so misleading that we can just not consider it.

In Python

mt = MyType(1)

both the fact the object is actually a pointer and the fact that allocation take place first are hidden (at syntax level). And this method is called ... __init__! O_O So misleading. С++ stack allocation fades in comparison with that one. =)


Anyway, the idea of having constructor in the language imply the ability to do allocation an initialization in one statement using some special kind of method. And if you think that this is "true OOP" way I have bad news for you. Even Smalltalk doesn't have constructors. It just a convention to have a new method on classes themselves (they are singleton objects of meta classes). The Factory Design Pattern is used in many other languages to achieve the same goal.

I read somewhere that concepts of modules in Fortran was inspired by Modula-2. And it seems for me that OOP features are inspired by Oberon-2. There is no constructors in Oberon-2 also. But there is of course pure allocation with predeclared procedure NEW (like ALLOCATE in Fortran, but ALLOCATE is statement). After allocation you can (should in practice) call some initializer, which is just an ordinary method. Nothing special there.

So you can use some sort of factories to initialize objects. It's what you actually did using modules instead of singleton objects. Or it's better to say that they (Java/C#/... programmers) use singleton objects methods instead of ordinary functions due to the lack of the later one (no modules - no way to have ordinary functions, only methods).

Also you can use type-bound SUBROUTINE instead.

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

    IF(i > 0) THEN
      this%x = 1
    ELSE
      this%x = 2
    END IF
  END SUBROUTINE init

END

PROGRAM test

  USE mymod

  TYPE(mytype) :: x

  CALL x%init(1)

END PROGRAM

INTENT(OUT) for this arg of init SUBROUTINE seems to be fine. Because we expect this method to be called only once and right after allocation. Might be a good idea to control that this assumption will not be wrong. To add some boolean flag LOGICAL :: inited to mytype, check if it is .false. and set it to .true. upon first initialization, and do something else on attempt to re-initialization. I definitely remember some thread about it in Google Groups... I can not find it.

like image 125
Wildcat Avatar answered Oct 19 '22 07:10

Wildcat


I consulted my copy of the Fortran 2008 standard. That does allow you to define a generic interface with the same name as a derived type. My compiler (Intel Fortran 11.1) won't compile the code though so I'm left suspecting (without a copy of the 2003 standard to hand) that this is an as-yet-unimplemented feature of the Fortran 2003 standard.

Besides that, there is an error in your program. Your function declaration:

  type(mytype) function init_mytype
    integer, intent(in) :: i

specifies the existence and intent of an argument which is not present in the function specification, which should perhaps be rewritten as:

  type(mytype) function init_mytype(i)
like image 35
High Performance Mark Avatar answered Oct 19 '22 05:10

High Performance Mark