Search code examples
scalaoverloadingpartialfunction

How to call function overloaded by function which return partail function


How to print "I'm not partial" using one of below f functions, and why below code is printing "I'm partial"? And maybe there are some general rules connected with functions (maybe with arity 0) which produced partial functions and name overloading in scala?

object T1 extends App{    
  case class C()
  def f: PartialFunction[C, Unit] = { case c:C ⇒ println( "I'm partial") }
  def f(c: C): Unit = { println("I'm not partial") }
  (f:C ⇒ Unit)(C()) // Why this is printing "I'm partial"?
}

Solution

  • The expression is not an application. Compare the definition of x with the ambiguous invocation:

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    object T1 extends App{    
      case class C()
      def f: PartialFunction[C, Unit] = { case c:C ⇒ println( "I'm partial") }
      def f(c: C): Unit = { println("I'm not partial") }
      (f:C ⇒ Unit)(C()) // Why this is printing "I'm partial"?
    }
    
    // Exiting paste mode, now interpreting.
    
    defined object T1
    
    scala> T1 main null
    I'm partial
    
    scala> import T1._
    import T1._
    
    scala> val x: C => Unit = f
    x: T1.C => Unit = <function1>
    
    scala> f(C())
    <console>:12: error: ambiguous reference to overloaded definition,
    both method f in object T1 of type (c: T1.C)Unit
    and  method f in object T1 of type => PartialFunction[T1.C,Unit]
    match argument types (T1.C)
                  f(C())
                  ^
    
    scala> x(C())
    I'm partial
    

    The spec says f is as specific as f(...) (bullet 3) but not conversely (by bullet 1).

    The parens of an application means you're comparing two things that look like f(...).

    In case this helps, the usual way to prioritize:

    scala> trait Helper { def f: PartialFunction[C, Unit] = { case c:C ⇒ println( "I'm partial") } }
    defined trait Helper
    
    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    object T extends Helper {
    def f(c: C): Unit = { println("I'm not partial") }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined object T
    
    scala> T f new C
    I'm not partial
    

    There are other API that you can write but not invoke in the normal way:

    scala> trait X { def f(i: => Int) = i }
    defined trait X
    
    scala> trait Y { def f(i: Int) = 2 * i }
    defined trait Y
    
    scala> class Z extends X with Y
    defined class Z
    
    scala> new Z().f(42)
    res5: Int = 84
    
    scala> typeOf[Z].members filter (_.name.toString == "f")
    res7: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method f, method f)
    
    scala> (new Z(): X).f(42)
    res8: Int = 42
    

    Or, no way to invoke the other function here:

    scala> class YY extends Y { def f(i: => Int) = i }
    defined class YY
    
    scala> new YY().f(42)
    <console>:20: error: ambiguous reference to overloaded definition,
    both method f in class YY of type (i: => Int)Int
    and  method f in trait Y of type (i: Int)Int
    match argument types (Int)
                  new YY().f(42)
                           ^
    
    scala> (new YY(): Y).f(42)
    res15: Int = 84