Connect IQ SDK

Hello Monkey C!

There is no better way to learn Monkey C than by jumping right in. Let’s take a look at the application object of a watch face.

using Toybox.Application as App;
using Toybox.System;

class MyProjectApp extends App.AppBase {

    // onStart() is called on application start up
    function onStart(state) {
    }

    // onStop() is called when your application is exiting
    function onStop(state) {
    }

    // Return the initial view of your application here
    function getInitialView() {
        return [ new MyProjectView() ];
    }
}

If this looks familiar and non-threatening, that’s the point. Monkey C is intended to be the language you didn’t know you already knew.

At the top is a using statement, which is analogous to C++’s using statement, or an import in Java™, Ruby, or Python™. using statements lexically bring modules into our name space. After a using clause, we can refer to a module by its shortened name (in this case System). Toybox is the root module for Monkey C system modules; all the cool toys are kept in there.

To print out values to the debug console, use:

System.println( "Hello Monkey C!" );

System refers to the Toybox.System module we imported with the using statement. Unlike Java namespaces, modules in Monkey C are static objects that can contain functions, classes, and variables. The println() function should be familiar to Java programmers—it prints a string and automatically adds a new line. The System module has a number of useful functions:

// Use println() to print to the console with a line terminator.
// @param a Object or string to display
function println(a)
{
    print( a.toString() + "\n" );
}

// Use print() to print to the console
// @param x Object or string to display
function print( x );

// Use getTimer() to get the current millisecond timer.
// @return [Number] System millisecond timer
function getTimer();

// Get the current clock time with getClockTime().
// @return [System.ClockTime] Current clock time
function getClockTime();

// Get the current system stats with getSystemStats().
// @return [System.Stats] Current system stats
function getSystemStats();

// In future versions of the SDK trap() will break into the debugger.
function trap();

// To end execution of the current system with an error message of
// "User terminated", call exit().
function exit();

// Call error() to cause an error. This will exit the system.
// @param [String] msg Error message to output
function error( msg );

Differences From Other Languages

As Italian and Spanish derive from Latin, Monkey C derives heavily from past languages. C, Java™, JavaScript, Python™, Lua, Ruby, and PHP all influenced the design for Monkey C. If you are familiar with any of those languages, Monkey C should be easy to pick up.

Java

Like Java, Monkey C compiles into byte code that is interpreted by a virtual machine. Also like Java, all objects are allocated on the heap, and the virtual machine cleans up memory (Java through garbage collection, Monkey C through reference counting). Unlike Java, Monkey C does not have primitive types—integers, floats, and chars are objects. This means primitives can have methods just like other objects.

While Java is a statically typed language, Monkey C is duck typed. In Java, the developer must declare the types for all parameters of a function, and declare the return value type. The Java compiler checks these at compile time to ensure type safety. Duck typing is the concept of “if it walks like a duck, and quacks like a duck, then it must be a duck”[1]. For example:

function add( a, b ) {
    return a + b;
}

function thisFunctionUsesAdd() {
    var a = add( 1, 3 ); // Return  4
    var b = add( "Hello ", "World" ); // Returns "Hello World"
}

The Monkey C compiler does not verify type safety, and instead causes a runtime error if a function mishandles a method.

Monkey C modules serve a similar purpose as Java packages, but unlike packages, modules can contain variables and functions. It is common for static methods to exist in the module as opposed to a particular class.

Lua/Javascript

The main difference between JavaScript or Lua and Monkey C is that functions in Monkey C are not first class. In JavaScript, a function can be passed to handle a callback:

function wakeMeUpBeforeYouGoGo() {
    // Handle completion
}

// Do a long running thing, and pass callback to call when done.
doLongRunningTask( wakeMeUpBeforeYouGoGo );

In Lua, to create an object, you bind functions to a hash table:

function doSomethingFunction( me ) {
    // Do something here
}

// Constructor for MyObject
function newMyObject() {
    local result = {};
    result["doSomething"] = doSomethingFunction;
}

Neither of these techniques works in Monkey C, because functions are bound to the object they are created in.

To create a callback in Monkey C, create a Method object. Method objects are a combination of the function and the object instance or module they originate from. You can then call the method using method():

// Handle completion of long
function wakeMeUpBeforeYouGoGo() {
    // Do something here
}

// Create a call back with the method method (jinx!)
doLongRunningTask( method( :wakeMeUpBeforeYouGoGo ) );

Ruby, Python, and PHP

Objects in Ruby and Python are hash tables, and have many of the properties of hash tables. Functions and variables can be added to objects at run time.

Monkey C objects are compiled and cannot be modified at runtime. All variables have to be declared before they can be used, either in the local function, the class instance, or in the parent module.

When importing a module, all classes inside the module have to be referenced through their parent module. You import modules, not classes, into your namespace.

Functions

Functions are the meat[2] of your program. Functions define discrete callable units of code.

Monkey C functions can take arguments, but because Monkey C is a dynamically typed language the argument types is not declared; just its name. Also, it is not necessary to declare the return value of a function, or even if a function returns a value, because all functions return values. You can specify the return value with a return statement, but if your function doesn’t have a return statement it will return the last value on the stack.

Functions can exist in a class or module, or appear in the global module.

Variables, Expressions, and Operators

The basic types supported by Monkey C are:

Keywords

Here is a list of keywords in the Monkey C programming language. You cannot use any of the following as variables or symbols in your programs. The keywords switch, case, and native are reserved, even though they are not currently used. true, false, null, NaN, new, and, and or might seem like keywords, but they are actually literals and operators; you cannot use them as identifiers in your programs.

break const else for if static using
case continue enum function instanceof switch var
catch default extends has module throw while
class do finally hidden return try

Declaring Variables

All local variables must be declared ahead of time using the var keyword. In the Monkey C language, all values (including numeric values) are objects.

var n = null;               // Null reference
var x = 5;                  // 32-bit signed integers
var y = 6.0;                // 32-bit floating point
var l = 5l;                 // 64-bit signed integers
var d = 4.0d;               // 64-bit floating point
var bool = true;            // Boolean (true or false)
var c = 'x';                // Unicode character
var str = "Hello";          // String
var arr = new [20 + 30];    // Array of size 50
var dict = { x=>y };        // Dictionary: key is 5, value is 6.0
var z = arr[2] + x;         // Null pointer waiting to happen

Monkey C supports the following operators:

Precedence Operator Description
1 new creation
! logical NOT
~ bitwise NOT
( ) function invocation
2 * multiplication
/ division
% modulo
& bitwise AND
<< left shift
>> right shift
3 + addition
- subtraction
| bitwise OR
^ bitwise XOR
4 < less than
<= less than or equals
> greater than
>= greater than or equals
== equals
!= not equals
5 && logical AND
and
6 || logical OR
or

Arrays

Arrays in Monkey C, like variables, are typeless, it is not necessary to declare a data type. There are two forms for creating a new array. To create an empty array of a fixed size, use this:

var array = new [size];

To pre-initialize an array, this syntax can be used:

var array = [1, 2, 3, 4, 5];

Elements are expressions, so multidimensional arrays can be created using this syntax:

var array = [ [1,2], [3,4] ];

Monkey C does not have a direct way of creating an empty two-dimensional array, one may be initialized with this syntax:

// Shout out to all the Java programmers in the house
var array = new [first_dimension_size];

// Initialize the sub-arrays
for( var i = 0; i < first_dimension_size; i += 1 ) {
    array[i] = new [second_dimension_size];
}

Dictionaries

Dictionaries, or associative arrays, are a built-in data structure in Monkey C:

var dict = { "a" => 1, "b" => 2 };  // Creates a dictionary
System.println( dict["a"] );        // Prints "1"
System.println( dict["b"] );        // Prints "2"
System.println( dict["c"] );        // Prints "null"

To initialize an empty dictionary, use the following syntax:

var x = {};                         // Empty dictionary

By default, objects hash on their reference value. Classes should override the hashCode() method in Toybox.Lang.Object to change the hashing function for their type:

class Person
{
    // Return a number as the hash code. Remember that the hash code must be
    // the same for two objects that are equal.
    // @return Hash code value
    function hashCode() {
        // Using the unique person id for the hash code
        return mPersonId;
    }
}

Dictionaries automatically resize and rehash as the contents grow or shrink. This makes them extremely flexible, but it comes at a cost. Insertion and removal of the contents can cause performance problems if there is accidental or excessive resizing and rehashing. Also, because hash tables require extra space for allocation, they are not as space-efficient as either objects or arrays.

Symbols

Symbols are lightweight constant identifiers. When the Monkey C compiler finds a new symbol, it will assign it a new unique value. This allows symbols to be used as keys or constants without explicitly declaring a const or enum:

var a = :symbol_1;
var b = :symbol_1;
var c = :symbol_2;
Sys.println( a == b );  // Prints true
Sys.println( a == c );  // Prints false

Symbols can be useful when wanting to create keys without having to declare an enum:

var person = { :firstName=>"Bob", :lastName=>"Jones" };

Constants

Constants are named, immutable values declared with the const keyword. These are useful for storing unchanging values that may be used repeatedly throughout code. Constants must be declared at the module or class level; they cannot be declared within a function.

Constants support the same types as listed for variables. It is important to note that with data structures like arrays, const functions similar to Java’s final keyword. For example, a const array prevents the array from being replaced by a new instance, but the elements of the array may be modified.

const PI = 3.14;
const EAT_BANANAS = true;
const BANANA_YELLOW = "#FFE135";

Enumerations

Enumerations are explicit or auto-incrementing constant mappings from symbol to integer. Unless explicity set (see the second example), each proceeding symbol is automatically assigned the value of its predecessor plus one, starting with 0. So, in the following example, the symbol Monday is automatically assigned the value 0, Tuesday is assigned 1, and so on. These symbols can be used just like constant variables (which is essentially what they are). Enums must be declared at the module or class level; they cannot be declared within a function.

enum {
    Monday,   // Monday = 0
    Tuesday,  // Tuesday = 1
    Wednesday // Wednesday = 2
    // ...and so on
}
enum {
    x = 1337, // x = 1337
    y,        // y = 1338
    z,        // z = 1339
    a = 0,    // a = 0
    b,        // b = 1
    c         // c = 2
}

Note that assigning anything other than an integer will cause an error.

Calling Methods and Functions

To call a method within your own class or module, simply use the function call syntax:

function foo( a ) {
    //Assume foo does something really impressive
}

function bar() {
    foo( "hello" );
}

If calling on an instance of an object, precede the call with the object and a ‘.’.

If Statements

if statements allow branch points in your code:

myInstance.methodToCall( parameter );

if ( a == true ) {
    // Do something
} else if ( b == true ) {
    // Do something else
} else {
    // If all else fails
}

// Monkey C also supports the ternary operator
var result = a ? 1 : 2;

The expression inside the if statement is required to be an expression; assignments are not allowed. Things that will evaluate to true are:

Loops

Monkey C supports for loops, while loops, and do/while loops. while and do/while loops have a familiar syntax:

// do/while loop
do {
    // Code to do in a loop
}
while( expression );

// while loop
while( expression ) {
    // Code to do in a loop
}

Loops must have braces around them because single-line loops are not supported:

// Monkey C does allow for variable declaration in for loops
for( var i = 0; i < array.size(); i++ ) {
    // Code to do in a loop
}

Control within loops can be managed by using the break and continue statements. These should also have familiar behavior:

// This for loop should only print 5, 6, and 7.
for (var i = 0; i < 10; i += 1) {
    if (i < 5) {
        continue;
    }
    System.println(i);
    if (7 == i) {
        break;
    }
}

Returning Values From Functions

All functions return values in Monkey C. You can explicitly set the return value by using the return keyword:

return expression;

The expression is optional. Functions without a return statement automatically return the last value operated on.

Instanceof and Has

As a duck-typed language, Monkey C gives the programmer great flexibility, but the trade off is that the compiler cannot perform the type checking like in C, C++ or Java. Monkey C provides two tools to do runtime type checking—instanceof and has.

The instanceof operator offers the ability to check if an object instance inherits from a given class. The second argument is the class name to check against:

var value = 5;
// Check to see if value is a number
if ( value instanceof Toybox.Lang.Number )
{
    System.println( "Value is a number" );
}

The has operator lets you check if a given object has a symbol, which may be a public method, instance variable, or even a class definition or module. The second argument is the symbol to check for. For example, assume we have magnetometer libraries in Toybox.Sensor.Magnetometer, but not all products have a magnetometer. Here is an example of changing your implementation based on those criteria:

var impl;
// Check to see if the Magnetometer module exists in Toybox
if ( Toybox has :Magnetometer )
{
    impl = new ImplementationWithMagnetometer();
}
else
{
    impl = new ImplementationWithoutMagnetometer();
}

Monkey C’s object-oriented design patterns in conjunction with the has and instanceof operator enables software that has implementations for many devices in one code base.

Errors

Because Monkey C uses dynamic typing, there are many errors for which the compiler cannot check. If the error is of high enough severity, it will raise an fatal API error and cause your app to terminate at runtime. These errors cannot be caught. At this time all of these errors are fatal and there is no way to trap them, though this may be addressed in future updates.

Array Out Of Bounds
An attempt is being made to reference an array outside of its allocated bounds
Circular Dependency
There is a loop in the dependency graph of a module or object that prevents a module or object from being constructed
Communications Error
An error has occurred in BLE communications
File Not Found
The app file could not be found, which is usually caused when trying to load a resource from the app file
Illegal Frame
The return address on the stack is corrupted
Initializer Error
An error occured in an initializer
Invalid Value
An argument passed to a function or method is invalid
Null Reference
A value is being requested from a null value
Out of Memory
Indicates no more system memory is available for allocation
Permission Required
An attempt was made to use a restricted API without permission
Stack Underflow
The stack pointer went past the bottom of the stack memory limit
Stack Overflow
The stack pointer went past the top of the stack memory limit
Symbol Not Found
An attempt was made to access a variable or method that does not exist in the specified object or method
System Error
A generic error used by the Toybox APIs for fatal errors
Too Many Arguments
Too many arguments used by a method, which are currently limited to 10 arguments
Too Many Timers
Too many Timer::Timer objects for the target device were started
Unexpected Type
Indicates an operation being done on a variable that is unsupported by the type; for example, trying to perform a bitwise OR on two string
Unhandled Exception
An Exception was thrown but was not caught by an exception handler
Watchdog Tripped
A Monkey C function has executed for too long; watchdogs prevent a Monkey C program from hanging the system via an infinite loop

Structured Exception Handling

Monkey C supports structured exception handling for non-fatal errors from which there can be recovery. The syntax should be familiar for Java and Javascript developers:

try {
    // Code to execute
}
catch( ex instanceof AnExceptionClass ) {
    // Code to handle the throw of AnExceptionClass
}
catch( ex ) {
    // Code to catch all execeptions
}
finally {
    // Code to execute when
}

You can use the throw keyword to throw an exception.

Objects

Objects are created with the class keyword. Classes allow data and operations to be bound together on an object.

Constructors

When an object is instantiated with the new keyword, the memory is allocated and the initialize method is called:

class Circle
{
    hidden var mRadius;
    function initialize( aRadius ) {
      mRadius = aRadius;
    }
}

function createCircle() {
    var c = new Circle( 1.5 );
}

Within a method implementation you can refer to your current instance using either the self or me keywords.

class A
{
    var x;
    var y;
    function initialize() {
        me.x = "Hello"; // Set current instance x variable
        self.y = "Hello"; // Set current instance y variable
    }
}

Inheritance

Monkey C uses the extends keyword to support class inheritance:

using Toybox.System as Sys;

class A
{
    function print() {
        Sys.print( "Hello!" );
    }
}

class B extends A
{

}

function usageSample() {
    var inst = new B();
    inst.print();           // Prints "Hello!"
}

You can call superclass methods by using the super class’s symbol:

using Toybox.System;

class A
{
    function print() {
        System.print( "Hello!" );
    }
}

class B extends A
{
    function print() {
        // Call the super class implementation
        A.print();

        // Amend the output
        System.println( "Hola!" );
    }
}

function usageSample() {
    var inst = new B();
    inst.print();           // Prints "Hello! Hola!"
}

Data Hiding

Classes have two levels of access—public and hidden. Public is the default. Hidden is the same as “protected”; it says that a variable or function is only accessible to a class or its subclasses:

class Foo
{
    hidden var mVar;
}
function usageSample() {
    var v = new Foo();
    Toybox.System.println( v.mVar ); // Runtime Error
}

Callbacks

Functions in Monkey C are not first class, meaning you cannot pass them as objects directly. On a class instance, you can get a Method object. This object allows you to store a method in a variable for later invocation.

class Foo
{
    function operation(a, b) {
        // The code here is really amazing. Like mind blowing amazing. You wish this method was in your program.
    }
}
function usageSample() {
    var v = new Foo();
    // Get the callback for the operation method.
    var m = v.method(:operation);
    // Invoke v's operation method.
    m.invoke(1,2);
}

A Method object will invoke a method on the instance of an object it came from. It keeps a strong reference to the source object.

Using hashtables and method objects, you can implement a [switch/case pattern][3].

class Foo
{
    // Switch based on 'input'
    function doSomethingNext(input) {
        var choices = {
            1=>:operation1,
            2=>:operation2,
            3=>:operation3
        };
        var choice = choice[input];
        if( choice != null ) {
            self.method(choices[input]).invoke();
        } else {
            operationDefault();
        }
    }
    // What to do on input 1
    function operation1() {
    }
    // What to do on input 2
    function operation2() {
    }
    // What to do on input 3
    function operation3() {
    }
    // On all other input
    function operationDefault() {
    }
}

Modules do not inherit from Object, and do not have access to the method object.

Weak References (CIQ 1.2)

Monkey C is reference counted, which means the runtime system will free memory when the number of objects referencing that memory decrements to zero. Reference counting allows memory to become available very quickly which is important in low memory environments. The kryptonite of reference counting are circular references. A circular reference happens when a cycle is formed in the reference chain. For example, imagine object C references object A, object A references object B, and object B references object A.

Now C gets invited to sit at the cool-kid table, so it dereferences A so it can hang out with its real friends.[4]

This forms a roundabout to nowhere. The memory for A and B should be freed at this point, but A and B both have a reference count of one because they reference each other. The memory used by A and B are now unavailable to objects from the cool-kids table.

Sometimes B really does need to reference A. In these cases, you can use a weak reference. A weak reference is an object that keeps a reference to an object but does not increment the reference count. This means the object reference can be destroyed, and is a case that should be handled.

To create a weak reference you use the weak() method. Weak is a method in Lang.Object and is available to all Monkey C objects.

// I would make a "Hans and Franz" reference but I
// think certain advertising has made them uncool.
var weakRef = obj.weak()

If you are calling weak on one of the immutable types (Number, Float, Char, Long, Double, String), then it returns the object itself. Otherwise it will return a WeakReference instance.

//! A weak reference is a loosely bound reference to
//! another object. If all strong references have been
//! freed, the get() method will return null.
//! This allows the developer to avoid circular references.
//! @since 1.2.0
class WeakReference
{
    //! Return if the reference is still alive.
    //! @return true if object is still alive, false otherwise.
    //!    When you are dead I will be STILL ALIVE
    //!    I feel fantastic and I am STILL ALIVE
    function stillAlive();

    //! Get the object referenced.
    //! @return Object referenced, or null if object is no
    //!         longer alive.
    function get();
}

You can use the stillAlive method to check if the reference has been cleaned up. Use get to create a strong reference to the object. Only keep the strong reference during the scope you need it!

// This is a triumph...
if( weakRef.stillAlive() ) {
    var strongRef = weakRef.get();
    strongRef.doTheThing();
}

Modules

Modules in Monkey C allow for the scoping of classes and functions. Unlike Java packages, Monkey C modules have many of the same properties as classes. You can have variables, functions, and classes at the module level:

module MyModule
{
    class Foo
    {
        var mValue;
    }
    var moduleVariable;
}

function usageSample() {
    MyModule.moduleVariable = new MyModule.Foo();
}

Using Statements

You can bring a module into your scoping level with the using keyword. using allows a module to be imported into another class or module by a symbol:

using Toybox.System;

function foo() {
    System.print( "Hello" );
}

The as clause provides a wat to assumed a module with a different name within scope. This is useful for shortening module names or when you simply disagree with our naming scheme[5]:

using Toybox.System as Sys;

function foo() {
    Sys.print( "Hello" );
}

using statements are scoped to the class or module in which they are defined.

APIs and App Types

The app type defines the user context of an app. Watch faces, for example, have many constraints because they operate in low power mode. To enforce these limits, the Connect IQ Virtual Machine will limit your available APIs based on your app type.

Module Name Data Field Watch Face Widget App
Activity
ActivityMonitor*
Ant*
Application
Attention
ActivityRecording*
Communications*
FitContributor*
Graphics
Lang
Math
PersistedLocations*
Positioning*
Sensor*
Sensor History*
System
Time
Timer
UserProfile*
WatchUi

*Requires app permission
Ant available in data fields and widgets since Connect IQ version 1.2.0

A Toybox module requested for your app type that is outside this list will result in a Symbol Not Found error.

Scoping

Monkey C is a message-passed language. When a function is called, the virtual machine does a look up operation at runtime to find the function being called. Here is the hierarchy that it will search:

  1. Instance members of the class
  2. Members of the superclass
  3. Static members of the class
  4. Members of the parent module, and the parent modules up to the global namespace
  5. Members of the superclass’s parent module up to the global namespace

For exmaple, if function a() is called on an instance of Child(), it will be able to access non-member functions b(), c(), and d() when:

The code below tries to clarify:

using Toybox.System as Sys;

// A globally visible function
function d() {
    Sys.print( "this is D!" );
}

module Parent
{
    // A module function.
    function b() {
        Sys.print( "This is B!" );
        d(); // Call a globally visible function
    }

    // A child class of a Parent module
    class Child
    {
        // An instance method of Child
        function a() {
            Sys.print( "This is A!" );
            b(); // Call a function in our parent module
            c(); // Call a static function within the class.
            d(); // Call a globally visible function.
        }

        // A static function of Child.
        // Note that static methods can't call instance method but still have
        // access to parent modules.
        static function c() {
            Sys.print( "This is C!" );
            b(); // Call a method in the parent module.
            d(); // Call a globally visible function
        }
    }
}

Sometimes you want to run your search from the global namespace instead of your current scope. You can do this using the bling symbol $. The bling symbol refers to global scope:

function helloFunction() {
    System.println("Hello Hello");
}

class A {
     function helloFunction() {
        System.println("Every time I say goodbye you say hello");
     }

    function b() {
        // Call global helloFunction
        $.helloFunction();
        // Call instance helloFunction
        helloFunction();
    }
}

If you are referring to a global variable, using bling can improve runtime performance[6]:

var globalScopedVariable = "Global String";

module A
{
    class B
    {
        function c() {
            // To find globalScopedVariable, the VM will search at runtime:
            //     instance B
            //     instance B's superclass Toybox.Lang.Object
            //     Module A
            //     Module A's parent globals
            // and finally find globalScopedVariable.
            System.println(globalScopedVariable);
            // This will search only the global namespace for globalScopedVariable.
            // Thanks bling!
            System.println($.globalScopedVariable);
        }
    }
}

Because Monkey C is dynamically typed, referencing a global variable will search your Object’s inheritance structure and the module hierarchy before it will eventually find the global variable. Using the bling symbol we can search globals directly.

Annotations

Monkey C allows associating symbols with class or module methods and variables. These symbols are currently written into the debug.xml file generated by the compiler, but may be used in the future to add new features without changing the Monkey C grammar:

(:debugOnly) class TestMethods
{
    (:test) static function testThisClass( x )
}

  1. This is different than Monkey Typing, where a thousand monkeys over infinite time write the works of Shakespeare.  ↩

  2. Tofu for the vegetarians, BBQ for Kansans…  ↩

  3. I could make some kind of argument that this pattern is way better than switch case because it works for any immutable object that supports hashCode(), but I like you too much to try line of argument that on you.  ↩

  4. Not that this ever happened to the author.  ↩

  5. We are all about conflict avoidance here.  ↩

  6. Do not forget to match your bling with pieces of flair; you can’t have enough of either.  ↩