Can you make a Func() reference to a Static/Class Method?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Wade Hatler
Posts: 60
Joined: 03 Oct 2013, 19:49
Location: Seattle Area
Contact:

Can you make a Func() reference to a Static/Class Method?

19 Nov 2013, 20:19

Anyone know a way to make a Func reference to a Static/Class method? For example, in the code below I'd like to be able to make a Func() reference that calls TestClass.TestMethod(), but can't quite figure out the syntax or even if it's possible.

Code: Select all

class TestClass {
    TestMethod() {
        MsgBox TestMethod
    }
}

    TestClass.TestMethod()                    ; Works as expected
    funcRef := Func("TestClass.TestMethod")   ; Returns an Object but doesn't seem to be usable
    %funcRef%.()                              ; Doesn't work
    %funcRef%()                               ; Doesn't work

    MethodCall := "TestClass.TestMethod"
    %MethodCall%.()                           ; Doesn't work
    %MethodCall%()                            ; Doesn't work
    ExitApp
Thanks
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Can you make a Func() reference to a Static/Class Method

19 Nov 2013, 22:53

Classes are global objects. (Important, just keep reading)
Objects that have methods store them as a key paired with a value like everything else.
The key is the method name, the value is the method function reference (func object)
This can easily be verified by trying to access a function property of TestClass.TestMethod

Code: Select all

class TestClass {
    TestMethod() {
        MsgBox TestMethod
    }
}

Msgbox % TestClass.TestMethod.name  ;Prints "TestClass.TestMethod"
In theory we could call the function like this:

Code: Select all

class TestClass {
    TestMethod() {
        MsgBox TestMethod
    }
}

funcRef := TestClass.TestMethod
funcRef.()  ;The function is not called (it silently fails)
But the message box doesn't show. why? Not enough parameters were passed. When you define a class like this, every class method is implicitly passed "this" referring to the calling object as the first parameter. So passing a parameter should at least get the function to be called, even if it isn't a real object:

Code: Select all

class TestClass {
    TestMethod() {
        MsgBox % "this: " this "`nIsObject? " IsObject(this)
    }
}

TestClass.TestMethod()  ;The function is called. IsObject(this) is true.
funcRef := TestClass.TestMethod
funcRef.(0)  ;The function is called with this = 0. IsObject(this) is false.
Really, you should pass TestClass to it instead of 0.

Code: Select all

class TestClass {
    TestMethod() {
        MsgBox % "this: " this "`nIsObject? " IsObject(this)
    }
}

TestClass.TestMethod()
funcRef := TestClass.TestMethod
funcRef.(TestClass)  ;Performs the same as TestClass.TestMethod()
Note if the function has additional parameters, you still need to pass something for the "this" parameter, just to get the function to be called. Additional parameters go after "this".
I guess the answer is that TestClass.TestMethod is already a Func reference. I personally think it's just as easy to type TestClass.TestMethod() though... Hope the explanation helps.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

20 Nov 2013, 02:52

Hmm, why does IsFunc("cy.method") not evaluate to true?

Code: Select all

class cx {
	method() {
		MsgBox, cx_method()
	}
}
class cy {
	static method := Func("cy_method")
}
cy_method(this) {
		MsgBox, cy_method()
}


MsgBox, % IsFunc("cx.method")	; 2
MsgBox, % IsFunc("cy.method")	; 0
	; why is this 0?

MsgBox, % IsFunc("cy_method")	; 2

MsgBox, % IsFunc(cy.method)		; 2
	; this works correctly
return

Documentation wrote:Methods are stored by reference in the class object.
=> there should be no difference between methods that are part of classes cx and cy?
Coco_guest

Re: Can you make a Func() reference to a Static/Class Method

20 Nov 2013, 04:58

Because "cy.method" (with quotes) is not a function name. The function cy_method is stored as reference in the method member of the object cy
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Can you make a Func() reference to a Static/Class Method

20 Nov 2013, 05:02

trismarck,

You are using IsFunc() in a way that is not supported. IsFunc("cx.method") is not guaranteed to return non-zero. It does so because in the current implementation, the function is automatically assigned a name based on the class name. If you were to assign cx.method := 0, you would no longer have a reference to the function, but IsFunc("cx.method") would still return 2. There is no connection between the function call and the class object.

Note that according to the documentation, IsFunc() accepts a function name, and that cy.method.Name returns "cy_method", not "cy.method". The function's name is also returned by A_ThisFunc and shown by ListVars while it is running.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

21 Nov 2013, 05:24

Right, so if I _don't_ define the method _outside of_ the body of the class, then that method will acquire a 'default' name of the method (~of the function) anyway. This is interesting as the dot is not a valid character of a name of the variable (~and of the function):

Code: Select all

class cx {
	static method := Func("cx.method")
}

;cx.method() {	; unexpected {
;cx`.method() {	; unexpacted {
cx_method() {

}

var := "cx.method"
%var% := 3	; the following variable name contains an illegal character
And yet Func() works with the name of that variable:

Code: Select all

class cx {
	method() {	; name: cx.method
		MsgBox cx.method()
	}
}
fun() {

}

MsgBox, % Func("fun")			; "" => success
MsgBox, % Func("cx.method")		; "" => success
	; => that 'strange' variable name works
	; 
fun2 := Func("cx.method")
fun2.(0)	; cx.method() called

The other thing to note is - what types of parameters work with Func() / IsFunc():
The parameter of Func():
  • can be a name of the function (a string): Func("fun")
  • can't be a name of the method (~a string that has a dot and that should be parsed to separate the class [name] from the key that contains the method) (well, actually it can, but the outcome is not reliable - i.e. Func("cx.method") in the example above. )
  • can't be the function object *
The parameter of IsFunc():
  • can be a name of the function (a string): IsFunc("fun")
  • can't be a name of the method (~a string that has a dot and that should be parsed to separate the class [name] from the key that contains the method) (well, actually it can, but the outcome is not reliable - i.e. IsFunc("cx.method") in the example above. )
  • can be the function object: IsFunc(cy.method)
So Func() and IsFunc() are not 'symmetric' in this regard:
Example for all of this:

Code: Select all

class cx {
	method() {
		MsgBox cx.method()
	}
}
class cy {
	static method := Func("cy_method")
}
cy_method() {
	MsgBox cy_method()
}

;~ MsgBox, % IsFunc("cx.method")	; 2
;~ MsgBox, % IsFunc(cx.method)		; 2
;~ MsgBox, % IsFunc("cx.method")	; 2

;~ MsgBox, % IsFunc("cy.method")	; 0
;~ MsgBox, % IsFunc(cy.method)		; 1
;~ MsgBox, % IsFunc("cy_method")	; 1


;~ MsgBox, % Func("cx.method")	; ""
;~ MsgBox, % Func(cx.method)	; 0
;~ MsgBox, % Func("cx.method")	; ""

;~ MsgBox, % Func("cy.method")	; 0
;~ MsgBox, % Func(cy.method)	; 0
;~MsgBox,  % Func("cy_method")	; ""
* Because this syntax fails: fun := Func(cy.method) it would look like it is impossible to create a reference (or another name) to a function that is ~a method. But it is actually possible to create a reference to a function object that is a method: instead of using Func(), just assign the Func object to another variable, which will store another reference to the function object in the variable. From now on, that variable becomes 'the new name' of the function:

Code: Select all

class cy {
	static method := Func("cy_method")
	; remember about the keyword 'static'
}
cy_method() {
	MsgBox cy_method()
}
; fun := Func(cy.method) vs fun := cy.method
; 
	; ~it is false that it is not possible to define
	; the function reference to a _method_ of a class.
	; 
fun1 := Func(cy.method)	; defining another function reference like this fails
fun2 := cy.method		; but defining the function reference like this works

fun1.()			; not called
MsgBox, % fun1	; 0 => Func() failed
fun2.(0)		; cy_method called
Also, could the return value of Func() be documented?

Thanks Lexikos and Coco.
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Can you make a Func() reference to a Static/Class Method

21 Nov 2013, 06:02

Also, could the return value of Func() be documented?
It is documented though?
If the function does not exist -> 0
If the function does exist -> function reference aka func object

Source: http://l.autohotkey.net/docs/Functions.htm#Func
Wade Hatler
Posts: 60
Joined: 03 Oct 2013, 19:49
Location: Seattle Area
Contact:

Re: Can you make a Func() reference to a Static/Class Method

21 Nov 2013, 11:18

Thanks guys. It all makes sense now.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

21 Nov 2013, 13:01

LinearSpoon wrote:
Also, could the return value of Func() be documented?
It is documented though?
If the function does not exist -> 0
If the function does exist -> function reference aka func object

Source: http://l.autohotkey.net/docs/Functions.htm#Func
D'oh! <Walks away.>
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Can you make a Func() reference to a Static/Class Method

22 Nov 2013, 03:05

trismarck wrote:Right, so if I _don't_ define the method _outside of_ the body of the class, then that method will acquire a 'default' name of the method (~of the function) anyway.
Huh? I can't make sense of that. The name of any method defined inside a class always contains the name of that class, from the moment it is defined. It doesn't matter what you do with the method afterward.
This is interesting as the dot is not a valid character of a name of the variable (~and of the function):
It's not valid in a function definition, since cx.method() { would be defining a function named "cx.method", not a method named "method" in a class named "cx".
And yet Func() works with the name of that variable:
The name of what variable? "cx.method" is not a valid variable name; therefore there cannot be any variable which has that name. Func() works with the name of a function. A function is not a variable; they just have similar naming rules.
can't be a name of the method (~a string that has a dot and that should be parsed to separate the class [name] from the key that contains the method) (well, actually it can, but the outcome is not reliable - i.e. Func("cx.method") in the example above. )
It can be the name of any function, and methods are functions. As I pointed out before, the name of the method which cy.method() calls is in fact "cy_method", not "cy.method".
can't be the function object *
There's no need to call Func() if you already have the function object.
So Func() and IsFunc() are not 'symmetric' in this regard:
That's a good point. I might change it.
From now on, that variable becomes 'the new name' of the function:
I think you have a strange perspective. The variable simply holds a reference to the same function. The function's name is exactly what it was before, and has nothing to do with the variable.
fun2 := cy.method ; but defining the function reference like this works
You're not "defining" a function reference; just copying a value from a class object to a variable. The value just happens to be a reference to a function object - i.e. a function reference.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

23 Nov 2013, 07:53

[unfinished version of the post got posted]
Last edited by trismarck on 23 Nov 2013, 09:07, edited 2 times in total.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

23 Nov 2013, 09:05

lexikos wrote:
trismarck wrote:Right, so if I _don't_ define the method _outside of_ the body of the class, then that method will acquire a 'default' name of the method (~of the function) anyway.
Huh? I can't make sense of that. The name of any method defined inside a class always contains the name of that class, from the moment it [the method] is defined. It doesn't matter what you do with the method afterward.
Hmm, by 'anyway', I've meant that _every_ method eventually has to get a name. Methods with names _explicitly_ defined by the user have _those_ names and even if the user doesn't define a name for the method, the compiler _implicitly_ creates a name for the method 'anyway'. After rethinking, what I wrote could also be understood that _after_ the name of the method is defined, I can change that name 'anyway' later on, through some command in the script, during the execution of the script. To clarify, this is not what I've meant.
Lexikos wrote:
This is interesting as the dot is not a valid character of a name of the variable (~and of the function):
It [the dot in the name]'s not valid in a function definition, since cx.method() { would be defining a function named "cx.method", not a method named "method" in a class named "cx".
Right, so what I got wrong here was:
  • naming conventions for functions and for variables are different (names of variables can't contain a dot)
  • within the same scope, there can exist a variable and a function with the same name and the compiler will differentiate between those two correctly (previously thought that I can have only one 'name' within the given scope, whether the name pertains to the name of the variable or to the name of the function)
  • a variable is a separate entity from the function (I had trouble differentiating between the name of the variable and the name of the function / how those two work together). Realizing this helped.
  • I'm not sure if I'm reading between the lines correctly:
    • the name of the function that is _not_ a method _can't_ contain the dot in the name
    • the name of the function that _is_ a method _can_ contain the dot in the name
      ?
Lexikos wrote:
And yet Func() works with the name of that variable:
The name of what variable? "cx.method" is not a valid variable name; therefore there cannot be any variable which has that name. Func() works with the name of a function. A function is not a variable; they just have similar naming rules.
Yeah, because the compiler can differentiate between names of variables and functions, it is possible for a function to only work with parameters that are names of _functions_. Previously I've thought that names of functions in the script are _subsets_ of names of variables, which is false.
Lexikos wrote:
can't be a name of the method (~a string that has a dot and that should be parsed to separate the class [name] from the key that contains the method) (well, actually it can, but the outcome is not reliable - i.e. Func("cx.method") in the example above. )
It [the parameter of IsFunc()] can be the name of any function, and methods are functions. As I pointed out before, the name of the method which cy.method() calls is in fact "cy_method", not "cy.method".
  • At that point in time, by the word 'reliable', I've meant that Func() will only 'parse' the name of the method if the method is defined _implicitly_ in the class object (and would fail for methods with explicitly given names ~not reliable for _all_ methods). Now I see that the whole thing is entirely backwards. Func() _never_ parses the contents of the string in search for the dot / the name of the method. Func() instead _always_ treats the whole string passed as the parameter as the name of the function. In case of cx.method, the name of the function just happens to resemble the structure of the class object, but in cases of functions that are not methods / functions that are methods with _explicitly_ defined names, there might even not be the class object and the name of the function will be recognized by Func() function correctly.
    What mislead me further at the beginning was a wrong interpretation of this quote:
    Lexikos wrote: You are using IsFunc() in a way that is not supported. IsFunc("cx.method") is not guaranteed to return non-zero. It [IsFunc()] does so [returns non-zero in this particular case] because in the current implementation, the function is automatically assigned a name based on the class name. If you were to assign cx.method := 0, you would no longer have a reference to the function, but IsFunc("cx.method") would still return 2. There is no connection between the function call and the class object.
    I've thought that 'unsupported' (~unreliable) means that if I _later on_ change the value of the key method in the object cx, then IsFunc() will 'return a false result', because the only reference to the function that was there was destroyed. This is again completely backwards. What really happens is that for a method that has no explicitly defined name, the compiler gives that method the name implicitly. That name then guarantees that by using the name I'll always refer to the particular function. The name of the function sort of then becomes a container that holds a reference to the function and the _value_ of that container can't be changed. Thanks to the fact that the name of the container cant' be changed, I can be sure that the compiler never forgets the definition of the function (it is not possible for the reference count of the function to go below 1). I can also be sure that by using the name of the function, I'll always refer to that particular function, even if the key [of the class object] that held a reference to the function is assigned a different value.
    Note also that _there is no connection_ between the name of the function "cx.method" and the value of the key method in the object cx. Namely, even if the value of the key will be changed, the _function_ won't be erased; furthermore the function will still be accessible through the name (through the string) "cx.method". The only problem with this now is that (at least for methods with implicitly given names), if the key that originally held a reference to the method is assigned a different value, there is no way to call the function whose name contains a dot. But this _can_ be circumvented by using Func() to obtain yet another reference to the function:

    Code: Select all

    class cx {
    	method() {	; implicit name: "cx.method"
    		MsgBox, % "cx.method()"
    	}
    }
    
    MsgBox, % IsFunc("cx.method")	; 2
    cx.method := ""
    MsgBox, % IsFunc("cx.method")	; 2
    cx.method()	; not called
    
    ; "cx.method"() ; this line contains unrecognized action
    cx`.method(0) ; not called?
    abc := Func("cx.method")	; get new reference to the function
    							; (sort of resurrect the function from
    							; the dead).
    							; 
    abc.(0)	; called
    
    Other thing to note is, why can't I call the function whose name has a dot in the first place, if the name of the function can contain the dot?

    Code: Select all

    cx`.method(0) ; not called?
    The following 'looks like' the dot can be part of name of the variable, but it really isn't how the code below works - cx`.method is interpreted as key method of class cx rather than a name of the variable cx.method.

    Code: Select all

    class cx {
    	method() {
    		MsgBox, cx.method()
    	}
    }
    
    cx`.method := 3
    MsgBox, % cx`.method	; 3
  • Inside of every script, there are three types of names:
    • names of variables
    • names of functions (including names of methods)
    • names of keys
    • other, like keywords / things I have no idea about?
    I've only found documentation on names of variables and names of keys.
    Each _name_ can be an element from a _subset_ of a set of all possible _values_. There can be three types of values:
    • a number
    • a string
    • a reference (to an associative array AHK object / to AHK Function object / to COM object / other)
    Is this correct / what would be the allowed names for functions that are:
    • methods
    • not methods
  • When I define a method, two things happen:
    • the name of the method is created "cx.method" or "cy_method"
    • the key of the object gets the value that is the reference to the function object, i.e.: obj.a := Func("cy_method")
    Note that regardless of what happens with the value of the key, the interpreter always has this additional way of referring to the function by the _name_ of the function.
  • Thought: if the dot in the name of the function was made forbidden, then if Func() gets a string as the parameter, Func() _could_ differentiate between of whether this string is the name of the function or whether the string is the name of the method that should be resolved 'dynamically' . I.e.
    • Func("cx.method") - there is a dot in the parameter => parse the string and find the value of the key 'method' in the object cx
    • Func("cx_method") - there is no dot in the parameter => the parameter is the name of the function - find out if there is a function with that name.
Not sure if this would be useful though.
Lexikos wrote:
From now on, that variable becomes 'the new name' of the function:
I think you have a strange perspective. The variable simply holds a reference to the same function. The function's name is exactly what it was before, and has nothing to do with the variable.
Yes now I see that there is no connection between the name of the function and the variable that holds the reference to the function. Namely, changing contents of the variable makes no difference of whether the function exists or not (~last ref to not fn removed).
Lexikos wrote:
fun2 := cy.method ; but defining the function reference like this works
You're not "defining" a function reference; just copying a value from a class object to a variable. The value just happens to be a reference to a function object - i.e. a function reference.
Yeah, it was a quick note, I've really meant: 'through this notation' the function reference 'works'. Thanks for pointing that out.

Another asymmetry I see is this:
Inside of the script, there are in general three entities:
  • variables
  • functions
  • classes
Contents of variables can be erased, but that's sort of not an issue. Contents of functions can't be erased (~the name of the function will always point to the definition of the function). Contents of class objects _can_ be erased.
I can now see two things:
  • because the whole OOP part of the language is 'dynamic' - for a given object, it is possible to add properties / methods to it or remove properties / methods or even whole objects, because of that, references to _classes_ are stored in _variables_ and thus contents of variables can be changed. That's probably why classes were placed in _variables_ and not in some other entities that the compiler recognizes.
  • there is a difference in how _function_ names and _class_ names are treated. The problem of being able to overwrite super-global variables that contain references to class objects has emerged before - this is troublesome as can happen unintentionally, esp. because super-globals leak into definitions of methods / functions. Classes are different than functions in that it is possible to overwrite the variable that holds the class but it is not possible to overwrite the definition of the function (so that the compiler forgets the definition of the function).
It looks that making _variables_ as containers of classes is sort of a compromise between the 'dynamic' abilities of the language and the friendliness of the language. Variables that hold classes can be overwritten (which is dangerous) but on the other hand being able to overwrite contents of variables adds flexibility to what can be done with classes.
I was thinking about something as the unique name of the class (just like the unique name of the function); if every class would have such a name that (the name) is independent of the variable that contains the class, even if the contents of the variable, that (the variable) holds the class object, are overwritten, the user could still refer to the class initially created through that _unique_ name of the class. I was also thinking about the possibility to access the 'snapshot' of the class that was initially defined in the script file, regardless of what happens with that class later on. The only problem I see with this is that what if _parts_ (and not _the whole_ snapshot) of this snapshot have to be 'dynamic' (changeable) - a better option than snapshots would be to define each variable / key as read-only (or being able to enable / disable read-only flag) than to have the snapshot. The snapshot would work in that, like with the function, one additional reference would be kept internally to each object within that class.. Yeah I can already see that having extra references to objects makes no sense, as those objects themselves might change later on... Nevermind.
Last edited by trismarck on 18 Mar 2014, 08:21, edited 1 time in total.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Can you make a Func() reference to a Static/Class Method

24 Nov 2013, 16:04

trismarck wrote:What really happens is that for a method that has no explicitly defined name, the compiler gives that method the name implicitly.
Every method has an explicitly defined name, since a method can't exist without the user having defined it. This is why I say I can't make sense of what you're saying.

When the user defines a function, the function name is stored for use with dynamic function calls, Func.Name, ListVars, A_ThisFunc, etc. When the user defines a function inside a class definition, the final function name includes both the class name and the name specified by the user.

A "method" in AutoHotkey consists of multiple parts:
  1. The function which implements it.
  2. The key-value pair which associates the target object/class with the function.
  3. The concept which ties it all together.
Since this discussion is about Func(), which only knows about functions, not methods, I've mostly used "method" to mean #1.
naming conventions for functions and for variables are different (names of variables can't contain a dot)
No. Variable, function, class and window group names all follow the same rules. However, the rules only apply to what the user types when defining the method/function.
within the same scope, there can exist a variable and a function with the same name
Correct, except that scope doesn't really apply to function names.
The name of the function sort of then becomes a container that holds a reference to the function and the _value_ of that container can't be changed. Thanks to the fact that the name of the container cant' be changed, (...)
The script internally keeps a list of all functions which have been defined, including methods. Users can't access this list directly.
I can also be sure that by using the name of the function, I'll always refer to that particular function, even if the key which held a reference to the function is assigned a different value.
No. You cannot be sure that Func() will return a method, because it isn't documented. It isn't documented because it isn't intended for use; it is just a consequence of the implementation. This is what I meant when I said "IsFunc("cx.method") is not guaranteed to return non-zero."
cx`.method(0) ; not called?
Escaping a dot has no special meaning, so this is the same as a regular method call.
Each _name_ can be an element from a _subset_ of a set of all possible _values_. There can be three types of values:
  • a number
  • a string
  • a reference (to an associative array AHK object / to AHK Function object / to COM object / other)
No. Keys can be integers, strings or references - this is documented. In cx.method, "method" is a key. You could also call it a method name, in that it is the name you use to refer to/call the method. However, this isn't what I'm talking about when I say the method's name, since I'm talking about the method/function itself, independent from cx.
Is this correct / what would be the allowed names for functions that are:
  • methods
  • not methods
When talking about what is allowed, only the part of the name explicitly written by the user is relevant (not the class name prefix). That part follows the same rules as for variables.
Func() _could_ differentiate between of whether this string is the name of the function or whether the string is the name of the method that should be resolved 'dynamically'
You're right; it could. A more likely use for this is to prevent Func() from ever returning a function which was defined inside a class. However, that could have a negative (but very small) impact on code size and performance; hence why it is the way it is.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

25 Nov 2013, 06:36

Lexikos wrote: When the user defines a function, the function name is stored for use with dynamic function calls, Func.Name, ListVars, A_ThisFunc, etc. When the user defines a function inside a class definition, the final function name includes both the class name and the name specified by the user.
Lets suppose we have three methods:

Code: Select all

class cx {
	chicken() {
	}
}

class cy {
	static cow := Func("cy_cow")
}
cy_cow(this) {
	
}

class cz {
	static lion := Func("cz_barn")
}
cz_barn() {
}
In those examples, the names of _methods_ would be:
  • "cx.chicken"
  • "cy_cow"
  • "cz_barn"
and would not be:
  • "cx.chicken"
  • "cy.cow"
  • "cz.lion" or "cz_lion"
Lexikos wrote: A "method" in AutoHotkey consists of multiple parts:
  1. The function which implements it.
  2. The key-value pair which associates the target object/class with the function.
  3. The concept which ties it all together.
Since this discussion is about Func(), which only knows about functions, not methods, I've mostly used "method" to mean #1.
Example1: if I define a function named "cy_cow" defined somewhere in the script, then "cy_cow" is the name of the _function_. If I additionally have an object with a key and the value of that key holds the reference to the function "cy_cow", then "cy_cow" is also a name of the _method_?
Example2: if _I_ define a function named "chicken" inside of the class object whose name is "cx" then the compiler will create a function named "cx.chicken" and "cx.chicken" will be the name of the _function_. If I additionally have an object with a key and the value of that key holds the reference to the function "cx.chicken" (the object doesn't necessary being the object "cx"), then "cx.chicken" is _also_ a name of the _method_.
This is how I understand the definition of the word 'method'.
Lexikos wrote:
naming conventions for functions and for variables are different (names of variables can't contain a dot)
No. Variable, function, class and window group names all follow the same rules. However, the rules only apply to what the _user_ types when defining the method/function.
Note: _user_.
Lexikos wrote:
The name of the function sort of then becomes a container that holds a reference to the function and the _value_ of that container can't be changed. Thanks to the fact that the name of the container cant' be changed, (...)
The script internally keeps a list of all functions which have been defined, including methods. Users can't access this list directly.
Because all methods have to have a function definition and that function definition has to have a name that is the name of the function, _all_ names of methods are names of functions?
Lexikos wrote:
I can also be sure that by using the name of the function, I'll always refer to that particular function, even if the key which held a reference to the function is assigned a different value.
No. You cannot be sure that Func() will return a _method_
If the parameter of Func() is a string that is the name of the function, then Func() will return the reference to the function. Because a method is:
  • a function definition (and part of that definition of the function is the _name_ of the function)
  • a key of the class object whose value holds the reference to the defined function
=> a method is always a function. So if I pass the name of the _method_ (which is at the same time the name of the function) to Func(), Func() will return a _function_ reference. If I pass a name of the method to Func() I _can_ be sure that Func() will return [a reference to] a method (because I know that I've passed a method to Func() ). But, if I _don't_ know if the name of the function that I pass to Func() is the name of the _method_, I _can't_ be sure that Func() will return a reference to a _method_. This is how I understand this.
So it's not that Func() _can't_ return a reference to the _method_, it's rather that if I pass a name of the function to Func(), I can't be sure if the reference to the function returned is also a reference to the method? (because I don't know if the name of the function that I passed to Func() was a method in the first place)?
Lexikos wrote: No. You cannot be sure that Func() will return a _method_, because it isn't documented. It isn't documented because it isn't intended for use; it is just a consequence of the implementation. This is what I meant when I said "IsFunc("cx.method") is not guaranteed to return non-zero."
Lets clear this up. There are two meanings one could derive from the word 'method' in "cx.method":
  • "cx.method" is treated as the name of the method (and at the same time the name of the _function_) _literally_, character by character, just like "cy_cow" or "cx_lion"
  • 'method' in "cx.method" is a placeholder for the name of any function name of the key, that (the key), when combined with the prefix "cx", ("cx" + "name of key") gives the name of the function that (the function) was defined inside of the body of the class that (the method) also happens to be part of (of the class)
To clarify, what I've meant by "cx.method" is the _former_ (just a literal name of the _method_).
Now, if I've meant the former, then is it correct that _even_ for functions that are defined _inside_ of the class and that are methods, IsFunc() _is_ guaranteed to return non-zero (because what I'm passing to IsFunc() is still a name of the _function_ (regardless of whether that function is a name of the method or not).

I don't seem to understand in what cases IsFunc() is _not_ guaranteed to return non-zero. Even if the argument of the function is the name of the function that was defined inside of the class, then, because I pass the name of the _function_ to IsFunc(), IsFunc() has to guarantee a non-zero result, because what I'm passing is the name of the _function_ (which also just happens to be the name of the method).
Lexikos wrote:
No. Keys can be integers, strings or references - this is documented. In cx.method, "method" is a key. You could also call it a method name, in that it is the name you use to refer to/call the method. However, this [the word "method" in the string "cx.method"] isn't what I'm talking about when I say the method's name, since I'm talking about the method/function itself, independent from "cx".
So, if the word 'method' in "cx.method" is treated _literally_ as the name of the method, just like "cx.chicken", then the name of the method is "cx.method" and not just "method", just like the name of the method is "cx.chicken" and not just "chicken"? This is what I've meant originally. whenever I wrote "cx.method" - I haven't intended the word 'method' to be a placeholder word. I should have quoted the whole string probably to remove the ambiguity.

Lexikos wrote:
Func() _could_ differentiate between of whether this string is the name of the function or whether the string is the name of the method that should be resolved 'dynamically'
You're right; it could. A more likely use for this is to prevent Func() from ever returning a function which was defined inside a class. However, that could have a negative (but very small) impact on code size and performance; hence why it is the way it is.
So Func() supports as the parameter:
  • names of functions that aren't methods
  • names of functions that are methods defined outside of the class
but does _not_ support names of functions that are methods defined _inside_ of the class? (Func() just returns a correct value of those because of the current implementation but I shouldn't rely on that value). If that is true, then it would be _false_ to say that Func() doesn't work with methods? (because Func() _has to_ work with names of functions that (the functions) are additionally names of methods; methods defined outside of the class).
I clearly lack the understanding of something there.
Last edited by trismarck on 18 Mar 2014, 08:22, edited 1 time in total.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Can you make a Func() reference to a Static/Class Method

25 Nov 2013, 16:45

Because all methods have to have a function definition and that function definition has to have a name that is the name of the function, _all_ names of methods are names of functions?
Because methods are functions, all names of methods are names of functions.
Example1: if I define a function named "cy_cow" defined somewhere in the script, then "cy_cow" is the name of the _function_. If I additionally have an object with a key and the value of that key holds the reference to the function "cy_cow", then "cy_cow" is also a name of the _method_?
I could say that "Lexikos" is the name of a forum user, and it is also the name of a man, and also the name of a human. Isn't that a rather awkward way of talking? As I said before, when I refer to a method I'm generally referring to the function which is used as such. They are the same thing. It might be clearer to say that "cy_cow" is the function name of the method cy.cow.
However, this [the word "method" in the string "cx.method"] isn't what I'm talking about when I say the method's name, since I'm talking about the method/function itself, independent from "cx".
The string "cx.method" has nothing to do with it. I wrote cx.method, literally an expression which returns the method. If you do cx.foo := cx.method, "foo" and "method" are both keys which can be used to call the method, but obviously "foo" has nothing to do with the string "cx.method".
So Func() supports as the parameter:
  • names of functions that aren't methods
  • names of functions that are methods defined outside of the class
Func() supports names of functions. That is all. From the program's perspective, a "method defined outside of the class" is not a method at all. What Func() returns is just a plain function, and has no association with any class.

My point about documentation is that the documentation doesn't guarantee that methodx defined inside classx will be named "classx.methodx", so there's no guarantee that Func("classx.methodx") will return it. It also doesn't say anything about Func() supporting methods (since it isn't intended to), but you could infer (not necessarily correctly) that since methods essentially are functions, it should work.

The point of Func() is to retrieve a reference to a function. You can't simply write funcname, because that would get the value of a variable, not a function reference. For methods you can simply write class.method, so there's no reason for Func() to support methods.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

26 Nov 2013, 04:58

Lexikos wrote:
Example1: if I define a function named "cy_cow" defined somewhere in the script, then "cy_cow" is the name of the _function_. If I additionally have an object with a key and the value of that key holds the reference to the function "cy_cow", then "cy_cow" is also a name of the _method_?
I could say that "Lexikos" is the name of a forum user, and it is also the name of a man, and also the name of a human. Isn't that a rather awkward way of talking? As I said before, when I refer to a method I'm generally referring to the function which is used as such.
~is the name of a particular _instance_ of a function. The function being 'a concept'.
I probably phrase this strangely because I'm not a native speaker.

Lexikos wrote: My point about documentation is that the documentation doesn't guarantee that methodx defined inside classx will be named "classx.methodx", so there's no guarantee that Func("classx.methodx") will return it. It also doesn't say anything about Func() supporting methods (since it isn't intended to), but you could infer (not necessarily correctly) that since methods essentially are functions, it should work.
Note that this implies, for a function that is defined inside of the body of the class, once the the key that holds the reference to that function is set to a different value (assuming that there are no other keys / variables that hold the reference to that function), that there is no guaranteed way to create another reference to that function, because I don't know for sure, what's the name of the function. Could one infer that this is a design flaw, because for all _other_ functions defined in the script, it is always possible and _guaranteed_ to create a reference to that function by using the _name_ of the function? (~for all other functions, we're guaranteed that the name of the function that we gave to the function _refers to_ that specific [definition of] the function)

Additional notes:
  • Functions can be defined:
    • outside of the body of the class, as 'functions'
    • outside of the body of the class, as 'methods'
    • inside of the body of the class
  • Whether it is _documented_ (~guaranteed), what the name of the function will be, depending on how that function was defined:
    • fn defined outside of the body of the class, as a 'function' -> name of the function guaranteed
    • fn defined outside of the body of the class, as a 'method' -> name of the function _not_ guaranteed
    • fn defined inside of the body of the class ('as a method') -> name of the function guaranteed
  • Func() and IsFunc() only work (or rather, are only guaranteed to work correctly) with names of functions for which (for the names) the documentation _states_ what the name of the function will be.
  • Lexikos wrote:[All] Methods are functions, so [all] names of methods are names of functions.
    Note that this also means that if thing, that (the thing) is a function, doesn't have a name of the function that (the name of the function) is guaranteed, then that thing, that (the thing) is also a method, doesn't _also_ have a guaranteed name of the _method_.
  • Lexikos wrote:[All] Methods are functions, so [all] names of methods are names of functions.
    Note that this doesn't imply that all functions are methods.
  • The method cy.cow has a function associated with the method. The name of that function is "cy_cow". The name "cy_cow" is guaranteed to be the name of that function.
    The method cx.chicken has a function associated with the method. The name of that function [in the current implementation] is "cx.chicken". The name "cx.chicken" is _not_ guaranteed to be the name of that function.
I.e.:

Code: Select all

class cx {
   chicken() {
   }
}

class cy {
   static cow := Func("cy_cow")
}
cy_cow(this) {
   
}

class cz {
   static lion := Func("cz_barn")
}
cz_barn() {
}
Func() and IsFunc() are only guaranteed to work with the following names of functions (which are also the names of methods): "cy_cow", "cz_barn", but not with "cx.chicken".

So the best practice to always make sure that there is at least one guaranteed name of the method (of the function) that I can refer to when there are _no_ variables / keys that hold a reference to that function in the script, is to always define that method (that function) _outside_ of the body of the class.

Ah, the wisdom has finally enlightened the rustic peasant, thanks Lexikos. It's time to feed the chicken now.
Last edited by trismarck on 18 Mar 2014, 08:23, edited 1 time in total.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Can you make a Func() reference to a Static/Class Method

26 Nov 2013, 05:49

trismarck wrote:Could one infer that this is a design flaw, because for all _other_ functions defined in the script, it is always possible and _guaranteed_ to create a reference to that function by using the _name_ of the function?
No. That is only the case for functions because there is no way to redirect or overwrite them during runtime, in the current feature set. Why should a method be accessible after it is removed from the class?
(~for all other functions, we're guaranteed that the name of the function that we gave to the function _refers to_ that specific [definition of] the function)
That's not very meaningful. You can rely on it returning a specific function because you know that you've only defined one function with that name.
Functions can be defined:
outside of the body of the class, as 'functions'
outside of the body of the class, as 'methods'
As a matter of semantics, I would argue that functions defined outside the body of the class are not defined as methods. It only becomes a method when you assign it to a class/object, at some point after definition.
fn defined outside of the body of the class, as a 'method' -> name of the function _not_ guaranteed
I don't know what gave you that idea. A function defined outside of the body of a class is just a function, and it's name is clearly whatever you wrote in the script. It only becomes a method when you assign it to a class/object; and to do that, you need to use the function's name. As I've said before and demonstrated, the function's name doesn't change.
Note that this also means that if thing, that (the thing) is a function, doesn't have a name of the function that (the name of the function) is guaranteed, then that thing, that (the thing) is also a method, doesn't _also_ have a guaranteed name of the _method_.
That's hard to follow, but I'm fairly certain it is redundant. Why state the obvious? It's like saying if the fruit is rotten, and the fruit is an apple, then the apple is also rotten. (I think this is incorrect, as "also" implies that the apple and the fruit are two different things. Similarly, your statement implies that "name of the method" and "name of the function" are two different things, when in fact they aren't; the thing has a "name", and the thing is both a function and a method.)
So the best practice to always make sure that there is at least one guaranteed name of the method (of the function) that I can refer to when there are _no_ variables / keys that hold a reference to that function in the script, is to always define that method (that function) _outside_ of the body of the class.
I can't begin to understand your motiviations - why you would ever want to erase a method from a class and than later refer to it by name.
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

26 Nov 2013, 11:15

Lexikos wrote:
trismarck wrote:Could one infer that this is a design flaw, because for all _other_ functions defined in the script, it is always possible and _guaranteed_ to create a reference to that function by using the _name_ of the function?
No. That is only the case for functions because there is no way to redirect or overwrite them during runtime, in the current feature set. Why should a method be accessible after it is removed from the class?
Those are the reasons I've had in my mind:
  • other class might want to use that method dynamically at some other point in time
  • it is inconsistent that methods defined outside of the class and methods defined inside of the class behave differently. Methods defined outside of the class are accessible by guaranteed name and methods defined inside of the class aren't, because the name is not guaranteed to be classname + dot + keyname and there is no other name to refer to.
Lexikos wrote:
(~for all other functions, we're guaranteed that the name of the function that we gave to the function _refers to_ that specific [definition of] the function)
That's not very meaningful. You can rely on it returning a specific function because you know that you've only defined one function with that name.
Right - if it was _I_ who gave the function the unique name, why would I expect the name not to be unique. OTOH, for functions that got the name from the compiler, it's hard to provide the uniqueness of the name w/o using the name of the key of the class as the prefix for the name of the function. I wrote that to put an emphasis on the fact that names of functions defined inside of the class aren't 'guaranteed'.
Lexikos wrote:
Functions can be defined:
outside of the body of the class, as 'functions'
outside of the body of the class, as 'methods'
As a matter of semantics, I would argue that functions defined outside the body of the class are not defined as methods. It only becomes a method when you assign it to a class/object, at some point after definition.
If that is true, then it means that even functions defined _inside_ of the class definition are mainly _functions_ (for the whole lifetime of the script) and because of that, there should be a mechanism that guarantees accessing those functions by name (like for every other function in the script).
Aside from that, I agree that in AHKS, a function becomes a method sort of 'temporarily' - after the value of the key that holds the reference to the method is changed, that method may turn into a function (or vice versa). By 'defined as a method' I've implicitly meant that I define the function and later on I define a class that has a key that holds a reference to the function as a value.
Lexikos wrote:
fn defined outside of the body of the class, as a 'method' -> name of the function _not_ guaranteed
I don't know what gave you that idea. A function defined outside of the body of a class is just a function, and it's name is clearly whatever you wrote in the script. It only becomes a method when you assign it to a class/object; and to do that, you need to use the function's name. As I've said before and demonstrated, the function's name doesn't change.
This is a mistake, thanks; I've meant:
Whether it is _documented_ (~guaranteed), what the name of the function will be, depending on how that function was defined:
  • fn defined outside of the body of the class, as a 'function' -> name of the function guaranteed
  • fn defined outside of the body of the class, as a 'method' -> name of the function _not_ guaranteed
  • fn defined _inside_ of the body of the class ('as a method') -> name of the function _not_ guaranteed
Lexikos wrote:
Note that this also means that if thing, that (the thing) is a function, doesn't have a name of the function that (the name of the function) is guaranteed, then that thing, that (the thing) is also a method, doesn't _also_ have a guaranteed name of the _method_.
That's hard to follow, but I'm fairly certain it is redundant. Why state the obvious? It's like saying if the fruit is rotten, and the fruit is an apple, then the apple is also rotten. (I think this is incorrect, as "also" implies that the apple and the fruit are two different things. Similarly, your statement implies that "name of the method" and "name of the function" are two different things, when in fact they aren't; the thing has a "name", and the thing is both a function and a method.)
:lol: I've meant: for functions that defined inside the class object (== for that particular subset of methods), saying "the name of the_function_ is not guaranteed" means exactly the same as saying "the name of the _method_ is not guaranteed". This is because in that particular case, the name of the function is _simultaneously_ the name of the method.
Lexikos wrote:
So the best practice to always make sure that there is at least one guaranteed name of the method (of the function) that I can refer to when there are _no_ variables / keys that hold a reference to that function in the script, is to always define that method (that function) _outside_ of the body of the class.
I can't begin to understand your motiviations - why you would ever want to erase a method from a class and than later refer to it by name.
Because that method is a function and because if something is a function, I should have the unique way of referring to _all_ functions, regardless of whether those functions temporarily become methods somewhere in the script. If a method is a function and I have the unique identifier for _most of_ the functions (excluding only functions that are defined inside of the class), why exclude those functions in the first place?
As one could infer from this quote:
Lexikos wrote: As a matter of semantics, I would argue that functions defined outside the body of the class are not defined as methods. It only becomes a method when you assign it to a class/object, at some point after definition.
a method is only sort of a 'temporary' state of the function.

Besides of that, please note that this is a purely theoretical discussion (at least from my point of view) and it will be a long time before I'll ever use the features that I describe here. Just to be clear, I don't even know if what I'm saying here is useful. I'm describing what I think about a particular feature of the language, but I don't have x years of experience of programming to tell if what I'm saying is actually relevant.
lexikos
Posts: 9690
Joined: 30 Sep 2013, 04:07
Contact:

Re: Can you make a Func() reference to a Static/Class Method

27 Nov 2013, 04:19

trismarck wrote:other class might want to use that method dynamically at some other point in time
That doesn't answer the question of why. Also, it seems like a very poor design. You could easily define the method elsewhere if it is going to be used in multiple places, and it would make more sense from an organizational perspective.

AutoHotkey_H has the capability to dynamically add code to the script. What if I wanted to purge a method-function from the script, and then later dynamically define another one with the same name? Anything attempting to refer to the old function by name would fail, while anything retaining a reference to the function might continue working.
it is inconsistent that methods defined outside of the class and methods defined inside of the class behave differently.
Wrong. Firstly, the difference is between methods defined inside a class and ordinary functions (there is no such thing as "methods defined outside of the class"). Secondly, they don't behave differently - both are accessible by Func() using the name reported by A_ThisFunc or ListVars. The difference is that Func() is intended for use with functions, not methods.
If that is true, then it means that even functions defined _inside_ of the class definition are mainly _functions_
No, it doesn't...
Whether it is _documented_ (~guaranteed), what the name of the function will be, depending on how that function was defined:
fn defined outside of the body of the class, as a 'function' -> name of the function guaranteed
fn defined outside of the body of the class, as a 'method' -> name of the function _not_ guaranteed
fn defined _inside_ of the body of the class ('as a method') -> name of the function _not_ guaranteed
You are overcomplicating, and making a distinction that is irrelevant. The reality is:
fn defined outside of the body of the class -> name of the function guaranteed
fn defined inside of the body of the class -> name of the function _not_ guaranteed
I've meant: for functions that defined inside the class object (== for that particular subset of methods), saying "the name of the_function_ is not guaranteed" means exactly the same as saying "the name of the _method_ is not guaranteed". This is because in that particular case, the name of the function is _simultaneously_ the name of the method.
Fixed. My earlier point was that it doesn't make sense to state that "the name of x is the name of y" when that is very obviously implied by "x is y". I think that if you break the facts down into their logical components, it makes learning and remembering much easier.
... why exclude those functions in the first place?
In a word, encapsulation. The method was defined inside a class; it belongs to that class, and should only be accessed through that class.
a method is only sort of a 'temporary' state of the function.
For Func(), the important distinction is based on where the function is defined, and that is constant (never changes). Furthermore, functions defined inside a class are permanently associated with that class (as in, the actual object), for use with the base pseudo-keyword. This doesn't change even if you remove the function from the class, or remove the class itself (as in classname := "").
User avatar
trismarck
Posts: 506
Joined: 30 Sep 2013, 01:48
Location: Poland

Re: Can you make a Func() reference to a Static/Class Method

28 Nov 2013, 07:05

Lexikos wrote:
trismarck wrote:other class might want to use that method dynamically at some other point in time
That doesn't answer the question of why. Also, it seems like a very poor design. You could easily define the method elsewhere if it is going to be used in multiple places, and it would make more sense from an organizational perspective.

AutoHotkey_H has the capability to dynamically add code to the script. What if I wanted to purge a method-function from the script, and then later dynamically define another one with the same name? Anything attempting to refer to the old function by name would fail, while anything retaining a reference to the function might continue working.
Ok, I agree. The method should not be accessible if I explicitly remove the method from the class. The reason I disagreed in the past was I've thought methods should be like functions. Even if some 'special' case occurred (in which I'd have to access the method by its name), I should rather redesign the script than rely on the name of the method (instead of on the reference to the method) to access the method.
Lexikos wrote:
it is inconsistent that methods defined outside of the class and methods defined inside of the class behave differently.
Wrong. Firstly, the difference is between methods defined inside a class and ordinary functions (there is no such thing as "methods defined outside of the class"). Secondly, they don't behave differently - both are accessible by Func() using the name reported by A_ThisFunc or ListVars. The difference is that Func() is intended for use with functions, not methods.
Ok, methods that 'link' to functions defined outside of the class (vs methods defined outside of the class).
There are two separate things here:
  • if I define a method (if I define a function inside of the class), is the name of that method _guaranteed_ to be var_that_holds_class_object.key?
  • Func() _guarantees_ that if I pass the name of the method to it, Func() will return 'a valid result'
Are both of those things not guaranteed? (if not, which one is/isn't)
//Update-20131129
Lexikos wrote:My point about documentation is that the documentation doesn't guarantee that methodx defined inside classx will be named "classx.methodx", so there's no guarantee that Func("classx.methodx") will return it. It also doesn't say anything about Func() supporting methods (since it isn't intended to), but you could infer (not necessarily correctly) that since methods essentially are functions, it should work.
So the answer is:
  • The name of a method is not guaranteed to be "classx.methodx" (~=> there is no guaranteed name for a method)
  • Func() is not guaranteed to work with names of _methods_ (with names of functions defined inside of the class). Func() currently works with those names because of the current implementation, but that might change in the future.
///Update
Lexikos wrote:
If that is true, then it means that even functions defined _inside_ of the class definition are mainly _functions_
No, it doesn't...
Ok, it doesn't because of the 'base' keyword (which is initialized at the point the compiler reads the definition of the class) and because of A_ThisFunc, which is also initialized at the point the compiler reads the class) and because of other things possibly.
Note that, for methods, A_ThisFunc contains the name of the function given to the function at the time of _definition_ of the function. var_that_holds_class_object.key is not 'reevaluated' every time a new call to the function is made.

Code: Select all

class cx {
	chicken() {
		MsgBox, % A_ThisFunc
	}
}
cx.chicken()
	; cx.chicken
	; 

cy := Object()
cy.chicken := Func("cx.chicken")
cy.chicken()
	; cx.chicken, not cy.chicken
	; 
Lexikos wrote:
Whether it is _documented_ (~guaranteed), what the name of the function will be, depending on how that function was defined:
fn defined outside of the body of the class, as a 'function' -> name of the function guaranteed
fn defined outside of the body of the class, as a 'method' -> name of the function _not_ guaranteed
fn defined _inside_ of the body of the class ('as a method') -> name of the function _not_ guaranteed
You are overcomplicating, and making a distinction that is irrelevant. The reality is:
fn defined outside of the body of the class -> name of the function guaranteed
fn defined inside of the body of the class -> name of the function _not_ guaranteed
I agree that in this particular scenario, the distinction is irrelevant. After rethinking - what's probably wrong about this is the word 'defined' (as methods outside of the class can't 'explicitly' be defined outside of the class - after defining a _function_ I might later on adjoin that function to the key of the class object, but the 'base' keyword will still not have a special meaning in that function and thus that function is not a 'full-blown' method).
So actually this could be divided further - for a given function, that function might have the following properties:
  • whether the function is defined inside of the class or outside of the class
  • whether base keyword works
  • whether there is a key of the object and that key that references to a function
Some of those properties would exclude others. But lets leave analyzing them.

Lexikos wrote:
I've meant: for functions are that defined inside the class object (== for that particular subset of methods), saying "the name of the_function_ is not guaranteed" means exactly the same as saying "the name of the _method_ is not guaranteed". This is because in that particular case, the name of the function is _simultaneously_ the name of the method.
Fixed. My earlier point was that it doesn't make sense to state that "the name of x is the name of y" when that is very obviously implied by "x is y". I think that if you break the facts down into their logical components, it makes learning and remembering much easier.
Ok, thanks.
Lexikos wrote:
... why exclude those functions in the first place?
In a word, encapsulation. The method was defined inside a class; it belongs to that class, and should only be accessed through that class.
Ok.
Lexikos wrote:
a method is only sort of a 'temporary' state of the function.
For Func(), the important distinction is based on where the function is defined, and that is constant (never changes). Furthermore, functions defined inside a class are permanently associated with that class (as in, the actual object), for use with the base pseudo-keyword. This doesn't change even if you remove the function from the class, or remove the class itself (as in classname := "").
Right, the more I test it the more I find out that relying on the _name_ of the method (vs on the reference to the method) might lead to undesired results.

Here is a script that shows the difference between:
  • this.base
  • base
  • A_ThisFunc -> className, className.base
  • reference to the correct 'current' class object, [the reference] passed explicitly
inside of the body of the method.

Code: Select all

; Four ways to get the 'base' object of the method - each way produces different results in certain circumstances.
class c1 {
	cow() {
		MsgBox, % "c1.cow()"
	}
}
class c2 extends c1 {
	;chicken(currentClassRef := c2) {
	chicken(currentClassRef) {
		base.cow()		; c1.cow()
		this.base.cow()	; c4.cow()
		
		RegExMatch(A_ThisFunc, "^([^.]*)", fnName), fnName := fnName1
		%fnName%.base.cow()	; c1.cow()
			; changes on c2 := Object("base", <new_base>)
			; 
		currentClassRef.base.cow()	; c1.cow()
			; always correct
			; 
			; always have to be passed explicitly (at least currently)
			; 
	}
}
class c3 extends c2 {
	
}
class c4 extends c3 {
	cow() {
		MsgBox, % "c4.cow()"
	}
}
class c5 extends c4 {
	
}
c5.chicken(c2)
	; c1.cow()
	; c4.cow()
	; c1.cow()
	; c1.cow()







MsgBox, % "c2 := <new_object>"
; overwrite variable that holds the class object in which
; the method was defined - the name of the method still
; contains the [name of the variable of the] old class object.
; 
class d1 {
	cow() {
		MsgBox, % "d1.cow()"
	}
}
c2 := {base: d1}
	; c3.base -> object with chicken()
	; funName in chicken is still c2
	; c2.base now points to d1, not to c1
	; 
c5.chicken(c3.base)
	; c1.cow()
	; c4.cow()
	; d1.cow()
	; d1.cow() ; Update-20140110: should be c1.cow() here







MsgBox, % "Method moved to another class"
; erase the reference to the method from the old class and assign the method
; to the new class. 'base' in the method still points to the base of
; the old class object.
; 
; We move the method 'chicken' from c2 to e2.
; 
c2.chicken := ""
class e1 {
	cow() {
		MsgBox, % "e1.cow()"
	}
}
class e2 extends e1 {
	static dog := Func("c2.chicken")
		; the name of the function "c2.chicken" is still valid, even though
		; c2.chicken (note no quotes ~evaluate the expression)
		; doesn't contain the function anymore.
		; 
}
class e3 extends e2 {
	
}
class e4 extends e3 {
	cow() {
		MsgBox, % "e4.cow()"
	}
}
class e5 extends e4 {
	
}

e5.dog(e2)
	; c1.cow()
	; e4.cow()
	; d1.cow()
	; e1.cow()
Things that I've found out through the script:
  • base keyword doesn't have a special meaning if base is used in a function that is defined outside of the class and that is at some point attached through a reference to a key of the class object. If the attachment happens, base still means a local variable inside of that function.
    • OTOH note, that if I use the 'base' pseudo-keyword in the definition of the _method_, base retains its special meaning even if the method is called 'as the method of another class' (see the third part of the script above)
  • base pseudo-keyword in the definition of the method always points to the base object of the object which initially held the _definition_ of the method (object that the variable c2 holds initially). Note that this is different from the base object of the object which contains the reference to the method and 'upon which' that method was called in the chain of 'base' objects (object that the variable e2 holds) (could such a thing be defined as a separate built-in variable? / what would be the possible use of it).
  • there is a slight distinction between what I can call a method:
    • [1]a function that was defined either inside of outside of the class and was _later on_ referenced by a key of the object
      [1]a function that was _defined_ inside of the class and we don't care what happens later on with the function
    In case '1', the 'base' keyword might not work in all methods, but in case '2', the 'base' keyword always works (has the _special_ meaning). In general, we assume a method to be '2'.

tags: AdrianH, a_ThisFunc, aThisFunc.

20150312
Information in this post was initially based on this thread by AdrianH.
Last edited by trismarck on 12 Mar 2015, 09:43, edited 4 times in total.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot] and 374 guests