Smart::Args::TypeTinyには, default と optional というパラメータがあります.
default
default は, 引数が渡らなかった時のデフォルト値を指定するパラメータです.
use strict; use warnings; use feature qw(say); use Smart::Args::TypeTiny qw(args); sub test { args my $arg => { isa => 'Str', default => 'bar' }; return $arg // 'undef'; } say test(arg => 'foo'); # => 'foo' say test(); # => 'bar' ( default が使われる ) say test(arg => undef); # => Type check failed in binding to parameter '$arg'; Undef did not pass type constraint "Str" (エラー)
なお, isa が Maybe の場合はこうなります:
use strict; use warnings; use feature qw(say); use Smart::Args::TypeTiny qw(args); sub test { args my $arg => { isa => 'Maybe[Str]', default => 'bar' }; return $arg // 'undef'; } say test(arg => 'foo'); # => 'foo' say test(); # => 'bar' say test(arg => undef); # => 'undef'
まとめると, default のパラメータがあるときは,
- 引数として
undef以外を渡す ... 渡した値が使われる (isaを満たさない場合は当然エラーになる) - 引数を渡さない ...
defaultが使われる - 引数として
undefを渡すisaがMaybeである ...undefがそのまま使われる (defaultは使われない)isaがMaybeでない ...isaを満たさないのでエラーになる
...という挙動になります.
optional
一方, optional はその名の通り, オプショナルであることを指定するパラメータです.
use strict; use warnings; use feature qw(say); use Smart::Args::TypeTiny qw(args); sub test { args my $arg => { isa => 'Str', optional => 1 }; return $arg // 'undef'; } say test(arg => 'foo'); # => 'foo' say test(); # => 'undef' (`optional` なので引数を渡さなくても問題ない. その場合は undef となる) say test(arg => undef); # => 'undef' (明示的に引数として`undef`を渡しても問題ない)
まとめると, optional のパラメータがあるときは,
- 引数として
undef以外を渡す ... 渡した値が使われる (isaを満たさない場合は当然エラーになる) - 引数を渡さない ... エラーにならず,
undefとして扱われる - 引数として
undefを渡す ... (isaを満たしていなくても)エラーにならず, そのままundefとして扱われる
defaultとoptional
では, defaultとoptionalのどちらも指定した場合はどうなるでしょうか.
use strict; use warnings; use feature qw(say); use Smart::Args::TypeTiny qw(args); sub test { args my $arg => { isa => 'Str', optional => 1, default => 'bar' }; return $arg // 'undef'; } say test(arg => 'foo'); # => 'foo' say test(); # => 'bar' (`optional` なので引数を渡さなくても問題ない. その場合は `default` で指定された値となる) say test(arg => undef); # => 'undef' (明示的に `undef` を渡しても問題ない)
この挙動, よくよく見ると2番目に紹介したdefaultを指定 + isaがMaybeと同じですね. つまり1つの挙動(optionalな引数で, undefを受け取れて, デフォルト値を指定したい)について, 2通りの書き方がある, ということです.
papixの意見
...とはいえ同じ挙動を複数の書き方ができる, というのは混乱を呼びそうです. どちらかに寄せよう! という合意を取れるといいのかな, と思います.
自分なら, こういう場合は前者(defaultを指定 + isaをMaybeにする)として, defaultとoptionalは同時に使わない... というふうにするのがわかりやすいんじゃないかな, と思いました.
というわけで以上です, すいませんがオチはないです...