Reputation: 34413
Following code imports the same symbol twice, because it imports two different objects which both export it:
object Ext:
def backwards(s: String): String = s.reverse
object A:
export Ext.*
object B:
export Ext.*
import A.*
import B.*
backwards("Hello")
The error is:
Reference to backwards is ambiguous. It is both imported by import A._ and imported subsequently by import B._
It is the same symbol eventually, therefore there is in fact no ambiguity, but I guess some implementations details of export
hide this from the compiler.
How can I solve this?
Motivation: In my project I have several objects which all export a set of useful extension functions so that anyone using any of those objects can use those extensions without having to import them explicitly.
Upvotes: 0
Views: 42
Reputation: 27535
Just don't export/import the ambiguous definition in one place:
import A.*
import B.{backwards => _, *}
backwards("Hello")
import A.{backwards => _, *}
import B.*
backwards("Hello")
or
object A:
export Ext.*
object B:
export Ext.{backwards => _, *}
object A:
export Ext.{backwards => _, *}
object B:
export Ext.*
Alternatively instead of skipping, rename it:
object A:
export Ext.{backwards => backwardsA, *}
object B:
export Ext.{backwards => backwardsB, *}
It is the same symbol eventually, therefore there is in fact no ambiguity, but I guess some implementations details of export hide this from the compiler.
export
just defines new val
s, def
s, type aliases, etc. Technically it's shortcut for copy pasting every signature and adding a delegation to the original definition. You could have export foo.*
, then modify it to skip a definition with export foo.{skipped => _, *}
so that you would implement it by hand and - as long as the signature would be the same - code would not notice a difference. So you cannot think of export
as of some magic batch alias. It's a codegen. Treat it as such and things like:
trait Foo:
def bar(baz: Baz): Bar
def addToString(foo: Foo)(str: String): Foo =
new Foo:
export foo.{toString => _, *} // generates definitions required by the interface
override def toString = str
suddenly make sense. It also makes sense why any analysis considers the same definition exported through 2 difference places as distinct - this can change any time and the fact that they refer to the same object in just a current implementation detail.
Upvotes: 4