io7m | single-page | multi-page | epub | Cedarbridge User Manual 1.1.0
2. Installation
Previous
Front Matter
Up
4. Command-Line Interface
Next

# 3. Tutorial

- 3.1. Overview
- 3.2. Preliminaries
- 3.3. Packages
- 3.4. Types
- 3.5. Protocols

## 3.1. Overview

1
This section of the manual attempts to provide a basic introduction to the cedarbridge language.

## 3.2. Preliminaries

1
The syntax of the cedarbridge language is based on S-expressions, with each cedarbridge source file consisting of a series of statements structured as S-expressions.
2
A cedarbridge file should start with a language statement indicating which version of the cedarbridge language the file is targeting. Should any backwards-incompatible changes be made to the language in the future, any files that explicitly declared which version of the language they are targeting would continue to be compiled correctly without errors. A file that does not contain a language statement will be compiled using whatever is the latest version of the language the compiler supports. The following example specifies that the file is intended for cedarbridge major version 1, minor version 0:

### 3.2.3. Language Statement

    (language cedarbridge 1 0)

4
The language allows for using parentheses or square brackets to enclose expressions as long as the use is balanced. For example, all of these expressions are valid:

### 3.2.5. Valid Parentheses/Brackets

    (language cedarbridge 1 0)
    [language cedarbridge 1 0]

6
However, these expressions are not valid and will cause a parse error:

### 3.2.7. Invalid Parentheses/Brackets

    (language cedarbridge 1 0]
    [language cedarbridge 1 0)

## 3.3. Packages

1
The cedarbridge language contains a basic package system. All declared message types and protocols must be declared inside packages. A package has a unique name conventionally in lowercase reverse domain notation. A package statement begins the definition of a package, and the definition continues to the next package statement or end-of-file, whichever occurs first. The following statement begins defining a package com.example:

### 3.3.2. com.example Package

    (package com.example)

3
Packages may import other packages using import statements:

### 3.3.4. Imports

    (import x.y.z z)
    (import a.b.c d)

5
An import statement (import x z) exposes all of the types present in package x via the short name z. For example, if a type T is declared in x, the type can be referred to using the qualified name z:T:

### 3.3.6. Qualified Names

    (import x.y.z z)

    (record Q
      [field something z:T])

## 3.4. Types

1
The cedarbridge language allows for defining message types based on algebraic sums and products. Product types are referred to as record types (similar to structs in the C language), and sum types are referred to as variant types (similar to algebraic data types in Haskell or the ML family of languages). Types may be parameterized by other types (referred to as generics or parametric polymorphism in other languages). A record type consists of a series of uniquely-named fields, and the order of fields is significant. The following statement declares a simple Color record type consisting of red, green, and blue fields:

### 3.4.2. Example Record

    (record Color
      [field red   Float64]
      [field green Float64]
      [field blue  Float64])

3
The cedarbridge language supports conventional variant types. The classic example for a variant type is the option type where values of type option may either be None or Some s for some value s. The following statement declares the classic parameterized Option type, with the None case having zero fields, and the Some case having exactly one field which is given the name value:

### 3.4.4. Example Option

    (variant Option
      [parameter A]
      [case None]
      [case Some [field value A]])

## 3.5. Protocols

1
In the cedarbridge language, there are no backwards-compatible changes possible for types: Adding, removing, or reordering record fields is a backwards-incompatible change. Reordering the cases of a variant type, or changing the fields of cases are backwards-incompatible changes. Rather than resort to the horrendously fragile and excessively permissive model used by other message protocol languages such as protobuf, the cedarbridge language exposes a strict and principled versioning mechanism that allows for unambiguous reasoning about any given version of a protocol; if you know the version of the protocol you are speaking, you know the exact shape of any and all messages that appear in that protocol without the possibility of any extra or missing fields.
2
A protocol declares a set of versions, with each version declaring the set of types present in each version of the protocol. The following example defines a simple protocol Foo with three versions:

### 3.5.3. Example Protocol

    [import com.io7m.cedarbridge cb]

    [record Command0
      [field name cb:String]
      [field ex   cb:IntegerUnsigned16]]

    [record Command1
      [field name cb:String]
      [field ex   cb:IntegerUnsigned32]]

    [record Command2
      [field name cb:String]
      [field ex   cb:IntegerUnsigned64]]

    [record Response
      [field text cb:String]]

    [protocol Foo
      [version 1
        [types-added Command0 Command1 Response]
      ]
      [version 2
        [types-added Command2]
      ]
      [version 3
        [types-removed Command0]
      ]

4
Note that Command0 and Command1 appear in the first two versions of the protocol, but version 3 of the protocol drops support for Command0. The Response type appears in all versions of the protocol. This allows for a disciplined approach to versioning; if a newer version of a protocol requires "changing" a message, the approach taken is to simply declare a new protocol version that contains a new message type (and, almost certainly, removes the old message type).
2. Installation
Previous
Front Matter
Up
4. Command-Line Interface
Next
io7m | single-page | multi-page | epub | Cedarbridge User Manual 1.1.0