I wanted to propose an alternate approach to defining types within ES. I don't 
think is actually a realistic proposal for changing ES4 or ES3.1, but more of 
as an interesting alternate language mechanism for utilizing the ES4 VM with 
ES3 syntax that I have been interested in exploring for a while now, and 
wanting to write out in case anyone was interested in the idea. The basic 
premise is to define Classes, records, and parameter types with a schema object 
that can easily defined with ES3/JSON, rather than using ES4 type annotation 
syntax. Type information would be defined with a schema that would act like an 
interface, and this could be used in combination with local type inference for 
local variables. My examples and proposal are based on using JSON schema[1] for 
defining types; my involvement in JSON Schema might preclude objectivity to 
some degree, but I do think it is the most reasonable ES3 compatible definition 
for types. Expressed in ES3, it is a simple object structure, with a high 
degree of correspondence to ES4 types. However, though the proposal is more 
about using a external type definition/schema even if an alternate format (like 
Cerny [2]) might be better.

This approach could have application even without actual native support. 
Development could potentially use this approach to have a codebase that could 
easily be adapted (possibly through automated transformation, or type omission) 
to various target ES VMs. Also this approach has nothing to do with "classes as 
sugar" proposal [3]; it could actually be considered the inverse. Rather than 
attempting ES4 class syntax with ES3(.1) semantics, it is about using ES3 
syntax to drive ES4 class/record semantics. This proposal is also not a 
complete in it's ability to define ES4 semantics with ES3 syntax. There are 
definitely plenty of typing forms that this approach can't define, but I would 
suggest that the majority of type definitions can be defined or inferred with 
this approach.

Motivation

1. The first motivation is that the code could run in ES3 or ES4 VMs. Of course 
the ES3 VM doesn't have native typing support, so it would either have to go 
without typing, or do code translation.

2. Separation of behavior and typing/structure concerns. 
    a. One can look at the schema for the strucuture and interface of the a 
given Class or data structure separately from looking at the code for a nice 
clean, minimal (no annotations) look at the implementation and behavior.
    b. One can easily include or exclude typing information for code. Certainly 
the biggest benefits of the ES4 type system are at development time, with the 
integrity, correctness, organization, and code completion assistance. Once in 
production, the majority of web applications spend far more time downloading 
JavaScript than they do executing it (especially after DOM deductions). 
Applications may be becoming more sophisticated, but sophisticated apps still 
increase download time and with ES VMs quickly improving, plus hardware 
improvements increasing at a faster rate than bandwidth widens, I think 
download times will continue to dominant execution times for quite a while. 
Consequently, it seems most likely that performance-savvy developers will 
mostly like strip the majority of type annotations off of code during 
compression (perhaps retaining some annotations for performance sensitive 
hot-spots if VMs prove to benefit from typing information, or retaining it in 
situations where correct execution depends on type errors, rather than only 
signalling incorrect execution).
    c. Existing applications could be retrofitted with type information without 
modifying the original code (or minimally modifying). Since type information is 
provided through a separate schema, the original code can be kept intact.

3. Class reflection has an obvious reification based on the schema. Using JSON 
Schema, type information is reflected as the schema object itself.

4. Language neutral interfaces - JSON Schema has been designed to be a language 
agnostic (I realize that might be a little wistful, JSON Schema bears influence 
from the primitives of JSON and ES, but JSON has proven pretty cross-language 
capable). One could actually use a JSON Schema defined structure or interface 
with implementations in various languages. This can even facilitate interaction 
through non-language-specific means (like RPCs), and JSON Schema is even being 
used for such with Simple Method Description with Dojo [4].

Example:

First we define the schema interface for our WebMail class, this could actually 
be in a separate file than the class impl, (note that we are doing it in pure 
JSON, except for a few comments, lot's of sugar could easily be applied):
Schema.WebMail = {
   description:"Webmail Client",
   type:"object",
   methods:{ // these are the methods for the Webmail class
      send: {parameters:[{$ref:"Msg"}]}, // refers to the Msg type defined below
      handleMessage: {returns:{$ref:"Msg"}}, 
      fetch: {returns:{$ref:"Msg"}},
      get: {parameters:[{type:"integer",name:"id"}], returns:{$ref:"Msg"}}
   },
   properties:{
      database:{
         type:"array",
         items:{
            id:"Msg",
            description: "Email message",
            properties:{
               to:{
                  type:"array",
                  items:{$ref:"Addr"} // use the Addr type
               },
               from:{
                  id:"Addr",
                  description: "Email address",
                  properties:{
                     at:[{type:"string"},{type:"string"}],
                     name:{type:"string"}
                  }
               },
               subject:{type:"string"},
               body:{type:"string"},
               read:{type:"boolean"},
               messageId:{type:"integer",unique:true,optional:true}
            }
         }
      }
   }
};

Now we define the actual class impl, once again this could be in a separate 
file than the schema:

WebMail = Class(Schema.Webmail,{
   send:function (msg) { // msg is determined to be a Msg from the schema
      msg.messageId = sendToServer(JSON.encode(msg));
      // this is typed check, msg and this.database[n] are both known to be 
Msgs from the schema
      this.database[msg.messageId] = msg; 
   },
   get: function(n) {
      if (n in this.database)
         // The value of database[n] can be determined from the schema, 
         // and it properly matches the return type of get
         return this.database[n];
      // handleMessage also has a return type that matches get, so it is safe
      return this.handleMessage(n);
   },
   showMessage: function(n){
      //local type inference can determine the type of msg from the return type 
of get from the schema:
      var msg = this.get(n);
      msg.read = 40; // this could statically be determined to be a type 
conversion error
      msg.read = true; // this is a correct assignment
      messagePane.innerHTML = msg.body; // can statically be determined to be a 
string (conversion check not necessary)
   },
   handleMessage: function(n) {
      // this line is tricky, should we auto cast like "wrap"?
      var msg = JSON.parse(fetchFromServer(n));
      if (msg.result == "no data")
         return null;
      // if we auto-wrap, the casting can be done on this 
      // line or the first line depending on local type inferencing
      return database[msg.messageId] = msg; 
   },
   database:[]
}
);

This approach creates the class implementation explicitly using the schema, 
with the schema reference being in the class constructor. One could also use a 
mechanism where the class loader would use a name-based convention for loading 
the schemas and connecting them to class constructors. This could be used to 
facilitate applying schemas/typing to completely pure unaltered ES3 code/files.

This is example is taken from a comparison of ES4 and ES3 (with typing checks) 
code size [3]. This approach provides an implementation that is more compact 
than either. Of course, this could be seen as just moving the extra text to 
another place, the schema, but this is intentional. The schema acts more as 
documentation, a contract for implementations, generous with descriptions and 
various other informative (and probably non-normative to the type checker) 
annotations. Implementations can benefit from minimal code side, and 
documentation/contract information can be extensively detailed and informative.

Note that it is also important that the schema and implementation be 
static/declarative (like JSON, no dynamic expressions) in order to be properly 
statically analyzed. It would be quite easy to create aliases/consts for parts 
of a schema if you didn't expect it to be shared with other languages/systems.

There would certainly be some interesting issues in exactly how to map a schema 
to ES4 semantics. I think it would make sense for method-less schemas to 
generally map to structural types instead of interfaces. Converting plain 
objects (from functions that return untyped objects) to typed variables and 
slots would probably require creating a new object with original properties 
mixed in (like the old wrap proxy). I am sure there would be other issues to 
solve, and some ES4 type semantics that simply couldn't be described.

Anyway, once again this is not so much a proposal for changing ES, but an 
exploration of an alternate approach to typing and defining type constraints 
for various ES VMs. Perhaps this discussion might be better done on LtU, not 
sure...

[1] http://groups.google.com/group/json-schema / 
http://groups.google.com/group/json-schema/web/json-schema-proposal---second-draft
[2] http://www.cerny-online.com/cerny.js/documentation/guides/schema
[3] https://mail.mozilla.org/pipermail/es4-discuss/2008-March/002496.html
[4] http://www.sitepen.com/blog/2008/03/19/pluggable-web-services-with-smd/ / 
http://groups.google.com/group/json-schema/web/service-mapping-description-proposal

Thanks,
Kris
_______________________________________________
Es4-discuss mailing list
Es4-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es4-discuss

Reply via email to