Targets · Go · Drivers

Drivers

The native drivers that provide the interface, console and network.

Contents

How a Program becomes Go, in parts. Start with the introduction, then follow each part into the rendered output and the runtime it links against.

Defining a driver

A driver is a Go value implementing the Driver interface: it drains one context channel and reconciles the resources it owns. Here is a console driver — it drains the Console.Lines channel and prints each line that has changed since the last cycle.

type ConsoleDriver struct {
    lastById map[int64]string
}

func NewConsoleDriver() *ConsoleDriver {
    return &ConsoleDriver{lastById: map[int64]string{}}
}

func (d *ConsoleDriver) Channel() string    { return "Console.Lines" }
func (d *ConsoleDriver) Kind() DriverKind   { return ArrayChannel }
func (d *ConsoleDriver) Init(addUpdates AddUpdates) {}

func (d *ConsoleDriver) Dispatch(emissions []Line) {
    for _, line := range emissions {
        if d.lastById[line.Id] != line.Text {
            fmt.Println(line.Text)
            d.lastById[line.Id] = line.Text
        }
    }
}

Registering it

A program lists the drivers it uses; the runtime opens a channel for each and never hardcodes one.

func main() {
    Program.Application(func() {
        Main()
    }, []Driver{
        NewConsoleDriver(),
    })
}

How the runtime runs it

Each cycle the runtime opens the driver's channel, runs the reactive program (which emits into it), drains it, and passes the slice to Dispatch:

Context.OpenArray("Console.Lines")
program = Reactive.Run(program, updates)
driver.Dispatch(Context.DrainArray("Console.Lines"))

A driver that produces events — a timer, a network reply, often on its own goroutine — calls the addUpdates it was given in Init, which schedules the next cycle. The three shapes are the same as everywhere: a tree renderer (the terminal interface), a request set (network), and a shared ticker.