デフォルト引数の問題

関数をコールする際、引数を省略してコールできる機能をもつ言語が多く存在する。

ここでは、その機能を「デフォルト引数」と呼ぶ。

デフォルト引数の例として、Lua のサンプルを次に示す。

1
2
3
4
local function func( x, y )
  print( x, y )
end
func( "abc" ) // abc nil

Lua では関数コール時に省略された引数は、 nil として処理される。 上記の func( "abc" ) は、引数 x, y のうち y が省略され、 実行すると abc nil が表示される。

デフォルト引数は、引数が多い関数を呼び出す際に有効な機能である。 特に Lua は、引数の違いによって実行する関数を切り替える関数オーバーロードがないため、 デフォルト引数は良く使われる機能の一つである。

しかし、デフォルト引数は便利である一方、不具合を発生させるリスクにもなる。

そのリスクとは、意図してデフォルト引数を使用しているのか、 それとも、本来指定すべき引数を指定し忘れているのか、を判断出来ないということである。 タイプミス等で関数に渡す引数を間違えることが良くある。 それを判断できないというのはリスクが高い。

Lua の トランスコンパイラである LuneScript でも、同じ問題を抱えている。

次は LuneScript のデフォルト引数のサンプルである。

1
2
3
4
5
6
7
8
9
fn func( val: int! ): int {
   when! val {
      return val + 1;
   }
   return 0;
}
print( func( 1 ) );   // 2
print( func( nil ) ); // 0
print( func() );      // 0

このサンプルは、デフォルト引数を持つ func() の関数呼び出しを 3 パターン行なっている。

  • func( 1 )
  • func( nil )
  • func()

LuneScript は Lua と同じで、引数が省略されると nil が指定される。 よって、 func( nil )func() は同義である。 しかし、 func() が引数の指定忘れではないと、誰が保証できるだろうか?

また、 LuneScript では nilable は必ず省略可能なデフォルト引数になってしまう。

デフォルト引数をサポートする多くの言語では、 デフォルト引数はデフォルト値を定義する必要がある。 一方 LuneScript では、nilable は必ずデフォルト引数になってしまう。

「nil の時でも省略せずに明示すべき」としたくても、 現在の言語仕様ではそれが出来ない。

この辺りを解決する方法を検討している。

ただこれを解決するには、現状の言語仕様との互換を持たせるのは難しいかもしれない。