Skip to the content.

Toit

CLI

The toit SDK installation is placed in ~/.cache/toit

Toit Language

Toit Terms

Variables

Classes

Basic Types

Toit Types

Types are optional. A variable is typed if followed by a /type-name. By default types are non-nullable, which means null is not a valid value.

class Coordinate:
  // An instance field that must be initialized by
  // constructors.
  // By writing `:= ?` we indicate that all constructors
  // must initialize the field.
  x /int := ?
  y /int := ?

  // We don't need to specify the type for constructor
  // arguments that are written directly to a typed field.
  constructor .x .y:

main:
  a := Coordinate 0 0

  // Error! The types of the fields (and therefore the
  // constructor arguments) are non-nullable, so null is not
  // a valid argument here:
  b := Coordinate null null  // Error!

Nullable types are defined using a ? after the type name.

class Foo:
  bar /Bar? := null
any/none - Two special types exists:
Return types

The return type is defined with -> type

// A function that doesn't return anything.
foo -> none:
  print "not returning anything"

// A function that takes an int and returns an int.
bar x/int -> int:
  return x + 1

Operator Precendence

See definition of operators on the classes for int, float and num

Functions

// simple function definition with 2 arguments, argumment 2 has a default value
some_fct argument1 argument2="default value":
  print "arguments: '$argument1' '$argument2'"

main:
  // showing calls to the 'some_fct' function
  some_fct "test 1"
  some_fct "test 1" "test 2"

Classes

// simple *class* definition
class SimpleAdder:
  addend1_ := null // private by convention as ending in '_'
  addend2_ := null // private by convention as ending in '_'

  // the constructor assigning addend1 and addend2, defaults to 0
  constructor .addend1_=0 .addend2_=0:

  sum:
    return addend1_ + addend2_

main:
  // creating an instance and calling 'sum'
  simple_adder := SimpleAdder 13 17
  print "the first sum is $simple_adder.sum"

  // creating an instance where addend2 is default value (0)
  simple_adder_noop := SimpleAdder 13
  print "the second sum is $simple_adder_noop.sum"

Toit also supports interfaces and abstract classes

The Advanced Constructor Topics details how an object is constructed and how the sequence is split into an initialization and an instance part.

Named Arguments

// function with named argument
say_hi name --greeting="Hello ":
  // Greet everyone individually!
  print "$greeting $name"

main:
  // calling a function with a named argument
  say_hi "Peter"
  say_hi "Berit" --greeting="Hi"

Loops and if..else

// loop using number.`repeat`
print_n_numbers n:
  // using repeat on number
  n.repeat: print it // `it` is an *automatic* variable that gives the iteration count

  // traditional for loop
  for i := 0; i < n; i++: print i

  // traditional while
  i := 0
  while i < n: print i++


// define a list and loop over it, using the `do` method available on all collections
print_list:
  list := [ "Horse", "Fish", "Radish", "Baboon" ]
  list.do: print it // `it` is an *automatic* variable that gives the element
  print (list.join ",")


// if..else
print_even_or_odd n:
  if n % 2 == 0: print "$n is even"
  else: print "$n is odd"

Maps and Sets

list_of_something := []   // empty list
map_of_x_to_y     := {:}  // empty map
set_of_something  := {}   // empty set

Iterating a map iterates the key value pairs - see block arguments

main:
  map ::= {
    1234: "Siri",
    2345: "John",
    3456: "Sue"
    }
  map.do: | id name |
    print "$name has ID $id"

Blocks

do and repeat looks like they are built in to the language like if and for, but they are normal methods on the List and Integer classes

class List:
  // ...
  do [block]:
    size.repeat: block.call this[it]

class Integer:
  // ...
  repeat [block]:
    for i := 0; i < this; i++:
      block.call i

As blocks are stack-allocated there are some restrictions on blocks.

Concurrency - tasks

Toit uses Cooperative scheduling where all tasks / fibers runs on the same heap and only switch task on yield points.

A task is started with task:: syntax (double :)

import gpio

// The red LED is connected to pin 17.
LED1 ::= gpio.Pin.out 17
// The green LED is connected to pin 18.
LED2 ::= gpio.Pin.out 18

main:
  // Note the double `::` on the next two lines.
  // Start a task that runs the my_task_1 function.
  task:: my_task_1
  // Start a second task that runs my_task_2.
  task:: my_task_2

my_task_1:
  while true:
    sleep --ms=500
    LED1.set 1
    sleep --ms=500
    LED1.set 0

my_task_2:
  while true:
    sleep --ms=123
    LED2.set 1
    sleep --ms=123
    LED2.set 0

Synchronization Methods

Synchronization between tasks is possible using the monitor library

Exception Handling

my_function:
  my_exception := catch --trace:
    code_that_might_throw 42 103
  if my_exception:
    code_to_run_when_an_exception_was_thrown "foo" "bar"

Hardware - ESP32

GPIO (General Purpose I/O)

GPIO pins are globally acquired

import gpio

main:
  pin := gpio.Pin 21  // Acquired system-wide.
  // ...
  pin.close           // Released, can be used by other applications now.

Two different modes:

Running apps on the Device

Two modes

Simulator Device

toit simulator start --alias TestDevice  # start a simulator device named 'TestDevice'

toit run -d TestDevice hello.toit        # run the hello program once
toit deploy -d TestDevice hello.yaml     # deploy the hello app to the device

toit device -d TestDevice ps             # list apps on the device
toit device -d TestDevice logs -f 10m    # attach to the logs from 10 minutes ago and tail
toit simulator stop TestDevice           # stop the device

Pubsub Communication

Asynchronous message communication between apps.

topic is a named resource which is used when messages are published.