I believe we've already discussed this, and I suggested that syntax. However, after jethrow brought up functions within functions, I started having doubts about whether it should assign the function to the object at load-time or when that line is reached during execution. If at load-time, how would it work if the function definition was nested inside another function? Assigning the function at run-time could be more intuitive, but without the capability to nest functions, you would need to use a global subroutine to initialize the class.Car.Run(){ ; Allow Functiondefinition directly for a Member
Simply allowing nested functions might be easy, and allowing a function to access it's parent's local variables might also be easy, but not in a way that's useful for objects. This is because each function has exactly one set of local variables. If a function is called before the previous call to that function returns (i.e. due to explicit recursion or thread interruption), its local variables are "backed up" and cleared. When that call returns, the variables are restored. When the only running instance returns, the local variables are cleared. So nested functions can't really provide much flexibility.
I think that many of the concepts used in languages like JavaScript (such as closures and anonymous functions) are probably so far beyond the current (AutoHotkey) interpreter's capabilities that it's best to just do it in a way that works for AutoHotkey. If the feasibility of more advanced features improves at some point, compatibility can be broken with another major version change.
Since realizing the approaches used in other prototype-based languages aren't necessarily feasible for AutoHotkey, I've overcome my initial resistence to the idea of adding class-definition syntax.
So if your code translates to ...class Car { Name := "woot" Run(){ msgbox % this.Name ; this is avaiable in this context } } ; 1. the class keyword is replaced with := Object() ; 2. Everything in braces in a class definition is in the Context of the given class; ; Name := "woot" is replaced with Car.Name := "woot" ; Run(){...} is replaced with Car.Run(){...} ; "this" keyword is avaiable in those methods
Car := Object() { Car.Name := "woot" Car.Run := "Car_Run" Car_Run(this) { msgbox % this.Name } }... when is this code executed, to initialize the class? Do you have to define it in the auto-execute section?
How do you create an instance of a Car? To create an object, you call Object(). So to create a Car, why not call Car()? "Class Car" could translate to a function definition (with this := Object() ... return this implied), but then we're back to the tricky question of how well to support nested functions. I think it would be more appropriate to just let the class author define a function, and let that function create and initialize the object. On the other hand, if we're going so far as to introduce class-definition syntax, it seems logical to have some shortcut way of writing a constructor, and therefore some new syntax to indicate we're calling one.
If you define Name := "woot", would you not expect to be able to access Name without writing this.Name in full? I would.
I know that the current behaviour of the semi-automatic "this" parameter confuses some users, and it also imposes certain limitations. For instance, you might think to call this.base.Method(this) to pass control to an overridden version of the method. Unfortunately, this will only work if this.base.HasKey("Method"), not if it is inherited from this.base.base.
As part of a solution, I've been considering implementing "this" as a built-in keyword. Perhaps rather than reserving that variable name everywhere, it could have special meaning only inside class/method definitions.
Being able to call an overridden version of a method can be important, and a "base" keyword could serve that purpose. Rather than referring to "this.base", it would refer to the base object of the enclosing class (i.e. it would refer to the super-class).
My idea in its current form:
; This would have no direct script analog in the sense of a pre- ; processor. Instead, some work would be done at load-time. class Foo extends Bar ; Entering class definition. Create a super-global var "Foo" and store ; an object in it. If "Bar" exists, store its value in Foo["base"]. { ; This is explicitly a declaration, not to be confused with a line ; of code to be executed. Store 0 in Foo["Flavour"]. New objects ; deriving from Foo won't receive this value directly, but will ; inherit it via the "base" mechanism. var Flavour := 0 ; Function declaration. Since we're in a class definition, instead ; of creating a global "Taste" function, create an anonymous ; function and store its reference in Foo["Taste"]. Taste() { ; Since Flavour was declared as a class var, we want to be able ; to refer to it as "Flavour" in addition to "this.Flavour". ; Technically, the preparser only needs to determine that the ; class object being defined has a key called "Flavour". The ; same would be true for method calls. if Flavour return Flavour ; This would be processed something like Foo.base.Taste(this), ; except that "this" isn't really a parameter. That is, "this" ; will contain the same value, not the value of "base". return base.Taste() } ; Constructor, perhaps called via "new Foo(flavour)". __New(aFlavour) { Flavour := aFlavour base.__New() } }