Edited at

2018-08-23 C++ > デフォルト引数 > 使わない理由(ソースリーディングの観点から)


動作環境

C++ Builder XE4



デフォルト引数

自分が使うC++ Builderなどで「デフォルト引数」「デフォルトパラメータ」という機能があります (以下、デフォルト引数と呼びます)。

関数の引数の初期値を関数宣言部で指定しておくことで、関数コール部分で指定する必要がない機能と認識しています。

デフォルト引数を使った実装を読むなかで、自分が「読むのに手間がかかる」と感じた経験から、デフォルト引数を使わないようにしています。


例として、様々なセンサーを初期化する処理を上げてみます。

様々なセンサーに対して、通信速度(bps)をそれぞれ自由に設定できる場合とします。

そのコードに対して「それぞれのセンサーの通信速度は何か?」を確認するソースリーディングを考えてみます。


デフォルト引数を使わない場合

void initDevices()

{
// 初期化(通信速度bps)
initDHT22(1200);
initRHT03(2400);
initSi7021(1200);
initTMP104(2400);
...
}

上記のコードの場合、initDevices()を見た時点で「それぞれのセンサーの通信速度は何か?」を確認できます。

2-3秒で全てのセンサーの設定を確認できるでしょう。


デフォルト引数を(一部)使った場合

void initDevices()

{
// 初期化(通信速度bps)
initDHT22();
initRHT03();
initSi7021(1200);
initTMP104(2400);
...
}

上記の場合、「DHT22とRHT03のデフォルト引数の値は何か?」という疑問を持ちます。

それらを知るためにはヘッダーの宣言をgrepで検索するか、IDEの関数引数ポップアップ機能などを使います。

ヘッダーを確認する場合でも、ポップアップで確認する場合でも、それぞれ「一つの関数ごと」にしか確認できません。

10個のセンサーを初期化する処理をinitDevices()で行う場合、一つの確認に2秒かかるとする(*1)と最大20秒の時間を通信速度を見るために使うことになります。

この作業を自分は「ソースリーディングを中断する」と考えています。

*1) F1などのキー入力、ポップアップの表示、ポップアップの消失時間の合計


短期記憶の容量 (mental juggling, mental baggage)

人の短期記憶の容量は7±2と言われることがあります。

10個の通信速度デフォルト引数の値を短期記憶に格納するのは7+2を超えます。また、短期記憶の項目が増えることは、Code Completeの「mental juggling」(やThe Art of Redable codeの「mental baggage」)になります。


ソースは書くよりも読まれる方が多い

@ プログラマが知るべき97のこと by Kevlin Henney

コードレイアウトの重要性 by Steve Freeman


プログラマは仕事の時間を、実際にコードをタイプすることよりも、コードを探すことと読むことに費やしている、そんな調査結果もあるようです。


僕自身、実際にソフトウェアをメンテナンスする中で、読む方が多いと経験しています。

読む方が多いコードに対して、「デフォルト引数を使うことは有効なのだろうか?」と疑問を持ちつづけました。そして、上記の理由から、2018年8月現在の自分の考えでは「使わない方がコードを読みやすい」という考えです。


備考

記事執筆者の記憶力はあまりよくありません。短期記憶は5かもしれません。

そういう人でも読みやすいソースコードは何か、を日々考えています。

C++のtemplateやoverloadをうまく使うことで「それぞれのセンサーの通信速度は何か?」を複数台(例:10台)に対して2-3秒で一覧する方法があれば、知りたいと思います。

また、デフォルト引数を使うことで、ソースリーディングはこのように効率化する、ということがあれば知りたいと考えています。

注記: 記事執筆時点の考えなので、もっと良い方法があれば、考え方を反転することもあります。