AOP Compatibility

# Kris Zyp (18 years ago)

It seems that one of more significant remaining compatibility issues with ES3 is the inability to set AOP advice on all methods. Many frameworks rely on the ability to replace functions in order to add advice/listen to methods. For example, this is how dojo.connect works, although this is certainly not the only function that uses this technique. This might not fail compatibility tests in the sense that pure ES3 code (no classes) will still operate properly in an ES4 environment. However, when ES4 classes are mixed with existing ES3 framework code, and when instances of classes are passed to AOP functions like dojo.connect, the AOP function will fail to be able to replace the function to add advice. Is there any way this compatibility can be mitigated? I am assuming there is no conceivable way to actually replace methods ad-hoc with arbitrary functions and retain sane typing and class expectations. However, would a more controlled AOP API be a reasonable approach to adding AOP advice to methods? At least, frameworks could be altered to handle the difference between ES4 class and dynamic Object, and use the AOP API when appropriate, and therefore general AOP providing functions could be altered to work in both ES3 and ES4 environments. I don't know if there another way to mitigate this incompatibility... Thanks, Kris

# Brendan Eich (18 years ago)

On Feb 20, 2008, at 10:17 AM, Kris Zyp wrote:

Is there any way this compatibility can be mitigated? I am assuming
there is no conceivable way to actually replace methods ad-hoc with arbitrary functions and retain sane typing and class expectations.

I'm not sure why you assume this. Latest RI downloaded from http:// ecmascript.org/ :

$ ./es4 ECMAScript Edition 4 RI v0.0M2 (Fri Feb 15 13:37:13 2008)

save_getTime = Date.prototype.getTime [function Function]

Date.prototype.getTime = function advice() { intrinsic::print ("before getTime"); let t = save_getTime(); intrinsic::print("after
getTime"); return t; } [function Function]

d = new Date

Wed, 20 Feb 2008 22:15:18 GMT+0000

d.getTime()

before getTime after getTime 1203545718235

save_Date_parse = Date.parse [function Function]

Date.parse = function more_advice() { intrinsic::print("yay!");

return save_Date_parse.apply(this, arguments); } [function Function]

Date.parse(Date())

yay! 1203545824000

The builtins are backward-compatible as to class object and prototype
mutation, including AOP hacks. The only proposed change for ES4,
dependent on opt-in versioning, is making the constructor (now type)
bindings immutable. Replacing Date in the global object is much less
commonly done (but not unknown: Joel Spolsky's fogbugz does this, we
learned via a crucial experiment in Firefox 3 beta 2).

# P T Withington (18 years ago)

On 2008-02-20, at 17:20 EST, Brendan Eich wrote:

On Feb 20, 2008, at 10:17 AM, Kris Zyp wrote:

Is there any way this compatibility can be mitigated? I am assuming there is no conceivable way to actually replace methods ad-hoc with arbitrary functions and retain sane typing and class expectations.

I'm not sure why you assume this. Latest RI downloaded from http:// ecmascript.org/ :

I thought the question was about annotating class fixtures?

But your reply made me think: So, built-ins cannot be classes,
because they require backward compatibility? Or maybe I missed that
there are sealed/class versions of built-ins (in some other
namespace?) with just a thin veneer of prototype around them for back
compatibility?

# Brendan Eich (18 years ago)

On Feb 20, 2008, at 3:35 PM, P T Withington wrote:

On 2008-02-20, at 17:20 EST, Brendan Eich wrote:

On Feb 20, 2008, at 10:17 AM, Kris Zyp wrote:

Is there any way this compatibility can be mitigated? I am assuming there is no conceivable way to actually replace methods ad-hoc with arbitrary functions and retain sane typing and class expectations.

I'm not sure why you assume this. Latest RI downloaded from http:// ecmascript.org/ :

I thought the question was about annotating class fixtures?

How could it be, since those do not exist in ES1-3?

Fixtures are in the intrinsic namespace, so yes, 'use namespace
intrinsic' will break AOP. The two do not mix, they're fundamentally
opposed to each other.

But your reply made me think: So, built-ins cannot be classes, because they require backward compatibility? Or maybe I missed that there are sealed/class versions of built-ins (in some other namespace?) with just a thin veneer of prototype around them for back compatibility?

You can read the code ;-). Built-in constructors such as Date are
dynamic classes. Here's part of builtins/Date.es:

package { import ECMAScript4_Internal.; import JSON.;

 use default namespace public;
 use namespace helper;
 use namespace informative;
 use namespace intrinsic;
 use namespace __ES4__;
 use strict;

 const NOARG = {};

 dynamic class Date
 {

     static const length = 7;

     /* E262-3 15.9.2: The Date Constructor Called as a Function */
     meta static function invoke(...args)   // args are ignored.
         (new Date()).public::toString();

     /* E262-3 15.9.3: The Date Constructor. */
     function Date(year=NOARG, month=NOARG, date=NOARG,  

hours=NOARG, minutes=NOARG, seconds=NOARG , ms=NOARG) { informative::setupNanoAge();

         switch (NOARG) {

etc.

Yes, typeof Date == "function" for backward compatibility. typeof is
broken and we can't fix it, but the |is| operator and the meta
objects proposal provides better alternative tools.

# Kris Zyp (18 years ago)

I thought the question was about annotating class fixtures?

Yes, that was my intent, sorry I wasn't clearer. I knew that built-ins were designed to be backwards compatible. I don't have the RI in front of me at the moment, but I assume you can't do replace a method on a user class with another ad-hoc function. Kris

# Brendan Eich (18 years ago)

On Feb 20, 2008, at 3:42 PM, Kris Zyp wrote:

I thought the question was about annotating class fixtures? Yes, that was my intent, sorry I wasn't clearer.

No problem, sorry for assuming you meant ES3-compatible code.

I knew that built-ins were designed to be backwards compatible. I don't have the RI in front
of me at the moment, but I assume you can't do replace a method on a user
class with another ad-hoc function.

Absolutely not with fixtures, but you can put the prototype qualifier
in front of function definitions in classes to create prototype
methods just like the ones in ES3's builtins, and you can make your
class dynamic (although IIRC, all class objects where static
properties live are mutable; class instances are fixed unless the
class is dynamic -- Graydon or Jeff should correct me if I'm wrong).
If you want to allow AOP, which is pretty much an integrity
violation, you have to lower your shields.

Formalizing AOP further, somehow supporting it without losing the
integrity guarantees needed for early binding and strict mode, is out
of scope for ES4. But you can do a lot with ES4's function types. If
the guarantee is not about function object identity (e.g. for
analysis of effects, or for inlining), rather only about function
type, it's fine to use a non-fixture that has a type annotation. | prototype function AOPmeHarder(this:Widget, a:int, b:string):boolean|
can be overwritten by advice, but the advice can't subvert type
judgments.

# Kris Zyp (18 years ago)

Absolutely not with fixtures, but you can put the prototype qualifier in front of function definitions in classes to create prototype methods just like the ones in ES3's builtins, and you can make your class dynamic (although IIRC, all class objects where static properties live are mutable; class instances are fixed unless the class is dynamic --
Graydon or Jeff should correct me if I'm wrong).

Of course a library function (like dojo.connect) that is called to advise a method on an object doesn't have control of how the object was created. If it is an instance of user class (and not dynamic), this function will this fail. This functionality is pretty core and heavily used by Dojo and I believe is used by other libraries as well. Of course existing code will continue to work, but it will be disappointing to find this function fail for new objects created with ES4 functionality. I don't know an easier solution, other than real AOP support. Kris

# Brendan Eich (18 years ago)

On Feb 20, 2008, at 4:21 PM, Kris Zyp wrote:

Of course a library function (like dojo.connect) that is called to
advise a method on an object doesn't have control of how the object was
created. If it is an instance of user class (and not dynamic), this function
will this fail. This functionality is pretty core and heavily used by Dojo and I believe is used by other libraries as well. Of course existing code
will continue to work, but it will be disappointing to find this
function fail for new objects created with ES4 functionality. I don't know an easier solution, other than real AOP support.

I think you're assuming a problem of the "Doctor, it hurts when I do
this" variety. Non-dynamic classes are not for everything. Where you
need them as integrity devices, you do not want Dojo's AOP, no way no
how. Most objects will continue to be plain old Object instances. But
note that even in today's world, DOM types are nominal -- there are
non-dynamic classes under the hood. Not all DOM or similar browser
embedding objects can be mutated freely. Dojo survives these hazards,
as far as I know.

# Neil Mix (18 years ago)

Another thought: does ES4 provide enough introspection capability to
write proxy objects that wrap an immutable class instance? It seems
as though it should be possible to create a single class (with *
getter/setter functions) that can wrap any object, emulate its
interface and provide AOP advice capabilities. If this is indeed
possible, would that prove useful for the situations Kris is
concerned about?

# Garrett Smith (18 years ago)

On Thu, Feb 21, 2008 at 7:47 AM, Neil Mix <nmix at pandora.com> wrote:

Another thought: does ES4 provide enough introspection capability to write proxy objects that wrap an immutable class instance? It seems as though it should be possible to create a single class (with * getter/setter functions) that can wrap any object, emulate its interface and provide AOP advice capabilities. If this is indeed possible, would that prove useful for the situations Kris is concerned about?

This thread is useless without code.

# Kris Zyp (18 years ago)

Another thought: does ES4 provide enough introspection capability to write proxy objects that wrap an immutable class instance? It seems as though it should be possible to create a single class (with * getter/setter functions) that can wrap any object, emulate its interface and provide AOP advice capabilities. If this is indeed possible, would that prove useful for the situations Kris is concerned about?

That is good question. It wouldn't truly solve the problem. When you call dojo.connect to request that your method add advice/a listener, the caller doesn't expect that it is going to be told that it should no longer use the original class instance, but rather a proxy. But this could still mitigate the problem. At least users could proxy class instances such that they are advisable in the same way their ol' dynamic ES3 objects were. I don't know if their is sufficient introspection capability though, I would love to know if that is possible. Thanks, Kris

# Brendan Eich (18 years ago)

On Feb 21, 2008, at 7:47 AM, Neil Mix wrote:

Another thought: does ES4 provide enough introspection capability to write proxy objects that wrap an immutable class instance? It seems as though it should be possible to create a single class (with * getter/setter functions) that can wrap any object, emulate its interface and provide AOP advice capabilities. If this is indeed possible, would that prove useful for the situations Kris is concerned about?

Sure, at the price of loss of identity. That may break AOP use-cases.