私は Java でプログラミングをして数年になります。ただし、現在、Fortran をサンプル コード (77 標準) として使用するコースを受講しています。私は常に Fortran を古い言語と見なしてきましたが、gfortran コンパイラーを使用して 2003 標準の最新の実装を試し、そのメリットを自分の目で確かめることにしました。これまでのところ、最新の機能には驚かされましたが、以下の例で示されている 1 つの問題に遭遇しました。
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
これにより、コンパイル エラーが生成されます: 「(1) の引数 'this' の型が一致しません。TYPE(type2) を CLASS(type1) に渡しました」というcall myType2%compute
ステートメントへの参照。
私の問題は範囲の問題です。ステートメントを通じて、class(<class_name>) :: this
コンパイラはサブルーチンを特定の派生型またはその子孫にバインドできるはずです。ここから、コンパイラがサブルーチン内でローカルに開始して の特定のインスタンスの祖先ツリーを上に進む変数定義を検索することは概念的に難しくないようですthis
。this%
これにより、いくつかのステートメントの後で、型にバインドされたプロシージャが読みにくくなる傾向がある明示的なステートメントがすべて削除されます。例えば、
this%tempNew(xI) = this%lamda*this%temp(xI-1)+(1-2*this%lamda)*this%temp(xI)+this%lamda*this%temp(xI+1)
よりも読み取り/書き込み可能性がはるかに低いようです
tempNew(xI) = lamda*temp(xI-1)+(1-2*lamda)*temp(xI)+lamda*temp(xI+1)
後者の場合、class(<class_name>) :: this
各変数をどこにバインドする必要があるかは、ステートメントから明らかです。
もう 1 つの結果は、2 つの別個の派生型が同じ名前のバインドされたサブルーチンを持つことができないように見えることです (エラー メッセージが示すように)。これを回避する 2 つの一般的な方法を見てきました。compute_type1
まず、各サブルーチンをandのように明示的に呼び出しますcompute_type2
。これらのサブルーチンにアクセスすると、コードが非常に見苦しく冗長に見えます。たとえばcall myType1%compute_type1
。2 番目のオプション (たとえばOverloaded fortran interface with different ranks、Type-bound function overloading in Fortran 2003を参照) の方が適切と思われるのは、バインド名とプロシージャ名を区別することです。たとえば、型定義には以下が含まれます。procedure :: compute type => compute_type1
. これにより、サブルーチンにアクセスする際の問題は解決しますが、同じバインディング名を実装する多くの派生型を持つ大規模なプロジェクトを開発する際に問題が発生することがあります。特定のプロジェクトで使用したサブルーチン名と使用していないサブルーチン名を追跡する必要はありません。これにより、名前が非常に長くなり、最終的に読みにくくなる傾向があります。
だから私の質問には3つの要素があります:
this%<var_name>
型バインド プロシージャのクラス メンバーの明示的な型付けに代わる、よりクリーンな方法はありますか?class(<class_name>) :: this
ステートメントに基づいてプロシージャをバインドする必要があることをコンパイラに認識させる方法はありますか? サブルーチン/関数名をオーバーロードする現在の方法は、これらを型にバインドすることを許可していない 90/95 標準のアーティファクトのようです。- そうでない場合、この実装に関連するパフォーマンスの向上はありますか? これらの問題は両方とも、コンパイル時に対処できるように思われますが、表現力を向上させるために喜んで犠牲にします。