Declarative smart contracts at a glance: Comparing Daml, Ethereum, Corda, and Hyperledger Fabric
When we want to build a Global Economic Network of seamlessly interconnected businesses, it helps to have the combination of declarative smart contracts and a distributed ledger that can be enhanced when deployed with complementary blockchains. That’s exactly what the Daml platform delivers, now with version 2.x enhanced with Canton.
Declarative vs. procedural thinking
There is a deep duality in how we think in general: the difference between declarative and procedural thinking. We can call this duality a very high level “separation of concerns”: declarative thinking is concerned about how things must be, while procedural thinking is concerned about what steps need to be taken in order to achieve the desired state.
None of these ways of thinking is superior to the other, as we need both to achieve any meaningful goal. Consider an everyday example—shopping. Writing the shopping list is the declarative step, and collecting the goods from the off shelves at the store is the procedure. If you don’t write the list, you run the risk of forgetting something while focusing on finding the next item in the maze of shelves. If you don’t collect the items on your list, your fridge remains empty, however long your shopping list is.
I’m a fan of Bartosz Milewski’s lectures on category theory, targeting functional programmers (they are also useful for advanced level Daml learners!). In one of his conference speeches—A Crash Course in Category Theory—he explains how the human mind is better at declarative thinking, while computers are much better at performing procedures. That’s why he advocates functional programming and category theory, which is its mathematical foundation.
He also explains in his book Category Theory for Programmers that this duality also exists in physics: most laws can be expressed a) in a local way, using infinitesimals, and b) in a global way, minimizing some functionality among all the possible paths between a starting state and an end state (like light refraction explained by minimizing travel time). One extreme of the local approach is Stephen Wolfram’s method of modeling the laws of physics by finite automata. An extreme of the global approach is Richard Feynman likening the work of physicists to trying to discover the rules according to which Nature plays, using the analogy of chess. The local way is like procedural thinking; the global way is like declarative thinking.
Smart contracts are declarative
There are at least two ways of thinking about smart contracts: the business/legal way and the technology way. Both approaches lead to the insight that smart contracts must be declarative.
From a business point of view, smart contracts implement the legal architecture of a business model. The Daml docs highlight how Daml ledgers are designed to mimic real-world interactions between parties, which are governed by contract law. Legal constructs in general form a hierarchy, with high-level declarations on the top, like the Universal Declaration of Human Rights, constitutions, and laws, all the way down to procedural rules. Contracts are still on the declarative side, declaring rights and obligations, detailing in a varying degree how these rights and obligations must be fulfilled.
From a technology point of view, smart contracts define the schema, semantics, rights, and obligations of interactions between parties in a network. They implement a general interface, which abstracts away the implementation details of a distributed transaction system (i.e., blockchain).
Interfaces in general are declarative. Another everyday example is a restaurant, where the interface between the “front of house” and the “back of house” (the kitchen) is the menu. The menu is declarative—sometimes waiters or waitresses like to explain how a certain menu item is prepared, but this serves marketing purposes rather than allowing the customers to interfere with the chef’s business.
Part of being declarative is being prohibitive. Ledgers and smart contracts are, by design, passive: they don’t do anything by themselves, but instead react to transaction requests coming from client applications. After validating the requests, the ledger either commits and distributes the request, or rejects it.
Functional languages and declarative programs
Functional languages like Daml or its parent language, Haskell, are especially suited for declarative programs. Some traits supporting this are:
- Immutable variables. Once a variable is declared, it cannot change its value. Just like in a legal contract—once you define something in a certain way, its definition doesn’t change.
- Type system, which clearly separates pure computations from actions (in the case of Daml, ledger updates), which may or may not succeed.
- Composability. You can declare the composition of actions in an atomic (all-or-nothing) way, while piping the returned result from one action to the next.
- Pattern matching. It’s almost like setting up an equation for a variable.
Canton, the distributed transaction platform under Daml
As mentioned before, declarations alone don’t solve problems. Machines work in a procedural way, the mathematical model of which is not category theory, but rather the Turing machine. Somebody, somewhere along the way, needs to translate declarations to procedures.
The procedural counterpart of the Daml ledger model is summarized as Daml’s execution model in the documentation. Its steps are command submission, interpretation, blinding, transaction submission, validation, commitment, and confirmation competition.
The magic of translating the declarative ledger model into the procedural execution model is performed by the Daml engine and the implementation of the Canton protocol, using Scala and Akka, and for the implementation of the distributed transaction handling vector clocks.
With the introduction of Daml 2.x, Daml has its own underlying distributed transaction system. It’s superior to Daml 1.x in multiple ways:
- Messages are encrypted at the participant level, which means that the content of the transaction is hidden from anyone who has access to information on the domain.
- Both centralized and decentralized topologies are supported.
- GDPR compliance: Canton-enabled drivers (along with 1.x VMBC drivers) provide history pruning and log redaction capabilities, meaning that it’s easy to comply with GDPR’s right to be forgotten.
- The network composability feature in alpha status anticipates the promise of seamless application composability across the whole network of blockchain networks and database infrastructures, forming a single Global Economic Network.
The grass is not greener on the other side
Sometimes the grass is greener on the other side, but not this time. By comparing Daml to other smart contract platforms and languages, we can conclude that it does a good job in defining its goal and in fulfilling it.
Daml vs. Ethereum
Conceptually, the Ethereum white paper doesn’t make a clear distinction between being declarative or procedural. In a parenthesized link, without explaining the relationship, it points to Nick Szabo’s smart contract concept, which is definitely declarative. The self-definition of Ethereum, on the other hand, is rather procedural: “What Ethereum intends to provide is a blockchain with a built-in, fully fledged, Turing-complete programming language that can be used to create ‘contracts’ that can be used to encode arbitrary state transition functions.” This ambiguity makes its position somewhat vague within the technology stack of a distributed application.
Daml vs. Corda
Distributed Corda applications can be written in Java or Kotlin. Both languages are object-oriented rather than functional, which doesn’t make them very well suited to expressing declarative programs. In general, you have to go deep into the implementation details when writing a Corda application—much more than what can be easily communicated with the product team and corporate lawyers.
In Corda, you have to write “contracts,” states, and flows separately to express roughly the same concepts as expressed by a Daml contract package. The essence of a Corda contract is the `verify` method, which imposes constraints on state transitions. The states (which are expressed as contract payloads in Daml) need to be created separately. The active part of state transitions (roughly, the consequences of Daml contract choices) need to be written as flows.
Daml vs. Hyperledger Fabric
In Hyperledger Fabric, smart contracts, which are also called “chain code”, are not conceived at all as declarative. As the docs point out: “Whereas a ledger holds facts about the current and historical state of a set of business objects, a smart contract defines the executable logic that generates new facts that are added to the ledger.” A Fabric smart contract must implement the chain code interface, but otherwise, it can be an arbitrary piece of Go or Java code, which doesn’t even have to be deterministic. The lack of control over the contents of smart contracts make them poorly suited to expressing legal relationship or universal interfaces to a distributed transaction system.
We also have a new learn section where you can begin to code online: