Global State On Servers Considered Harmful


The
other day I noted that extending the built-in objects in JScript .NET is no longer
legal in “fast mode”.  "urn:schemas-microsoft-com:office:office" />Of
course, this is still legal in “compatibility mode” if you need it, but why did we
take it out of fast mode?

 

As
several readers have pointed out, this is actually a kind of compelling feature.  It’s
nice to be able to add new methods to prototypes:

 

String.prototype.frobnicate
= function(){/* whatever */}

var s1
= “hello”;

var s2
= s1.frobnicate();

 

It
would be nice to extend the
Math object,
or change the implementation of
toLocaleString on Date objects,
or whatever.

 

Unfortunately,
it also breaks ASP.NET, which is the prime reason we developed fast mode in the first
place.  Ironically, it is not the additional
compiler optimizations that a static object model enables which motivated this change!  Rather,
it is the compilation model of ASP.NET.

 

I
discussed earlier how ASP uses the script engines — ASP translates the marked-up
page into a script, which it compiles once and runs every time the page is served
up.  ASP.NET’s compilation model is similar,
but somewhat different.  ASP.NET takes
the marked-up page and translates it into a class that
extends a standard page class.  It compiles
the derived class once, and then every time the page is served up it
creates a new instance of the class
and calls the
Render method
on the class. 

 

So
what’s the difference?  The difference
is that multiple instances of multiple page classes may be running in the same application
domain.  In the ASP Classic model, each
script engine is an entirely independent entity.  In
the ASP.NET model, page classes in the same application may run in the same domain,
and hence can affect each other.  We don’t
want them to affect each other though — the information served up by one page should
not depend on stuff being served up at the same time by other pages.

 

Now
I’m sure you see where this is going.  Those
built-in objects are shared by all instances of all JScript objects in the same application
domain.  Imagine the chaos if you had
a page that said:

 

String.prototype.username
= FetchUserName();

String.prototype.appendUserName
= function() { return this + this.username; };

var greeting
= “hello”;

Response.Write(greeting.appendUserName());

 

Oh
dear me.  We’ve set up a race condition.  Multiple
instances of the page class running on multiple threads in the same appdomain might
all try to change the prototype object at the same time, and the last one is going
to win.  Suddenly you’ve got pages that
serve up the wrong data!  That data might
be highly sensitive, or the race condition may introduce logical errors in the script
processing — errors which will be nigh-impossible to reproduce and debug.

 

A
global writable object model in a multi-threaded appdomain where class instances should
not interact is a recipe for disaster, so we made the global object model read-only
in this scenario.  If you need the convenience
of a writable object model, there is always compatibility mode.

Comments (5)

  1. Dan Shappir says:

    Question 1: Is this the reason you also enforce the use of var in fast mode?

    Question 2: Doesn’t this make the term "fast mode" a bit of a misnomer? Shouldn’t it be "ASP.NET mode"?

    Question 3: Out of curiosity – can you say how JScript.NET is fairing in the ASP.NET world vs. C# and VB.NET ?

  2. Eric Lippert says:

    1) Yes — enforcing var improves clarity, improves optimizations and prevents accidental fouling of the global namespace.

    2) Don’t be silly. I mean, we could have called them "incompatibility mode" and "slow mode" too, but obviously we wouldn’t. Fast mode was motivated by the requirements of ASP.NET, but the benefits go beyond ASP.NET scenarios.

    3) I have not the faintest idea. Remember, I haven’t actually worked on JS.NET for over two years now, and even if I was, I’m a developer, not a market researcher. (I can tell you that as far as throughput performance goes, JScript.NET on ASP.NET performs about as well as VB.NET, and both are 5%-10% slower than the equivalent C# in common scenarios — or, at least that was the case when I last ran the numbers.)

  3. Anonymous says:

    Ignore me I am testing.

  4. Blake says:

    Perhaps a compromise could be reached for a future version of the language. It seems most of the interesting reasons for modifying the prototypes of the built in objects are all cases that are one-time setup. If these prototypes were writable only at appdomain creation time and read-only there after I think both sides could be happy?

    (Not that there’s any current way to implement a .cctor in JS.NET that I’m aware of.)

  5. Samuel Bronson says:

    "ASP.NET mode" may be ridiculously specific, but it still seems like "fast mode" doesn't say enough: it doesn't say anything about allowing the script engine to be longer-lived or shared…

    Maybe it should be called something like "static mode"?