関数といえば、プログラミングにおいては、なんらかの仕事をする「機械」のようなものであり、C#上だとメソッドとも言われます。
関数とはコードを部品化、あるいはモジュール化して再利用しやすくするためのものだ、というような説明がなされます。それはその通りなのですが、初心者からすれば、コードを書いた経験もないので、再利用による恩恵が実感できず、結果的に関数というものの存在意義が掴みづらいのではないのか?と思います。(自分がそうでした。)
久々の投稿になりますが、リハビリも兼ねて、今回はプログラミングの基本的な部分である「関数」について、書いてみたいと思います。
数学の関数とは違う?
まず名前がややこしいですよね。数学における関数というのは、y = 2xみたいなもので、一定の処理をする計算式です。
プログラミングは究極的には、計算の集合ではあるので、一定の仕事をするコードを関数というのは間違ってはいないと思います。しかし、文脈上のニュアンスが異なるということを、初心者は気をつけるべきです。
では本題に入っていきます。
名前をつけることの重さ
名は体をなす。という言葉があります。名前というものはプログラミングに限らず、実際、とても重要なものです。名前にこそ魂が宿る、という考えもありますよね。
と同時に、いかなる名前を付けるべきか?という問題も存在します。そのモノの本質を表すような名前をつけなければいけないからです。
プログラミングにおいても、この「名前付け」こそ、もっとも重要で困難な作業であったりします。可読性や、コードの働きへの認識に大きな影響を与えるからです。
「処理」に名前をつける。
プログラムはなんらかの問題を解決するための「処理」の集合体とも言えます。複数の「処理」を積み重ねることにより、大きな「処理」をしている、ということです。(実際には、クラスも分割の単位にいれるべきですが、ここでは省略します。)
小さな処理もまたより細かい「処理」により、構成されています。もっとも小さな処理の一単位を一行のコード、実行文とします。
つまり、関数とは一定の処理をする、複数行のコードに対して、名前を与えて、まとめあげるためのものだということです。一言で言うならば、ある処理を抽象化するもの、ということになります。
抽象化とは?
プログラミングにおける抽象化とは、人間の考え方、認識の仕方に近づける、ということです。
つまりは、物事を漠然と捉える、余計な細かいことは気にしない、ということになります。
プログラミング言語というのは、人間のためのものであり、人間が読みやすいように書かれるべきですが、それは人間側の都合です。
コンピュータ側の都合で、コードは必ずしも人間に分かりやすいものではないかもしれません。例えば、次のようなコードがあります。
int numMAX = array[0];
for(int i = 1; i < array.Length; i++)
if( array[i] > numMAX)
numMAX = array[i];
これは整数の配列(集合)の最大値を見つけるための処理です。つまり、やっていることをそのまま名前にして、関数化してしまえばいいんです。
つまり・・・
int FindMAXinArray(int[] array){
int numMAX = array[0];
for(int i = 1; i < array.Length; i++){
if( array[i] > numMAX)
numMAX = array[i];
}
return numMAX;
}
FindMAXinArray(配列の最大値を見つける)、というストレートな名前ですが、これで具体的にどんな細かい処理をやっているかを無視して、どんな目的のことをやっているかにだけ注目できます。
つまり、人間の認識、思考能力には限界があるので、目の前に出される情報量を制限しよう、というのが抽象化であり、そのための手段に関数があるということになります。(より高度な抽象化のためのツールとして、「クラス」があります。)
細かいことを意識から外すことで、より高度なことが出来るのが人間、ということになるかと思います。(細かいことを正確に早く出来るのがコンピュータ)
再利用よりも抽象化
再利用という考え方は大事ですが、再利用というのは関数化したことによる結果論であり、再利用を前提としなくとも、関数化した方がよい場合もあります。
自身の経験談としても、抽象化するために関数を作る、という風に意識を変えていった頃から、コードをより良く書けるようになった記憶があります。つまり、必要な処理がどんなものかを考え、先にその処理の名前を考える、というプロセスです。
再利用するかもしれないし、するかもしれない。たくさん再利用するかもしれないし、二回しかしないかもしれない。そんなあやふやなメリットを強調するよりも、こっちの方がより分かりやすいのではないかと思います。(もちろんコード全体に散らばる重複部分を関数化するというのも、立派な再利用の恩恵といえますが。これはリファクタリングの範疇ですかね?)
まとめ!
というわけで、今回は関数というものについて書きました。何らかの処理に対して、適切な名前を授ける、という意識で関数を作る、という考え方の方が初心者にとっても、分かりやすいんではないか?という主張でした。