Some.apply() は引数1つなんです。
実践Scala:121ページ目。Some(( p.name, p.age )) って書いてあるけど、これは説明のためで、普通は Some(p.name, p.age) って書くってことでいいのだろうか。括弧2重に書くのが普通? #scala
2011-06-19 22:16:35@aoi0308 括弧2重に書かないと、ときに思わぬ罠にはまることが…。というか、本来は括弧2重であるべきなんですよ。Some.applyの引数は2個じゃないので。 #scala
2011-06-19 22:23:10@kmizu ついでに質問させて下さい。Someは引数1つなのに、複数引数を受け付けられるのはなぜなんでしょう?コンパイルエラーになってくれたほうが素直な気がしますが。
2011-06-19 22:38:23@aoi0308 まず、前提として:Someだけが特例なわけではないです。applyメソッド呼び出し && 多相メソッドが重なったときにおきる問題です。 #scala
2011-06-19 22:43:21@aoi0308 さて、その上で何が起こるか、というと、Some.apply(100, 200)のような呼び出しにおいて、Scalaの型推論器はA = (Int, Int)のように解釈してしまいます。
2011-06-19 22:49:34@aoi0308 つまり、複数引数を受け付けられる、のではなく、1タプルを引数としたメソッド呼び出しとして解釈されてしまいます。 #scala
2011-06-19 22:50:26@aoi0308 それでも謎なところはあって、何故、Some.apply(100, 200)の時点で、型推論する前に複数引数のメソッド呼び出しと解釈してくれないのか、という点です。 #scala
2011-06-19 22:53:05@aoi0308 で、言語仕様読んでみたところ、一応は、仕様どおりであることはわかりました。ただ、これは実装じゃなくて言語仕様のバグじゃないかという気がしています。 #scala
2011-06-19 22:59:07@aoi0308 どういう風に仕様どおりかというと、def f[T](x: T)というメソッド定義に対して、f(x, y)という呼び出しがあった場合の扱いについて、特にこれをrejectするような形で書かれていませんでした。 #scala
2011-06-19 23:01:03@kmizu ふむふむ。型パラメータをタプルだと解釈するわけですね。始めの方でapplyメソッド && 多相 っていう言い方をしてましたけど、apply以外でも起こりうるわけですよね?(手元で試せてません)
2011-06-19 23:07:49@aoi0308 問題の本質は、Some.apply(1, 2)というテキストと、Some.apply(1, 2)という抽象構文木の間のマッピングが明確に定義されていない点だと考えています。ちょっとわかりにくいので、続けます。
2011-06-19 23:10:47@aoi0308 まず、パーズ時点で、Some.apply(x, y) は具象構文にしたがっているので無事にパーズできます。しかし、この後の解釈が問題で言語仕様を読む限りでは、Some.apply((x, y))のように解釈しても矛盾が生じないように読めてしまいます。
2011-06-19 23:12:42まあ、言語仕様上の理由についてはそんな感じですけど、実装の観点で考えた場合、なんでこんな挙動するのかは簡単に説明がつきます。 #scala
2011-06-19 23:18:07たとえば、Some apply (100, 200) と Some.apply(100, 200) というメソッド呼び出しがあったとします。このとき、パーズが終わった後かパーズ中かはわからないですけど、前者は後者の形式にdesugarされているはずです。
2011-06-19 23:20:02で、そのせいで、パーズが終わった段階で既に、 Some apply (100, 200) と Some.apply(100, 200) の違いは区別が付かない。ここで、複数引数呼び出しみなしてrejectしてしまうとまずい、何故なら、
2011-06-19 23:21:07Some apply (x, y) は Someに タプル(x, y) を渡して apply を呼び出している、と解釈されるので。それで、複数引数かタプル引数かの判断を後のフェーズに任せた結果こうなったのだろうと。
2011-06-19 23:23:03