Code inside class declarations: classes are interpreted statically?

Topics: Language Specification
Sep 12, 2013 at 7:09 PM
An objective of TypeScript that I enjoy, is that it retains JavaScript language semantics as closely as possible - but it seems like classes veer from this principle a bit.

I don't know if my computer theory language is strong enough to actually explain this in the right terms, so please bear with me, and feel free to correct my language if you feel it helps clarify what I'm trying to get across.

In JavaScript, "class declarations" are not interpreted at "compile-time" - they are actually code that executes at run-time, as illustrated by a simple example:
module foo {
    class Bar
    {
        public run() {
            // ...
        }
    }
}
Which compiles into:
var foo;
(function (foo) {
    var Bar = (function () {
        function Bar() {
        }
        Bar.prototype.run = function () {
            // ...
        };
        return Bar;
    })();
})(foo || (foo = {}));
In JavaScript, the symbol Bar is defined first - and then run() method is defined independently, after the declaration of Bar. The class Bar which has the method run() is not one closed unit that is identified and defined at compile-time, it is defined step by step, at run-time.

This appears not be true of TypeScript, where apparently the class Bar with the method run() is a single unit that gets identified and defined at compile-time.

In JavaScript, if I wanted, I could write the following:
var foo;
(function (foo) {
    var Bar = (function () {
        // I can do things here!
        var a = [1,2,3];
        for (var i=0; i<a.length; i++) {
            // ...
        }       
        function Bar() {
        }
        Bar.prototype.run = function () {
            // ...
        };
        return Bar;
    })();
})(foo || (foo = {}));
Several things happen inside the anonymous closure that produces the Bar prototype, but they don't occur as one "thing" that exists independently or at "compile-time", because that's not how JavaScript works - it's prototypical, and things actually build up and get defined one method/property at a time. It's actively "doing something" when the code loads.

This appears not to be the case in TypeScript, where the following is not possible:
module foo {
    class Bar
    {
        var a = [1,2,3];

        for (var i=0; i<a.length; i++) {
            // ...
        }

        public run() {
            // ...
        }
    }
}
Why not?

I realize the compiled JavaScript of course does build out prototypes at run-time, and obviously it has to, since that's how JavaScript works.

But it appears as though TypeScript class definitions are different, in the sense that they are defined and interpreted "statically", or "as a whole"...

If this is true, it seems like a pretty radical departure from JavaScript semantics, and in a sense, it changes the nature of the language entirely - from being more like JavaScript or Ruby, where every class-definition is code that actually executes, towards something like PHP, where a class-definition is something that gets loaded and compiled statically, ahead of actually executing any of the code in the file.

To give a valid PHP example:
<?php

$foo = new Foo();

class Foo
{
}
And a corresponding valid TypeScript example which will fail at run-time:
var foo = new Foo();

class Foo
{
}
Which produces the corresponding JavaScript:
var foo = new Foo();

var Foo = (function () {
    function Foo() {
    }
    return Foo;
})();
This of course fails at run-time in JavaScript, but the code is valid JavaScript, and the TypeScript code, consistently, is also valid, but will fail at run-time. So far so good.

Source order matters in JavaScript, where class-definitions must actually execute before the classes are created, at run-time.

I'm sure I'm missing something totally obvious, but: Why doesn't TypeScript take the full consequence of this important semantic aspect of JavaScript, and treat a class-definition, and it's member-definitions, as individual statements like any other statements?
Developer
Sep 12, 2013 at 10:21 PM
It seems to me that what you want is basically static constructors akin to what C# has http://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx Then it would be fairly simple to represent this pattern (you could do something similar now but it would require manually tracking how many times a particular class has been instantiated).
Sep 13, 2013 at 2:06 AM
Static constructors in C# execute on load - in JavaScript, everything executes on load, so not having class-constructors (code that runs on load) isn't even really an option.

That's where I think TS class semantics detour from JS semantics - the class and member constructs are co-dependent in TS, whereas in JS, "classes" (prototypes) are created independently of any members created and added to them subsequently.

So the difference in language semantics in TS kind of take away this one dynamic aspect of JS - for better or worse, but there is definitely a difference, right?