Class method addition and replacement (was Re: AOP Compatibility)

# Kris Zyp (17 years ago)

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,

I was thinking about this, is there any reason why you can't replace a class's method with another method or install a method on an instance object that overrides the class's method, assuming that the method signature remains the same, the body has correct typing use of |this|, and the class is non-final? This seems to have the same integrity as method overriding in subclasses. Being able to do this (and possibly dynamically adding methods to classes) would bring the level of dynamicism that Mark had suggested with his ES4 sugar proposal (being able to create classes on the fly), but without destroying the fundamental ES4 typing/fixture system. This could be used to solve AOP as well, and bring a distinctly higher level of dynamicism which could be leveraged to progressively build, serialize (with proper introspection), and deserialize classes.

Essentially, are there mutations to classes and object instances that do not effect integrity and do not violate explicit contracts against mutation (final annotation=no method mutations) that we could allow?

Thanks, Kris

# Peter Hall (17 years ago)

Replacing a method effectively changes the type, even if the signature is the same. If some code creates an instance of a class using "new" it should be able to rely on it being that type, and make assumptions about how that object will behave. (This is not a matter of breaking polymorphism because the same code created the instance such that there is no possibility of a sub-type instance being present). Allowing methods to be replaced means that other parts of a program could alter the behaviour of an object in a way that could contradict those assumptions.

Additionally, allowing methods to be replaced could reduce the effectiveness of early binding optimisations. (Jeff Dyer can correct me if I'm inaccurate here..) In AS3, class methods are referenced via the class's traits table. They may be accessed by name, but calls are bound to addresses where possible, at compile time via the traits. Allowing methods to be overridden would mean a choice of copying the traits for each instance, which would increase memory usage dramatically; or else checking for overrides at runtime for every method call, which would hurt performance.

Peter

# Lars Hansen (17 years ago)

Just to echo Peter here, changing a method violates integrity in the worst way. If I say "new Cls" I know that the object I get is of type Cls, and if I know the implementation of that class I know what a call to a method of the type will do. There is no way subclassing can get in the way of that knowledge, but allowing methods to be arbitrarily assigned to (even with constraints on type compatibility) completely destroys that invariant. But that invariant is one of the main benefits of having classes in the first place.

(There are efficiency concerns too, but I think the violation of integrity is the important part.)

# Brendan Eich (17 years ago)

On Apr 3, 2008, at 8:23 AM, Kris Zyp wrote:

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,

I was thinking about this, is there any reason why you can't replace a class's method with another method or install a method on an
instance object that overrides the class's method, assuming that the method signature remains the same, the body has correct typing use of |this|, and
the class is non-final? This seems to have the same integrity as method
overriding in subclasses. Being able to do this (and possibly dynamically adding
methods to classes) would bring the level of dynamicism that Mark had
suggested with his ES4 sugar proposal (being able to create classes on the fly)

Mark's sketch did not allow method replacement, however.

AOP is not the root password to mutation barriers added to enforce
integrity properties. It is not even formally sound, last I looked.
And its main use-case is logging or other such post-hoc, cross- cutting instrumentation. If the universe of objects already contains
some (like certain built-in objects including DOM nodes in most
browsers) whose methods cannot be replaced, which must therefore be
wrapped for AOP-style hacking, then why wouldn't we want classes to
behave as proposed in ES4?

Wrappers will be required; they already are for security in browsers
I've studied (or they are coming soon, at any rate). Any code not
insisting on a nominal type relation, i.e., using * (implicitly as in
untyped code today, or explicitly), or a like test, or a structural
subtype test, could let wrappers through. Just as DOM wrappers can
satisfy hand-coded "shape tests" in today's untyped libraries that
use AOP.

# Kris Zyp (17 years ago)

Just to echo Peter here, changing a method violates integrity in the worst way. If I say "new Cls" I know that the object I get is of type Cls, and if I know the implementation of that class I know what a call to a method of the type will do. There is no way subclassing can get in the way of that knowledge, but allowing methods to be arbitrarily assigned to (even with constraints on type compatibility) completely destroys that invariant. But that invariant is one of the main benefits of having classes in the first place.

But if I want the class to behave exactly the same as when I created, why would I change the method? Isn't changing a method an explicit indication that a developer doesn't want the class to be invariant? I believe this is more a philosophical/preferential question. Do you value class integrity/immutably more or dynamicism/mutably? Obviously my preference is towards the latter camp, but perhaps I am in the minority, and the concerns over efficiency are certainly important as well. Thanks, Kris

# Peter Hall (17 years ago)

If you want mutability, you can define methods as vars in the first place.

class Foo {

// can be modified on a per-instance basis public var f : function (a:T):S = function (a:T):S { return null; }

}

but that is an explicit intent to permit that behaviour by the class author.

Peter

# Lars Hansen (17 years ago)

Most of the time I would not agree that "changing a method is an explicit indication that a developer doesn't want the class to be invariant". Most of the time it's just an indication that I'm (a) hacking to make something (appear to) work or (b) tired and making a mistake. And this goes doubly for team programming and for programs that have a long maintenance life.

Classes provide the integrity that is necessary for large systems written by many people over significant periods of time to work; such systems reward commitments to invariants even if those invariants later can become a straightjacket (and require reengineering). In such a system the variation points are (and need to be) explicit.

# Brendan Eich (17 years ago)

On Apr 3, 2008, at 6:12 PM, Lars Hansen wrote:

In such a system the variation points are (and need to be) explicit.

EIBTI!

# Nathan de Vries (17 years ago)

On 04/04/2008, at 1:35 PM, Brendan Eich wrote:

EIBTI!

Perhaps not the best reference given the topic, given that Python
makes class overriding and resurrection of overridden classes
possible with their builtin module.

I'm actually quite surprised to hear that there are so many on this
list who are happy to drop EcmaScript's usual dynamicism in favour of
so called "integrity". Monkey patching is prevalent on the web, and I
believe that the practice should be supported, not feared. Sure,
developers will be able to explicitly mark areas in their code which
they deem appropriate for another developer to change, but that
strikes me as a bit of a fantasy land.

The majority of code which requires patching by external developers
was never written to be patched, but people do it anyway. This is
good, don't you agree?

-- Nathan de Vries

# Brendan Eich (17 years ago)

On Apr 5, 2008, at 12:42 AM, Nathan de Vries wrote:

On 04/04/2008, at 1:35 PM, Brendan Eich wrote:

EIBTI!

Perhaps not the best reference given the topic, given that Python makes class overriding and resurrection of overridden classes possible with their builtin module.

Good point. Slogans like EIBTI are too binary to handle the fullness
of Python, never mind JS. Let's stick to ES3 and ES4 here. Since no
one is proposing to do away with dynamic typing or mutable objects in
ES4...

I'm actually quite surprised to hear that there are so many on this list who are happy to drop EcmaScript's usual dynamicism in favour of so called "integrity".

... "drop" here is false. We're adding missing tools to make
immutable properties and objects that can't be extended, that's all.

Monkey patching is prevalent on the web, and I believe that the practice should be supported, not feared.

How about both? ;-)

I picked mutable by default in JS1 intentionally, because it allowed
content authors to monkey-patch or wholesale-mutate the built-in
objects, to work around bugs or simply suit their own needs. This was
assuming a same-origin single trust domain.

Two things have happened since 1995 (really, both started happening
right away in 1996, but few noticed):

  1. JS code has scaled up to "programming in the large" domains, where
    even without hostile code or mutual suspicion, producers and
    consumers of library code want greater integrity properties than they
    can enforce with closures for private variabables (which are still
    mutable objects).

  2. JS from different trust domains is being mixed, most obviously via
    script injection (for advertising, among other things), to overcome
    same-origin restrictions. Fixing this takes more than integrity in my
    view (confidentiality via secure information flow is something we're
    researching at Mozilla, partnering with others). But integrity is
    foundational, non-optional.

Sure, developers will be able to explicitly mark areas in their code which they deem appropriate for another developer to change, but that strikes me as a bit of a fantasy land.

The fantasy here would be that JS has been kept down on the same- origin and small-scale storybook farm where it was born. It's in the
big city now. ;-)

The majority of code which requires patching by external developers was never written to be patched, but people do it anyway. This is good, don't you agree?

See above.

# Nathan de Vries (17 years ago)

On 06/04/2008, at 1:38 AM, Brendan Eich wrote:

Sure, developers will be able to explicitly mark areas in their code which they deem appropriate for another developer to change, but that strikes me as a bit of a fantasy land.

The fantasy here would be that JS has been kept down on the same- origin and small-scale storybook farm where it was born. It's in
the big city now. ;-)

The majority of code which requires patching by external developers was never written to be patched, but people do it anyway. This is good, don't you agree?

See above.

I'm not denying that the problems you're trying to fix aren't
problems, it's just that I believe a wholesale locking down of the
language will be too drastic and may result in a shift away from the
language Javascripters have come to know and love.

To give some context, when you speak of "producers" & "consumers" of
Javascript code I guess I would classify myself as a predominant
consumer. You may be surprised to hear that mutability is one of the
things that I love about the language, and that I don't particularly
"want greater integrity properties" (despite desiring the side
effects :) ).

I have experience as both a Javascript & Actionscript 3 programmer,
so you could say that I've had a little bit of a taste of what's to
come. One experience of mine you might be interested in is as a
consumer of Adobe's Flex framework. Quite often, I feel the need to
extend the various Flex classes (as you do). Unfortunately, many of
the classes have properties defined as "private" instead of
"protected", despite being clearly suitable candidates for consumers
to extend. This results in developers like myself being forced to
copy-paste entire classes just to override "high integrity"
properties. In Javascript, this would not be an issue.

Do you get the feeling that the majority of developers who aren't
writing the Javascript you're talking about will be left with a new
language that doesn't fit their development profile? Do you think
that the developers who will write large-scale Javascript will cater
to those who are used to a more traditional approach?

My gut feeling to those two questions are "yes" and "no", but
unfortunately that's all it is; a gut feeling.

Cheers,

-- Nathan de Vries

# Brendan Eich (17 years ago)

On Apr 6, 2008, at 3:06 AM, Nathan de Vries wrote:

I'm not denying that the problems you're trying to fix aren't problems, it's just that I believe a wholesale locking down of the language will be too drastic and may result in a shift away from the language Javascripters have come to know and love.

You're doing it again: "wholesale locking down" is false as a general
statement, and almost entirely false broken down into particulars.

Are we "locking down" objects created by operator new applied to a
function, or to the built-in Object, Array, String, Number, Boolean,
Date, RegExp, and *Error constructors? No.

Are we "locking down" objects created by initialisers? No (but we are
using the original values of the Object and Array bindings, even in
ES3 implementations today including Firefox 3, to preserve integrity
for defense in depth, against JSON hijacking attacks).

Are we "locking down" classes, new in ES4, so that their prototypes
cannot be extended? No.

Are we "locking down" classes so that their prototype-declared
methods can't be overridden? No.

Are we "locking down" classes against instance extension via ad-hoc
property assignment? Yes, unless you use the 'dynamic' modifier in
front of 'class'.

Is this one last "Yes" therefore "wholesale"? Obviously not.

Since you grant use-cases for sealing objects against mutation, are
you simply arguing about what the default should be (that 'dynamic
class' should not be required to get an extensible-instance factory,
that 'class' should do that)?

Do you get the feeling that the majority of developers who aren't writing the Javascript you're talking about will be left with a new language that doesn't fit their development profile?

No, because as noted above and copiously documented, ES4 is a
superset of ES3. I expect "JS hackers" to continue doing what they
have been doing, with newcomers choosing from a larger toolbelt and
set of styles. We're opening up pathways for evolution that are
either closed or clogged by high-cost barriers in ES3.

Do you think that the developers who will write large-scale Javascript will cater to those who are used to a more traditional approach?

Which tradition do you mean? There are several.

That most Ajax libraries reinvent classical OOP, sometimes with bugs
and always with inefficiencies in code size, runtime, and memory use,
and with integrity holes, suggests that common traditional approaches
could be improved. This we are proposing to do in ES4.

My gut feeling to those two questions are "yes" and "no", but unfortunately that's all it is; a gut feeling.

I think assertions about "wholesale locking down" reflect feeling
trumping analysis. I hope the Q&A above helps you see that
"wholesale" is false.

If we should argue about the default extensibility of instances
created by unmodified class definitions, let's do that. If this is
about other syntax choices, we can argue about those too, but with
specifics, not vague generalities or angst.

If anyone thinks the missing integrity property support (readonly,
don't-delete, inextensible, not shadowable/overrideable, etc.) can be
dispensed with, I've yet to hear a coherent claim to that effect.

Adding minimal metaprogramming functions to mutate existing ES3
structures to enforce some of these properties is not enough, unless
you take the performance hit, close the "in the middle of
construction" integrity holes, and sugar it all with a code generator
or macro system (we have code generators, but they cost enough that
people avoid them and code to the JS metal; we don't have macros yet).

Classes are an integrity device, for programming in the large as much
as for defense against malicious code. There are other such measures
in ES4, e.g. types, fixtures, and const. These fill gaps in ES3 that
can't be faked.

It seems to me the way forward is to make specific arguments about
these proposals, not generalize inaccurately about their being
"wholesale" in effect (they aren't), or untraditional (to the extent
that JS authors today try to fake it, they are not).

# Garrett Smith (17 years ago)

On Thu, Apr 3, 2008 at 5:20 PM, Peter Hall <peter.hall at memorphic.com> wrote:

If you want mutability, you can define methods as vars in the first place.

class Foo {

// can be modified on a per-instance basis public var f : function (a:T):S = function (a:T):S { return null; }

}

A common idiom is to have a default value in the ADT's prototype. (I'm calling a constructor-with-a-prototype an "ADT" -- ES3, which doesn't have true "class" classes).

ES3 example:

function Button() { }

Button.prototype = { ondepress : function(){}, _isDepressed : false };

var b = new Button; b.ondepress = buttonDepressed;

  • b - just got a new instance property: ondepress.

So when defining an ES4 class, instead of putting a default - ondepress - in the prototype, a dummy function will be added to the instance.

I'm not understanding the syntax well enough to post an example.

This will have the result of more function objects being created for a program that does not use - ondepress - for Button instances. Would the Button class be better off by having a private EMPTY function? Or maybe that goes on a larger scale, to the event notification system, but then that wouldn't work unless the event system's empty Function instance was immutable.

[snip]

# Nathan de Vries (17 years ago)

On Sun, 2008-04-06 at 13:07 -0700, Brendan Eich wrote:

You're doing it again: "wholesale locking down" is false as a general
statement, and almost entirely false broken down into particulars.

You're right, "wholesale locking down" is false. However, it is the migration path for developers who will be using ES4 to its fullest.

Since you grant use-cases for sealing objects against mutation, are
you simply arguing about what the default should be (that 'dynamic
class' should not be required to get an extensible-instance factory,
that 'class' should do that)?

Yes, dynamic classes seem more in line with my expectations. Perhaps D's concepts of const/invariant [1] could apply as optional class / member decorations available to developers with immutability in mind.

No, because as noted above and copiously documented, ES4 is a
superset of ES3.

It's the superset I'm concerned about (and talking about), mainly because that's the migration path for Javascript developers as I mentioned previously.

It seems to me the way forward is to make specific arguments about
these proposals, not generalize inaccurately about their being
"wholesale" in effect (they aren't), or untraditional (to the extent
that JS authors today try to fake it, they are not).

Sure. I'll do my best to do that, keeping in mind that some of the concepts being discussed WRT language design are outside my field of expertise.

Cheers,

-- Nathan de Vries

[1] www.digitalmars.com/d/2.0/const3.html