読者です 読者をやめる 読者になる 読者になる
ようこそ。睡眠不足なプログラマのチラ裏です。

いまさらですが、VB.NETで「関数名に代入的な記法」で戻り値を決定するのが“やっぱりキモい”件。

プログラミング VB.NET C# Delphi 雑談

ハイクの方で書いたネタですが、結構おもしろいネタだったので、
加筆修正などしてこちらにも投下しておきます。


なんぞこの記法。VBがマゾ言語と言われる由縁のひとつがこれだ。

VBおよびVB.NETでは下記のような感じで関数を記述することができる。
(VB.NETでは新たにReturnによって戻り値を返すことも可能)

Sub Main()
  Debug.Print(Hoge(False))
  Debug.Print(Hoge(True))
End Sub
Function Hoge(ByVal fuga As Boolean) As String
  Hoge = "hoge"
  If fuga Then
    Hoge = "fuga"
    Exit Function
  End If
End Function


生粋のVBプログラマだった自分が言うのもなんだが、VB.NETでこれやられると流石にキモい。
この関数名に代入的な記法は、どうも行儀がよくないと思う。
たぶん普通の「行儀の良い人」ならやらないと思うが、VB.NET(VB9以降)の場合、
関数名に対して拡張メソッドを呼び出すこともできてしまったりするから、更に行儀が悪い。
コードの可読性の低下を招くとともに、バグの温床となる臭いがぷんぷんします。


VB6までは関数名に代入的な記法でのみ、関数の戻り値を決定していました。
しかし、それを全く新しい言語に生まれ変わったVB.NETでまでサポートする必要はあったのだろうか。
(プロパティのgetterもプロパティ名に代入的な記法が可能ってのも・・)


GoSub〜Return構文の存在
VB6までは、そのご先祖様であるQuickBASICとかその他のBASIC言語と同じように、
下記のような「GoSub〜Return」構文がサポートされていました。

Private Sub Main()
  Call Test
End Sub

Private Sub Test()
  Debug.Print("開始")
  GoSub hoge
  Debug.Print("終了")
  Exit Sub
hoge:
  Debug.Print ("サブちゃんだよ!")
  Return
End Sub


この構文を使うと、GoSubのところで継続位置が記憶され、hogeへジャンプし、
Returnで記憶したGoSub位置からまた処理が継続されて、上記のプログラムでは

開始
サブちゃんだよ!
終了


と出力されます。


これは古来からあるBASIC言語の名残のレガシー機能であり、構造化プログラミングの構文とはかけ離れたものです。
確かにVB6までもサポートされていましたが、そもそもVBでは構造化プログラミングをサポートしているので、
VBの時点でこの構文は既に不必要なものでした。なのでこの「GoSub〜Return」構文の存在を知らないVBプログラマも多いかもしれません。


関数名に代入的記法はVB.NETにも本当に必要だったのでしょうか?
VB.NET設計者は.NETファミリ言語として、VB.NETC#と同系統のオブジェクト指向言語にすることを目指しました。
そして、非直観的で整合性を乱すような「GoSub〜Return」構文などのレガシー機能の一部をサポートをしないことに決定しました。
その代わりに、Returnに別の意味を持たせました。「関数名に代入的な記法」に代わるC系言語でお馴染みのやつです。


VB6まではReturnは別の意味(GoSubで記憶した位置に戻る)で使われていましたが、VB.NETではそれが変わったのです。
つまり、この決定が下されたタイミングで「関数名に代入的な記法」は事実上不必要となったと言えます。
にもかかわらず、なぜVB.NET設計者はこの関数名に代入的な記法を残したのでしょう。不思議です。
もちろん、マイグレーション的な意味で残したであろうことは想像に難しくありませんが、
中途半端に残されたレガシー機能であること。可読性も低下しバグの温床となりやすいこと。
IL(中間コード)に落とされたときに最適化されず、余計なコードが吐かれる(暗黙的に変数が宣言されるなど)のでパフォーマンスが低下すること。
などの様々な観点からみて、VB.NETの設計「どうしてこうなった」感がぬぐいきれません。
私が設計者だとしたら、思い切って「関数名に代入的な記法」はすっぱり切り捨てたと思う。
だから関数名に代入的な記法で戻り値を決定する仕様がVB.NETに残されたことは、とても「キモい」と思うし、それを使う行為もまた「キモい」。



マイクロソフト的にも、関数名に代入の記法は使わないでねという指針が示されています。
(だったらサポートすんなって言いたい。もしくはオプションで警告またはエラーにできるとか。)


以下のあたりが参考になると思われます。
VB 6.0 ユーザーのための VB .NET 移行ガイド - プロシージャ
http://msdn.microsoft.com/ja-jp/library/dd297703.aspx


VB 6.0 ユーザーのための VB .NET 移行ガイド - レガシー機能
http://msdn.microsoft.com/ja-jp/library/dd297708.aspx



ということで、VB.NETではこの「関数名に代入的な記法」は使うべきではありません。
マイグレーションの場合、規模によっては工数的な問題で適用が難しく仕方なく目をつぶる・・ことはあるとして(本当はつぶっちゃダメだよ!)。
新規プロジェクトであればVB.NETで「関数名に代入的な記法」はコーディング規約で禁止するなり、
コードレビューなどで精査して、断固禁止とすべきでしょう。ちゃんとしたところでは、そうしていますよ。


ちなみに

過去にDelphiを2年ほど使ってましたが、Pascal系のResult代入な記法も似たような感じで私はきもく感じました。
まぁそれ以前に「begin〜end」が目障りすぎだろうという噂もありますがw