引数が変更されているかどうかわからないから明示したい
引数が変更されているかどうかわからないから明示したい
引数が変更されているか追うのが面倒
皆さんはこんな経験ないですか?「この引数って変更されているの?」
いやいや、普通わかるでしょ・・・本当にそうでしょうか?
じゃあ、これは分かるでしょうか。
increment(value);
明らかに、変更していなさそうですよね。
sort
メソッドやsorted
関数のように、非破壊的に見える命名って、結構あります。
でも、実際には中で値を変えているかもしれない。そうなると、関数の中身を見るまで安全かわからないわけです。
これは、リファクタやバグ修正時にとてもやっかいです。
明示したい、書き換えを!
理想はこうです。
- 値が破壊されるときは、そのことを明示してほしい
- 新しく値が返るなら、それも分かりやすくしてほしい
例えばこういうコードがあったとします。
a = sort(a);
これ、sort
が非破壊なら納得です。
でも、もし sort
が中で a
を書き換えていたら・・・危険ですよね?
変数 a
に破壊的な変更が入るなら、見た目でもわかるようにしてほしい。
じゃあ、新しい構文を考えよう!
「破壊されるなら、それを明示したい!」ということで、こんな構文を考えてみました。
sort(a): a;
この : a
の部分がポイントです。
この関数は a を変更しますよと明示しているんです。
戻り値があればこんなふうにも書けます。
c = sort(b): b;
ここでは b
を破壊的に変更して、その結果を c
に代入しています。
もちろん b
に上書きしても構いません。
b = sort(b): b;
: b
があることで、「これは破壊的操作ですよ」とはっきり分かります。
クラスの内部変数を破壊しているときは?
じゃあ、クラスのメンバ変数を変更するメソッドはどう表現すればいいでしょう?
こうします。
obj.:update();
この .:
は、「obj
の内部状態を変更するメソッドですよ」というマークです。
つまり、インスタンスの外から見ると、副作用を持つ処理であることがひと目で分かる。
さらに、どのメンバが変更されるのかも明示したい場合はこうします。
obj.:update(): .:x, .:y;
-
.:x
はobj.x
が変更されることを意味します -
.:y
も同様にobj.y
に破壊的な変更があると分かります
これの良いところは、次のような曖昧さを避けられる点です。
newy = obj.update(): .x .y; // ← これは .x.y に見えるかも?
この場合、.x.y
を参照しているようにも読めてしまいます。
でも、こう書けば一発で「破壊される変数」だと分かります。
newy = obj.:update(): .:x, .:y;
**「これは書き換え対象です」**というだけの意味だと明確になります。
メソッドチェーンでも分かりやすく!
obj
-:> setName("Alice") // 内部を書き換えるメソッド
-:> increment()
-> clone(); // 非破壊的に新しいオブジェクトを返す
->
と -:>
を使い分けることで、破壊的かどうかを簡単に見分けられます。
副作用のある処理をチェーンで見落とすミスも減らせそうです。
🗨️ 追加コメント(C++との比較)
C++では次のように宣言することで、引数が変更されることが分かります。
void sort(std::vector<int>& ary);
この場合、「あ、参照渡しなんだな」と分かるので、呼び出し元で ary
が変更される可能性があると察せます。
ただし、これは関数の宣言を見に行かないと分からないのが問題なんですよね。
もちろん、IDEの補助で多少は楽になりますが、パッとコードを読んだだけでは判断しづらいです。
また、C++では const
を使って「変更不可」を明示できるのは強みです。
void sort(const std::vector<int>& ary); // コンパイルエラーで守れる
これによって、「変更するつもりがないのに変更される」という事故を防げます。
逆に、意図せず変更可能な変数を渡してしまったときに、何の警告もなく変更されてしまうのはちょっと怖いところ。
そういう意味でも、呼び出し側で“この関数は変数を書き換える”と一目で分かる構文があると理想的だなと思います。
🔁 構文の見直し案:明示性と視認性の両立
C++::
と少し被るので「これは破壊される変数ですよ」と明示する目的を保ちつつ、
視覚的に他の記号とかぶらず、直感的にも理解しやすい記号にする案をいくつか考えてみました。(ChatGPTが)
!
を使う
案1:sort(a): !a;
obj.:update(): !x, !y;
強い警告感があり、変更される印象がダイレクトに伝わります。
^
を使う
案2:sort(a): ^a;
obj.:update(): ^x, ^y;
変動・特殊な変数の印象を与え、記号としても比較的珍しいので衝突しにくいです。
~
を使う
案3:sort(a): ~a;
obj.:update(): ~x, ~y;
揮発性や変化を感じさせるが、ビット反転との混同に注意。
mut
)
案4:キーワード方式(sort(a): mut a;
obj.:update(): mut x, mut y;
Rust風の表記。最も明示的で初心者にも伝わりやすいです。
|>
を使う
案5:sort(a) |> a;
obj.:update() |> .:x, .:y;
関数型っぽさがあり、視覚的にも区別しやすい構文です。
✅ 個人的おすすめ
記法 | 見た目 | 意味の直感性 | 他と競合しにくい | コメント | |
---|---|---|---|---|---|
: a |
○ | △ | △(C++と被る) | 現行案 | |
!a |
◎ | ◎ | ○ | 強い印象、視認性高 | |
^a |
◎ | ○ | ○ | 柔らかくシンボリック | |
~a |
○ | △ | △ | ちょっと曖昧 | |
mut a |
◎ | ◎ | ◎ | 最も説明しやすい | |
` | > a` | ◎ | △ | ◎ | 関数型好き向け |
まとめ
- 「変数が変更されるかどうか分からない」問題は現実によくある
- 明示的に破壊を示す構文があると読みやすさ・安全性が向上する
- 破壊される変数は
: x, y
や.:x
などで示すと曖昧さが減る - クラスの状態変更は
-:>
や.:
で明示すると分かりやすい - 記号やキーワードは用途や好みに応じて選べるとさらに良い
「値を変更する」というのは大きな意味を持つ操作です。
だからこそ、それをコード上で明示できる仕組みがもっとあってもいい。
そう思って、こんな構文があったらいいな、という話でした。
まあ、コンパイラ作る人ではないので、考えたところでという感じですが。
作成サポート
- ChatGPT
Discussion