In reading this section on handling name collisions, in the import section, I am confused by why we need to prefix both packages? Is
import Foo1.X as X1
import X as X2
ambiguous ?
In reading this section on handling name collisions, in the import section, I am confused by why we need to prefix both packages? Is
import Foo1.X as X1
import X as X2
ambiguous ?
The difference is in your example you have Foo1.X
and X
so they are different module names. In the docs both modules are called X
. If you import it unqualified damlc does not know which one it should use.
Sorry, I think that I am missing a step in the process. When I import something with as
doesn’t that change the name?
Would
import Foo1.X qualified as X1
import X qualified as X2
still be ambiguous?
So there are a couple things going on here.
First off, the linked documentation page attempts to address the case where you depend on two packages that both export the same module. In all of your code snippets here, you’re using syntax that assumes modules already have different names, but export the same symbols. I’m assuming you know this, but for the benefit of other readers let’s delve into it a little bit more.
In your case (different modules with same-name symbols), yes, you can use as
syntax to disambiguate. Note that when you import M1 as M2
, you import all of the symbols of M1
both “naked” and qualified. This is useful if you generally prefer using unqualified names, but you have maybe one or two symbols in that package that conflict with other packages.
When you import qualified M1 as M2
(or import M1 qualified as M2
, which is equivalent), you only import the qualified variants of the symbols in M1
, so they’re not available in their “naked” form.
It’s probably important to point out that Daml, inheriting that behaviour from Haskell, will fail on ambiguous use of a multiple-times-imported symbol, not when importing it. So if you have two modules, M1
defining f1
and f2
, and M2
defining f1
and f3
, the following code will not produce an error on the ambiguous f1
, because it’s not used:
import M1
import M2
a = undefined f2
b = undefined f3
This would fail to compile:
import M1
import M2
a = undefined f2
b = undefined f3
c = undefined f1 -- FAIL: ambiguous reference to f1, could mean M1 or M2.
And this would work:
import M1 as M1
import M2 as M2
a = undefined f2
b = undefined f3
c = undefined M1.f1
d = undefined M2.f1
Now, the documentation you linked is about two packages exporting the same module. In that case you need an extra level: in your daml.yaml
file, you can give a name to the package itself, and then use that name in the import
statement as an extra string argument. By default, packages use their own name, which will work in cases where the packages have different names (you could depend on two versions of the same package, in which case they’ll have the same name, and then you can use special syntax in the daml.yaml
file to give them different names).
So your question is really at the daml.yaml
level. If I may rephrase it: assuming you are depending on two versions of the same package foo, would the following daml.yaml
be enough to avoid conflicts?
build-options:
- '--package'
- 'foo-1.0.0 with (X as Foo1.X)'
- '--package'
- 'foo-2.0.0'
Presumably this would define the X
module from foo-1.0.0
into the Foo1.X
module for local compilation, and the X
module from foo-2.0.0
would be defined as plain X
, so it looks like there’s no conflict. I’m afraid I don’t know the answer there, but I hope I’ve at least clarified the question for more knowledgeable people. (@cocreature ?)
Take a look at 7.9. Packages — Glasgow Haskell Compiler <release> Users Guide. Renaming using with
is additive so you still get a collision using the unqualified name. However, you can use it without the with
to avoid that.
@Gary_Verhaegen Amazing answer! And you’re right I am thinking at the package import level.
I think I’ve figured out one subtlety; the build-options
--package
renaming can only be used on a per module basis. So it would be inefficient to use it to apply to all modules in a package. Which is what the module-prefixes
accomplishes?
Another related question, do build-options
and module-prefixes
apply only to data-dependencies
or dependencies
too?
module-prefixes
is just syntactic sugar for renaming all modules in a package so purely for convenience.
Both build-options
and module-prefixes
apply to deps & data-deps although I strongly recommend only using data-deps. If there is a reason that forces you to use deps, it’s probably a good idea to raise an issue before this becomes an issue for you once you upgrade SDKs.