LoginSignup
5
1

More than 3 years have passed since last update.

Fortran の final 処理について

Last updated at Posted at 2019-05-06

暫定メモです。

ファイナライザ(デストラクタ)

Fortran 2003 で導入されたオブジェクト指向の仕様のなかに、オブジェクト解放時のの自動呼出し処理としてのファイナライザ(いわゆるデストラクタ)があります。

Modern Fortran Explained の著者の一人マルコム・コーエンが、日本で行った講演の中で、Fortran 2003 ではその仕様に問題があって Fortran 2008 で修正したと述べております。

6c88594962933a57d47c970a2405b363.png

どこをどう変えたのか調べようと思いつつサボって、私はちょっと把握していません(笑)。 いずれにせよ、仕様が複雑で使い方が難しいと指摘されています。

実際、final 処理の挙動が、派生型変数間の代入時に intel fortran と gfortran で異なることを先に見ました。

ISO Fortran 2008 の規格によれば生の代入文では右辺の式が評価された後に、左辺の変数のファイナライズ処理が行われるとあるので、gfortran の挙動は規格にのっとっていないのではないかと思われました。

参考:ISO Fortran 2008 ドラフト
https://j3-fortran.org/doc/year/10/10-007.pdf
4.5.6.3 When finalization occurs

9 When an intrinsic assignment statement is executed, the variable is finalized after evaluation of expr and before the definition of the variable.

ここでは、また別の例を見てみることにします。

子孫型から先祖型への代入

オブジェクト指向では、派生型の拡張 (extension) で要素成分が増えて大きくなった型からベースとなったより小さい型への代入が出来ます。(継承により生じた子孫型から先祖の型の変数への代入)

大きいものが小さいものに入るのは変な気がしますが、これは暗黙裡に成分の射影が取られて、射影成分が代入されているものと考えられるかと思います。(代入演算子『 = 』は本来は適切ではなく、ディラック的な記号での射影演算子 P の付いた『 =P 』あるいは『 =|P><P| 』と考えられる?)

しかしながら、この場合も代入時のファイナライザ処理が絡んでくるので、代入される変数側でファイナライザ処理が行われるならば、素朴な射影による要素代入イメージは適切ではないかもしれません。

そうして、ここでも intel fortran と gfortran で挙動が違っています。上記の場合と同様 intel fortran はファイナライザを呼び出しますが、gfortran はファイナライザ呼び出さず要素成分の代入処理だけを行います。

規格によれば、代入なので intel fortran の挙動が正しい気がしますが、成分射影のイメージからすれば gfortran の挙動ももっともな気もします。

プログラム例

子孫型変数を先祖型変数に代入する。この時、先祖型は再割り付けされることなく、先祖型のまま、子孫型変数中の先祖型の成分が射影され代入される。

    module m_mod
        implicit none
        type :: t_base
            integer :: ix
        contains
            final :: fin_b
        end type t_base

        type, extends(t_base) :: t_ext
            integer :: iy
        contains    
            final :: fin_e     
        end type t_ext

    contains

       subroutine fin_b(this)
            type(t_base), intent(in) :: this
            print *, 'final:: t_base', this%ix
        end subroutine fin_b    

        subroutine fin_e(this)
            type(t_ext), intent(in) :: this
            print *, 'final:: t_ext ', this%ix, this%iy
        end subroutine fin_e 
    end module m_mod


    program Console6
        use m_mod
        implicit none

        class(t_base), allocatable :: tx
        type (t_ext ), allocatable :: ty

        tx = t_base(1)
        ty = t_ext(2, 3)
        print *, tx%ix                ! 1
        print *, ty%ix, ty%iy         ! 2, 3
        print *, '****************************'

        tx = ty
        print *, tx%ix                 ! 2
!        print *, tx%ix, tx%iy ! error

    end program Console6

実行結果

intel fortran v.19

           1
           2           3
 ****************************
 final:: t_base           1
           2

gofortran v.7.1.1

           1
           2           3
 ****************************
           2

結論

このように、比較的単純な代入操作でも処理系ごとの挙動が異なり、脳内イメージともしっくりこないとなると、確かに final 処理は使いにくいと言わざるおえません。便利な機能だと思うのですが。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1