Lambda functions in TIScript

I’ve added new short notation for anonymous (lambda functions) in TIScript build #2.0.0.3
Example of such notation – sort array a in descending order:

a.sort(:v1,v2:v2 - v3);

This is a direct equivalent of:

a.sort( function(v1,v2) { return v2 - v3; } );

Therefore anonymous functions in TIScript can be declared in place in of the three forms:

    1. classic JavaScript form:
      function ( < parameters > ) { < statements > }
    2. single expression lambda function form
      : < parameters > : < statement >;
    3. “block with parameters” form
      : < parameters > { < statements > }

Terra Informatica Script v. 2.0

TIScript v. 2.0 has been published.

New features, language:


  • Built-in persistent storage, classes Storage and
    Index by Alexei Marinets.

  • Built-in XML/HTML tokenizer class. It is based on my code from article on CodeProject

  • Improved memory management.

New features, API:



  • API ::TIS_define_class – allows to define native packages and classes. See struct TIS_class_def in tiscript.h file. See implementation of sample classes in SDK/samples/console/native_classes.cpp.

  • SDK now includes json_value.h and json_aux.h files. Use of json::value allows to pass objects, arrays and scalar types between native and script code.

We express our gratitude to:



  • David Betz for his perfect BOB language and implementation. TIScript was inspired by BOB in many aspects.

  • Konstantin Knizhnik for his excellent DyBase engine. Slightly modified DyBase engine is a core of TIScipt built-in persistent storage.

Color-chooser, part III. Prototype… of what?

This is a continuation of: Color-chooser, part II. Three pieces of the Puzzle.

First of all:  Sciter executes scripts after completion of document tree parsing. This is major difference from how conventional browser deals with scripts. So script execution in Sciter is deterministic – code in script files executed when DOM is loaded and in the order of how script files are included in the master HTML document.

Next phase after DOM and scripts are getting loaded is a binding of behaviors: Sciter scans DOM tree for elements having prototype attribute defined in CSS and assigns script classes of behaviors to correspondent DOM elements.  Thus, if you have following CSS declaration:

input[type="color-chooser"]
{ 
     background: …. ; /* and other rendering styles */
     prototype: ColorChooser /* behavioral style definition */
}

and existing variable ColorChooser of type Behavior somewhere in your scripts, that DOM element is said to be of class of ColorChooser.


Each object (DOM elements are also first class script objects) in the script is a collection of properties – pairs of a key and a value. That value can be a function.


Each object has special prototype field. That prototype field establishes instance/class relationship- links objects and their classes.


Method invocation like obj.foo() simply means following instruction: try to find property foo in obj collection of properties and if it is is not found then try to find it in object referred by prototype variable, etc. If such foo value is found in the chain and it is a function – call it with this environment variable set to the obj.


"Class" object can also have prototype field set – it is said that one class is derived from another.


Here is what happens when DOM element has prototype defined in CSS:


As you may see Sciter in this case simply changes value of prototype field of the DOM object from reference to Element (class) object to the reference of your custom Behavior class-object.


The last phase of behavior assignment: after changing prototype field of the DOM object Sciter tries to call method attached() if it is defined in the behavior. Method attached() by its concept is close to a constructor method. Variable this inside method code points to the DOM element this behavior has been assigned to. The only difference between attached and constructor is that at the moment of invocation of the attached() DOM element already exists and is a "citizen" of the DOM.


NB: the prototype attribute in Sciter is read/write entity thus you can change behavior of the element in your code at any time. You may need this if, say, some element has clearly two or more states in which it should behave significantly differently.

What the hell is that JSON-DB?

JSON-DB… You can, probably, guess that it’s a compound word, which consists of JSON and DB (database). And you are absolutely right! It’s a way to save javascript objects in a persistent storage.

Let’s imagine that you have a state object in javascript, which you’d love to persist. And the state consists of different objects of different types. Wouldn’t be nice to say:

db.state = state;

Or, alternatively restore the same state with:

var state = db.state;

Do you like it? How about:


db.messages[key] = 
  { 
     text: "Hello world!",
     id: 456,
     author: authorObj;
  };

Thus, if JSON helps you to get data and easily evaluate into native javascript objects, JSON-DB allows you to seamlessly work with persistent data in javascript. Any scripting object can be persisted in the database and there is no need to use special entities like recordset, field, etc.

JSON-DB (a.k.a. persistent storage) is implemented in version 2.0 of TiScript engine:

  1. supports up to 2 GB storage size.
  2. supports transactions: commit/rollback
  3. uses lazy reads, e.g. only top level objects are loaded physically. Objects are loaded from storage on demand.
  4. storage supports indexes: storage.createIndex( String | Integer | Float ). Index object supports effective index access: [key] and range [ key1 .. key2 ]. Indexes use effective B+Tree algorithm.
  5. TiScript extended by two additional core objects: Storage and Index. Objects and Arrays got storage attribute referring to the Storage the object stored in (if any)

Persistent Storage implementation in TiScript is based on Konstantin’s Knizhnik excellent DyBase library modified to support TiScript “natively”.

Eval, JSON and curly braces.

Say, you have JSON data (object literal) stored as a string somewhere:

  "{ one:1, two:2 }"

and you want to parse (convert) this string into scripting object.

Obvious solution for this would be to write something like this:

  var dataStr = "{ one:1, two:2 }";
  var data = eval( dataStr );

Looks nice and simple but will not work. To make it work you need to wrap your string in ( ) brackets:

  var dataStr = "(" + "{ one:1, two:2 }" + ")";
  var data = eval( dataStr );

Reason is simple and I’ll try to explain it using plain words:

eval accepts sequence of statements of JavaScript and at this level JavaScript parser
interprets ‘{‘ token as a start of a block and not a start of an object literal.

When you will enclose your literal into () brackets like this: ({ one:1, two:2 })
you are switching JavaScript parser into expression parsing mode. Token ‘{‘ inside expression means start of object literal declaration so JavaScript will accept it.

Delegates in JavaScript. Now with parameters.

Here is an extended delegate function:

  function delegate( that, thatMethod )
  {
    if(arguments.length > 2)
    {
      var _params = []; 
      for(var n = 2; n < arguments.length; ++n) _params.push(arguments[n]);
      return function() { return thatMethod.apply(that,_params); }
    }
    else  
      return function() { return thatMethod.call(that); }
  }

And here is an example. Note that obj.method now accepts additional parameter p

  var obj =
  {
    name: "someName",
    method: function (p ) { alert( this.name + ":" + p );  }
  }

  function testIt()
  {
    window.setTimeout( delegate( obj, obj.method, "parameter!" ), 1000 );
  }

Example of the delegate is delegate-test.

Note: this is so called parametrized delegate - parameters defined at the point of construction of the delegate - in delegate() call per se.

If you need delegate that will be inoked with parameters supplied by the caller you should use this one:

  function delegate_cp( that, thatMethod )
  {
      return function() { return thatMethod.apply(that,arguments); }
  }

So caller will call it as:

  var d1 = delegate_cp( obj, obj.method );
  ...
  d1( param1, param2 ); /* parameters for the delegate
           call provided at the point of invocation. */
  

Delegates in JavaScript

Simple definition:


  • delegate is a value – reference to the pair of object and its method. Lets name them as delegate.object and delegate.method.

  • delegate invocation is a way of calling of delegate.method in context of delegate.object. So inside code of the delegate.method variable this points to the delegate.object.

To be practically useful delegate in JavaScript must be implemented as a reference to function so, for example, we can say:



window.setTimeout( delegate( obj, obj.method ), 1000 );

and obj.method will be invoked one second later with this referring to the obj.


Here is probably simplest possible implementation of such delegate function in JavaScript (and in TIScript):



function delegate( that, thatMethod )
{
return function() { return thatMethod.call(that); }
}

It returns reference to the function-thunk ( delegate per se ). This function-thunk being called will invoke thatMethod in context of that object. This implementation employs the fact that namespace of inner function in JS includes namespace of outer function.


Technically this means following: call frames in JS are also (GC-able) objects and body of the function (callee) has access to the frame of caller.