Question

I've been programming in Java for a few years; however, I'm now taking a course which uses Fortran as example code (77 standard). Although I've always viewed Fortran as an ancient language, I decided to try out the latest implementation of the 2003 standard using the gfortran compiler to see its merits for myself. So far, I've been surprised with the modern features, but I have run into one issue which is demonstrated by the example below.

    module mod1
      type type1
        real :: x
        real :: y
        contains
        procedure :: compute
      end type type1
      contains
      subroutine compute(this)
        class(type1) :: this
        this%y = this%x*2 - 1
        write (*,*) this%x,this%y
      end subroutine
    end module mod1

    module mod2
      type type2
        real :: x
        real :: y
        contains
        procedure :: compute
      end type type2 
      contains
      subroutine compute(this)
        class(type2) :: this
        this%y = this%x - 5
        write (*,*) this%x,this%y
      end subroutine
    end module mod2

    program test
      use mod1
      use mod2
      implicit none
      type(type1) myType1
      type(type2) myType2
      myType1%x = 4
      myType2%x = 5
      call myType1%compute
      call myType2%compute
    end program test

This produces the compile error: "Type mismatch in argument 'this' at (1); passed TYPE(type2) to CLASS(type1)" in reference to the call myType2%compute statement.

My issue is that of scope. It seems that, through the class(<class_name>) :: this statement, the compiler should be able to bind the subroutine to a specific derived type or its descendants. From here, it doesn't seem conceptually difficult for the compiler to search for a variable definition starting locally in the subroutine then proceeding up the ancestry tree of the specific instance of this. This would eliminate all the explicit this% statements which tend to make my type-bound procedures difficult to read after several statements. For example,

    this%tempNew(xI) = this%lamda*this%temp(xI-1)+(1-2*this%lamda)*this%temp(xI)+this%lamda*this%temp(xI+1)

seems to be much less read/writeable than

    tempNew(xI) = lamda*temp(xI-1)+(1-2*lamda)*temp(xI)+lamda*temp(xI+1)

In the latter case, it is fairly obvious through the class(<class_name>) :: this statement, where each variable should be bound.

The other consequence is that it appears that two separate derived types cannot have bound subroutines of the same name (as shown by the error message). I've seen two common ways around this. First is to explicitly call each subroutine something like compute_type1 and compute_type2. When accessing these subroutines, this looks very ugly and redundant in code. For example call myType1%compute_type1. The second option, (see for example Overloaded fortran interface with different ranks, Type-bound function overloading in Fortran 2003) which seems better, is to differentiate the binding name and the procedure name. For example, the type definition would include procedure :: compute type => compute_type1. This resolves the issue when accessing the subroutine, but I can see issues when developing large projects with many derived types which implement the same binding name. I'd rather not have to keep track of which subroutine names I have and haven't used in any given project. This would tend to keep names quite long and less readable in the end.

So my question has 3 components:

  • Are there cleaner alternatives to the explicit typing of this%<var_name> for class members in type-bound procedures?
  • Is there any way to have the compiler recognize that a procedure should be bound based on the class(<class_name>) :: this statement? The current methods of overloading subroutine/function names seem to be an artifact of the 90/95 standard which did not allow these to be bound to types.
  • If not, is there some performance gain associated with this implementation? Both of these issues seem like they could be addressed at compile time, which I would gladly sacrifice for the improved power of expression.
Was it helpful?

Solution

This is more of an extended comment, but it appears that you're being forced to speculate because of a compiler failing. I've compiled the code with gfortran 4.8.3 without error, and with the expected result. Also, it seems to me that what you want to happen should happen.

The other consequence is that it appears that two separate derived types cannot have bound subroutines of the same name (as shown by the error message).

While both subroutines are called compute they are in separate modules and this is allowed, although your use statements make a call compute(...) (which you aren't doing) ambiguous. If the type definitions were in the same module then you would have to resort to the procedure :: compute => compute_typex trick, but call mytype1%compute would still be acceptable.

I would recommend that if you're exposing the compute subroutines through the type-binding then you have them as private in the module, or at the very least, don't explicitly use them. [That is, have use mod1, only : type1.]

As for whether you're stuck with type%... in the subroutines, then yes, I think you are. That said, under Fortran 2008 there is the associate construct

subroutine compute(this)
  class(type1), intent(inout) :: this
  associate (x => this%x, y => this%y)
    ...
  end associate
end subroutine

but that doesn't gain much in this case. And there are other terrible tricks which I won't detail.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top