Scala Programming Language
  1. Scala Programming Language
  2. SI-2628

Ambiguous method overloading compiles, but should not

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: Misc Compiler
    • Labels:
      None

      Description

      The following compiles, yet neither method is callable due to ambiguity (although I have yet to be pointed to where in the spec that is considered ambiguous).

      object Foo {
        def bar(i: Int) = println(i)
        def bar(i: Int) (f: Float) = println(i*f)
      }
      

        Issue Links

          Activity

          Hide
          Adriaan Moors added a comment -

          Sorry, thanks for persisting (in the future, it would help, though, to simply copy/paste output from the interpreter, as I've done below)

          Martin: I tried out various combinations of argument types, and could refer to the overload with one argument list (except not in the given example – see below for one where I did manage), but never to the one with two.

          scala> object Foo {
               |   def bar(i: Int) = println(i)
               |   def bar(i: Int) (f: Float) = println(i*f)
               | }
          defined module Foo
          
          scala> Foo.bar(5): (Float => Unit)
          <console>:6: error: ambiguous reference to overloaded definition,
          both method bar in object Foo of type (i: Int)(f: Float)Unit
          and  method bar in object Foo of type (i: Int)Unit
          match argument types (Int)
                 Foo.bar(5): (Float => Unit)
                     ^
          
          scala> object x{def a(i: String): Option[String] = Some("a"); def a(i: String)(b:  List[String]): Int = 1}
          defined module x
          
          scala> x.a("a"): Option[String]
          res10: Option[String] = Some(a)
          
          scala> def f(xs: List[String]): Int = x.a("a")(xs)                         
          <console>:5: error: ambiguous reference to overloaded definition,
          both method a in object x of type (i: String)(b: List[String])Int
          and  method a in object x of type (i: String)Option[String]
          match argument types (java.lang.String)
                 def f(xs: List[String]): Int = x.a("a")(xs)
                                                  ^
          
          
          Show
          Adriaan Moors added a comment - Sorry, thanks for persisting (in the future, it would help, though, to simply copy/paste output from the interpreter, as I've done below) Martin: I tried out various combinations of argument types, and could refer to the overload with one argument list (except not in the given example – see below for one where I did manage), but never to the one with two. scala> object Foo { | def bar(i: Int) = println(i) | def bar(i: Int) (f: Float) = println(i*f) | } defined module Foo scala> Foo.bar(5): (Float => Unit) <console>:6: error: ambiguous reference to overloaded definition, both method bar in object Foo of type (i: Int)(f: Float)Unit and method bar in object Foo of type (i: Int)Unit match argument types (Int) Foo.bar(5): (Float => Unit) ^ scala> object x{def a(i: String): Option[String] = Some("a"); def a(i: String)(b: List[String]): Int = 1} defined module x scala> x.a("a"): Option[String] res10: Option[String] = Some(a) scala> def f(xs: List[String]): Int = x.a("a")(xs) <console>:5: error: ambiguous reference to overloaded definition, both method a in object x of type (i: String)(b: List[String])Int and method a in object x of type (i: String)Option[String] match argument types (java.lang.String) def f(xs: List[String]): Int = x.a("a")(xs) ^
          Hide
          Martin Odersky added a comment -

          I see, but would classify this as a corner case due to the unit conversion. There's no attempt in the spec to classify overloads that will always yield ambiguous errors when referenced as illegal. I believe adding such rules would be quite tricky, and it's not a priority for us.

          Show
          Martin Odersky added a comment - I see, but would classify this as a corner case due to the unit conversion. There's no attempt in the spec to classify overloads that will always yield ambiguous errors when referenced as illegal. I believe adding such rules would be quite tricky, and it's not a priority for us.
          Hide
          Nils added a comment -

          Replying to [comment:10 odersky]:
          > I see, but would classify this as a corner case due to the unit conversion. There's no attempt in the spec to classify overloads that will always yield ambiguous errors when referenced as illegal.

          That would be fine if there was some way to call the second method. There is not (that I know of, short of using reflection).
          I was using Eclipse, which is why I couldn't easily copy/paste my results. Apologize for that. Here's more using a slightly modified version (returning Float) from the console:

          scala> object Foo {def bar(i:Int):Float=i;def bar(i:Int)(f:Float)=i*f;}
          defined module Foo
          
          scala> Foo.bar(5)
          <console>:6: error: ambiguous reference to overloaded definition,
          both method bar in object Foo of type (Int)(Float)Float
          and  method bar in object Foo of type (Int)Float
          match argument types (Int)
                 Foo.bar(5)
                     ^
          
          scala> Foo.bar(5)(3.2f)
          <console>:6: error: ambiguous reference to overloaded definition,
          both method bar in object Foo of type (Int)(Float)Float
          and  method bar in object Foo of type (Int)Float
          match argument types (Int)
                 Foo.bar(5)(3.2f)
                     ^
          
          scala> Foo.bar(5): Float
          res2: Float = 5.0
          
          scala> Foo.bar(5)(3.2f): Float
          <console>:6: error: ambiguous reference to overloaded definition,
          both method bar in object Foo of type (Int)(Float)Float
          and  method bar in object Foo of type (Int)Float
          match argument types (Int)
                 Foo.bar(5)(3.2f): Float
                     ^
          
          scala> Foo.bar(5) _
          <console>:6: error: ambiguous reference to overloaded definition,
          both method bar in object Foo of type (Int)(Float)Float
          and  method bar in object Foo of type (Int)Float
          match argument types (Int)
                 Foo.bar(5) _
                     ^
          
          scala> Foo.bar(5): (Float=>Float)
          <console>:6: error: ambiguous reference to overloaded definition,
          both method bar in object Foo of type (Int)(Float)Float
          and  method bar in object Foo of type (Int)Float
          match argument types (Int)
                 Foo.bar(5): (Float=>Float)
                     ^
          

          It does not seem right that one can define methods that simply cannot be called. I would much prefer that both methods could be called, since they do not appear ambiguous to me

            Foo.bar(5)      // Unambiguously calls the single parm variant
            Foo.bar(5) _    // Unambiguously calls the double parm variant partially
            Foo.bar(5)(2f)  // Unambiguously calls the double parm variant.
          

          Short of that, it seems that the same ambiguity rules should be applied to defs, preventing creation of methods that are impossible to reference.

          Show
          Nils added a comment - Replying to [comment:10 odersky] : > I see, but would classify this as a corner case due to the unit conversion. There's no attempt in the spec to classify overloads that will always yield ambiguous errors when referenced as illegal. That would be fine if there was some way to call the second method. There is not (that I know of, short of using reflection). I was using Eclipse, which is why I couldn't easily copy/paste my results. Apologize for that. Here's more using a slightly modified version (returning Float) from the console: scala> object Foo {def bar(i:Int):Float=i;def bar(i:Int)(f:Float)=i*f;} defined module Foo scala> Foo.bar(5) <console>:6: error: ambiguous reference to overloaded definition, both method bar in object Foo of type (Int)(Float)Float and method bar in object Foo of type (Int)Float match argument types (Int) Foo.bar(5) ^ scala> Foo.bar(5)(3.2f) <console>:6: error: ambiguous reference to overloaded definition, both method bar in object Foo of type (Int)(Float)Float and method bar in object Foo of type (Int)Float match argument types (Int) Foo.bar(5)(3.2f) ^ scala> Foo.bar(5): Float res2: Float = 5.0 scala> Foo.bar(5)(3.2f): Float <console>:6: error: ambiguous reference to overloaded definition, both method bar in object Foo of type (Int)(Float)Float and method bar in object Foo of type (Int)Float match argument types (Int) Foo.bar(5)(3.2f): Float ^ scala> Foo.bar(5) _ <console>:6: error: ambiguous reference to overloaded definition, both method bar in object Foo of type (Int)(Float)Float and method bar in object Foo of type (Int)Float match argument types (Int) Foo.bar(5) _ ^ scala> Foo.bar(5): (Float=>Float) <console>:6: error: ambiguous reference to overloaded definition, both method bar in object Foo of type (Int)(Float)Float and method bar in object Foo of type (Int)Float match argument types (Int) Foo.bar(5): (Float=>Float) ^ It does not seem right that one can define methods that simply cannot be called. I would much prefer that both methods could be called, since they do not appear ambiguous to me Foo.bar(5) // Unambiguously calls the single parm variant Foo.bar(5) _ // Unambiguously calls the double parm variant partially Foo.bar(5)(2f) // Unambiguously calls the double parm variant. Short of that, it seems that the same ambiguity rules should be applied to defs, preventing creation of methods that are impossible to reference.
          Hide
          Martin Odersky added a comment -

          "Short of that, it seems that the same ambiguity rules should be applied to defs, preventing creation of methods that are impossible to reference." I just wrote above that there is no attempt to do such a thing in the spec. I challenge you to give a set of complete and decidable rules to do this.

          Show
          Martin Odersky added a comment - "Short of that, it seems that the same ambiguity rules should be applied to defs, preventing creation of methods that are impossible to reference." I just wrote above that there is no attempt to do such a thing in the spec. I challenge you to give a set of complete and decidable rules to do this.
          Hide
          Nils added a comment -

          So in Scala, it should be possible to define methods that no one can call? That's a rather odd goal.
          As I've said before, I would prefer that the methods could actually be called, rather than ambiguity being determined by the first argument list only, but that is also not a goal.
          So that leaves one with a rather odd situation of having methods that compile fine, and can be unambiguously referenced by any human, yet the Scala compiler, which has a general goal in other aspects to be smart, cannot.

          Show
          Nils added a comment - So in Scala, it should be possible to define methods that no one can call? That's a rather odd goal. As I've said before, I would prefer that the methods could actually be called, rather than ambiguity being determined by the first argument list only, but that is also not a goal. So that leaves one with a rather odd situation of having methods that compile fine, and can be unambiguously referenced by any human, yet the Scala compiler, which has a general goal in other aspects to be smart, cannot.

            People

            • Assignee:
              Martin Odersky
              Reporter:
              Nils
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development