This style guide details the formatting and styling of Daml and client-side code that is contained within this repository.
- Use 2 spaces for indentation
- Use single empty line to separate sections (and end the file with a single empty line)
- Use at most 100 characters per line. As a visual guide, you can add
"editor.rulers": [100]
to your vscodesettings.json
.
-
Order imports alphabetically with upper-case before lower-case:
import DA.Set (Set, empty) import Daml.Script
-
Use qualified imports for interface modules:
import Daml.Finance.Interface.Asset.Holding qualified as Holding (view, I, V)
-
Use explicit imports and order them alphabetically:
In case of no name clashes, use unqualified imports:
import DA.Set (fromList, singleton)
and otherwise qualified imports:
import DA.Map qualified as Map (fromList) import DA.Set qualified as Set (fromList, null)
- Only use explicit export lists when not all types or functions in a given module are exported
- Use the
-- | HIDE
annotation for anything that is not exported - Do add comments for types and functions that are not exported
- If you want an internal function to be tested individually, add it to the export list but
annotate it with the
-- | HIDE
comment.
-
Modules use the following newlines:
module Foo.Bar where import A.B.C import A.B.D template Baz with ... template Baz2 with ...
-
Templates use the following indentation and newlines:
template Foo with party1 : Party party2 : Party where signatory party1 observer party2 key party1 : Party maintainer party1 let a = 1 b = 2 choice Delete : () with party : Party controller party do pure ()
-
Group all serializable interface fields into a
View
type:-- | View for `Account`. -- This data type is .. data View = View with custodian : Party -- ^ Party providing accounting -- services. id : Text -- ^ Textual description of -- the account. owner : Party -- ^ Party owning -- this account. deriving (Eq, Show)
-
Add a
viewtype
definition to the interface with theView
type:interface Account where viewtype View ...
-
Define
I
andV
type aliases for the interface and view type, respectively:type I = Account type V = View
-
In consuming code, use qualified imports to refer to interfaces and view typs, e.g.,
import Daml.Finance.Interface.Holding.V4 qualified as Holding (I, V)
. -
For interface choices with empty implemenations
To prevent us from keeping the implementation arguments 'in sync' with the choice arguments, we use
foo : Foo -> Update res choice Foo : res with a : A b : B controller actor do foo this arg
instead of
foo : A -> B -> Update res choice Foo : res with a : A b : B controller actor do foo a b
Recall that
arg
is syntactic sugar forFoo with a; b
when used in the body of the choice.
-
Place the main
do
in a choice on its own line:choice Delete : () controller party do pure ()
-
Place
do
in functions and expressions on the same line:let foo = do if a then do ... else do ...
-
Use the CamlCase naming convention for types, variables, and functions. For example:
data MyOptions = OptionOne | OptionTwo | OptionThree deriving (Eq, Ord)
mySum : Decimal -> Decimal -> Decimal mySum a b = a + b
myTerm = 3
-
Use plural 's' when naming
Set Party
.
-
Single-line body:
let a = b
-
Multi-line body:
let a = if b then c else d
-
Multiple bindings:
let a = b c = d
In case of flexible controllers, e.g.,
choice Foo : ()
with
actor : Party
bar : Int
controller actor
do
pure ()
we let the actor : Party
be the first argument of the choice.
-
Add function type signatures to all top-level functions:
add : Decimal -> Decimal -> Decimal add a b = a + b
-
Don't add type signatures for functions in
let
bindings (unless you think it is necessary):let add a b = a + b
-
Use
pure
instead ofreturn
as more idiomatic
-
Use
;
to separate parameters to differentiate from list and tuple separators:let foo = Foo with a = b; c = [d, e]; f = (g, h)
-
Use short-hand parameter notation:
let foo = Foo with a; b; c
-
Don't use
..
as it makes code harder to understand (and might cause bugs in case of code changes) -
Don't use positional constructors as they are harder to read (and might cause bugs in case of code changes)
In VS Code you can search using regex expressions. Here are some useful regex expressions to help enforce some of the points in this style guide:
-
\w\s{2}\w
finds 2 whitespaces between words. -
\n{2,}$
finds two or more empty lines. -
^.{101,}$
finds rows that contain more than 100 characters. -
\b(\w+)\s*=\s*\1\b
findsw = w
wherew
is some arbitrary word. -
\b(\w+)\s*=\s*(\w+)\s*(?:,\s*\b(\w+)\s*=\s*(\w+)\s*){1,}
finds comma separated assignments likeFoo with a = b, c = d
(we prefer using;
like inFoo with a = b; c = d
). -
submitMulti \[\w+\] \[\]
findssubmitMulti
which can be replaced bysubmit
. -
(\w+),(\w+)
finds comma separated values with no whitespace.