ByRef does not work for arrays which are class member

Discuss the future of the AutoHotkey language
Pchief123
Posts: 2
Joined: 06 Feb 2021, 04:10

ByRef does not work for arrays which are class member

Post by Pchief123 » 06 Feb 2021, 05:15

I'm using AutoHotkey_2.0-a123-e5801ee8, the latest version as of now.

Suppose there is a function:

Code: Select all

foo(ByRef a) {
	a := []
	a.Push("1")
	a.Push("2")
}
Passing a normal array to it gives the expected result:

Code: Select all

b := []
foo(b)
MsgBox b[1]   ; MsgBox'es 1
But if an array belonging to some class is provided, there's error:

Code: Select all

class bar {
	b := []
	__New() {
		foo(this.b)
		MsgBox this.b[1]   ; throws "Invalid index" exception
	}
}
d := bar.New()
MsgBox d.b[1]  ; again the same exception
by the way, foo(&a){...} does not work as indicated in https://www.autohotkey.com/boards/viewtopic.php?f=37&t=86283

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: ByRef does not work for arrays which are class member

Post by swagfag » 06 Feb 2021, 06:08

image.png
image.png (8.94 KiB) Viewed 2422 times
Pchief123 wrote:by the way, foo(&a){...} does not work as indicated in https://www.autohotkey.com/boards/viewtopic.php?f=37&t=86283
nor is it supposed to(unless ure running said special build but even then im not so sure)
that said, u can still push to an array assigned to an object's property, since objects are always subject to reference semantics, eg:

Code: Select all

foo(a) {
	; a := []
	a.Push("1")
	a.Push("2")
}

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: ByRef does not work for arrays which are class member

Post by lexikos » 10 Feb 2021, 04:50

It is not possible to pass properties of objects (such as foo.bar), A_Clipboard or other built-in variables to a function by reference. Instead, the function acts as though ByRef was omitted.
Source: Functions - Definition & Usage | AutoHotkey v2
A property is not a "variable". ByRef is for variable references, not values, not properties.

If you assign a := this.b, then both a and this.b contain a reference to "a normal array". It does not belong to either one. In fact, this is exactly how it is after you call foo(this.b); the function foo has an ordinary local variable named a which contains a reference to an array.

The array and the variable are two different things. See Variable References vs Values.


In the experimental build, foo(&a){...} is just the new foo(ByRef a){...}. It is the other changes which are interesting - allowing a variable reference to be turned into a value and used as one. For instance, if you assign this.b := &x, foo(this.b) is the same as foo(&x). But in that case, %this.b% is the same as x. It is still not suitable for mere indirect assignment to a property.

User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: ByRef does not work for arrays which are class member

Post by vvhitevvizard » 14 Mar 2021, 07:19

@lexikos please look at updated #37 paragraph.
Idea of object member (expression) to be passed to a function for indirect assignment as if it was a variable, making &obj.prop and &-77 (pure number), &"string" possible. AHK would alleviate this frequently mentioned issue by using a temporary variable secretly.

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: ByRef does not work for arrays which are class member

Post by lexikos » 14 Mar 2021, 22:17

It makes no sense to pass a reference to a constant value.

Opening the possibility of passing a reference to a property was one of the reasons I made the change, but it is not a priority for v2.0.

User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: ByRef does not work for arrays which are class member

Post by vvhitevvizard » 15 Mar 2021, 03:17

lexikos wrote:
14 Mar 2021, 22:17
It makes no sense to pass a reference to a constant value.
I beg to differ. Imagine a function requires a parameter to be a VarRef, yet we wanna ignore the function output and r bound to use &(expr) as a temporary holder only. Same case as "intP", 0 for dllcall that we touched upon yday.
Opening the possibility of passing a reference to a property was one of the reasons I made the change, but it is not a priority for v2.0.
I see. None the less, the proposed kludge in #37, granted that it's hassle free to implement, will do its work temporarily.

BTW, in the light of what has been done to byref "specificator", what do u think of replacing unset with * or ? shorthand, e.g.: param:=unset -> param:=?

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: ByRef does not work for arrays which are class member

Post by lexikos » 16 Mar 2021, 01:58

What you want is to pass something which is not a reference to a variable, to a parameter which is designed to take a reference to a variable. If the designer of the function (whether that's you or not) wants to allow either case, they should do it by handling VarRef explicitly. &param (currently) guarantees that the function does not execute if the parameter did not receive something it can assign to.

&param says a reference to a variable should be passed, whereas "intP" only says the address of an integer should be passed.

I changed ByRef to & because & is used when passing the variable - it is not just more convenient, but also allows declarations to be copy-pasted and then used as calls, and reminds the reader that they must use & when calling the function. There is no connection between unset and ?. You cannot evaluate an unset variable as boolean (e.g. with ternary).

User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: ByRef does not work for arrays which are class member

Post by vvhitevvizard » 16 Mar 2021, 02:28

There is no connection between unset and ?. You cannot evaluate an unset variable as boolean (e.g. with ternary).
@lexikos I didn't have in mind ternary operator ?: or any boolean related stuff. For example, the very same & symbol can be unary and binary operator, boolean and bit-wise depending on context for the sake of having a limited number of ASCII symbols to allot to.
What I mean is any suitable shorthand symbol (?, *, !, whatever) for unset "keyword": param:=*
What you want is to pass something which is not a reference to a variable, to a parameter which is designed to take a reference to a variable. (...)
Not quite that. Along with being compliant to the function's requirement and being shorthand, I want to use a temporary short-term life (just for the callee time line) variable w/o allocating any name to it within the caller's namespace. Yes, discarding any output to that var on purpose.

()=>expr creates an anonymous function's reference.
&(expr) could create a variable reference the same anonymous way. We might assign the reference to some variable function(ref:=&(expr)), otherwise the anonymously created variable would be discarded after the call.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: ByRef does not work for arrays which are class member

Post by iseahound » 28 Mar 2021, 01:05

vvhitevvizard wrote:
16 Mar 2021, 02:28
What I mean is any suitable shorthand symbol (?, *, !, whatever) for unset "keyword": param:=*
That probably deserves its own topic.

But writing f(p1, p2 := unset) => as f(p1, p2?) => would be nice

Post Reply

Return to “AutoHotkey Development”