TIScript Language, A Gentle Extension of JavaScript

How the TIScript language is different from its prototype - JavaScript

Introduction

As a language, TIScript is an extended version of ECMAScript (JavaScript 1.X). You could think of it as JavaScript++, if you wish.

The design of TIScript was based on the analysis of practical JavaScript use cases. In some areas, it simplifies and harmonizes JavaScript features. For example, the prototype mechanism was simplified. In other cases, it extends JavaScript, while preserving the original "look-and-feel" of JS.

This article describes the major features of TIScript that do not exist or differ from JavaScript. You should be familiar with at least the basics of JavaScript, or any other dynamic language, such as Python, Perl, Lua, Ruby, etc.

Namespaces

Namespaces are declared by using the namespace keyword. They can contain classes, functions, variables, and constants:

JavaScript does not support namespaces. You can emulate them by using objects, but that is just an emulation indeed.

Namespaces in TIScript are simply named scopes. For example, while handling the assignment to something that looks like a global variable, the TIScript runtime first makes an attempt to find that variable in the current namespace chain this function belongs to.

Classes, Constructors, and Properties

TIScript introduces real classes. A class is declared by the class keyword, and may contain functions, property-functions, variables, constants, and other classes:

Here is an example of how you would sort an array in descending order by using a comparator function that is defined in-place:

var arr = [1,2,3];
arr.sort( :a,b: a < b? 1:-1 );

Here, :a,b: a < b? 1:-1 is an inplace declaration of a lambda function that will be passed to the Array.sort() method.

Decorators

Decorators are a sort of meta-programming feature that was borrowed from the Python language. In TIScript, a decorator is an ordinary function. Its name must start with the '@' character, and it must have at least one parameter. That parameter (the first one) is a reference to some other function (or class) that is being decorated. Here is an example of a decorator function declaration:

Here, the two @KEY entries decorate two anonymous functions (see the previous section). The code above assumes that there is a class Widget defined somewhere with the callback method onKey(event).

Decorators is an advanced feature, and may require some effort to understand. When established, decorators may significantly increase the expressiveness of your code. More detail about decorators can be found here and here.

Iterators

JavaScript (and so TIScript) has a pretty handy for-each statement: for( var item in collection ){..}, where the collection is an instance of an object or an array.

In TIScript, a list of enumerable objects is extended by function instances. Thus, the statement for( var item in func) will call the func and execute the body of the loop with its value on each iteration. Example, this function:

People from Mozilla introduced their version of Iterators in Spider Monkey that was, I believe, borrowed "as is" from Python. I think that my version of iterators better suits the JavaScript spirit. At least, it does not introduce new entities and classes.

The Prototype Property

Compared with JavaScript, the prototyping mechanism has been simplified in TIScript.

Each object in TIScript has a property named prototype. The prototype of an object is a reference to its class, which is also simply an object. The prototype of a class is a reference to its superclass. Similarly, the prototype of a namespace (which is an object, like anything else) is a reference to its parent namespace.

Type System

The number type of JavaScript unifies integer and float numbers into one. In TIScript, it's split into two distinct classes: Integer and Float, as they really represent two distinct entities.

TIScript also introduces a number of new types:

Stream is a sequence of characters or bytes. The TIScript runtime supports three types of streams: in-memory (a.k.a. String stream), socket stream, and file stream. In-memory streams are an effective way of generating text. They are introduced for the same purposes as the StringBuffer/StringBuilder classes in the "big Java".

An instance of the Bytes object is an array of bytes.

These two classes make up the core of the TIScript built-in persistence. A TIScript object (and all objects it refers to) can be made persistent by assigning it to the storage.root property. The whole tree of objects is transparently placed in a storage file on the hard drive. Essentially, this is an Object Oriented Database (OODB). I call this JSON-DB, as only a JSON subset of JS objects can be persistent. For example, the socket stream is not persistent by nature.

Almost all dynamic languages have a concept of atoms in one form or another. TIScript has them too.

Symbols

A name of an object is a string of allowed characters. A symbol is a number associated with the name. TIScript maintains a global map of such name<->int pairs (implemented internally as a ternary search tree). At compile time, each name gets translated into an Int32 number - its symbol.

In some cases, you may want to declare symbols explicitly. In this case, symbol literals come in handy. The symbol literal is a sequence of characters that starts with the '#' character. It can contain alpha-numeric characters, underscores ('_'), and dashes ('-'). Dashes are used in symbols for compatibility with CSS (Cascading Style Sheets), where they are parts of name tokens.

"Stringizer" is an ordinary function with the name starting from '$' character and accepting variable number of parameters. On call of such function sequence of characters inside '(' and ')' are treated as a sequence of characters of string literal (same as between '"' and '"').
Symbols '{' and '}' inside stringizer call have special meaning - they allow to insert results of expressions they enclose to the string.

debug namespace; // prints current state of namespaces stack to stdout
debug stacktrace; // prints current stacktrace to stdout

In Sciter SDK we have also scide.exe application - IDE written in HTML/CSS/TIScript with the use of Scintilla editor. ScIDE has output panel (pink area on the image below) that reports errors. It parses errors and creates hyperlinks for them. Clicking on such link will bring you to the place where error was detected.

As of "mix standard Javascript code in with TIScript?" answer depends on what "standard" here means.

If that JS code is not using JS prototype / __proto__ things then you should be able to use such code "as is".
If you do have some JS code that does something like this (adds foo() method to String class):

String.prototype.foo = function() { ... };

then in TIScript this should be rewritten as

String.foo = function() { ... };

or just as:

function String.foo()
{
...
}

after that you can use it as:

"some string".foo();

Another difference that may affect porting is that TIScript has two distinct classes Integer and Float rather than unified Number class as in JS.
E.g. in TIScript all this evaluate to true: