String finality (was: Re: ARGUMENTS.SHOULD.BE.ARRAY bug-fix)

# Brendan Eich (19 years ago)

On Mar 19, 2007, at 1:01 PM, zwetan wrote:

but still out of curiosity, in a case where someone would want to do the same kind of methods
delegation but with non-generic methods (this value required to be of the
original type) does ES4 offers some way of doing it ?

Bound methods cannot be called on a |this| parameter of the wrong
type -- they carry their |this| around once extracted (e.g. from a
class instance).

I'm thinking of reusing Date methods for examples in a "new" classes like DateTime, TimeSpan, etc... but Date methods require that the this value be the Date Object.

You can't do this today, and it won't work in ES4.

or another ex, like trying to inherit from the class String on the
prototype

But String's methods are all generic, except for toString and
valueOf, so you could reuse String's generic methods in several ways
(by extracting references to them or their static counterparts; by
subclassing String -- see below; by one-off delegations via .apply or
equivalent).

cf

class String2 { prototype = new String();

//etc...
}

I know that String is final,

String is final in AS3, but not final in proposed ES4 as of the last
face-to-face meeting.

Here is the latest plan of record for primitive (string) vs. wrapper
(String) types:

  • Suppose we support primitive types via final class string!, etc.,
    and model wrapping as follows:
    • class string! extends String.
    • The fixed methods of the final primitive class are all
      intrinsic only, not prototype.
    • Which implies that the standard methods of String are only
      prototype [at the time this was written, intrinsic => final -- we are

revisiting, but backward compatibility does not require intrinsic
methods in String. /be]. * Thus we split intrinsic functionality from String and push it
down into string. * “hi”.charAt(0) therefore invokes String.prototype.charAt on
the string “hi” in the absence of a 'use namespace intrinsic'. * If you want speed and not AOP, 'use namespace intrinsic' or
call “hi”.intrinsic::charAt(0) (or in this case, use indexing). * To support “hi”.nosuch === undefined and “hi”.foo = 42 where a
subsequent "hi".foo results in undefined, we use Jeff’s catchalls
suggestion [defining get *() {...} and set *() {...} on class
string], which simulates ES1-3’s wrapping under ToObject * Code may freely use string and unless it explicitly uses
intrinsic, AOP via String.prototype still works. * And (thanks to the catchalls) generic get-and-test-against- undefined (or equivalent) and useless sets still work.

This applies to boolean/Boolean too. Number is different, given the
several primitive types (int, uint, double, decimal). I'll defer
getting into Number and let people digest the above.

# Brendan Eich (19 years ago)

On Mar 19, 2007, at 1:49 PM, Brendan Eich wrote:

On Mar 19, 2007, at 1:01 PM, zwetan wrote:

but still out of curiosity, in a case where someone would want to do the same kind of methods delegation but with non-generic methods (this value required to be of the original type) does ES4 offers some way of doing it ?

Bound methods cannot be called on a |this| parameter of the wrong type -- they carry their |this| around once extracted (e.g. from a class instance).

I should have distinguished the case of an instance-bound method,
where |this| carried along by the method closure, from a type- constrained |this| method, where you could extract and call on a
different instance, but the type would still be constrained to be a
subtype of the type from which you extracted the method.

We allow both cases to be expressed. To see both instance-bound and
type-constrained |this| methods, consider this class:

class C { public var x; function C(x) : x = x { }

// An instance-bound class method -- a "fixture" // (DontEnum/DontDelete/ReadOnly and type-constrained // by its function type). function m() { return x; }

// An unbound prototype method with type-constrained |this|. prototype function p(this: {x:*}) { return this.x; } };

let c = new C(42); let m = c.m; print(m()); // prints 42

print(c.p()); // prints 42 also

let o = {m: m, x:43}; print(o.m()); // prints 42 still

o.m = c.p; print(o.m()); // prints 43

So class instance methods are instance-this-bound. Prototype methods
(among other features) are unbound and by default their |this|
parameter is not type-constrained. But you can write (this:T at the
start of a formal parameter list or function type signature to
constrain the type of |this|.