duck typing

次のような関数を用意し、引数が数値なら足し算、文字列なら連結、というように引数にoperator+を適用させたいとします。

def plus(x, y):
    return x + y

ところが、これをコンパイルすると次のようなエラーが発生します。

BCE0051: Operator '+' can't be used with a left hand side of type 'System.Object' and a right hand side of type 'System.Object'.

引数x, yは型を指定していないため、デフォルトでObject型になります。Object型はoperator+をサポートしていないのでエラーになります。なので数値や文字列に対応させるには型毎にオーバーロードさせることになります。ある程度の規模のソフトウェアを開発するにはタイプセーフであることは好ましいですが、ちょっとしたプログラミングではちょっと面倒です。Booではduck型という実行時にメソッドの解決を行う型が用意されており、次のように書くことが出来ます。

def plus(x as duck, y as duck):
    return x + y

print plus(1, 2)
print plus(0.1, 0.2)
print plus([1, 2], [3, 4])
print plus(1, 'two')
print plus('one', 2)

/* 結果
3
0.3
[1, 2, 3, 4]
1two
one2
 */

実行時にメソッドをチェックしoperator+をサポートしていれば、数値や文字列、さらにはリストでも渡せてしまいます。

ところで、例ではわざと文字列と文字列の連結を入れませんでした。何故かと言うと・・・

print plus('one', 'two')

こんなコードを書くと、

System.Reflection.AmbiguousMatchException: あいまいな一致が見つかりました。
(以下略)

と、エラーになってしまったからです。おそらく文字列同士の連結させるか、それともObjectとしてToString()で文字列にして連結させるかであいまいだと言われていると思います。これはバグでしょうね。

(追記) 修正されました。(http://d.hatena.ne.jp/akiramei/20041216#p1参照)