scala - Why does a unary operator enable a ()=>X implicit conversion? -
i encounter issue implicit ()=>x
conversion happens when define , use unary operator. below minimal example:
class gate { def unary_!(): gate = } class foo { private def foo(f: () => gate) = 1 val gate = new gate // compiles, -xprint:typer shows becomes // foo.this.foo({ // (() => foo.this.gate.unary_!()) // }) foo(!gate) // not compile, // error: type mismatch; // found : gate // required: () => gate // foo(gate) foo(gate) }
where () => gate
conversion happens , why happen unary_!
?
edited
thanks answer! raised question because eta expansion (from x
() => x
blocks implicit conversion defined x
, wanted happen. removing unnecessary parentheses unary_!
solves problem us. thanks!
this eta-expansion, turns method function.
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#eta-expansion
the trigger expected type function.
the link ambiguous in spec, expansion @ 6.26.5.
compare these 2 forms:
scala> foo(gate.unary_!()) <console>:11: error: type mismatch; found : gate required: () => gate foo(gate.unary_!()) ^ scala> foo(gate.unary_!) res3: int = 1
the first case application of function. doesn't type check.
what second case? instead of adding parens implicitly turn application, first eta-expand make function, type checks.
it's been suggested adding parens ("empty application" in spec) should come first, behave same first case.
here's spec wording how prefix op handled:
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#prefix-operations
a prefix operation op;e consists of prefix operator op, must 1 of identifiers ‘+’, ‘-’, ‘!’ or ‘~’. expression op;e equivalent postfix method application e.unary_op.
but example shows it's member selection, not application.
here's counterexample without parens on method definition:
scala> class gate { def unary_! : gate = } defined class gate scala> def foo(f: () => gate) = 1 foo: (f: () => gate)int scala> val gate = new gate gate: gate = gate@2db0f6b2 scala> foo(!gate) <console>:11: error: type mismatch; found : gate required: () => gate foo(!gate) ^
there simple evaluation first, first conversion in 6.26.2.
more examples on related ticket.
a comment there on linked ticket suggests not changing order of implicits, disabling eta-expansion case:
i'd inclined go further , deprecate eta-expansion given expected type of function0, , avoid triggering sam types of same shape outset.
which bad, because have made nice little puzzler.