はじめに
最近はVBでもPythonみたいに関数内に関数を定義できねーかなぁと考えている弊社です。
あと、出来ればVBでもカリー化関数を扱いたい。 もっとカジュアルに関数を扱いたいのでMicrosoftさんオナシャス。
とまぁ、儚い夢を願ったところで本題です。 VBには3項演算子*1と3項演算子っぽい何かがあるのは生産性アプリケーションを書いている皆さんには常識的な事だと思います。
旧来からある(らしい)IIf関数と割と新顔(らしい)*2If演算子の二つです。
まぁ、関数ってある時点で色々と察しがつくのですが、とりあえずmsdnを見てみましょう。
If 演算子 (Visual Basic) | Microsoft Docs
IfとIIfの違いは上のリンク内に書いてあるので使い方の説明は割愛します。
Let's IL
Dim result = IIf(True, a(), b())
IIfの実態はMicrosoft.VisualBasic.Interactionに属する3項演算子っぽい働きをする関数です。
よって関数の呼び出し前に3つの式が評価されてからIIfが呼ばれます。
.maxstack 3
.locals init ([0] object result)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: call int32 SectionOperator.Module1::a()
IL_0007: box [mscorlib]System.Int32
IL_000c: call int32 SectionOperator.Module1::b()
IL_0011: box [mscorlib]System.Int32
IL_0016: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool,
object,
object)
IL_001b: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
IL_0020: stloc.0
IL_0021: nop
IL_0022: ret
resultにはa()の返り値が格納されますが、IIf呼び出し前にa()とb()の両方が呼び出さています。
なのでa()やb()などに副作用がある場合は予想に反する動きをして戸惑うかもしれません。
また、IIfは返り値がIIf(bool, object, object) -> objectなのでOption Strict Onとはキャストのオンパレードとなり相性が悪いと思います。
Dim result = If(True, a(), b())
.maxstack 1 .locals init ([0] int32 result) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: brtrue.s IL_000b IL_0004: call int32 SectionOperator.Module1::b() IL_0009: br.s IL_0010 IL_000b: call int32 SectionOperator.Module1::a() IL_0010: stloc.0 IL_0011: nop IL_0012: ret
If演算子では条件によってどちらか一方しか評価されません。
また、IIfのように明示的にキャストする必要もないのでこちらの方が便利ですね。
まとめ
以上のことから今のご時世IIfを使うメリットはほぼ無いと思います。
むしろIIfを使い必ず副作用を発生させないといけないような設計をしている場合は今すぐ改めるべきです。
おわり