 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
guiKey
Joined: 25 Nov 2006 Posts: 7
|
Posted: Sat Feb 03, 2007 8:13 am Post subject: Serious debug for StringSplit needed |
|
|
Consider function f(x) containing a StringSplit command.
Briefly, calling f(x) from different points in the script, StringSplit gives different results. When StringSplit doesn't work, arrays are left blank.
Loop, Parse command solves the problem.
(WinXP SP2, AutoHotkey 1.0.46.07)
Last edited by guiKey on Sat Feb 03, 2007 10:08 am; edited 2 times in total |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5887
|
Posted: Sat Feb 03, 2007 9:46 am Post subject: Re: Serious debug for StringSplit needed |
|
|
| guiKey wrote: | | Briefly, calling f(x) from different points in the script, StringSplit gives different results. When StringSplit doesn't work, arrays are left blank. |
If you use StringSplit inside a function, the elements of the pseudo-array will not be visible outside the function. To overcome this use global at the beginning of your function.
| Code: | StringSplit( "Arr", "The Quick Brown Fox", A_Space )
MsgBox, %Arr1%`n%Arr2%`n%Arr3%`n%Arr4%
StringSplit( OutputArray, InputVar, Delimiters="", Omitchars="" ) {
Global
StringSplit, %OutputArray%, InputVar, %Delimiters%, %OmitChars%
Return (%OutputArray%0)
} |
 |
|
| Back to top |
|
 |
guiKey
Joined: 25 Nov 2006 Posts: 7
|
Posted: Sat Feb 03, 2007 9:59 am Post subject: |
|
|
| It's not about variables scope. Talking about array processed locally inside f(x). Unbelievable for me too, but ListVars in certain cases gives blank values. Have you ever seen that? |
|
| Back to top |
|
 |
SKAN
Joined: 26 Dec 2005 Posts: 5887
|
Posted: Sat Feb 03, 2007 10:51 am Post subject: |
|
|
| Quote: | | Unbelievable for me too, but ListVars in certain cases gives blank values. Have you ever seen that? |
I have not used StringSplit much. It would help very much if you can post some code that can reproduce the effect.
 |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Sat Feb 03, 2007 2:39 pm Post subject: |
|
|
| Yes, it would help to see an example. The behavior or local vs. global arrays is often a source of confusion. |
|
| Back to top |
|
 |
KZ
Joined: 06 Feb 2007 Posts: 4
|
Posted: Sat Mar 17, 2007 9:45 pm Post subject: Re: Serious debug for StringSplit needed |
|
|
| guiKey wrote: | Consider function f(x) containing a StringSplit command.
Briefly, calling f(x) from different points in the script, StringSplit gives different results. When StringSplit doesn't work, arrays are left blank.
Loop, Parse command solves the problem.
(WinXP SP2, AutoHotkey 1.0.46.07) |
Don't know if this is related to the original post, but I've just
spent a few hours debugging a similar (same?) problem.
| Code: |
; KZ_BUG001.AHK -- Reporducer for StringSplit bug
GetEnvInfo() ; Works if called here
x := "var=123"
StringSplit,temp,x,=
MsgBox, %temp1% . %temp2%
; GetEnvInfo() ; Does not if called here
return
; Functions
GetEnvInfo() ; Get info
{
y := "var=456"
StringSplit,temp,y,=
MsgBox, %temp1% . %temp2%
return
}
|
I fixed the problem by using "junk" in the function (instead of "temp" twice), which shows I still have to learn about globals in AHK. I would really
like to use "temp" as I do in all other languages, ie, without worrying about the scope. |
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sat Mar 17, 2007 11:16 pm Post subject: |
|
|
I think I've found the specific problem here. Hope you don't mind a lot of examples, but it's easier than explaining it. First, observe this script that works correctly:
| Code: | f()
MsgBox main`n%temp1% %temp2%
return
f()
{
x = ab
StringSplit,temp,x
MsgBox f()`n%temp1% %temp2%
return
} |
Function f()'s MsgBox will show 'a b' and the global MsgBox will show nothing. This is expected, since the array should be created locally in f(). Now, how about this script?
| Code: | f()
MsgBox main`n%temp0% %temp1% %temp2%
return
f()
{
x = ab
StringSplit,temp,x
MsgBox f()`n%temp1% %temp2%
return
} |
In this one, f()'s MsgBox shows nothing, but unexpectedly, the global MsgBox shows the result of the StringSplit! When temp0 is referenced at global scope, but not at function scope, the array seems to be created globally, even if it's referenced after the function call. Here's a script that corrects the problem:
| Code: | f()
MsgBox main`n%temp0% %temp1% %temp2%
return
f()
{
x = ab
StringSplit,temp,x
MsgBox f()`n%temp0% %temp1% %temp2%
return
} |
Once again, it works correctly, apparently because temp0 is referenced locally in function f() as well as globally.
This could be related to this part of the function documentation:
| Documentation wrote: | | All variables referenced or created inside a function are local by default (except built-in variables such as Clipboard, ErrorLevel, and A_TimeIdle). |
However, the issue is clearly addressed later on in that same section:
| Documentation wrote: | | For commands that create arrays (such as StringSplit), the resulting array is local if the assume-global mode is not in effect or if the array's first element has been declared as a local variable (this is also true if one of the function's parameters is passed -- even if that parameter is ByRef -- because parameters are similar to local variables). Conversely, if the first element has been declared global, a global array is created. |
Since assume-global mode has not been specified, and temp0 hasn't been declared as global, the array should be local. AHK gets confused when temp0 is referenced globally, though, unless I'm missing another part of the docs that allows for that case.
By the way, this is the same thing that's happening in KZ's script, too. It's harder to tell, but temp0 is created globally when he does the StringSplit in the main thread. It must be different between creating and referencing, because my example script doesn't work even though the call is before the reference. In addition, it seems that StringSplit creating temp0 inside the function doesn't count as creating it locally. So, to summarize:- When temp0 is created globally before the function call or referenced globally anywhere, StringSplit violates the documented behavior and creates its array globally when 'global' hasn't been specified and temp0 hasn't been declared with 'global temp0'.
|
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2397
|
Posted: Sun Mar 18, 2007 4:01 am Post subject: |
|
|
Unless I'm misunderstanding the issue, I had reported a similar bug previously and the conclusion was that using MsgBox for debugging variable values is useless since the variables in the MsgBox lines will be declared as globals if they are referenced anywhere that is not in a function. Even if the line containing the MsgBox command is never executed if I remember correctly (it's been a while though... I might be mistaken...)...
Edit: Hmm... maybe I was thinking of this topic...
Edit: Typo. I should use a spell checker... |
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sun Mar 18, 2007 6:34 am Post subject: |
|
|
Fair enough, but it can still be produced the way KZ demonstrated, and by explicitly setting the variable before the call:
| Code: | temp0=1
f()
MsgBox main`n%temp1% %temp2%
return
f()
{
x = ab
StringSplit,temp,x
MsgBox f()`n%temp1% %temp2%
return
} |
|
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sun Mar 18, 2007 7:04 am Post subject: |
|
|
Aha. I suppose I missed this part:
| Documentation wrote: | | Note: any non-dynamic reference to a variable creates that variable the moment the script launches. For example, a reference to Array1 outside a function creates Array1 as a global the moment the script launches. Conversely, a reference to Array1 inside a function immediately creates it as a local. |
So, since StringSplit sees that temp0 is created, it makes the whole array global. It's documented behavior, and the solution is to reference or create temp0 inside the function. |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2397
|
Posted: Sun Mar 18, 2007 7:32 am Post subject: |
|
|
| That does seem to be a bug since the function seems to update the global variables instead of updating the variables when they are modified in the function. I've guessed this by viewing the variable contents and lines last executed using the AHK window for the script when both MsgBoxes appear. |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2397
|
Posted: Sun Mar 18, 2007 7:41 am Post subject: |
|
|
I understand what you are saying about the variables being considered global but the bug is the inconsistency. StringSplit and MsgBox inside the function should reference the same variables (unless I'm misunderstanding).
Edit: It's good that bugs are documented though ... I guess...
I would have expected that the StringSplit line should create a local variable from being referenced the same way that the MsgBox line seems to... |
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sun Mar 18, 2007 10:37 pm Post subject: |
|
|
Well, it's already clear that StringSplit creates a global array if temp0 is global, and a local array otherwise. That's certainly not a bug, it's expected and necessary behavior. The issue here is when temp0 is considered global.
In this case, since temp0 is taken as global, the array (including temp1 and temp2) are created globally, which is why StringSplit and MsgBox reference different variables. |
|
| Back to top |
|
 |
corrupt
Joined: 29 Dec 2004 Posts: 2397
|
Posted: Mon Mar 19, 2007 1:11 am Post subject: |
|
|
| jonny wrote: | | In this case, since temp0 is taken as global, the array (including temp1 and temp2) are created globally, which is why StringSplit and MsgBox reference different variables. | This is not logical though. The array in the StringSplit line is not a dynamic reference. Therefore it should create a local array the same way that the variables in MsgBox were created as locals. ...or the variable references in the MsgBox line should have referenced the global variables the same way the StringSplit line did. This is not consistent and it is a bad design to have 2 commands use 2 different methods.
The main reason I mentioned using MsgBox though is that it is the source of grief in this example also. The variables seem to be created as locals because they were referenced in the MsgBox line. Why is the StringSplit line immune to this but the MsgBox line isn't?
Here's an example to demonstrate: | Code: | temp0=1
f()
MsgBox main`n%temp1% %temp2%
return
f()
{
x = ab
t = temp
out = f()`n
StringSplit,temp,x
MsgBox % out . %t%1 . %t%2
return
} |
|
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Mon Mar 19, 2007 2:24 am Post subject: |
|
|
| corrupt wrote: | | jonny wrote: | | In this case, since temp0 is taken as global, the array (including temp1 and temp2) are created globally, which is why StringSplit and MsgBox reference different variables. | This is not logical though. The array in the StringSplit line is not a dynamic reference. Therefore it should create a local array the same way that the variables in MsgBox were created as locals. ...or the variable references in the MsgBox line should have referenced the global variables the same way the StringSplit line did. This is not consistent and it is a bad design to have 2 commands use 2 different methods. |
What's your fixation with MsgBox? It isn't relevant to the issue at all, regardless of what problems it may have. The only issue here (and it's already documented, even if it isn't ideal behavior) is that if temp0 is already a variable in global scope, StringSplit inside a function will create the array globally. This means any reference in global scope will cause it to function that way. So, how is MsgBox concerned with this?
Just to make it even clearer, here's an example without MsgBox's. The two relevant lines are highlighted.
| Code: | temp0=1
f()
ToolTip %temp1% %temp2%
Sleep 3000
return
f() {
x = ab
StringSplit,temp,x
ToolTip %temp1% %temp2%
Sleep 3000
return
} |
First tooltip shows nothing, second tooltip shows 'a b'. This proves that array 'temp' is created at global scope, due to temp0 being referenced. Remove the first line and the first tooltip outputs 'a b' with the second being blank. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|