Fortran の final 処理について

暫定メモです。

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

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

http://site.hpfpc.org/home/events/parallel_fortran_sympo3

![6c88594962933a57d47c970a2405b363.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44522/ddddcfb6-f73b-f952-de24-eb4adb6eff59.png)

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

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

https://qiita.com/cure_honey/items/aa477bdf364a0604d416

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 の挙動ももっともな気もします。

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

```fortran
    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 処理は使いにくいと言わざるおえません。便利な機能だと思うのですが。