これは何ですか?
汎用プログラミングとは、データ形式に依存しないコンピュータ・プログラミングのことです。
関数の多重定義(Overloading)は、テンプレート無しでも、身近に、汎用プログラミングを実現できる方法です。
関数型(またはモジュール型)のプログラミングは、値に注目しますが、汎用プログラミングは、
型 に注目します。
渡された引数の型に基づいて、同様の関数が呼ばれます。
関数の多重定義は、汎用プログラミングへの脇道です。
一つの関数名(関数識別子)を、さまざまな異なる型で使える、さまざまな関数に関連付けることができます。
そして、クライアント(あなた)は、その関数名を使えるようになります。
簡単に言うと、関数の多重定義は、同じ名前で、しかし、異なった
署名を持っている関数を定義できることです。
関数の署名は、関数を正しく参照するために必要なすべての情報の組み合わせで、関数の引数リストと戻り値の型が含まれています。
これらが、私たちが再定義する、つまり多重定義するものです。
簡単な例で、始めましょう。
数値の文字列表現を出力する関数が必要だとします。
下のプログラムを参照下さい。
#lang "fblite"
Option Explicit '' 変数の明示宣言を強制します
Option ByVal '' 値渡しの規則を、デフォルトとします
'' 関数が同じでも、異なった引数型を受け入れる関数を宣言するために、
'' 私たちは'単に'新しい関数名を作成します :(
Declare Function print_byte( As Byte ) '' stringified バイト出力する
Declare Function print_short( As Short ) '' stringified short を出力する
Dim As Byte b = 102
Dim As Short s = 10240
print_byte
( b )
print_short
( s )
Sleep :
End 0
'' 関数定義を、短縮して一行にまとめています。
'' - スペースが圧迫されているチュートリアル以外では、こういう書きかたをしないでください ;}
Function print_byte( n As Byte ) :
Print Str( n ) :
Return :
End Function
Function print_short( n As Short ) :
Print Str( n ) :
Return :
End Function
これは私のために何をしますか?
上の例の問題は、2つの異なる関数署名があるだけでなく、2つの異なる
関数名 があるということです。
私たち (コンパイラーではなくて) は、必要な関数を呼び出すために、両方の
関数名 を覚えておく必要があります。
ご想像のとおり、あなたがさらに INTEGER、SINGLE、DOUBLE もサポートしたいとしたら、これはかなり混乱することになるでしょう。
さらに、完全を期すために、これらの各バージョンで、符号付きと符号なしの両方を考慮した関数が必要になるかもしれません。
明らかに、これを自分で簡単にするために、なんらかの命名構想を考える必要があります。
もちろん、あなた独自の TYPE もサポートしたいでしょう。
そして、 - ああ少し待って下さい。我々はポインターのことを忘れていました。
では、関数名のリストを思いつく2倍にする必要があるだけでなく、これらの関数を使うコードを実際に作成するときに、これらを覚えておく必要があります。
結局、あなたは、あなたにが利用できる(強要される)暗黙の変換をします。そして、コンパイラは、幸いなことに、print_integer 関数に、DOUBLE をつけ加えることができるでしょう。 - おっと!
バグ-都市、ここに、私たちは来ました!
きっと、もっと良い方法があるに違いありません?
あります。そして、私を Shirley と呼ばないでください。(映画「
フライング・ハイ」(原題"Airplane!")の台詞)
私は、上で、コンパイラは、関数の署名として、2つの主要な構成要素「引数リストと、戻り値の型」を使う、と述べました。
私は、また、多重定義により、署名が異なる複数の関数を定義して、それらのすべてで、同じ関数名を使うことができる、と述べました。
あなたは、これが、私たちのジレンマ、複雑な名前空間などから抜け出す方法だと思うかも知れません。
そうです。あなたは正しいです。- 下のプログラムを試してください:
#lang "fblite"
Option Explicit '' 変数の明示宣言を強制します
Option ByVal '' 値渡しの規則を、デフォルトとします
'' 関数 print_numeric を多重定義します。
'' 関数名前をそのままにして、異なる引数型を受け入れるように再定義できます。
'' 我たちは、最初の関数で、OVERLOAD キーワードを使います
Declare Function print_numeric Overload( As Byte ) '' stringified byte を出力
Declare Function print_numeric( As Short ) '' stringified short を出力
Declare Function print_numeric( As Integer ) '' stringified integer を出力
Declare Function print_numeric( As LongInt ) '' stringified longint を出力
'' いくつかの変数を定義します
Dim As Byte b = 102
Dim As Short s = 10240
Dim As Integer i = 1024000000
Dim As LongInt li = 1024000000000000000
'' 関数多重定義の素晴らしい世界に入ります :)
print_numeric
( b )
print_numeric
( s )
print_numeric
( i )
print_numeric
( li )
Sleep :
End 0
'' 私たちの関数多重を定義します
Function print_numeric( n As Byte ) :
Print Str( n ) :
Return :
End Function
Function print_numeric( n As Short ) :
Print Str( n ) :
Return :
End Function
Function print_numeric( n As Integer ) :
Print Str( n ) :
Return :
End Function
Function print_numeric( n As LongInt ) :
Print Str( n ) :
Return :
End Function
これは何を意味しますか?
すぐに分かる 1つは、この方法が、信じられないほど簡単に実現していることです。
自由、柔軟性、
type-safety を考えると、これは奇妙に見えるかもしれません。
しかし、それでも、ほとんどの、高レベルの構造物は、このようなものです。
簡単に言えば、このメソッドを使うと、あなたの作業が非常に簡単になるだけでなく、デバッグの時間を減らすことができます。
そして、あなたがどのような種類のコードを書いてもよいことです。
これは
柔軟性を意味します。
関数の多重定義は、現在のコードをそのまま維持しながら、より多くの機能 (print_numeric (f as fraction)) を加える能力を提供します。
ハンカチや鎧などの数値表現の出力をサポートしたいだけなので、コードは壊れません。
あなたは今、上のコードはそれほど簡単ではないと考えているかもしれませんが、本当にシンプルだから簡単に見えるのは、より良いコードを書くための基礎です。
あなたは正しいでしょう。
これは
保守性を意味します:
そのとおり、あなたは、作成されてデバッグ済の、"使いたいときに、毎回参照しなければならない、長い名前を出力する" 、という 80 の関数を手に入れたのです。
あなたの小さな苦痛で自己嫌悪する世界では、すべてが素晴らしい。
何か変更する必要があるときは、どうなりますか?
たとえ、これらの関数の 1つでも変更する必要があっても、BAM !
保守管理の悪夢。
あなたは、全体のコードベースを捜さなければならないでしょう。ここそこで、関数を修正もれしていないのを
完全に確信できるようにするためです。
土曜日の夜を過ごすための嘆かわしい方法で、私の友人がそうです。
これは
安全を意味します:
この例で、下の 2 つのオプションを利用していることに気付くでしょう:
OPTION EXPLICIT と
OPTION BYVAL。
渡辺注:fb のデフォルトなので、fb では不要です。
私は安全を大事にしているし、コンパイラに背中を見守ってもらっています。
上の 2 つのオプションを使うと、より安全なので、私はこれらを使います。私は利用できる、すべての安全策を取るつもりです。
関数の多重定義もまた、あなたに安全を提供します。 - 不吉な(偶然の読み取り)暗黙の変換に対する安全です。
これらの関数が、実際に値を返したかどうか考えてください。値は、我々が関数に渡した引数に依存しています。
上では、ダブルが、私たちが知らないうちに頭を切り捨てられてしまうならば、そのデバッグの頭痛を癒すエクセドリン(鎮痛解熱剤)の錠剤がたくさん必要になることを、意味します。
それは型の安全性の全てです。多くの人々が C
pp(C Preprocessor) をあざ笑うところです。
まとめ
あなたは、少なくとも関数の多重定義の基礎 (それが私がカバーしたすべてです) を学んだことを願っています。
そして、私が提示したテーマについて、これまで考えたことが無かったなら、考え始めることを願っています。
次回は、私は、引数の数が異なり、戻り値型が異なる、多重定義関数について、議論するつもりです。面白さと落とし穴の両方も含めて。乞うご期待。
sancho3 が、2018年2月8日 に修正しました。