#2713 closed Bug (Duplicate)
ByRef Copy Bug
Reported by: | anonymous | Owned by: | |
---|---|---|---|
Milestone: | Component: | AutoIt | |
Version: | 3.3.11.5 | Severity: | None |
Keywords: | byRef | Cc: |
Description (last modified by Mat)
In the following script, the presence of ByRef causes $b to be a reference, not a copy.
Local $a[2] = [1, 2] test($a[0]) Func test(ByRef $foo) Local $b = $a $foo += 1 ConsoleWrite($a[0] & @LF) ConsoleWrite($b[0] & @LF) EndFunc ;==>test
Attachments (0)
Change History (11)
comment:1 follow-up: ↓ 2 Changed 11 years ago by Mat
- Description modified (diff)
comment:2 in reply to: ↑ 1 Changed 11 years ago by anonymous
Replying to Mat:
This has been discussed
Was there an outcome of the discussion? Is it a language feature?
comment:3 follow-up: ↓ 4 Changed 11 years ago by Mat
The discussion was only among the MVPs, the developers have not yet commented. The majority of the conversation was about what actually caused the behaviour you were seeing.
If by "language feature" you are asking whether you should rely on this behaviour in code, you definitely shouldn't. There are better ways to write your original code that avoid this issue.
As to whether it's a bug, I don't know. I'd be inclined to say yes, other MVPs thought it wasn't though, so we'll leave it to Jon to decide.
comment:4 in reply to: ↑ 3 ; follow-up: ↓ 5 Changed 11 years ago by anonymous
Replying to Mat:
The discussion was only among the MVPs, the developers have not yet commented. The majority of the conversation was about what actually caused the behaviour you were seeing.
Is this connected to ticket 2502?
If by "language feature" you are asking whether you should rely on this behaviour in code, you definitely shouldn't. There are better ways to write your original code that avoid this issue.
I may not even know that the argument is an element of the copied array (or object).
comment:5 in reply to: ↑ 4 ; follow-up: ↓ 6 Changed 11 years ago by Mat
- Resolution set to Duplicate
- Status changed from new to closed
Replying to anonymous:
Is this connected to ticket 2502?
Yes it is. I hadn't realised this had been looked at before (but it looks like the conclusion was similar (variable != r-value, and byref might use either, or might not). I'll close this as a duplicate.
If you want to guard against this, then just force it to copy by writing to the array:
Local $a[2] = [1, 2] test($a[0]) Func test(ByRef $foo) Local $b = $a $b[0] = $b[0] ; Force COW $foo += 1 ConsoleWrite($a[0] & @LF) ConsoleWrite($b[0] & @LF) EndFunc ;==>test
comment:6 in reply to: ↑ 5 Changed 11 years ago by anonymous
Replying to Mat:
If you want to guard against this, then just force it to copy by writing to the array
That's an ugly hack. Should I do this every time I copy a variable that might be an array, if the function has a ByRef argument (like $instance, the class generator creates countless arguments)?
comment:7 follow-up: ↓ 8 Changed 11 years ago by Melba23
In my testing the problem only arises when you pass a single element of an array ByRef - passing the entire array produces what would be expected, regardless of whether the copy array is taken from the original or the passed array:
Global $a[2] = [1, 2] test1($a) test2($a[0]) test3($a) ; Entire array passed Func test1(ByRef $foo) Local $b = $a ; $a is Global $foo[0] += 1 ConsoleWrite("Should be 2 : " & $a[0] & @CRLF) ConsoleWrite("Should be 1 : " & $b[0] & @CRLF) ConsoleWrite(@CRLF) EndFunc ;==>test1 ; Single array element passed Func test2(ByRef $foo) Local $b = $a $foo += 1 ConsoleWrite("Should be 3 : " & $a[0] & @CRLF) ConsoleWrite("Should be 1 : " & $b[0] & @CRLF) ; Error here ConsoleWrite(@CRLF) EndFunc ;==>test2 ; Entire array passed Func test3(ByRef $foo) Local $b = $foo ; $foo is $a passed ByRef $foo[0] += 1 ConsoleWrite("Should be 4 : " & $a[0] & @CRLF) ConsoleWrite("Should be 3 : " & $b[0] & @CRLF) EndFunc ;==>test3
The comment:
Should I do this every time I copy a variable that might be an array
is nonsense as passing an array does not produce the error. You can only pass an array element by using the [ # ] syntax, so you have an easy check on whether the problem will appear and can take measures to deal with it.
Better still - pass the entire array rather then a single element and then the problem will never arise.
M23
comment:8 in reply to: ↑ 7 Changed 11 years ago by anonymous
Replying to Melba23:
The comment:
Should I do this every time I copy a variable that might be an array
is nonsense as passing an array does not produce the error.
[...]
Better still - pass the entire array rather then a single element and then the problem will never arise.
It doesn't matter that the ByRef argument might be an array. Also, the following does exhibit the problem:
Local $instance = [1] Local $array = [$instance, 2] test ($array [0], $array) Func test (ByRef $first, $arr) Local $copy = $arr $first [0] = 3 ; "3 3", should be "1 3" ConsoleWrite (($copy [0]) [0] & " " & ($arr [0]) [0] & @CRLF) EndFunc
You can only pass an array element by using the [ # ] syntax, so you have an easy check on whether the problem will appear and can take measures to deal with it.
I don't know if the function will be called with a reference to a "normal" variable or an "unnatural" array element. It's required that the argument is a reference, I need to modify it. The function also copies another argument (which may be an array). There are some possible solutions:
- Duplicate the function and every function that forwards these two arguments: One version for "normal" variables and one version for "unnatural" array elements. If the other argument is an array, the second version forces AutoIt to copy the array, if the other argument really is an array. Then I will just need to call the adjusted function, if I use an "unnatural" array element.
- Like the first with additional arguments indicating the kind of referenced object.
- I could wrap the other argument to that function (and any other function like that) with a function like "identity" that simply returns the passed value when using an "unnatural" array element.
- I could ensure that any copy of the other argument is a real copy, if that argument is an array. Again, I might use "identity".
The first three are inacceptable, they would require the caller to do something which should be done automatically and reliably (by the interpreter), without needing to examine every single array access. The last two actually copy the other argument if it is an array, even when the copied array never contains the referenced object.
comment:9 Changed 11 years ago by Melba23
I am sure it is possible to come up with a myriad scenarios where the interpreter does not do what someone thinks it should - just remember this is a free-to-use hobbyist language and you cannot expect perfection. Anyway, I am not getting into discussions in Trac - there is an open ticket which may, or may not, get fixed (it would not be high on my list for the next round of development work). Now you realise that the problem exists, I suggest you recast your code to get around it. :)
M23
comment:10 Changed 11 years ago by mLipok
Personally, I'm glad I know that.
It is always better to know.
Thanks for the info.
comment:11 Changed 9 years ago by not so anonymous
ConsoleWrite("Should be 1 : " & $b[0] & @CRLF) ; Error here
Yep. Someone forgot, while writing that, that test1($a) has actually changes $a[0] from a 1 to a 2.
O wait, this is not the ByRef issue I'm looking for.
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
This has been discussed here: http://www.autoitscript.com/forum/topic/161296-supposed-byref-bug/ (Link is to MVP section)
I've changed the code in the report to be much simpler, without the OPs attempt to write object oriented AutoIt without objects.