Suggestions

# Nicolas Cannasse (19 years ago)

I've been talking with Brendan a few weeks ago and I made some suggestions about ES4. I'm copying them here so they can be discussed publicly. They are mainly related to the specific usage I'm making of Javascript but might be useful for all kind of ES4 users/hackers :

  • A full reflection API. See for example the Reflect haXe class : haxe.org/api/Reflect. It has to use some tricks. In particular the difference between an "object field" and a "prototype field" is not very clear in JS, so for instance to get the "object fields" you need to build a list with for...in then filter with hasObjectProperty.

  • how you will support interitance ? Will you be able to create your own prototype-chains ? In haxe you can "implements" classes. Be able to add add object in the subtyping relation would help.

  • the ability to create "naked" objects, with no prototype, and no magic field, so every field of the object can be freely manipulated. It would be nice to be able to idenpendantly set the object prototype and set the "field" prototype. For instance Neko gives prototype access through primitives $objgetproto and $objsetproto instead of giving "magic" access through .prototype or proto.

  • exceptions with complete stack traces : not as strings but as objects, so we can easily extract the line numbers and replace them by the original language file/line numbers. That can also be implemented by the ability to add specific comments in generated code, such as :

#line MyClass.hx:203

(similar to OCaml Camlp4)

  • "magic" fields __resolve, __call and __get/__set (array accesses) would help to implement several kind of highlevel features transparently.

  • true continuations (à la Ruby) would help to implement some highlevel features such as microthreads and scalable event systems

  • be able to manipulate Strings as array of bytes (and not only as UTF8 chars) would be great for binary protocols. For example Firefox allows \0 in strings, not IE or Flash.

  • block-context : you introduce that with "let", so I think it will make it within TG1 ? Right now haXe for instance is renaming variables to make them unique. (since then, I've been completing full block-level variables emulation for JS and Flash)

  • gotos : would permit to efficently generate pattern-matching without bloating the code.

# P T Withington (19 years ago)

On 2006-06-28, at 15:00 EDT, es4-discuss-request at mozilla.org wrote:

From: Nicolas Cannasse <ncannasse at motion-twin.com> Date: 28 June 2006 12:33:10 EDT

[...]

Nicholas, lots of interesting ideas here. I have a few comments.
I'm just coming up to speed here, so pardon me if I am covering old
ground.

  • A full reflection API. See for example the Reflect haXe class :
    haxe.org/api/Reflect. It has to use some tricks. In
    particular the difference between an "object field" and a
    "prototype field" is not very clear in JS, so for instance to get
    the "object fields" you need to build a list with for...in then
    filter with hasObjectProperty.

Reflection conflicts with optimizations such as sealing (but then, so
does having eval in your language). That said, I would love to see a
reflection API like Flash's ASSetPropFlags, which would allow user
programs to create read-only, non-enumerable and un-deletable
properties. This would go a long way to being able to write a useful
debugger in the language, instead of it having to be a separate
program with a back-door. It also makes it possible to write a leak- detector in the language.

The current proposal at developer.mozilla.org/es4/proposals enumerability.html is not really sufficient, since you have to
already know the existence of a property to set its enumerability,
but if you can't enumerate the property? ASSetPropFlags allows you
to set the flags on all the properties of an object, so you can
make them all enumerable (by enumerating them first, you know which
ones to make un-enumerable when you are done).

Perhaps reflection and eval are turned off in strict mode?

  • how you will support interitance ? Will you be able to create
    your own prototype-chains ? In haxe you can "implements" classes.
    Be able to add add object in the subtyping relation would help.

Not sure I follow you here. You can already create arbitrary
prototype chains in ECMAScript:

function makeInheritedHash (parent) { if (parent) { function xtor() {}; xtor.prototype = parent; return new xtor(); } return new Object; };

  • the ability to create "naked" objects, with no prototype, and no
    magic field, so every field of the object can be freely
    manipulated. It would be nice to be able to idenpendantly set the
    object prototype and set the "field" prototype. For instance Neko
    gives prototype access through primitives $objgetproto and
    $objsetproto instead of giving "magic" access through .prototype or
    proto.

This can be simulated in current ECMAScript by filtering with
hasOwnProperty, but I agree that it is a wart that is too easy to
stumble over (using an Object as a HashTable and not realizing that
there are some keys 'already defined'). I think this could be solved
by letting you set a constructor's prototype to null, but the spec
would have to specifically state that this must be supported (it
would have to define what operations must work on objects with no
prototype). Making an object with a null prototype breaks several
current implementations.

  • exceptions with complete stack traces : not as strings but as
    objects, so we can easily extract the line numbers and replace them
    by the original language file/line numbers. That can also be
    implemented by the ability to add specific comments in generated
    code, such as :

Isn't this really just part of your introspection request? IWBN to
have introspection interfaces to the execution context. As long as
we are re-implementing Lisp, eval needs to take an execution context
as an argument: mitpress.mit.edu/sicp/full-text/book/book-Z- H-26.html#%25_idx_4230. (This would also be helpful writing a
debugger).

  • "magic" fields __resolve, __call and __get/__set (array accesses)
    would help to implement several kind of highlevel features
    transparently.

Please elaborate?

[...]

No comments on the last three items.

# Nicolas Cannasse (19 years ago)
  • how you will support interitance ? Will you be able to create your own prototype-chains ? In haxe you can "implements" classes. Be able to add add object in the subtyping relation would help.

Not sure I follow you here. You can already create arbitrary prototype chains in ECMAScript:

function makeInheritedHash (parent) { if (parent) { function xtor() {}; xtor.prototype = parent; return new xtor(); } return new Object; };

Yes but it's a single list. When you start having interfaces in the language, it means that you have several supertypes. It would be interesting to access/modify this supertype list used for runtime subtyping.

  • the ability to create "naked" objects, with no prototype, and no magic field, so every field of the object can be freely manipulated. It would be nice to be able to idenpendantly set the object prototype and set the "field" prototype. For instance Neko gives prototype access through primitives $objgetproto and $objsetproto instead of giving "magic" access through .prototype or proto.

This can be simulated in current ECMAScript by filtering with hasOwnProperty, but I agree that it is a wart that is too easy to stumble over (using an Object as a HashTable and not realizing that there are some keys 'already defined'). I think this could be solved by letting you set a constructor's prototype to null, but the spec would have to specifically state that this must be supported

Yes for example this works on current Safari JS implementation I think.

(it would have to define what operations must work on objects with no prototype). Making an object with a null prototype breaks several current implementations.

Accessing fields for reading/writing looks enough.

  • exceptions with complete stack traces : not as strings but as objects, so we can easily extract the line numbers and replace them by the original language file/line numbers. That can also be implemented by the ability to add specific comments in generated code, such as :

Isn't this really just part of your introspection request? IWBN to have introspection interfaces to the execution context. As long as we are re-implementing Lisp, eval needs to take an execution context as an argument:

mitpress.mit.edu/sicp/full-text/book/book-Z-H-26.html#%_idx_4230.

(This would also be helpful writing a debugger).

Actually, there is another way to do this. If the exception stack trace gives the file+line table representation the stack, then we can do appropriate replacements by remaping line X of the generated JS to the file/line of the original files.

  • "magic" fields __resolve, __call and __get/__set (array accesses) would help to implement several kind of highlevel features

transparently.

Please elaborate?

For instance, when an unknown field is accessed in ActionScript2, __resolve is called instead (if exists). It has an argument which is the field name.

When an object is used as a function and called, the __call method could be invoked with the list of arguments.

Here's an exemple of what is happening at runtime :

o.unknownField => o.__resolve("unknownField")

o.xxx = 0 => o.__setfield("xxx",0)

o(1,2,3) => o.__call(1,2,3)

o[56] => o.__get(56) // or __resolve(56) ?

o[56] = 5 => o.__set(56,5) // or __setfield(56,5) ?

This can be optimized correctly by storing some bits in the object telling which magic accessor it has. This then only require one additional test in some specific cases.

# Peter Hall (19 years ago)

Nicholas, what is your view of how reflection is implemented in AS3? That is, as an XML dump of the object's traits table. AS3 reflection has a dependency on e4x, of course, which might be problematic since e4x is an optional extension. But I likewise feel that Reflection should, in any case, be an optional extension, as opposed to part of the core language.

For instance, when an unknown field is accessed in ActionScript2, __resolve is called instead (if exists). It has an argument which is the field name.

When an object is used as a function and called, the __call method could be invoked with the list of arguments.

Do you have a criticism of AS3's Proxy class? Personally, I think it is cleaner and more transparent. However, it could do with some extension to bring the functionality up to the same level (that is, being able to essentially turn any existing dynamic object into a proxy). For that, Proxy would have to be made a special case for compile-time type-checking and have the ability to override the "as", "is" and "instanceof" operators (and probably others).

# Nicolas Cannasse (19 years ago)

Nicholas, what is your view of how reflection is implemented in AS3? That is, as an XML dump of the object's traits table. AS3 reflection has a dependency on e4x, of course, which might be problematic since e4x is an optional extension. But I likewise feel that Reflection should, in any case, be an optional extension, as opposed to part of the core language.

There is two kind of reflections :

a) accessing the class metadatas + fields types at runtime. This is what AS3 is doing. It's of course possible since all theses infos are present in the SWF9 binary format, and are needed by the JIT to perform appropriate optimizations. This is not what haXe is doing. Only some metadatas are accessible at runtime, like the class name and the inheritance tree.

b) an API to access objects in an abstract manner. See haxe.org/api/Reflect

Do you have a criticism of AS3's Proxy class? Personally, I think it is cleaner and more transparent.

You have to "extend" Proxy to get the __resolve. I think that's a very bad design since with single inheritance you cannot add a __resolve by extending another class. That means you have to choose either Proxy or Subclass. If Proxy was an interface that would have been possible...

However, it could do with some extension to bring the functionality up to the same level (that is, being able to essentially turn any existing dynamic object into a proxy). For that, Proxy would have to be made a special case for compile-time type-checking and have the ability to override the "as", "is" and "instanceof" operators (and probably others).

Yes, this is what haXe Proxy is doing. But since there is no __resolve support (or equivalent) on all platforms, it's restricted to method calls :

see lists.motion-twin.com/pipermail/haxe/2006-June/003203.html for a quick example.

# Lars T Hansen (19 years ago)

Nicolas Cannasse writes:

  • gotos : would permit to efficently generate pattern-matching without bloating the code.

Proper tail calls takes care of some of this need, but that said, Opera has had 'goto' since 8.0 or so.

(Why? I hear you cry. The reason is pretty silly. The 550 point version of Colossal Cave Adventure was originally written in Fortran and then machine translated to C-with-gotos. C and ECMAScript being syntactically close I wanted to run it with minimal changes as a script in Opera. So 'goto' was added solely for this reason, though it's later found some other uses as well.)