inheriting statics

# Peter Hall (19 years ago)

What was the rationale when deciding not to inherit static members?

developer.mozilla.org/es4/spec/chapter_9_classes.html#static_methods

Peter

# Nicolas Cannasse (19 years ago)

What was the rationale when deciding not to inherit static members?

developer.mozilla.org/es4/spec/chapter_9_classes.html#static_methods

It's actually pretty logical. Since inheritance does not apply to static members, giving an access to them through subclasses make people misunderstand what's really a static.

See "The Class Duality" part in haXe Typesystem documentation : haxe.org/doc/types

# Peter Hall (19 years ago)

"Since inheritance does not apply to static members"

Your assumption is what I was questioning. Why doesn't inheritance apply to static members?

Peter

# zwetan (19 years ago)

On 1/7/07, Peter Hall <peterjoel at gmail.com> wrote:

"Since inheritance does not apply to static members"

Your assumption is what I was questioning. Why doesn't inheritance apply to static members?

statics are defined on the class itself not the instances of this class so when you inheriting you can not access static members trough the instance, only throught the class

but within your classes definition, you can access static members trough the scope chain

all is pretty well explained in the Flex2 doc

Programming ActionScript 3.0 / Object-Oriented Programming in ActionScript / Inheritance then look at the examples for Static properties not inherited and Static properties and the scope chain

I know only one special case where a static member is used for inheritance, it's the static var prototype :)

quoting the doc "... This property is static in that it is specific to the class or function that you create. For example, if you create a class, the value of the prototype property is shared by all instances of the class and is accessible only as a class property. Instances of your class cannot directly access the prototype property. "

# Brendan Eich (19 years ago)

On Jan 7, 2007, at 9:50 AM, Peter Hall wrote:

"Since inheritance does not apply to static members"

Your assumption is what I was questioning. Why doesn't inheritance apply to static members?

Right, the assumption should be justified. One rationale is by
extension of ES1-3 (plain ol' JS):

function SpecialString(s) { this.value = s; } SpecialString.prototype = new String; SpecialString.prototype.toString = function () { return this.value; } s = new SpecialString("hello"); t = s.charCodeAt(3); alert(t); alert(SpecialString.fromCharCode(t));

The last line throws TypeError: SpecialString.fromCharCode is not a
function.

Inclusion of statics in the scope chain within instance methods is a
convenience afforded by the new special form of methods defined via
function definitions nested in a class definition. But it's not
inheritance.

# Brendan Eich (19 years ago)

On Jan 7, 2007, at 11:10 AM, zwetan wrote:

quoting the doc "... This property is static in that it is specific to the class or function that you create. For example, if you create a class, the value of the prototype property is shared by all instances of the class and is accessible only as a class property. Instances of your class cannot directly access the prototype property. "

This seems misleading to me, since the "value of the prototype
property" is an object that is not shared as if it were a static
property value. Instead, the properties of the static prototype
property are visible in all instances, unless overridden
("shadowed"). So prototype is not an exception to the rule that
static properties are not inherited by instances -- it's a different
animal.

Also, function prototypes are not "static" in any sense (the proposed
Function.apply static method is a class static in ES4; Date.parse is
a static method in ES1-4; but Function.prototype is the prototype of
the Function class/constructor -- it's different from f1.prototype
and f2.prototype for two functions f1 and f2). Function prototypes
are "instance variables" of each particular function object.

(I'm nit-picking the AS3 doc just so this doesn't get copied into the
ES4 spec :-/.)

# P T Withington (19 years ago)

On 2007-01-07, at 14:32 EST, Brendan Eich wrote:

On Jan 7, 2007, at 9:50 AM, Peter Hall wrote:

"Since inheritance does not apply to static members"

Your assumption is what I was questioning. Why doesn't inheritance apply to static members?

Right, the assumption should be justified. One rationale is by
extension of ES1-3 (plain ol' JS):

[...]

Inclusion of statics in the scope chain within instance methods is
a convenience afforded by the new special form of methods defined
via function definitions nested in a class definition. But it's not
inheritance.

One could still ask, "should classes inherit static properties of
their superclass?" Should the statics of my superclass be in my
scope chain? Should statics of an instance's superclass be visible
in the instance's constructor?

class Foo { static const ZOT = 42;

function zotValue() { return this.constructor.ZOT; } }

class Bar extends Foo { function improvedZotValue() { return this.constructor.ZOT + 1; } }

# Brendan Eich (19 years ago)

On Jan 7, 2007, at 12:23 PM, P T Withington wrote:

Inclusion of statics in the scope chain within instance methods is
a convenience afforded by the new special form of methods defined
via function definitions nested in a class definition. But it's
not inheritance.

One could still ask, "should classes inherit static properties of
their superclass?"

Yes, you're right that classes are not functions -- hence f.prototype
is an instance property of each function object f, not a static of an
(unnamed, varargs-type-parameterized?) Function subclass magically
created "backstage" for f's function definition, and f.prototype is
not of course the same object as Function.prototype.

So adding classes creates choice for the designer about static
inheritance and scope. I'll defer to Jeff or Ed to speak to the AS3
design goals and experience.

Should the statics of my superclass be in my scope chain?

Define "my".

Should statics of an instance's superclass be visible in the
instance's constructor?

class Foo { static const ZOT = 42;

function zotValue() { return this.constructor.ZOT; } }

class Bar extends Foo { function improvedZotValue() { return this.constructor.ZOT + 1; } }

Is this use-case important in your experience? The sketch here does
not need to abstract away from Foo or Bar via this.constructor, but
perhaps you have an example motivating such abstraction?

# zwetan (19 years ago)

On 1/7/07, Brendan Eich <brendan at mozilla.org> wrote:

On Jan 7, 2007, at 11:10 AM, zwetan wrote:

quoting the doc "... This property is static in that it is specific to the class or function that you create. For example, if you create a class, the value of the prototype property is shared by all instances of the class and is accessible only as a class property. Instances of your class cannot directly access the prototype property. "

This seems misleading to me, since the "value of the prototype property" is an object that is not shared as if it were a static property value. Instead, the properties of the static prototype property are visible in all instances, unless overridden ("shadowed"). So prototype is not an exception to the rule that static properties are not inherited by instances -- it's a different animal.

agreed, that's a little misleading from the doc, but as I said it's one special case I could think of :).

Maybe it's because I'm too biased toward the way ES3 is working, but not inheriting static make perfect sens to me.

I always saw ES3 closer to the objects, and for statics I just consider them as slot attached to an object and not part of the inheritance chain (either prototype or traits), even if the object is a class definition it's still an object.

Also, function prototypes are not "static" in any sense (the proposed Function.apply static method is a class static in ES4; Date.parse is a static method in ES1-4; but Function.prototype is the prototype of the Function class/constructor -- it's different from f1.prototype and f2.prototype for two functions f1 and f2). Function prototypes are "instance variables" of each particular function object.

(I'm nit-picking the AS3 doc just so this doesn't get copied into the ES4 spec :-/.)

the AS3 doc is quite good imho, but still could be improved on what someone may call "advanced subjects": the relation between prototype chain and traits chain, the order of lookup for inheritance, etc. the kind of subject that if you dealt with ES3 and then start to learn ES4 should be ok to follow, but if you just start with ES4 could be hard to fully understand.

tricky ex: if you declare a property in the prototype, and redefine it from an instance, does the shared property get redefined at the prototype level or instance level ?

class Blah { prototype.shared = "hello world";

function Blah() {}

}

test1:Blah = new Blah(); test2:Blah = new Blah(); test1.shared = "bonjour le monde"; trace( test2.shared ); // ???

for someone knowing how prototype works in ES3 it can be easy, but if you didn't dealt with object-based / prototype-based language before hehe class ain't gonna help you to understand that ;)

and going on, now that you know that it is redefined at the instance level how could you make it work at the prototype/shared level ?

class Blah { prototype.shared = "hello world";

function Blah() {}

public function change( value:String ):void
    {
    this.constructor.prototype.shared = value;
    }

}

oh so that means that I can actually define a read-write property shared by all my instances ?

class Blah { prototype.shared = "hello world";

function Blah() {}

public function set shared( value:String ):void
    {
    this.constructor.prototype.shared = value;
    }

public function get shared():String
    {
    return prototype.shared;
    }

}

test1:Blah = new Blah(); test2:Blah = new Blah(); trace( test1.shared ); //hello world trace( test2.shared ); //hello world test1.shared = "bonjour le monde"; trace( test2.shared ); // bonjour le monde

but wait that can also be done with a static

class Blah { private static var _shared:String = "hello world";

function Blah() {}

public function set shared( value:String ):void
    {
    _shared = value;
    }

public function get shared():String
    {
    return _shared;
    }

}

test1:Blah = new Blah(); test2:Blah = new Blah(); trace( test1.shared ); //hello world trace( test2.shared ); //hello world test1.shared = "bonjour le monde"; trace( test2.shared ); // bonjour le monde

sorry for the lengthy and boring examples, but simply put about static and prototype and inheritance etc...

it should be really helpfull imho to start now to find real use case examples that can show the real differences, why favour prototype over statics for sharing data between instances, or why not

I think people who gonna want to use ES4 and seeing only its class-based nature will have question as "why still use the prototype, what can I do with prototype that I can not do with static/class/etc. ?"

zwetan

# P T Withington (19 years ago)

On 2007-01-07, at 15:53 EST, Brendan Eich wrote:

On Jan 7, 2007, at 12:23 PM, P T Withington wrote:

Inclusion of statics in the scope chain within instance methods
is a convenience afforded by the new special form of methods
defined via function definitions nested in a class definition.
But it's not inheritance.

One could still ask, "should classes inherit static properties
of their superclass?"

Yes, you're right that classes are not functions -- hence
f.prototype is an instance property of each function object f, not
a static of an (unnamed, varargs-type-parameterized?) Function
subclass magically created "backstage" for f's function definition,
and f.prototype is not of course the same object as
Function.prototype.

So adding classes creates choice for the designer about static
inheritance and scope. I'll defer to Jeff or Ed to speak to the AS3
design goals and experience.

Should the statics of my superclass be in my scope chain?

Define "my".

I my sketch below, should methods of Bar have ZOT in their scope
chain? Should I be able to write:

class Bar extends Foo { function improvedZotValue() { return ZOT + 1; } }

and have ZOT resolve to Foo.ZOT?

Should statics of an instance's superclass be visible in the
instance's constructor?

class Foo { static const ZOT = 42;

function zotValue() { return this.constructor.ZOT; } }

class Bar extends Foo { function improvedZotValue() { return this.constructor.ZOT + 1; } }

Is this use-case important in your experience? The sketch here
does not need to abstract away from Foo or Bar via
this.constructor, but perhaps you have an example motivating such
abstraction?

My motivation is to keep the door open for a mix-in, where the
superclass(es) could be different for different concrete classes.
But it also would make refactoring easier if I could move a static
property to a different superclass and not have to update all uses of
it in subclasses.

# Peter Hall (19 years ago)

But it also would make refactoring easier if I could move a static property to a different superclass and not have to update all uses of it in subclasses.

So there's a use-case for inheriting static members. Not a hugely impressive one, but a use-case nonetheless.

The case for inheriting statics:

  1. static members are inherited in Java and C# (I think)
  2. It won't break existing code because that code either would be in error or else would have overridden the member.
  3. easier refactoring, if you move the member within an inheritance chain.

The case against inheriting statics:

  1. Static members are not inherited in ES3 or JS1
  2. It's a change to what's in the spec already

One thing that I do feel strongly about is the scoping of super-class statics in sub-classes. I find that behaviour confusing, as it feels a bit like inheritence, but it isn't. What is the value of that behaviour?

Peter

# Neil Mix (19 years ago)

The case for inheriting statics:

  1. static members are inherited in Java and C# (I think)
  2. It won't break existing code because that code either would be in error or else would have overridden the member.
  3. easier refactoring, if you move the member within an inheritance
    chain.

IIRC static data members in Java are inherited but cannot be
overridden, which may provide a bit of a catch-22 for #1 and #2?

# Francis Cheng (19 years ago)

Just to allay Brendan's fears, I can guarantee that this won't be copied into the ES4 spec. This quote is from the AS3 language reference documentation for the Object class, and is not from the AS3 language specification. I'll make sure the Adobe documentation gets fixed.

Francis

# Peter Hall (19 years ago)

IIRC static data members in Java are inherited but cannot be overridden, which may provide a bit of a catch-22 for #1 and #2?

Good point. If there is a reason why Java disallows inherited statics to be overridden then that reason is likely applicable and a decent enough rationale for not inheriting statics at all in ES4...

Peter

# P T Withington (19 years ago)

On 2007-01-09, at 04:52 EST, Peter Hall wrote:

IIRC static data members in Java are inherited but cannot be overridden, which may provide a bit of a catch-22 for #1 and #2?

Good point. If there is a reason why Java disallows inherited statics to be overridden then that reason is likely applicable and a decent enough rationale for not inheriting statics at all in ES4...

But is there a reason? Or does Java do that just because C++ did that?

Dylan permits members on class, each-subclass, and instance. They
are all inherited (and all visible through the instance):

www.opendylan.org/books/drm/Slots#MARKER-9-629

Subclasses and instances can give different values to class slots:

www.opendylan.org/books/drm Instance_Creation_and_Initialization#MARKER-9-677

(See "Initialization of Class Allocated Slots")

# Dave Herman (19 years ago)

IIRC static data members in Java are inherited but cannot be overridden, which may provide a bit of a catch-22 for #1 and #2?

Are we sure? I tried the following in Java 5:

// -- public class C1 { public static int foo = 10; } public class C2 extends C1 { public static int foo = 1000; } public class Main { public static void main(String[] args) { C2 x = new C2(); System.out.println(x.foo); System.out.println(((C1)x).foo); System.out.println(((C2)x).foo); } } // --

and it compiled, ran, and printed:

1000 10 1000

In other words, statics are inherited and can be redefined, although they are statically resolved, so they have shadowing semantics (like instance fields) rather than overriding.

# Peter Hall (19 years ago)

In other words, statics are inherited and can be redefined, although they are statically resolved, so they have shadowing semantics (like instance fields) rather than overriding.

So there does not even need to be a requirement that the type of static variables be related to the type of the variable in the super-class, or for static method signatures to match.

But I'm wondering..

class A { public static function foo (){ } }

class B extends A { // should this non-static method be allowed? public function foo(){ // and, if so, can I do this? super.foo(); } }

class C extends B { public static function foo(){ // and, if so, would this invoke A.foo or be an error? super.foo(); } }

Peter

# Neil Mix (19 years ago)

In other words, statics are inherited and can be redefined,
although they are statically resolved, so they have shadowing
semantics (like instance fields) rather than overriding.

Yes, but it still means that you can't emulate Java's behavior
without breaking backward compatibility. Thus, if I'm understanding
correctly, no matter how you slice it one of Peter's list of 3
advantages won't hold.

For example, modifying your Java example slightly:

public class C1 { static int foo = 10; void C1() { }

void print() {
	System.out.println(this.foo);
}

}

class C2 extends C1 { static int foo = 1000; }

public class Main { public static void main(String[] args) { C2 x = new C2(); x.print(); } }

Which will print 10.

# Jeff Dyer (19 years ago)

In AS3 and draft ES4 'super', like 'this', resolves to a value of an instance type, and so in your example below the static foo in A will not be found by 'super.foo()'.

And yes, the definition of foo as a static in class A and an instance method in class B is allowed. In fact, a static and instance definition in the same class with the same name is allowed. They appear in different scopes.

Jd

-----Original Message----- From: es4-discuss-admin at mozilla.org [mailto:es4-discuss-admin at mozilla.org]

# zwetan (19 years ago)

My motivation is to keep the door open for a mix-in, where the superclass(es) could be different for different concrete classes. But it also would make refactoring easier if I could move a static property to a different superclass and not have to update all uses of it in subclasses.

but we already got that in ES4/AS3

class A { static var foobar:String = "foobar"; ... }

class B extend A {

public function test():String { return foobar; //you can access the static } }


class A { ... }

class B extend A {

static var foobar:String = "foobar"; //you can move its defintion

public function test():String { return foobar; } }


so where is the problem really ?

do you want to be able to access the static inherited like that:

trace( A.foobar );

and if class B extend A trace( B.foobar ); even if static foobar is defined in class A ?

zwetan

# Peter Hall (19 years ago)

Right. So to access a static method of a super-class, where you have shadowed it with another method, you must access it via the class name..

I could see this leading to errors, since the override attribute would not be used in this context. The same errors could equally happen with the existing ES3 scoping rules.

Is that an argument against inheriting?

Peter

# Jeff Dyer (19 years ago)

The argument against inheriting statics is one for simplicity. A class defines a factory and the type of instances created by that factory. The class objects (the factories, not the instances) of different classes have unrelated types and purposes, even if the instance types they introduce are subtypes. Class statics are a simple convenience for sharing state that is somehow associated with the meaning of a particular class. Aliasing them through other class objects could lead to annoying name conflicts and obscure their otherwise clear meaning.

Jd

-----Original Message----- From: Peter Hall [mailto:peterjoel at gmail.com] Sent: Tuesday, January 09, 2007 9:15 AM To: Jeff Dyer Cc: Dave Herman; Neil Mix; P T Withington; Brendan Eich; Nicolas

Cannasse;

es4-discuss at mozilla.org Subject: Re: inheriting statics

Right. So to access a static method of a super-class, where you have shadowed it with another method, you must access it via the class name..

I could see this leading to errors, since the override attribute would not be used in this context. The same errors could equally happen with the existing ES3 scoping rules.

Is that an argument against inheriting?

Peter

On 1/9/07, Jeff Dyer <jodyer at adobe.com> wrote:

In AS3 and draft ES4 'super', like 'this', resolves to a value of an instance type, and so in your example below the static foo in A will

not

be found by 'super.foo()'.

And yes, the definition of foo as a static in class A and an

instance

method in class B is allowed. In fact, a static and instance

definition

in the same class with the same name is allowed. They appear in different scopes.

Jd

-----Original Message----- From: es4-discuss-admin at mozilla.org [mailto:es4-discuss-admin at mozilla.org] On Behalf Of Peter Hall Sent: Tuesday, January 09, 2007 8:16 AM To: Dave Herman Cc: Neil Mix; P T Withington; Brendan Eich; Nicolas Cannasse; es4- discuss at mozilla.org Subject: Re: inheriting statics

In other words, statics are inherited and can be redefined,

although

they are statically resolved, so they have shadowing semantics (like

# zwetan (19 years ago)

On 1/9/07, Peter Hall <peterjoel at gmail.com> wrote:

Right. So to access a static method of a super-class, where you have shadowed it with another method, you must access it via the class name..

I could see this leading to errors, since the override attribute would not be used in this context. The same errors could equally happen with the existing ES3 scoping rules.

Is that an argument against inheriting?

yep :)

basically I see inheriting acting more at the instance scope even if off course defined in the class scope

accessing member |_ instance scope |_ traits chain |_ prototype chain |_ not found

to over simplify it

if you consider static as just slot added to an object, the class Object

inheriting static it would be like being able to inherit from a litteral object

var obj = {} obj.mystatic = "foobar";

class A extend obj { ... public function test():String { return mystatic; } ... }

after if your concern is mainly about API access, so you could actually move thestatic without breaking anything you can combine static and getter/setter :)


package test {

class A
    {

    //public access
    static function get mystatic():String
           {
           return __mystatic;
           }
    }

}

//internal access var __mystatic:String = "foobar";

and the nif you wantto change the public access you can just redirect to it

On 1/9/07, Peter Hall <peterjoel at gmail.com> wrote:

Right. So to access a static method of a super-class, where you have shadowed it with another method, you must access it via the class name..

I could see this leading to errors, since the override attribute would not be used in this context. The same errors could equally happen with the existing ES3 scoping rules.

Is that an argument against inheriting?

yep :)

after if your concern is mainly about API access, you already have it :)

about

But it also would make refactoring easier if I could move a static property to a different superclass and not have to update all uses of it in subclasses.


package test {

class A
    {
    public static var mystatic:String = "foobar";

    }

class B extend A
    {

    public function test():String
           {
           return mystatic;
           }
    }

}

if you change the superclass where is defined the static


package test {

class A
    {
    //removed
    //public static var mystatic:String = "foobar";

    }

class C
    {
    public static var mystatic:String = "foobar";

    }

class B extend C
    {

    public function test():String
           {
           return mystatic; //you don't need to change the access
           }
    }

}

also if you want you can also combine getter/setter in a static definition :)

class X { public static function get mystatic():String { //your real acces here that you can change anytime } }

zwetan

# P T Withington (18 years ago)

[Picking up on this ancient thread...]

If that is the argument against inheritance, why have the class
statics of all your superclasses be 'in scope'? Doesn't that lead to
similar obscurity? Doesn't it make for fragile code?

On 2007-01-09, at 12:55 EST, Jeff Dyer wrote:

The argument against inheriting statics is one for simplicity. A class defines a factory and the type of instances created by that
factory. The class objects (the factories, not the instances) of different classes have unrelated types and purposes, even if the instance types they introduce are subtypes. Class statics are a simple convenience for sharing state that is somehow associated with the meaning of a particular class. Aliasing them through other class objects could lead to annoying name conflicts and obscure their otherwise clear meaning.

Jd [...]

# Sho Kuwamoto (18 years ago)

FWIW, many Flex customers (who are used to Java) have complained about statics not being inherited.

# Nicolas Cannasse (18 years ago)

FWIW, many Flex customers (who are used to Java) have complained about statics not being inherited.

-Sho

It's always difficult for people to forget about bad habits :)

# Peter Hall (18 years ago)

Seems to me like everything would just be simpler if they are not inherited and not in-scope in subclasses...

Peter

# zwetan (18 years ago)

On 4/23/07, P T Withington <ptw at pobox.com> wrote:

If that is the argument against inheritance, why have the class statics of all your superclasses be 'in scope'? Doesn't that lead to similar obscurity? Doesn't it make for fragile code?

where is the obscurity ?

the static is defined "in scope" of the class, so accessing it "in the class definition scope" make sens to me.

On 4/24/07, Peter Hall <peter.hall at memorphic.com> wrote:

Seems to me like everything would just be simpler if they are not inherited and not in-scope in subclasses...

for the not inherited I agree, for the "not in-scope in subclasses" I don't, it is usefull to be able to access statics in such way.

my 0.2€ zwetan

# Jeff Dyer (18 years ago)

Having base class statics in scope can actually make your code less fragile. Classes are factories that create related instances. Those related instances might get initialized using related values. Access to base class statics makes relating such values more convenient.

Also, the obscurity I wrote about relates to the meaning of 'extends'. Should 'extends' mean copy all the names of all the statics in all the base classes into my derived class object? And if it does, what do those inherited names mean (add a new property, alias a shared property,...)? We've decided to keep it simple and have 'extends' mean something only to instance objects, not class objects. I think Java should have done the same.

Jd

-----Original Message----- From: P T Withington [mailto:ptw at pobox.com] Sent: Monday, April 23, 2007 1:22 PM To: Jeff Dyer Cc: Peter Hall; Dave Herman; Neil Mix; Brendan Eich; Nicolas Cannasse; es4-discuss at mozilla.org Subject: Re: inheriting statics

[Picking up on this ancient thread...]

If that is the argument against inheritance, why have the class statics of all your superclasses be 'in scope'? Doesn't that lead to similar obscurity? Doesn't it make for fragile code?

On 2007-01-09, at 12:55 EST, Jeff Dyer wrote:

The argument against inheriting statics is one for simplicity. A

class

defines a factory and the type of instances created by that factory. The class objects (the factories, not the instances) of different

classes

have unrelated types and purposes, even if the instance types they introduce are subtypes. Class statics are a simple convenience for sharing state that is somehow associated with the meaning of a particular class. Aliasing them through other class objects could

lead

to annoying name conflicts and obscure their otherwise clear

meaning.