Skip to content

Separate compilation breaks extension methods with the same name #16920

Closed
@Ichoran

Description

@Ichoran

Compiler version

3.2.2 (and still in 3.3.0-RC2)

Minimized code

Scastie: https://scastie.scala-lang.org/Ichoran/fgRflBYNRciNP6bBG9WtSw/14

object One:
  extension (s: String)
    def wow: Unit = println(s)

object Two:
  extension (i: Int)
    def wow: Unit = println(i)

object Three:
  extension (s: String)
    def wow: Unit = println(s)
  extension (i: Int)
    def wow: Unit = println(i)

object Four:
  implicit class WowString(s: String):
    def wow: Unit = println(s)

object Five:
  implicit class WowInt(i: Int):
    def wow: Unit = println(i)

object Compiles:
  import Three._
  def test: Unit =
    5.wow
    "five".wow

object AlsoCompiles:
  import Four._
  import Five._
  def test: Unit =
    5.wow
    "five".wow

object Fails:
  import One._
  import Two._
  def test: Unit =
    5.wow
    "five".wow

Output

value wow is not a member of Int.
An extension method was tried, but could not be fully constructed:

    Playground.Two.wow(5)    failed with

        Reference to wow is ambiguous,
        it is both imported by import Playground.One._
        and imported subsequently by import Playground.Two._

value wow is not a member of String.
An extension method was tried, but could not be fully constructed:

    Playground.Two.wow("five")    failed with

        Reference to wow is ambiguous,
        it is both imported by import Playground.One._
        and imported subsequently by import Playground.Two._

Expectation

Extension methods work when compiled independently for different argument types (in different namespaces).

Thus, extension methods should be equally usable when compiled independently or jointly, and also are equally as usable as the implicit class extension mechanism.

Actual Behavior

Independent compilation does not work with extension methods when the extension methods have the same name because the import ambiguity mechanism vetoes the successfully-resolved method call. (Note that the error message tells you that it has actually fully successfully dispatched the method based on type.)

This prevents removal of the implicit class mechanism for extension methods, because implicit class does not have this problem.

(It seems that this problem should have been reported already by now, but I can't find it. However, if this is not fixed, to be safe, nobody should use extension methods in any library, because it is impossible to predict when a collision might occur with some other library extending some other class. It's particularly acute with Java classes where you might want to define some obvious operation like +, but someone might want to define it on Duration and someone else might want to define it on Path.)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions