Connect IQ > Monkey C

下位ページ

Content


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

class MyProjectApp extends App.AppBase {

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

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

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

using statement

C++のusingステートメント, Java™, Ruby, Python™のimportのようなもの。
using statements lexically bring modules into our name space.
using節のあとで、, we can refer to a module by its shortened name (in this case System).

Toybox

Monkey C のルートモジュール


Toybox.System

Toybox.Syste
例:デバッグコンソールに表示する場合
System.println( "Hello Monkey C!" );

Javaの名前空間と違って、Monkey C のモジュールは関数、クラス、変数を含んだ、staticなオブジェクトであり、有用な関数を含んでいる

  • println():コンソールに表示する(改行する)
  • print():コンソールに表示する(改行しない)
  • getTimer():ミリ秒のタイマー
  • getClockTime():現在時刻の取得 = System.ClockTimeを取得する
  • getSystemStats():現在のシステムステータスの取得 = System.Statsを取得する
  • trap():デバッグ用(今後のSDKで採用?)
  • exit():"User terminated"のメッセージを出して終了
  • error():エラーを発生させて、終了

Monkey C と その他言語との違い


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 and floats 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, than 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
}

doLongRunningTask( wakeMeUpBeforeYouGoGo );

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

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

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():

function wakeMeUpBeforeYouGoGo() {
   // Do something here
}

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 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.

構文

Ifステートメント


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 は次の演算子もサポートしている
var result = a ? 1 : 2;

なお、trueと判定されるのは
  • true
  • A non-zeroでない整数
  • Nullでないオブジェクト

ループ

  • while loops
  • do/while loops

do/while loop

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

whileループ

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

一行での表現はサポートしていないので、括弧囲みで画

forループ

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

関数の戻り値

Monkey Cでは全ての関数に戻り値がある。returnキーワードを使って、戻り値を設定する必要がある。

return expression;

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

Instanceof and Has

Monkey Cでは、プログラマにダック・タイピング言語のような自由さがあるが、トーレドオフとして、コンパイラのチェックが不十分である。そのため?実行時のチェック用に
  • instanceof
  • has
という演算子が準備されている。
instanceof演算子は、そのインスタンスが、あるクラスから継承されているか、チェックする

var value = 5;
// 変数 value が Number かどうか?
if ( value instanceof Toybox.Lang.Number )
{
    System.println( "Value is a number" );
}

has演算子は、与えられたオブジェクトがシンボル(など)を持っているかチェックする。
たとえば、Toybox.Sensor.Magnetometer は magnetometerのライブラリをもっているが、全てのGarmin製品が磁気探知機の機能 を持っているわけではない。このようなとき、
an example of changing your implementation based on those criteria:

var impl;
// Toybox に Magnetometer module が存在するか、チェックする 
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.

エラー


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


Java/Javascriptのような、try-catchをサポートしている

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
}

throwも使える

Objects


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

コンストラクタ

initializeメソッドで実施

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

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

継承 Inheritance

extendsキーワード

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

public と hidden がある。hidden は protectedと同じで、サブクラスからもアクセスできる

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

Weak References (Connect IQ 1.2.x)


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.[3]

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.

var weakRef = obj.weak()

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

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!

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[4]:

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.



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

スコープ


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:

   Instance members of the class
   Members of the superclass
   Static members of the class
   Members of the parent module, and the parent modules up to the global namespace
   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:

   b() is a member of the parent module of the object
   c() is a static member of the object
   d() is the parent module of the parent module, also known as the globals module

The code below tries to clarify:

using Toybox.System as Sys;

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
       }
   }
}

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 )
}

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

   Tofu for the vegetarians, BBQ for Kansans…  ↩

   Not that this ever happened to the author.  ↩

   We are all about conflict avoidance here.  ↩
最終更新:2016年02月14日 15:51