Why does this explicit call of a Scala method allow it to be implicitly resolved?

后端 未结 3 498
闹比i
闹比i 2020-12-03 07:45

Why does this code fail to compile, but compiles successfully when I uncomment the indicated line? (I\'m using Scala 2.8 nightly). It seems that explicitly calling str

相关标签:
3条回答
  • 2020-12-03 08:04

    If you put object Implicits first, it works. This looks like a bug to me in the logic for making multiple compiler passes; it assumes it can get away without really knowing about string2Wrapper when compiling bar. My guess is that if you use it, it knows it can't get away with not knowing what string2Wrapper really is, actually compiles Implicits, and then realizes that ==> is implicitly defined on String.

    Edit: Based on what Retronym posted, maybe it's a "feature" not a bug. Still seems screwy to me!

    0 讨论(0)
  • 2020-12-03 08:21

    If you were just ooooone nightly later you would instead have seen the error message I added yesterday.

    <console>:11: error: value ==> is not a member of java.lang.String
     Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
               "A" ==> "B"
               ^
    <console>:12: error: value ==> is not a member of java.lang.String
     Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
               "B" ==> "C"
               ^
    <console>:13: error: value ==> is not a member of java.lang.String
     Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type
               "C" ==> "D"
               ^
    
    0 讨论(0)
  • 2020-12-03 08:29

    Explicitly ascribing the return type of string2Wrapper fixes the problem.

    class A {
      import Implicits._
    
      def bar() {    
        "A" ==> "B"
        "B" ==> "C"
        "C" ==> "D"
      }
      object Implicits {
        implicit def string2Wrapper(s: String): Wrapper = new Wrapper(s)
        class Wrapper(s: String) {
          def ==>(s2: String) {}
        }
      }
    }
    

    Defining Implicits before bar also works:

    class A {
      object Implicits {
        implicit def string2Wrapper(s: String) = new Wrapper(s)
        class Wrapper(s: String) {
          def ==>(s2: String) {}
        }
      }
    
      import Implicits._
    
      def bar() {    
        "A" ==> "B"
        "B" ==> "C"
        "C" ==> "D"
      } 
    }
    

    If you need to rely on a implicit conversion defined below within the current scope, make sure you annotate its return type. Pretty sure this has come up on the mailing lists before, and may be expected behaviour rather than a bug. But I can't locate it at the moment. I guess the explicit call in foo triggers the type inference of the return type of bar, which is then valid when typing the contents of bar.

    UPDATE

    What is the danger of the cyclic reference error?

    The body of the implicit method may call the method that requires the implicit conversion. If both of these have an inferred return type, you're at an impasse. This doesn't apply in your example, but the compiler doesn't attempt to detect this.

    Why does an explicit call make a difference?

    The explicit call earlier triggers type inference of the return type of the implicit method. Here's the logic in Implicits.isValid

    sym.isInitialized ||
          sym.sourceFile == null ||
          (sym.sourceFile ne context.unit.source.file) || 
          hasExplicitResultType(sym) ||
          comesBefore(sym, context.owner)
    

    UPDATE 2

    This recent bug looks relevant: https://lampsvn.epfl.ch/trac/scala/ticket/3373

    0 讨论(0)
提交回复
热议问题