C
C++
リファクタリング
初心者
switch

初心者だけど初心者にswitch文をもっと真っ当に教えてほしい件

More than 1 year has passed since last update.


背景

プログラミングの勉強を始めて半年のペーペーの初心者です。

業務で必要に迫られてレガシーコードのリファクタリングをやったりしてます。

その程度の初心者がC言語の勉強を始めて1週間も経たずに、ポインタなんかよりもswitch文に敵意が湧きました。(なお現在C言語歴2ヶ月程度)

適切に使えばswitchも便利なのかもしれませんが、

なんでもかんでもswitchするコードが多すぎる!!!

もはやプログラミング初心者にswitch文を教えないでおいてほしいとすら思ってきます。

(なお、ここでいう初心者というのはプログラミング初めて1週間とかの初心者、というか入門者を指しますのであしからず)


そもそも論

そもそもプログラム、というか情報処理の基本はif文による条件分岐とfor文による繰り返しであると言えるでしょう。

if文とfor文(と逐次処理)で書けないプログラムはないという話もあります。

初心者にはせめてそのことを教えてあげてください。

そしてまずはif文とfor文による制御文を自由に使えるようにしてあげてください。

間違っても条件分岐の記述についてswitch文から入らないでほしいし、極端なことを言えば(初めは)switch文の使用を禁止するくらいの構えがあってもいいのではないでしょうか。


switchの誘惑

if ~ else if ~ else文は確かに初心者にはとっつきにくい部分があります。

分岐条件を理解するのにいちいち立ち止まって考えなければならないので、もどかしさがあります。

switch文はインデントが揃って見た目もきれいに条件分岐を記述できるので、一見してとてもシンプルに見えます。

加えて、enumとの相性が(あたかも)とても良いように見えるということも、switchの誘惑に拍車をかけている気がします。


初心者が書いてしまうであろうswitch文

では実際に初心者にswitchを教えたらどうなるかを見ていきます。

私が実際にリファクタリングしている、既に製品化されたコードの一部を簡単にして掲載しています。

enum state {

hage,
hige,
huge,
hege,
hoge,
};

int var;
int i = 0;
int j = 100;
int hogehoge_state; // enum stateを条件分岐して代入

/* 中略 */

switch (hogehoge_state) {
case hage:
var = 0;
i++;
j++;
break;
case hige:
var = 1;
i++;
j++;
break;
case huge:
var = 2;
i++;
j++;
break;
case hege:
var = 3;
i++;
j++;
break;
default:
var = 0;
break;
}


switchが便利なのはわかるが、、、

enumやswitchを用いてプログラムの振る舞いを記述するのが一見してわかりやすいというのはたしかに理解できます。

おそらく、上述のコードはC言語歴1時間程度でも動作を理解できることでしょう。

しかし、本当にswitch文で書かれたコードが 「読みやすく」 なっているでしょうか。

さらに言えば 「保守しやすく」 なっているでしょうか。

上述のコードを参考にswitch文の害悪について考察してみましょう。


switchの弱点


  • コピペでコードが書ける、コピペを強要する


    • 個人的には最大の問題点だと思います

    • 上述のサンプルコードが case から break までコピペで書かれたコードであることは想像に難くないでしょう

    • switch文そのものを書き換えない限り、 保守する側にもコピペを強要します

    • コピペの結果、条件分岐や処理が増えるにつれて倍々にコードが増えていきます



  • 状態を全列挙する必要がない


    • サンプルでは case hoge: が記述されておらず default に含まれてしまっています

    • コードを読む側には case hoge:記述されていない意図 がわかりません(バグなのか仕様なのかすら判断できないためコメントなどで補足があるべきでしょう)

    • 意図しないバグの原因になりますし、コードを保守する際にも落とし穴になりえます

    • サンプルコードはたかだか5分岐程度ですが、10も20も条件分岐していたらもはや大混乱です



  • フォールスルー問題


    • 言語によっては break; を抜かすことができてしまいます




ちなみに、if文ならこう書ける

上述のswitch文をリファクタリングしてみましょう。

if (hogehoge_state < hoge) {

var = hogehoge_state;
i++;
j++;
} else {
var = 0;
}

たしかに、if文による条件分岐を読み解くのにswitch文ほどには直感的ではないため、立ち止まって考える必要があるかもしれません。

しかしながら、コピペいらずで、機能も追加しやすく、読む側にも意図が明確に伝わり、圧倒的に保守しやすいコードになっています。


まとめ

Qiitaに投稿したりコメントしたりするレベルの方々にとっては「なんて幼稚な話なんだ」と呆れられることかと思います。

しかしながら、実際にこんなコードでお金をもらっている人々がいるのも事実。

switch文についてググればC言語のみならず実にさまざまな言説を見かけますが、実際にサンプルのようなコードをこれでもかと言うほどにたくさん見ている身としては、安易に

「switch文を使えば条件分岐がわかりやすく記述できる」

などと宣伝して欲しくはないと思わせられる今日この頃です。

もちろん、うまく使えばとても便利なことも承知していますが、メリットデメリットについてきちんと伝えることが大事なのではないでしょうか。

要するに 使い所の問題 だと思うのです。


おまけ

switch文について涙を流しながら参考にするページが時々あります

私はswitch文が嫌い

switchを消すメイキング的な話