This blog is for news, announcements and questions regarding the Mascara JavaScript compiler

This blog is for news, announcements and questions regarding the
Mascara JavaScript compiler. Try it online | Download latest release
Sunday
May182014

Ecmascript 6 syntax in Mascara

Mascara continuously tracks development in the ECMAScript 6 (code name "Harmony") specification. While the Harmony spec is still under development, some parts are stable enough that the recent Mascara version have updated syntax to bring it in line with the spec.

For-of loops

For-of loops iterates over the values in an array or collection. This is in contrast with for-in loop with iterates over the indices, which is much less convenient. Example:

for (var name or ["blue", "green", "red"]) {
    print(name);
}
// prints blue, green red

for (var name in ["blue", "green", "red"]) {
    print(name);
}
// prints 0, 1, 2

The same semantics as for-of have previously been supported using the for-each-in syntax, but going forward for-of is the recommended syntax. (For-each-in syntax will remain supported for backwards compatibility, but may be deprecated in the future.)

Array comprehensions

The new array comprehensions syntax looks like this:

var doubles = [for (x of [7,9,13]) x * 2];

var evens = [for (i of numbers) if (i % 2 === 0) i];

This is in contrast with previous proposals where the syntax was kind of backwards with the target expression placed before the first 'for', like [x * 2 for (x of [7,9,13])]. The new syntax is an improvement in my opinion, since it is more straightforward (the old syntax could be especially confusing if multiple 'for''s was used). Additionally the new syntax better allows editor hints like code completion, because the variable are defined before they are used.

The old syntax will remain supported in Mascara for backwards compatibility, but may become deprecated in the future

Arrow functions

These have been supported by Mascara for a long time, but now it is official! The simplest way to write function expression is with the 'fat arrow' syntax. For example:

[1,2,3].map(x=>x**2); is equivalent to [1,2,3].map(function(x){return x**2});

$("#button").click(event=>{ .... }); is equivalent to 
$("#button").click(function(event){ .... });

Previously Mascara have supported the little known alternative shorthand syntax "function()x**2", but this will be deprecated. Good riddance - the arrow is much nicer.

Automatic properties in object literals:

This is a smaller syntax improvement, but pretty cool. In standard object literals, you explicitly name every property: var size = {length: 17, height: 200}; In the new syntax, you can leave out the name if the value expression is an identifier: Example :

var length = 17;
var height = 200;
var size = {length,height} // similar to writing size {lenght:length, height:height};

Neat, but when is this actually useful?

Well it is pretty cool for creating on-the-fly objects and destructuring them again:

function getSize() {
    var height = 100;
    var width = 50;
    return {height,width};
}

var {width,height} = getSize();
import "console";
console.log(height);
console.log(width);

Note the similar destructuring syntax which does the reverse: It creates a local variable with the same name as the property and initializes it with the property values. I reversed the order of the names in the destructuring just to highlight that they are matched by name, not by order.

Friday
Nov302012

The Declare attribute

Some times it is useful to declare the type of a function, class or variable, without actually providing an implementation. For example when using built-in objects or third-party libraries which is included at runtime. The declare attribute is used for this.

For example, you may want to use the console.log() method which is built-in in most modern browsers. By declaring the method signature, you make it available for the type-checker, so you get verification, code completion and so on.

declare class console {
    static log(...args) : void;
}
console.log("hello world"!); // uses the built-in console at runtime

When compiling, no output will be generated for the declaration, so the built-in console implementation will be used at runtime. (Note: You don't actually need to write the above declaration. A declaration file for the console-object is supplied with Mascara, so you just need to write import logging; to make the console definition available.)

Declares are also useful for third-party libraries like jQuery. Mascara provides a declaration file for the jQuery interface, which you can import with import jqueryapi;. This makes the jQuery API available during development for type-checking and code completion. The actual implementation of jQuery should be included at runtime with a standard script-tag.

See more: declare

Note: Previously there was a native attribute for similar purpose, but it only supported functions. declare supports variables, functions, classes and modules. native remains as an alias for declare

Thursday
Nov292012

New class syntax

The latest version of Mascara support a new syntax for class members. The syntax is based on the latest ECMAScript proposals, and brings Mascara in line with other implementations like Google Traceur and MS TypeScript. (The old syntax continues to be supported in Mascara.)

In the new syntax, the keywords function and var are not necessary when defining methods and fields in classes and interfaces. Example:

class Car {
    wheels : int = 4;
    drive() { .. }
    private get speed() { return 17; }
    static speedLimit = 80;
}

In the old syntax it would be:

class Car {
    var wheels : int = 4;
    function drive() { .. }
    private function get speed() { return 17; }
    static var speedLimit = 80;
}

Furthermore, constructors are now designated with the keyword constructor. Eg. new syntax:

class Car {
    wheels = 0;
    constructor(wheels : int) { this.wheels = 4 }
}

In the old syntax, a constructor is declared as a method with the same name as the class name:

class Car {
    var wheels = 0;
    function Car(wheels : int) { this.wheels = 4 }
}

More details in the class documentation.

The old syntax continues to be supported, but may be deprecated in the future, depending on user feedback.

Tuesday
Oct092012

Welcome, TypeScript

At last Mascara gets some serious competition! Microsoft has released TypeScript, a tool with the same basic idea as Mascara: A superset of JavaScript with type annotations, based on proposals for future extensions to ECMAScript, but compiled to plain Javascript which will run in today’s browsers.

This is great news for the users of Mascara. It shows the approach taken by Mascara is sound and getting traction. More importantly, an alternative implementation reduces the risk of lock in. If you get dissatisfied with Marasca, you can (with a modest amount of conversion) shift to TypeScript and vice-versa. This makes Mascara a safer choice for a long-term strategy.

Furthermore this will provide some valuable cross-pollination of ideas between the different approaches. Just as Microsoft has obviously been inspired by Mascara, Mascara is going to copy all the best ideas from TypeScript!

Syntax differences

One caveat: The class and module syntax of TypeScript is based on different ECMAScript drafts than Mascara. Mascara is based on the original ActionScript-compatible proposal. A different (not ActionScript-compatible) syntax have since been proposed, and since major players are now behind the new syntax, Mascara will also go forward and also support this syntax. A beta with support for the new syntax is available. (The old syntax continues to be supported alongside.)

I expect the older ActionScript-compatible syntax will be deprecated at some point in the future. (Although feedback from Mascara users is appreciated – if compatibility with ActionScript syntax remains important, please let me know.)

I will document the differences in an upcoming post, but in short, the keywords “function” and “var” are superfluous when declaring class members, and constructors are identified with the keyword “constructor”. Example:

Old syntax:

class Volvo {
  var licensenumber : string;
  function Volvo(licensenumber : string) {
     this.licensenumber = licensenumber;
  }
    function drive() : void {…}
  }
}

New syntax:

class Volvo {
   licensenumber : string;
   constructor(licensenumber : string) {
       this.licensenumber = licensenumber;
   }
   drive() : void {…}
}

TypeScript has some great ideas, some less great, and some limitations. Here is my subjective take. (It is based on a quick reading on the spec so it's not exhaustive, and it probably contains mistakes.)

Great ideas

Arrow-syntax in function types. This a natural extension of the arrow syntax for function expressions (which Mascara already supports). For example string=>bool describes a function which takes one argument, a string, and returns a Boolean. This is concise and elegant (and now supported by the Mascara beta).

Overloads. Allows declaration of multiple type signatures for a single function implementation. This is for example heavily used in JQuery, where the same function have different semantics and return different values based on parameter types. The union-type kind of solves the same problem, but overloads are a much cleaner solution.

Open interfaces: It is possible to declare an interface multiple times, thereby adding members to an already declared interface. This is a great idea!

Automatic fields: When using the attribute public or private on constructor parameters, a field is automatically created, which is assigned the value. Elegant and useful.

Automatically import window/DOM api In Mascara you have to explicitly write import browserapi to get the window and DOM-types in scope.

Dubious ideas

There are also a few ideas where I’m not convinced of the merit.

  • Members must be prefixed with this., even when accessed in methods of the same class. I am not convinced there is any benefit to this overhead typing.

  • The angle brackets “casting” syntax, e.g. <string>x. This could become rather ugly (visually) when combined with generics which also uses angle brackets. (This is not an issue for TypeScript currently though, since it doesn’t support generics.)

  • this in static functions refers to the Function prototype. This is kind of logical if you know the intricacies of the JavaScript object model, but basically it will mostly be s source of confusion and bugs. In Mascara it is simply not legal to access this in static methods.

Limitations

There are a some limitations (compared to Mascara) which may be due to it being a new less-mature product, or different design goals. The most important limitations as I see it:

Browser compatibility. TypeScript generated code uses some of never JavaScript features (like defineProperty), which is not supported by all browsers in normal use. (For example IE7 does not support defineProperty.) This is probably a deliberate design tradeoff. In contrast Mascara has as a primary objective that the generated code should work in all browsers. Web developers have enough to worry about as it is.

Generics. There is a somewhat kludgy support for typed arrays, but no general support for generics. My experience is that generics are needed for a type system to be sufficiently powerful for general use. (Microsoft should know this, just take a look at the elegance of Linq in C#, which would be unthinkable without generics).

Backwards compatibility. The support for old-style objects/constructors in the type system seem to be limited and not directly compatible with the class system. This again is probably a deliberate design choice. Mascara in contrast attempts to make old-style constructors directly interchangeable with classes, to make gradual upgrade from legacy JavaScript to Mascara smother.

No include mechanism. TypeScript generate a seperate output file for each input file, and require you to include each output file with a script tag. A benefit to Mascara is you can split the code into as many files you want, but still have them merged to a single file, so you avoid the hassle and performance overhead by downloading numerous smaller files.

Non-nullable types. No support for declaring non-nullabel types. This is sad, since nullable everywhere is the billon dollar mistake!

  • No block scoping and no definite-assignment analysis.
  • No support for constants.
  • “Public” and “private” modifiers, but no “protected”.
  • No support for destructuring variable declarations or destructuring assignments.
  • No doc-comment.
  • No array comprehensions.
  • No support for yield.
  • No multiline strings or multinline reqular expression.
    While features like these are not as high profile than a type system, I think niceties like these overall makes for a much more pleasant coding.

Bottom line: TypeScript is great, Microsoft seems to “get it”. It is also seem to be not as powerful as Mascara, but then again I am biased. Feedback and opinions welcome as always (in email or comments).

Monday
Apr162012

Sourcemap support in Chrome greatly improves debugging

The latest version of the Chrome browser has support for 'sourcemaps' which promises to make degugging compiled JavaScript much more pleasant.

Until now, a major drawback to compiled JavaScript (like what is produced by Mascara) is that debugging becomes more tricky. Moderne browsers have quite nice debugging tools, but they only operate on the generated code, not the source we initially wrote.

Browser vendors have recognized this issue and agreed on "source map", a standard for matching compiled javascript with source code. Chrome is the first browser to support this feature.

As an example, here is some code which will generate an error at runtime:

// some filler code just to be sure lines are different
class A {}
class B {} extands A {}

var a : Date = null;
g.getDate(); // should throw runtime error

This is how the runtime error will be displayed normally, if you open the Developer Tools window in Chrome: (Wrench icon -> Tools -> Developer Tools or press F12)

You see the error in the (more or less opaque) generated code. You have to manually match with the source code to find the source of the error.

But with sourcemap support, the browser can show the error directly in the original source:

It is even possible to set breakpoints and debug through the original source:

I havent yet investigated how "deep" the support is for sourcmap in Chrome, but it looks impressive. I would love to hear feedback from Mascara-users about how this feature works for them.

How it works

Under the hood Mascara generating a seperate "sourcemap"-file which associates code positions in the generated code with the source. (The sourcemap file has the same name as the generated file but with an additional ".map" extension.) Debugging requires requires that the map and source files is deployed along with the generated files. You might choose to only allow debugging on the development server and not deploy the map and sources to the production server.

How to enable

When using the command-line compiler, source maps are enabled with the cli argument "--generate-source-mappings-file", eg.

python translate.py somesourcefile.esx --generate-source-mappings-file

Sourcemaps are generated by default when using the Eclipse-plugin though.

It also reqires enabling in Crome developer tools. Click the bolt in the lower right corner of the window to get the settings window, and check "enable source map":

Chrome is the first browser to support source map, but support is also underway in Mozilla/Firefox.

Here is a more detailed article about source maps.