Letâs start with a very simplified version of your example to illustrate the problem:
module Main where
import Daml.Script
data CustomsInfo = CustomsInfo
deriving (Eq, Show)
template ShipmentReceived
with
p : Party
customsInfo : Optional CustomsInfo
where
signatory p
controller p can
AddCustomsInfo : ContractId ShipmentReceived
with
customsInfoNew : CustomsInfo
do
let
this.customsInfo = customsInfoNew
create ShipmentReceived with ..
setup : Script ()
setup = do
p <- allocatePartyWithHint "P" $ PartyIdHint with partyIdHint = "P"
cid <- submit p (createCmd ShipmentReceived with p = p, customsInfo = None)
shipments <- query @ShipmentReceived p
debug shipments
cid <- submit p (exerciseCmd cid (AddCustomsInfo CustomsInfo))
shipments <- query @ShipmentReceived p
debug shipments
pure ()
As you said, this doesnât work. We get the following output when running daml script
:
[DA.Internal.Prelude:540]: [(<contract-id>,ShipmentReceived {p = 'P', customsInfo = None})]
[DA.Internal.Prelude:540]: [(<contract-id>,ShipmentReceived {p = 'P', customsInfo = None})]
Now what is going wrong here?
The crucial point is the following piece of code
let
this.customsInfo = customsInfoNew
create ShipmentReceived with ..
If you remove a bit of syntactic sugar this is equivalent to
let
this.customsInfo = customsInfoNew
create ShipmentReceived with p = p, customsInfo = customsInfo
Now the crucial questions is what does the customsInfo
at the very end refer to.
To understand that we have to understand what the following line does.
let this.customsInfo = customsInfoNew
Remember that DAML is an immutable language. You cannot simply mutate a field in a template. This line isnât mutating the customsInfo
field so that customsInfo
changes its meaning. customsInfo
at the end still refers to the old value which is why you see the unchanged value.
To fix your code you have to actually change the value, e.g.,
createCmd ShipmentReceived with p = p, customsInfo = Some customsInfoNew
or if you want to use a let
and ..
you can use the following
-- Note that this does not mutate customsInfo. It defines a new variable of this name that hides the one from your template.
let customsInfo = Some customsInfoNew
createCmd ShipmentReceived with ..
If you now rebuild and rerun your script you will see the expected output:
[DA.Internal.Prelude:540]: [(<contract-id>,ShipmentReceived {p = 'P', customsInfo = None})]
[DA.Internal.Prelude:540]: [(<contract-id>,ShipmentReceived {p = 'P', customsInfo = Some CustomsInfo})]
Now there is one remaining piece of the puzzle. What does let this.customsInfo = customsInfoNew
actually do? This is rather confusing: It defines an infix operator called .
which accepts two arguments this
and customsInfo
and will return customsInfoNew
. So you could call "hello" . "world"
afterwards and it will give you back customsInfoNew
.