Accessing an optional return value in DAML script

I have an Asset template created based on the DA ex-collateral repo here. An asset has Merge and Split operations. What I’m attempting to do is, within the scope of one ‘do’ block in DAML script, to split and asset and merge the two parts back. However, I have not been able to find the right syntax to access the returned objects from Split correctly.
I believe the reason is the definition of the split action returning an ‘Optional’, which I’m not sure how to access.

The asset template’s Split function:

template Asset
...
    controller owner can
      Split
        : (ContractId Asset, Optional (ContractId Asset))
        with splitQuantity: Int
        do
          splitCid <- create this with quantity = splitQuantity
          restCid <-
            if quantity == splitQuantity
            then return None
            else do
              cid <- create this with quantity = quantity - splitQuantity
              return (Some cid)
          return (splitCid, restCid)

As you can see, it returns a tuple where the second item is Optional.
In DAML script, I have the following working block which runs fine:

do
...
  splitResult  <- submit partyX do
    exerciseCmd existingAssetObject Split
      with
        splitQuantity = 50

My attempt at code to merge them back:

  mergedBack <- submit partyX do
    exerciseCmd splitResult._1 Merge
      with
        otherCid = splitResult._2

splitResult._1 seems accessible. However, splitResult._2 does not work and gives the following error:

    • Couldn't match type ‘Optional (ContractId Asset)’
                     with ‘ContractId Asset’
        arising from a functional dependency between:
          constraint ‘DA.Internal.Record.HasField
                        "_2"
                        (ContractId Asset, Optional (ContractId Asset))
                        (ContractId Asset)’

What is the simplest way to access the optional return value?

Hi antvi and welcome to the forum!

The optional type is described in Module DA.Optional — Daml SDK 2.2.0 documentation.

In your case, there are two options:

  • if you are sure that the option will not be a None (because splitQuantity will be different than quantity in your use-case) then I suggest using fromSome to extract the value from the option (or fromSomeNote for a nicer error message)

  • if, on the other hand, you want to consider the case where the option corresponds to a None, you could do as follows:

  mergedBack <- case splitResult._2 of
    Some cid -> submit partyX do
        exerciseCmd cid Merge
          with
            otherCid = splitResult._1
    None -> pure splitResult._1

In the latter case, you are effectively returning splitResult._1 unchanged if there is no asset to merge.

1 Like

Thanks a lot for your reply Matteo! :slight_smile:

I was able to use fromSome directly, but ran into an issue with your better example. After a couple tries, I reversed which split parts were used for the logic, and got the following to work:

  mergedBack <- case splitResult._2 of
      Some cid -> submit partyX do
          exerciseCmd splitResult._1 Merge -- using the guaranteed-to-exist split part here
            with
              otherCid = cid -- using the optional-to-exist split part here
      None -> pure splitResult._1
  

Glad you got it to work!

There was indeed a typo in my code code snippet above.

Cheers,
Matteo

1 Like