Cyclic dependencies, with an example
I am trying to create a simple example to illustrate the guidance in the old topic, Cyclic dependencies.
What if I start with a PingPong module, like this:
PingPong.daml
module PingPong where
template Ping with
party : Party
where
signatory party
choice RespondWithPong : ContractId Pong
controller party
do create Pong with ..
template Pong
with party : Party
where
signatory party
choice RespondWithPing : ContractId Ping
controller party
do create Ping with ..
Let’s pretend the PingPong module is getting too big. We would like to break it into two pieces – a module for Pings and a module for Pongs.
Naively copy-and-pasting the two templates into new modules results in the Cyclic module dependency between Pings, Pongs error.
Pings.daml
module Pings where
import Pongs
template Ping with
party : Party
where
signatory party
choice RespondWithPong : ContractId Pong
controller party
do create Pong with ..
Pongs.daml
module Pongs where
import Pings
template Pong
with party : Party
where
signatory party
choice RespondWithPing : ContractId Ping
controller party
do create Ping with ..
For this contrived example, what would the Daml look like when applying @bernhard’s suggestion:
…think about breaking the cycling dependency. I have often found that if I have a dependency
A <-> B, it makes sense to split this out into the “downstream” and “upstream” parts of the dependencies leading to four templatesA_d, A_u, B_d, B_uwith dependencies
Hi @WallaceKelly,
I believe the example you created falls into the description the the first paragraph in @bernhard’s reply. Since the templates are too simple to be broken apart into multiple ones, I see no option here to resolve the dependency other than moving the two templates into the same module (as they were originally).
Thanks, @Mate_Varga, for taking a look with me.
The example is definitely simple and contrived. I was thinking about it over the weekend and the best I could come up with is this:
- Ping and Pong templates no longer generate the responses, since they cannot know about each other. (These become the “upstream”)
- Introduce new Pinging and Ponging templates to generate the responses. (These are the “downstream”).
I’d welcome a better example!
Ping.daml
module Ping where
template Ping with
party : Party
where
signatory party
Pong.daml
module Pong where
template Pong with
party : Party
where
signatory party
Pinging.daml
module Pinging where
import Ping
import Pong
template Pinging
with party : Party
where
signatory party
choice Create : ContractId Ping
controller party
do create Ping with ..
choice Respond : ContractId Ping
with pong : ContractId Pong
controller party
do
archive pong
create Ping with..
Ponging.daml
module Ponging where
import Ping
import Pong
template Ponging
with party : Party
where
signatory party
choice Create : ContractId Pong
controller party
do create Pong with..
choice Respond : ContractId Pong
with ping : ContractId Ping
controller party
do
archive ping
create Pong with..
Main.daml
module Main where
import Daml.Script
import Pinging
import Ponging
demo = script do
party <- allocateParty "party"
ping <- submit party $ createAndExerciseCmd (Pinging party) Pinging.Create
pong <- submit party $ createAndExerciseCmd (Ponging party) Ponging.Respond with ..
ping <- submit party $ createAndExerciseCmd (Pinging party) Pinging.Respond with ..
pure ()