Module collisions in multi-dar projects
This is a follow-on from https://discuss.daml.com/t/behaviour-of-relative-paths-in-source-in-multi-dar-projects. Repeating the example for context here:
I have the following directory structure setup, to support building of multiple *.dar files (an interface and an implementation):
src/interface/daml.yaml
src/implementation/daml.yaml
src/main/daml.yaml
src/main/daml/Daml/Finance/Implementation/Token.daml
src/main/daml/Daml/Finance/Interface/Transferable.daml
src/main/daml/Daml/Finance/Interface/Issuable.daml
src/main/daml/Daml/Finance/Types.daml
src/main/daml/Daml/Finance/Test/Token.daml
All the source code resides in src/main. the other two directories just contain daml.yaml files that reference subdirectories, i.e.:
cat src/interface/daml.yaml
source: ../main/daml/Daml/Finance/Interface
cat src/implementation/daml.yaml
source: ../main/daml/Daml/Finance/Implementation
dependencies:
- ../interface/.daml/dist/daml-finance-interface-0.0.1.dar
Now I’ve noticed some rather strange behaviour. There is a common file, src/main/daml/Daml/Finance/Types.daml that has some common type definitions. It sits outside of the Interface or Implementation directories. Yet it is pulled into the builds (I can see this with damlc inspect).
What happens if I have dependencies to these common types in both the interface and implementation package? Shouldn’t there be some sort of a package clash, because it’s being included in both of them now? Is there any way to prevent this kind of behaviour? For instance, could I use the build-options : -I directive instead of source : ? Is there any difference here?
what happens if I have dependencies to these common types in both the
interfaceandimplementationpackage? Shouldn’t there be some sort of a package clash, because it’s being included in both of them now?
If a third project imports both of the dars you generate
dependencies
- daml-finance-interface-0.0.1.dar
- daml-finance-implementation-0.0.1.dar
and then from a new module you try to import one of the modules defined in both of these, you will get an error
Ambiguous module name ‘Daml.Finance.Types’:
it was found in multiple packages:
daml-finance-interface-1.0.0 daml-finance-implementation-1.0.0
You can get around that one with package-qualified imports,
import qualified "daml-finance-interface" Daml.Finance.Types as Interface.Types
import qualified "daml-finance-implementation" Daml.Finance.Types as Implementation.Types
but then the types themselves wouldn’t match
foos = [Interface.Types.Foo, Implementation.Types.Foo]
• Couldn't match expected type ‘Implementation.Types.Foo’
with actual type ‘Interface.Types.Foo’
NB: ‘Interface.Types.Foo’
is defined in ‘Daml.Finance.Types’ in package ‘daml-finance-interface-1.0.0’
‘Implementation.Types.Foo’
is defined in ‘Daml.Finance.Types’ in package ‘daml-finance-implementation-1.0.0’
• In the expression: Interface.Types.Foo
In the expression: [Implementation.Types.Foo, Interface.Types.Foo]
In an equation for ‘foos’: foos = [Implementation.Types.Foo, Interface.Types.Foo]
So, my suggestion would be to split off the shared parts into a separate package that can be depended on by both interface and implementation packages. I think in that case these two wouldn’t need the .. parent directory in their configuration files, since they would just depend on the types package directly. The main drawback would be needing to build the dars sequentially, but that can be taken care of outside of damlc.