LogoLogo
ClausesDatafieldsSpecial FunctionsStylingQ&AAPI
  • Welcome!
  • Getting started
    • What is Clause9?
    • Structuring your clause library
    • Structuring your clauses
    • Drafting modes in Clause9
    • Creating a questionnaire
    • Sample clauses
    • Videos
      • Concepts and datafields
      • Conditions
      • Q&As
      • Binders
      • Styling
      • Enumerations
      • Tables
      • Definitions
      • Snippets
      • Cross-references
      • Special functions
      • Examples of common clauses
      • Import clauses from MS Word
      • Grammatical conjugations
      • Action buttons
      • Alternative clauses
  • Assemble document
    • Document toolbar
    • Clause hierarchies
    • Focus Mode
    • Bulk generation of documents
    • Exporting documents
    • Assemble Document - FAQ
    • How to: Assemble Document
      • Insert images
  • Assemble Document Operations Panel
    • Operations panel
    • File pane
    • Edit pane
    • Document pane
    • Binder pane in the operations panel
    • Search pane
    • Browse pane
    • Terms pane
    • Data dashboard
    • Advanced pane
    • Styling pane
    • Miscellaneous pane
    • Visibility settings & actions menu
  • Binders
    • Binders: general
    • Styling cross-references to subdocuments
    • Global and local definition lists
    • Document and binder properties
    • Styling of a Binder versus subdocuments
    • (Un)locking documents in a binder
    • Binders - FAQ
    • How to: binders
      • Make a subdocument in a binder conditional
  • Clauses
    • Introduction to clauses
    • Clause structure
    • Grammar sheet
    • Writing conditions
    • Examples of conditions
    • Using codes instead of text fragments
    • Bold, italic and underline
    • Special codes
    • Enabled?
    • Links
    • Cross-references
    • Introduction to tables
    • Deviating table styling
    • Shrinking clauses
    • Action buttons
    • Enumerations
    • File position
    • Snippets
    • Parameters
    • Conjugations
    • Mixing data types
    • For-loops
    • Clause versioning
    • Abstract article references
    • Advanced multi-language features
    • Clauses - FAQ
    • How to: clauses
      • Create an ad-hoc clause
      • Create a library clause
      • Make a clause repeat
      • Make a paragraph within a clause conditional
      • Use a shortcut to refer to a concept
      • Insert a line break or page break
      • Creating a list with both predefined options and free input
      • Defining alternative clauses
      • Creating cross-references
      • Creating signature blocks
      • Creating advanced party introduction clauses
      • Automatically numbered annexes or schedules
      • Reuse any clause in a different context
      • Setting MS Word document properties
      • Add action buttons to clauses
      • Electronically signing documents
  • concepts
    • Introduction to concepts
    • Creating concepts
    • Concept labels
    • Links
    • Organising concepts
    • Concepts - FAQ
    • How to: concepts
      • Add predefines to a datafield
  • Datafields
    • Introduction to datafields
    • Types of datafields
    • Rules of thumb for using datafields
    • Data-expressions
    • Datafield aliases
    • Datafield labels
    • Datafield special tags
    • Datafield descriptions
    • Repeating list datafields
    • Datafield predefines
    • Datafields - FAQ
    • How to: datafields
      • Change datafield type
      • Change the datafield's name or alias
  • Definitions
    • Introduction to definitions
    • How to: definitions
      • How do definitions work?
      • Create a definition
  • Files
    • How files are organised
    • Browse files
    • File types
    • Custom styling
    • Legal comments
    • File description
    • Attributes
    • Reporting
    • File name
    • File category
    • Access rights
    • How to: files
      • Creating advanced folders
      • Naming your files
      • Shortcuts to folders or files
  • Q&A
    • About cards
    • Cards pane
    • About changes
    • Changes pane
    • Types of changes
    • Adding conditions
    • Question options
    • Copying & pasting answers
    • Comments, notes & documentation
    • Interactive Q&A inspection
    • Embedding questions into a document
    • “Changes” button
    • Batch create pane
    • Identifiers pane
    • Import pane
    • Edit clauses pane
    • Q&A options
    • Q&A - FAQ
    • How to: Q&A
      • Create predefined answers to a question
      • Add disclaimers
      • Create categories of questions
      • Modify the exported filename
      • Create a question to change the language of a document
      • Send a questionnaire to someone without a ClauseBase account
      • Create questions for repeating list datafields
      • Selecting legal entities & addresses
      • Create a questionnaire using "batch create"
      • Launch other Q&As
    • Leveraging ClauseBuddy Smart Templates in Clause9
  • Import
    • Introduction to importing clauses
    • Uploading clauses
    • Defined terms in Import mode
    • Datafields in Import mode
    • Cross-references in Import mode
    • Assigning folders
    • Conversion process
    • Exporting
    • Stashing intermediate results
    • Tips, tricks & limitations
  • Styling
    • Styling overview
    • Base styling
    • Numbering
    • Definitions styling
    • Enumerations styling
    • Locale styling
    • References styling
    • Page styling
    • Styling of a Binder versus subdocuments
    • Styling: tips and tricks
    • Advanced styling topics
    • Copying headers and footers from an MS Word file
    • How to: styling
      • Using custom fonts
      • Change bullet styling
  • Special functions
    • Introduction
    • Calculations
    • Concepts
    • Conditions
    • Conjugations
    • Content Control Elements
    • Datafields
    • Dates & durations
    • Languages
    • Lists
    • Numbers
    • References
    • Repeating (looping)
    • Special items
    • Text structure
    • Text modification
    • User
    • Q&A
  • Settings
    • Account
    • Preferences
    • Access bundles
    • Favourites
    • Saved searches
    • Saved datafields
    • Styles
    • Default styles
  • Admin
    • General
    • Users
    • User rights
    • Profiles
    • Groups
    • Styles
    • Default styles
    • Attribute models
    • Usage page
    • Custom homepage
    • Global placeholders
    • Access rights
    • How to: admin
      • Adding a new user
      • Disabling a user
      • Managing group memberships
  • Miscellaneous
    • Advanced tips & tricks
    • Typing special symbols on your keyboard
    • Shortcuts
    • Grammar style guide
    • Inserting MS Word files
    • Globo-panel
    • Creating high-quality documents
    • Excel calculations and lookups
  • Integrations
    • Overview
    • Spreadbases
    • E-signing documents
    • Drag & drop integrations
  • For developers
    • Clause9 API
    • Custom functions
    • Example custom functions
Powered by GitBook
On this page
  • Natural language versus conditions & calculations
  • Calculation mode
  • Condition mode
  • Data type
  • Supported currencies
  • Conversions between data types
  • Explicit conversions
  • Implicit conversions of basic data types
  • Implicit conversions of undefined
  • Implicit conversions to true/false in a condition
  • Implicit duration conversions
  • Implicit conversions to clause text
  • Avoided implicit conversions
  • Disallowed operations
  • Dealing with the data type of if/then/else
  • Examples
Export as PDF
  1. Clauses

Mixing data types

PreviousConjugationsNextFor-loops

Last updated 1 year ago

While drafting clauses in Clause9 is certainly not “programming” in the traditional sense, Clause9 borrows some best-practices from traditional programming languages. Legal experts who have never done any traditional programming are often confused by these practices.

One such issue is the concept of data types — aka the issue of not mixing apples and oranges. This page deliberately takes a deep-dive into dealing with these types, to fully explain how they work in Clause9.

Natural language versus conditions & calculations

A first important idea to grasp is the distinction between natural language mode and conditions/calculations mode.

The standard mode in Clause9 is the natural language mode. This is the mode you will implicitly arrive in when starting to type something in a clause. It will consist of “human” language stuff, such as words in English/French/Dutch, punctuation and numbering, etc. For example, the following clause entirely consists of the natural language mode elements:

A clause that consists entirely of natural language mode elements will be completely static, i.e. aside from the numbering and formatting of the clause, this clause will not change appearance. To insert dynamic elements, you insert conditions and calculations, for example:

As soon as you type in an opening accolade { you will leave the natural language mode, and enter either

  • the condition mode, for which the result’s type is always true or false); or

  • the calculation mode (for which the result’s type depends on the kind of calculation being made).

In the example above, #contract^value < 500 EUR and #contract^value < 2000 EUR are written in the condition mode, while apples^amount * #apples^unit-price is written in the calculation mode.

After the closing accolade }you will in any case leave these modes, and return to the natural language mode. However, the switch between the modes is more complex than just looking at the opening and closing accolade. For example, in paragraph 1. above, the parts between the colon (:) and the vertical bar (|) are once again in the natural language mode, i.e. the words low and medium and high.

Calculation mode

As the name implies, calculation mode expects to perform calculations. The input to these calculations consists of a mix of countable elements and optional operators — e.g. 5 + 24 or 5 * 4.5 EUR, but also 12 months * 4 or 2020_11_23 + 3 days, because you can perform interesting calculations with durations and dates.

Instead of using directly countable elements, you can also work with elements that ultimately boil down to numbers. For example, in apples^amount * #apples^unit-price, the datafields “amount” and “unit-price” can be assumed to contain countable things. When, for example, the number 5 would be assigned to apples^amount and the #apples^unit-price would be assigned the value 0.4 EUR, Clause9 will happily perform the calculation for you and return the result (2 EUR).

Note that natural text cannot, as such, be used in calculation mode. After all, text is — as such such — not countable. It does not make sense to, for example, perform a calculation to divide the words “the Buyer buys an apple” by the words “the Seller sells a pear”.

Condition mode

Writing in the condition mode will be writing in calculation mode, with one exception. Condition mode is meant to ultimately result in true or false, and will therefore contain a left side with a calculation, a comparison operator and a right side with yet another calculation.

For example, in the condition apples^amount * #apples^unit-price < 2000 EUR, you will see a left side (containing a calculation on apples), a comparison-operator (smaller than <), and a right side (with a single currency-value).

Data type

In Clause9, as in most programming languages, you can only calculate with elements of the same data type, and you can only compare elements of the same data type. For example, it does not make sense to add 25 EUR to a date, or to compare the text “alpha” to the duration of 5 months.

Clause9 offers the following basic data types:

Data type
Examples

whole number

0; 5; 21456

floating point number

4.56; 2457.8975

currency number

0 EUR; 56.34 EUR

text

"alpha"; "Main Street 56 Brussels"

date

5 January 2020; 8 July 2022

duration

3 years; 4 months; 2 days

true/false

true

In addition, the following special data types are also offered.

Data type
Example

list of elements (any of the other types allowed)

5, 6 EUR, 3 January 2020

clause text

1. Alpha * Beta ** Gamma

clause part

@ALPHA

defined term

#contract

datafield reference

#contract^value

nothing / undefined

The three different modes result in three different data types:

Mode
Result

natural language mode

always results in clause text

calculation mode

result type will depend on the elements used — e.g. 3 + 3 results in a whole number

condition mode

always results in true/false

Supported currencies

Clause9 currently supports the following currencies:

Currency
Symbol used in Clause9

euros

EUR

British pound

GBP

United States dollar

USD

Japanese Yen

JPY

Australian dollar

AUD

Canadian dollar

CAD

Swiss franc

CHF

yuan

CNY

Kenyan shilling

KSH

Hong Kong dollar

HKD

New Zealand dollar

NZD

Swedish krona

SEK

South Korean won

KRW

Singapore dollar

SGD

Norwegian krone

NOK

Mexican peso

MXN

Indian rupee

INR

Russian ruble

RUB

South African rand

ZAR

Turkish lira

TRY

Brazilian real

BRL

New Taiwan dollar

TWD

Danish krone

DKK

Polish złoty

PLN

Thai baht

THB

Indonesian rupiah

IDR

Hungarian forint

HUF

Czech koruna

CZK

Israeli shekel

ILS

Chilean peso

CLP

Phillipine peso

PHP

UAE dirham

AED

Colombian peso

COP

Saudi riyal

SAR

Malaysian ringgit

MYR

Romanian leu

RON

Conversions between data types

While it is not possible to perform calculations or comparisons with elements of different data types, it is possible to convert an element to another data type. This conversion can either be done explicitly or implicitly.

Explicit conversions

At first glance, this may look like nothing changed; under the hood, however, the type of this element changed from a duration to a text, meaning that the operations that can be applied to a duration element (e.g., addition or subtraction) will suddenly no longer work, while the operations that can be applied to a text element (e.g., capitalization) will suddenly become possible. If the active language is not English, the conversion will be much more visible. For example, @str(3 months) may also be converted to “trois (3) mois” in French, with a styling setting where numbers are always converted to both letters and numbers.

Most special functions will perform something more than solely converting an argument from one data type to another data type. Examples:

  • @round and @floor will convert the floating point number passed to them, and then either round that number or truncate the decimal part, returning a whole number

  • @comma-split will take a text element and return a list element that contains individual text elements (e.g. @comma-split("alpha, beta, gamma") will return a list with text elements "alpha", "beta" and "gamma".

Implicit conversions of basic data types

It would be cumbersome to always have to explicitly convert data types — e.g., imagine that in order to take 5.5 times the duration of a contract, you would have to write 5.5 * @float(@months-in(#contract^duration))

The underlying reasoning is as follows: you are performing a multiplication of a floating point number and a duration, which is not possible. There exists a special function @months-in that takes a duration and returns a whole number that corresponds to the amount of months in that duration. However, you would then have to perform yet another conversion from this whole number to the floating point number. You would therefore have to use the hypothetical @float function.

To avoid these situations, Clause9 will implicitly perform conversions for you when no ambiguity is involved:

Data type 1
Data type 2
Resulting data type
Example

whole nr

floating point nr

floating point nr

5 + 5.5 results in 10.5

whole nr

currency nr

currency nr

200 + 300 EUR results in 500 EUR

floating point nr

currency nr

currency nr

229.5 + 300 EUR results in 529.5 EUR

date (*)

duration

date

2018_7_12 + 1 month results in 2018_8_12

list (**)

(any data type)

list

@list("alpha", "beta") + "gamma" results in @list("alpha", "beta", "gamma")

  • (*) When mixing a date with a duration, note that the order and operation matters. The conversion will only be applied with date +/- duration. If you change the ordering (e.g., duration first) or the operation (e.g. multiplication), the result will be an error.

  • (**) When mixing a list with, the order and operation matters: the conversion will only be applied with list +/- element, not with element +/- list.

    • When using the - operator, the element(s) at the right side are removed from the list at the left side. For example, @list("alpha", "beta") - "alpha" and @list("alpha", "beta") - @list("alpha") both result in @list("beta").

    • When using the + operator, the result depends on the right-side:

      • If both the left & right side are lists, then the result will be a concatenation of the two lists, with all the elements of the right list appended to the left list, irrespective of whether they were already present in the left list. For example, @list("alpha", "beta", "gamma") + @list("alpha", "delta") will result in @list("alpha", "beta", "gamma", "alpha", "delta"). (If you want a union of the list, where elements-already-present are not added again, use the @union special function instead of +).

      • If the right side is not a list, then it will be added as a new element of the left list, irrespective of whether the right side element was already present in the list. For example, @list("alpha", "beta") + "alpha" will result in @list("alpha", "beta", "alpha"). (If you want a union of the list and the single element, where the right-side element is not added again to the left list, use the @union special function instead of +).

Implicit conversions of undefined

When using datafields, values will often not be present, because they have not (yet) been filled in by the end-user. Within a calculation/condition, to avoid errors, Clause9 will try to convert this undefined value to a sensible default value:

Datatype

Converted into

Example

number

0

55 * undefined results in 0

currency

0 (same valuta)

5 EUR + undefined results in 5 EUR 5 EUR * undefined results in 0 EUR

duration

duration with length 0

5 days + undefined results in 5 days

text

empty text

empty text is simply ignored in the output

list

empty list

@list("alpha") + undefined results in @list("alpha")

Note that the date field is missing from the table above: an undefined will never be implicitly converted to a date field. (After all, there exists no date that would make sense here: what could possibly be considered “date zero”?)

Implicit conversions to true/false in a condition

In condition mode, the following implicit conversions are carried out to convert a data type to true/false:

Data type

Converts to true when

Converts to false when

Text

Non-empty text value

Equal to the empty-text value (“”)

(Whole/floating/currency) number

Not equal to 0

Equal to 0

Duration

Amount higher than 0

Amount equal to 0

List

Not empty

Empty (no elements)

Date

Assigned some value

Never

Undefined (e.g., datafield without value)

Never

Always

Note that in an if-then-else condition, you can omit the operator and right-hand side of the comparison for the sake of brevity; Clause9 will then automatically insert = true. For example:

  • Instead of writing {#contract^is-dutch-law = true: ... } you can also write {#contract^is-dutch-law: ... }. If the datafield is-dutch-law is a true/false datafield, then no implicit conversions will occur.

  • Instead of writing {#contract^value > 0: ... } you can also write {#contract^value = true: ... } or the shorter version{#contract^value: ... }. In both of these cases, the contract-value whole number datafield will be converted into a true/false, meaning it will result in true if a non-zero value is assigned to this datafield; it will instead result in false when no value is assigned at all, or when the value that is assigned to this datafield, is equal to zero.

Implicit duration conversions

When combining duration elements of different units in a calculation, conversions may be necessary — e.g., when you add 2 days to 3 months. You should be aware that such conversions will in many cases result in rounding errors and unexpected results, because a duration does not contain any context about the month or year it relates to.

Clause9 will convert durations with different units into the lowest time unit, e.g. year + months will be converted to months, year + days will be converted into days, and months + weeks will be converted into weeks. Clause9 tries to use sensible averages during this conversion, but unexpected results are bound to happen due to the lack of context.

The bottom line is that you should try to avoid these implicit conversions as much as possible.

For example, Clause9 happens to convert 27 months + 1 day to 822 days, because it first converts 27 months to two years (= 730 days) and 3 months (= 3 times average of 30.417 days, so 91 days), and then adds yet another day. An equally sensible result would, however, be 811 days (= 27 * 30 days + 1 day). Similarly, Clause9 happens to convert a month into 4.345 weeks, so that 3 months + 1 week gets converted to 14 weeks. Other software or people would perhaps answer 13 weeks.

Implicit conversions to clause text

Clause9 allows you insert a datafield directly into natural text. For example:

While perhaps not immediately obvious, this is also a situation where apples (clause text) are combined with oranges (number datafield). To avoid that you would have to insert all kinds of ugly codes to allow this, Clause9 will implicitly convert this datafield into clause text for you.

In most situations, this conversion will be very straightforward. However, do note the following.

  • A (whole/floating point/currency) number and a date value be converted into text in accordance with the locale styling rules (e.g., for the decimals style, currency symbol placement, short/long date format, etc.).

  • A true/false value will get translated — e.g., Alpha {true}. will be converted into Alpha true in English and Alpha vrai in French.

  • A list value will have its elements printed consequentially with spaces in between — e.g. @list("alpha", "beta", "gamma") will be converted into alpha beta gamma. If you want to have comma’s plus and/or etc. in such list, or perhaps convert it into a bullet-list, then you need to use one of the special functions — e.g., @enumerate-andor(@list("alpha", "beta", "gamma")).

Avoided implicit conversions

Some conversions are deliberately not performed, because they would be ambiguous:

  • Adding a (whole/floating/currency) number to a duration or date. For example, 3 months + 3 results in an error because it will be difficult for the software to figure out whether you want the result to be a duration (6 months) or a whole number instead (6).

  • Adding a number to a date. For example, 2020_04_07 + 3 results in an error, because it is not clear whether you would like to add 3 years, 3 months, 3 weeks or 3 days instead.

Other conversions are deliberately not performed because they make no sense:

  • Mixing text and whole/floating/currency numbers. It will usually be obvious that this does not make sense — e.g. "alpha" + 6 — but this may not always be intuitive to those new to Clause9. For example, if you create a text datafield #contract^value, then Clause9 will treat the contents of this datafield as text, and issue an error when you try to do a calculation such as #contract^value * 2. This error will make perfect sense when the end-user would type in “real” text (such as the word “Paris”), because you can obviously not multiply Paris by two. However, when an end-user would type in a number (e.g., 3500), then it will not be so obvious why the software is complaining.

Disallowed operations

While not a data type conversion issue, you should also note that some operations are not allowed between elements of the same data type:

  • You cannot mix different currencies — e.g., adding {200 EUR + 300 USD} results in an error.

  • You cannot add dates to each other — e.g. {2020_04_03 + 2020_05_3} results in an invalid operation error.

Dealing with the data type of if/then/else

An if/then/else construction will normally result in clause text. For example,

1. Upon drafting @CONTRACT, the parties agreed to have @CONTRACT screened by the authorities. If @CONTRACT would turn out to be ...

CONTRACT = {#contract^with-annexes: this Employment And Restructuring Contract (ERC) including its annexes | else: this ERC}

However, it is also possible to use the if/then/else construction to return other data values. You can do this by wrapping the content of the if/then/else after the colon (:) between curly braces. For example:

1. Buyer will pay an amount equal to {@INTEREST * 1.5} before 1st January. If this payment is not successfully performed, it will be automatically increased to {@INTEREST * 2}.

INTEREST = {#contract^jurisdiction = "dutch": {0.05 * #contract^value} | else: {0.08 * #contract^value} }

It is interesting to analyse why you will get a “value is not a number” error when you omit the two pairs of curly braces in the if/then/else construction:

1. Buyer will pay an amount equal to {@INTEREST * 1.5} before 1st January. If this payment is not successfully performed, it will be automatically increased to {@INTEREST * 2}.

INTEREST = {#contract^jurisdiction = "dutch": 0.05 * #contract^value | else: 0.08 * #contract^value }

The reason is that Clause9 will do the following:

  • When encountering the {@INTEREST * 1.5}, it will replace the @SNIPPET with the contents of the internal snippet, arriving at {#contract^jurisdiction = "dutch": 0.05 * #contract^value | else: 0.08 * #contract^value } * 1.5

  • It will then execute the if/then/else construction, and check whether the contract’s jurisdiction is equal to “dutch”. Assuming this is indeed the case, Clause9 will notice that the associated fragment it has to insert into the main part of the clause is 0.05 * #contract^value.

  • Because this fragment is not wrapped in curly braces, Clause9 will treat the fragment as clause text. For example, if the contract’s value is currently set to 1000, and the current styling happens to be metric, it would convert the fragment into the text “0.05 * 1.000” . Notice that:

    • because the fragment is treated as clause text, Clause9 will treat the 0.05 literally, i.e. not consider it to be a number. Accordingly, despite the fact that the styling settings are set to metric (so that a floating point number such as 0.05 would be printed with a comma as “0,05”), Clause9 will print it as “0.05”

    • the contract’s value (1000) is a whole number that is inserted into clause text, and will therefore get converted to clause text, respecting all the styling settings (such as the metric style’s dot between the 1 and the three zeroes)

  • Next, it will try to multiply the clause text “0.05 * 1.000” by the number 1.5, which obviously does not make sense because you cannot multiply text by a number. It will therefore issue a warning “value is not a number”.

Pursuant to article 3§4 of the Civil Code, #Buyer shall ...

Examples

Why is shall pay 10.20 EUR printed as “shall pay 10.20 EUR”, while my styling settings dictate metric style with a euro-symbol?

Why do I see an error message with Pursuant to article 3§4 of the Civil Code, #Buyer shall ... ?

I get an “incompatible argument types” error when using the following clause: #Buyer shall pay interest equal to @days-between(#contract^start-date, @today)

The software does not accept the following clause (shows a yellow error): #Buyer shall pay interest equal to @days-between({#contract^prolonged: #contract^prolongation-date | else: #contract^start-date}, @today)

Explicit conversions can be achieved using . For example, the special function @extract-number will take a currency number (e.g., 5.5 EUR) and return the floating point number (5.5). Similarly, the sole purpose of the special function @str is to convert the argument passed to it into text — e.g. @str(3 months) will, depending on the styling settings, result in the text 3 months when the active language is English.

Tip: when you do not like these implicit conversions of unavailable values inside a calculation, you may want to use . For example, while you may be happy with {#apples^amount * 0.2 EUR} resulting in 0 EUR when the amount of apples has not yet been completed by the end-user, it may equally be the case that you absolutely need the user to fill in this amount. If so, then use {#apples^!amount * 0.2 EUR} instead — this will result in a box that invites the user to fill in this value, signaling that the calculation simply cannot be completed without a value assigned to the amount of apples.

The contents of the CONTRACT will be clause text, because its sole element is an if/then/else construction between curly braces. Such clause text can be inserted into the main body of the clause without any conversion being necessary.

special functions
internal snippet
an exclamation point after the hash