Daml choice annotations

Update 2020-01-27

As of SDK version 0.13.47, the behaviour of preconsuming has changed. It is no longer an alias for a standard choice, but has the behaviour of a nonconsuming choice with an archive self as the first sub-action. There is no difference in behaviour, except that the privacy implications are subtly different. Observers see all consequences of a standard choice, whereas they only see the archive subaction of a preconsuming choice.

Introducing pre- and post-consuming choices

Choices in Daml can be ‘consuming’ or ‘non-consuming’ with respect to the contracts on which they are exercised. In short, a consuming choice on a contract leaves the contract inactive, a non-consuming choice does not. By default, a choice is assumed to be consuming. To indicate a non-consuming choice, Daml provides the nonconsuming keyword. Recently, Daml choice annotation syntax has been added to further categorize choices as ‘pre-consuming’ or ‘post-consuming’. This post reviews the consuming concept and explains the meaning of the newly added preconsuming and postconsuming keywords. The example code used here can be found in this Gist.

[Note: The code here uses the new ‘flexible controller’ syntax first introduced in this blog post.]

Consuming choices

Normally, exercising a choice on a contract amounts to actions that terminate the contract or replace the contract with one or more new contracts. For this reason, by default, exercising a choice on a contract is assumed to ‘consume’ the contract. For example, suppose a contract represents some kind of offer to purchase goods or services with provision for the provider to withdraw the offer:

Screen Shot 2019-11-14 at 9.42.58 AM

Daml guarantees that any Offer instance on which a Withdraw choice has been exercised is thereafter ‘inactive’—meaning any attempts to exercise further choices on that instance must fail. Exercising a Withdraw choice is said to ‘archive’ the contract.

Non-consuming choices

It's sometimes the case though that exercising a choice on a contract instance does not imply the instance should be archived. For such a choice, we can indicate that with a nonconsuming annotation. To illustrate, here's a simple model of a leasing agreement between a landlord and tenant. The landlord may like to, say, extend to the tenant the opportunity to ‘refer a friend’ in order to obtain a cash-premium—so we write that into the contract like so:

Screen Shot 2019-11-14 at 9.43.45 AM

In this case, no matter how many times a ReferAFriend choice is exercised on a Lease contract instance, that lease contract remains active.

Introducing pre- and post-consuming choices

Suppose we wish to write a clause into our Lease agreement allowing for its termination. Put yourself in the role of the developer contracted by the realtor to model their business process that mandates that, on termination, not only is the agreement archived but also a ReferAFriendOffer is issued. That would lead us to try to write something like the following.

Screen Shot 2019-11-14 at 9.44.10 AMAs indicated by the comment though, what we wrote won't cut it. The reason is, at the point at which we try to exercise the ReferAFriend choice on the lease contract, the lease has already been archived! The semantics of this auto-archiving are ‘pre-consuming’. The contract on which the choice is being exercised is archived before the choice body is executed—and so the attempt to exercise the ReferAFriend choice on the lease in the Terminate choice body fails because the lease is inactive.

In fact, the newly introduced preconsuming choice annotation is provided for those that wish to be explicit in their definitions. That is,

Screen Shot 2019-11-14 at 9.44.52 AMand,

Screen Shot 2019-11-14 at 9.44.57 AM mean the same thing and, as we have seen, the semantics of this archival scheme hinder our ability to naturally express the business process.

What's lacking here is a choice archival scheme with slightly different semantics—one that auto-archives its contract but not before the choice body has been executed. This is provided for by the newly added postconsuming annotation. Now we have the tools to express our intent. 

Screen Shot 2019-11-14 at 9.44.10 AMWhat we see here is that the postconsuming annotation, in contrast to a preconsuming annotation, means that the contract remains active for the duration of the choice body and is archived thereafter.

There is one subtlety left to explain regarding privacy rules with respect to post-consuming choices. Like non-consuming choices, contracts created in the choice body are known only to the signatories and controllers of the contracts and not made known to the observers of the contract on which the choice was exercised. That means, in terms of the example, a guarantor will not be privy to the creation of a ReferAFriendOffer raised by exercising Terminate on a lease but, as a stakeholder, will be privy to the archiving of the Lease itself.

A remark for ledger writers

In practice, Daml-LF only has pre-consuming choices. Post-consuming choices are implemented by code generation during the Daml to Daml-LF desugaring process. Don't worry if this remark doesn't mean anything to you as a Daml developer—you can safely ignore it!

Summary

In this note, we have revisited the notions of ‘consuming’ and ‘non-consuming’ choices. Consuming choices render their contracts inactive; non-consuming choices have no effect on their contracts. Consuming choices can be further nuanced into ‘pre-consuming’ and ‘post-consuming’ choices. Pre-consuming choices archive their contracts before their bodies are executed, and post-consuming choices archive their contracts after their bodies are executed. Annotations preconsumingnonconsuming, and postconsuming can be attached to choice definitions to select between the different possibilities. If you don't annotate a choice then it defaults to preconsuming.

Join the community and download the Daml SDK at daml.com

About the author

Shayne Fletcher, B.Sc. - Language Engineer – Daml Language Team, Digital Asset

Shayne joined Digital Asset’s language engineering team in 2018 where he works on the Daml compiler. Shayne has 20+ years experience with C++ and OCaml. He has a deep understanding of programming language theory and a wealth of experience in finance and building language based-products. In a previous role with Bloomberg, Shayne led the team that built the BLAN language for modeling exotic derivative securities. @shayne_fletcher