Why are static definitions not inherited?

Discuss the future of the AutoHotkey language
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Why are static definitions not inherited?

20 Aug 2019, 16:32

There's no way for an instance of a class to interact with the static definitions. Even if I define some important variable such as static TickCount := A_TickCount, I can't even access it. More importantly, when a new user makes a property or a method static, they expect that an instance should be able to access them. This only adds another barrier for new users to understand classes.

I even checked Java's use of the static keyword... and they provide a clear way to access a static variable from inside the class. By using the variable itself.

Code: Select all

// A java program to demonstrate use of 
// static keyword with methods and variables 
  
// Student class 
class Student  
{ 
    // static variable 
    static String cllgName; 

    // instance variable
    String name; 

    public Student(String name){ 
        this.name = name; 
    } 

    // instance method 
    void getStudentInfo(){ 
        // accessing instance variable 
        System.out.println("name : " + this.name); 

        // accessing static variable 
        System.out.println("cllgName : " + cllgName); 
    } 
} 

//Driver class 
public class StaticDemo  
{ 
    public static void main(String[] args) 
    { 
        // setting static variable without instantiating Student class 
        Student.cllgName = "XYZ"; 
      
        Student s1 = new Student("Alice"); 
        Student s2 = new Student("Bob"); 
          
        s1.getStudentInfo(); 
        s2.getStudentInfo(); 
    } 
} 
modified from: https://www.geeksforgeeks.org/static-keyword-java/

Keep in mind the following line:

Code: Select all

        // accessing static variable 
        System.out.println("cllgName : " + cllgName);
where cllgName is straight up defined as a static variable.


Here's some AHK v2 code to accomplish a similar goal of accessing a static variable from within the class:

Code: Select all

a := new set
b := new set
c := new set
MsgBox Set.instances
a := b := c := ""
MsgBox Set.instances

class Set {
   static instances := 0

   __New() {
      %this.__class%.instances++
   }

   __Delete() {
      %this.__class%.instances--
   }
}
I'm not saying AHK should become more like Java. In fact I hate Java. But the clear fact that Java has a better time of getting users to access static variables from inside the class is astounding. My recommendation is to remove the feature where static properties and instance properties of the same name can coexist alongside each other. This is a source of confusion. Instead make static variables inheritable as in v1 giving us the ability to access static variables with a simple this.property. Currently a new user to v2 would find it odd and pointless that static properties, which serve to hold overarching information about the class, can not be accessed within the class. This horrid workaround, %this.__class%.property, can not stand.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Why are static definitions not inherited?

20 Aug 2019, 16:39

ah didnt see u had made another thread just now. so ill copy paste my response here, since the other is already marked solved and this one is likelier to gain more traction
i dont think u can anymore actually. this appears to have been lifted from c# and the doc just hasnt been updated to reflect that.
static are meant to be accessed through the class only, it seems

actually this makes sense kinda

Code: Select all

class Cls
{
	static var := 1
	var := 2

	f() {
		MsgBox this.var ; which property am i invoking here? the instance 'var'
	}
}

c := new Cls()
c.f() ; 2
disambiguates between the two vars easily. how would u do that otherwise?
Last edited by swagfag on 20 Aug 2019, 17:02, edited 3 times in total.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Why are static definitions not inherited?

20 Aug 2019, 16:59

C++ does the same thing as Java which is that static variables can be referenced by name inside the scope of the class.
Python doesn't make a distinction between instance and static variables, all variables are considered to be static. (Python is known for being easy to learn and user friendly)

I've always liked the categorical definition of what an instance of a class is: It's a copresheaf on a functor. You can visualize it as all the arrows pointing into the object and just collecting all the arrows - because each arrow is a function or a variable. Essentially it's saying that an instance is a copy of all the arrows, with the arrows being references to specific method or property, and not copies of the actual functions themselves. (Actually I wonder if methods/functions in an instance are still references in v2).

But the underlying idea is pretty clear - I write a class, which is all the stuff I put into my object (presheaf). When I execute my code by double clicking on an AHK file it gets loaded into memory and becomes my (object). Then I take an instance of my class (copresheaf) and I expect to get back all the stuff I put into my class. For every object I placed in my class, my instance should have a corresponding object, in a one-to-one relationship (bijection). So just being able to access my static definitions with this.property should be consistent with what Python does, and what v1 currently does.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Why are static definitions not inherited?

20 Aug 2019, 17:15

but c++ doesnt permit another non-static variable shadowing the static one(so accessing it directly is a non-issue), whereas ahk does
It's a copresheaf on a functor. You can visualize it as all the arrows pointing into the object and just collecting all the arrows - because each arrow is a function or a variable.
okay u lost me there. im not even gonna try to pronounce this
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Why are static definitions not inherited?

20 Aug 2019, 18:29

Currently I can't even access my own static variable anyways without resorting to a global. I understand it's an advantage, but does that actually make the code we write better? Hypothetically, assuming we could access the static variable in a straightforward manner, having a static variable and an instance variable of the same name seems to lend itself to confusion. We already have this.var and local var in objects, and we could as many underscores before the variable if need be _cls := new cls.

Java does have some cool stuff like a static block (equivalent to an auto execute section, except inside a class definition

Code: Select all

    // static block 
    static { 
        System.out.println("Inside static block"); 
    } 
But they're pretty clear on what the goal of a static property is:
Use the static variable for the property that is common to all objects.
So it would be nice to be able to access my static property internally.
coffee
Posts: 133
Joined: 01 Apr 2017, 07:55

Re: Why are static definitions not inherited?

20 Aug 2019, 21:28

iseahound wrote: Currently I can't even access my own static variable anyways without resorting to a global
I'm going to assume you are complaining about not being able to access common properties across instances. Quoting 'java can do it x way' when you are using autohotkey specific gimmicks with the percentages signs and all the other syntax is kinda irrelevant. Specially when it's pretty clear autohotkey is going it's own "unique" way of doing anything, and in some cases trying to do things in a somewhat jarring way compared to what is supposedly "conventional". Case in point: obj.%method%() can be pretty damn jarring, depending on what your background is. Even though this update brings more improvements that outweigh these things.

Where's your example where you follow the documentation and it still doesn't let you access the new way of defining common properties across instances?
Hey I just went live, and this is crazy, but here's my manual, so read me maybe wrote: Object is based on Class.Prototype, which is based on Object.Prototype, so classes can inherit methods and properties from any of these base objects.

Code: Select all

msgbox( "set2.prototype.base == set.prototype :: " (set2.prototype.base == set.prototype) ) ; true

a := new set
msgbox( "a.base == set.prototype :: " (a.base == set.prototype) ) ; true

b := new set
msgbox("b.instances :: " b.instances) ; 2
msgbox('b.hasOwnProp("instances") :: ' b.hasOwnProp("instances")) ; 0

c := new set
; c.WhoDoIBelongto() ; This won't work and will throw an exception.
; c.base.WhoDoIBelongTo() ; This won't work and will throw an exception.
Set.WhoDoIBelongTo()
c.ProtoMethod()
msgbox('c.HasOwnMethod("ProtoMethod") :: ' c.HasOwnMethod("ProtoMethod")) ; no
msgbox('c.base.HasOwnMethod("ProtoMethod") :: ' c.base.HasOwnMethod("ProtoMethod")) ; yes

MsgBox("Set.prototype.instances :: " Set.prototype.instances) ; 3

a := b := c := ""
MsgBox("Set.prototype.instances __DEL :: " Set.prototype.instances) ; 0

class Set {
	static lexikos_this_may_need_a_better_solution := Set.prototype.instances := 0
	
	static WhoDoIBelongTo()
	{
		msgbox("I belong to SET")
	}
	
	ProtoMethod()
	{
		msgbox("PROOOOTO")
	}
	
	__New() {
		this.base.instances++
	}

	__Delete() {
		this.base.instances--
	}
}

class set2 extends set {
}
There probably is or will be a better way to do above, but in case it still isn't clear for anyone else, static inheritance was changed. The old 'static' way of common properties, is through Class.prototype. Class.prototype is what is inherited, not Class. I'm pretty sure lexikos has explained the whys of this already. Although this is more of a autohotkey v2.5 or v3 type of change.

I may be wrong, but there was a lot of heads up of this in objects.ahk and whatever discussions were made on these threads (or maybe I just dreamed it, that's a possibility), where static belong to class object and class object only, regardless of java, python, c++, c#, f#, a, b, c, d or the new hot blog post you read yesterday.

I suppose this and its documentation will only improve in the future.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Why are static definitions not inherited?

20 Aug 2019, 22:16

It doesn't look like you've managed to actually access a static variable in your posted example. It needs to be a top level static member, "own" using the newer terminology.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Why are static definitions not inherited?

21 Aug 2019, 02:07

We are explicitly stating that we access the instance with the this. syntax.
Im not convinced that you can access static class members in Java with this.staticClassMember.
Nonetheless I agree that we need a way to access them and reference the class we are currently in.
Recommends AHK Studio
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Why are static definitions not inherited?

21 Aug 2019, 02:23

static definitions are inherited by subclasses.
they provide a clear way to access a static variable from inside the class. By using the variable itself.
It is not clearer than cls.var, it might be more convenient until you or someone else doesn't realise it will affect all instances which uses the static var.

recall that,
v1 wrote: If an object x is derived from ClassName and x itself does not contain the key "ClassVar", x.ClassVar may also be used to dynamically retrieve the value of ClassName.ClassVar. However, x.ClassVar := y would store the value in x, not in ClassName.
was a common source of confusion.

A property to more directly access the class might be useful, eg, this.class vs %this.__class%.

Cheers.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Why are static definitions not inherited?

21 Aug 2019, 02:41

Neither this.class nor %this.__class% would succeed for objects that are instances of inheriting classes. We need something bound to the class this method is in - not something bound to the object instance.
Recommends AHK Studio
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Why are static definitions not inherited?

21 Aug 2019, 14:08

I'm really not following. I don't understand what the problem is with just referencing it via ClassName.Property. Can someone try to simplify it?
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Why are static definitions not inherited?

21 Aug 2019, 14:38

Consider:

A)

Code: Select all

class ParentClass {
	class ContainedClass {
		static staticMember := ""
		method() {
			return ?.staticMember
		}
	}
}

class ContainedClass {
	static staticMember := "Hello World"
}
B)

Code: Select all

ParentClass := new ParentClass()

class ParentClass {
	static staticMember := ""
	method() {
		return ?.staticMember
	}
}
C)

Code: Select all

test := new InheritingClass()
test.method()
class ParentClass {
	static staticMember := ""
	method() {
		return ?.staticMember
	}
}
class InheritingClass extends ParentClass {
	static staticMember := "something else"
}
Recommends AHK Studio
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Why are static definitions not inherited?

21 Aug 2019, 21:40

Helgef wrote:
21 Aug 2019, 02:23
It is not clearer than cls.var, it might be more convenient until you or someone else doesn't realise it will affect all instances which uses the static var.
I agree.
Helgef wrote:
21 Aug 2019, 02:23
If an object x is derived from ClassName and x itself does not contain the key "ClassVar", x.ClassVar may also be used to dynamically retrieve the value of ClassName.ClassVar. However, x.ClassVar := y would store the value in x, not in ClassName.
I didn't know that actually.
Helgef wrote:
21 Aug 2019, 02:23
A property to more directly access the class might be useful, eg, this.class vs %this.__class%.
Exactly this.

The main problem I have with the current implementation is that it feels like static classes and instance classes are completely different things. I think that people will eventually write classes that are purely static, and classes that are purely meant to be instantiated. I'll answer this in the post below.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Why are static definitions not inherited?

21 Aug 2019, 22:26

kczx3 wrote:
21 Aug 2019, 14:08
I'm really not following. I don't understand what the problem is with just referencing it via ClassName.Property. Can someone try to simplify it?
Sure. A class is like an object except with all its internals laid out. So if my class was a Car and it has a nested class Engine and maybe a static variable Engine_Model_Number, I'd be forced to access the model number like this: Car.Engine.Engine_Model_Number. Except that doesn't make much sense, the model number of the engine belongs to the engine, not the car.
Click to show code.
So it's really just Absolute paths vs. relative paths. Car.Engine.Engine_Model_Number vs. this.Engine_Model_Number corresponds to C:\Car\Engine\Engine_Model_Number.txt vs. .\Engine_Model_Number.txt


A major problem with this distinction is that it leads to new programmers programming in absolute terms. That is, something like this:

Code: Select all

SecondCounter.Start(), Sleep(5000), SecondCounter.Stop(), Sleep(2000)

; An example class for counting the seconds...
class SecondCounter {

    static interval := 1000
    static timer := () => ToolTip(++SecondCounter.count)

    static Start(n := 0) {
        SecondCounter.count := n
        SetTimer SecondCounter.timer, SecondCounter.interval
        ToolTip "Counter started"
    }
    static Stop() {
        SetTimer SecondCounter.timer, "Off"
        ToolTip "Counter stopped at " SecondCounter.count
    }
}
as opposed to using instances of a class:

Code: Select all

(counter := new SecondCounter), counter.Start(), Sleep(5000), counter.Stop(), Sleep(2000)

; An example class for counting the seconds...
class SecondCounter {

    interval := 1000
    timer := () => ToolTip(++this.count)

    Start(n := 0) {
        this.count := n
        SetTimer this.timer, this.interval
        ToolTip "Counter started"
    }
    Stop() {
        SetTimer this.timer, "Off"
        ToolTip "Counter stopped at " this.count
    }
}
And I know this will happen, with new programmers confused between going fully static or fully instance, because I made this same mistake when I was learning.

(As an exercise for the reader, the interval should be static and everything else instance :D. That way, the user should be able to change SecondCounter.interval and affect the interval of all counters currently in progress.)
Source: https://lexikos.github.io/v2/docs/commands/SetTimer.htm (bottom of page, with improvements using newer v2 syntax.)
Last edited by iseahound on 21 Aug 2019, 22:43, edited 2 times in total.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Why are static definitions not inherited?

21 Aug 2019, 22:32

ur analogy breaks down. if u wanted the engine to be usable by other vehicles as well, u make it it's own class, not a nested class of car. then u don't have the problem it describing.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Why are static definitions not inherited?

22 Aug 2019, 00:16

Using nested classes anywhere else in the script was a key feature of v1. It needs to be retained until a suitably simple and intuitive method for seperating namespaces has been developed.
Currently we only have Helgefs design which imo is a bit over the top.
Recommends AHK Studio
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: Why are static definitions not inherited?

22 Aug 2019, 07:52

swagfag wrote:
21 Aug 2019, 22:32
ur analogy breaks down. if u wanted the engine to be usable by other vehicles as well, u make it it's own class, not a nested class of car. then u don't have the problem it describing.
See I would agree with this. There's no reason to make the engine model a static member anyways. That's something you'd pass in the constructor of new Car.Engine. Just because it doesn't change after you initially assign it doesn't make it static. That's a constant.

I have no problem referencing nested classes static variable via absolute path. However, I rarely see myself having the need to do that anyhow.
iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: Why are static definitions not inherited?

22 Aug 2019, 16:52

A class is actually two things: and object and a collection. When classes are also used to organize code as a collection of objects they become a namespace. This means that the class isn't meant to be instantiated, but rather used as an organizing principle. This gives static variables local scope. Restricting the access of static variables inside the scope of the class, whose sole purpose is to prevent global namespace clutter, just doesn't make sense.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: Why are static definitions not inherited?

23 Aug 2019, 05:40

kczx3 wrote:
21 Aug 2019, 14:08
I'm really not following. I don't understand what the problem is with just referencing it via ClassName.Property. Can someone try to simplify it?
It's mainly about convenience and modularity. When you you refer to the class directly you have to commit to its name, in a force local method you also have to declare it, the name or path might be long.

This can be helped by a class property, and in accordance with nnnik's comments, a this_class keyword for methods, cf. base. The this_class keyword would simply refer to the class in which the method was written.

Cheers :train:
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Why are static definitions not inherited?

23 Aug 2019, 10:07

this was the whole problem with introducing the idea of "classes" into AHK. there are no classes in AHK. the class keyword was syntax sugar, to make it easier to write prototype based objects, which is what AHK uses, not class based objects. when you write class in AHK, you ARE instantiating an object. you don't need to use new. that object already exists and is created as soon as you write "class x". i think that whole syntax sugar was a mistake. and the class keyword should never have been introduced to prevent these misunderstandings compared to other languages.


Return to “AutoHotkey Development”

Who is online

Users browsing this forum: thqby and 32 guests