 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Laszlo
Joined: 14 Feb 2005 Posts: 4012 Location: Pittsburgh
|
Posted: Sat Mar 03, 2007 8:20 pm Post subject: Recursive function with ternary operator |
|
|
The two functions below should return the same value ("y"), but they don't. | Code: | MsgBox % f("xy") ; y
MsgBox % g("xy") ; x
f(x) {
IfEqual x,, Return
z := f(SubStr(x,2,1))
Return z = "" ? SubStr(x,1,1) : z
}
g(x) {
IfEqual x,, Return
Return (z := g(SubStr(x,2,1))) = "" ? SubStr(x,1,1) : z
} |
|
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sat Mar 03, 2007 8:38 pm Post subject: |
|
|
I'm not sure exactly why, but they both return the same value if z starts out non-blank:
| Code: | z=5
MsgBox % f("xy")
MsgBox % g("xy")
f(x) {
global z
If x =
return
z := f(SubStr(x,2,1))
Return z = "" ? SubStr(x,1,1) : z
}
g(x) {
global z
If x =
return
Return (z := g(SubStr(x,2,1))) = "" ? SubStr(x,1,1) : z
} |
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4012 Location: Pittsburgh
|
Posted: Sat Mar 03, 2007 8:44 pm Post subject: |
|
|
| It is important that z was local, because it gets changed in the recursive calls, and we need the value in the current level, not the last assigned value (global). However, jonny's observation shows that the bug can be related to the handling of local variables. |
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sat Mar 03, 2007 8:50 pm Post subject: |
|
|
| It shouldn't matter if z is being assigned after the recursive call, which it is in both versions. The problem could lie in the true/false expressions being evaluated before the conditional expression in the ternary operator, which would explain the first script working (where the assignment takes place before the whole expression), but not the second one. |
|
| Back to top |
|
 |
jonny
Joined: 13 Nov 2004 Posts: 3004 Location: Minnesota
|
Posted: Sat Mar 03, 2007 8:52 pm Post subject: |
|
|
Hmm, never mind, that can't be it:
| Documentation wrote: | | To enhance performance, only the winning branch is evaluated (see short-circuit evaluation). |
|
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4012 Location: Pittsburgh
|
Posted: Sat Mar 03, 2007 9:05 pm Post subject: |
|
|
| jonny wrote: | | It shouldn't matter if z is being assigned after the recursive call | True. The example I posted was simplified until the problem remained. The bug cost me many hours of debugging in Monster, where there are more than one recursive calls, messing up z, if it was not local. |
|
| Back to top |
|
 |
Joy2DWorld
Joined: 04 Dec 2006 Posts: 422 Location: Galil, Israel
|
Posted: Sun Mar 04, 2007 3:54 am Post subject: |
|
|
well,
the issue is not strictly with the recursion,
it relates instead to the VALUATION of the ASSIGNMENT (:=)
eg
| Code: | g(x) {
IfEqual x,, Return ""
z = ok
Return ( (g(SubStr(x,2,1))) = "" ) ? SubStr(x,1,1) : z
} |
works great.
ie.
| Code: | g(x) {
IfEqual x,, Return ""
static v
if !v
v = 0
v++
tooltip % v " - " x
z = ok
Return ( (mx := g(SubStr(x,2,1))) = "" ) ? SubStr(x,1,1) : z
} |
or, ie. the issue is in the evaluation of := and not with Ternary operators as such...
eg:
| Code: | g(x) {
IfEqual x,, Return ""
static v
if !v
v = 0
v++
tooltip % v " - " x
if (z := g(SubStr(x,2,1))) = ""
return SubStr(x,1,1)
else
return z
} |
which produces the same x result and uses an IF, not a Ternary operator.
| Quote: | If an assignment is used as the input for some other operator, its value is the variable itself. For example, the expression (Var+=2) > 50 is true if the newly-increased value in Var is greater than 50. This also allows an assignment to be passed ByRef, or its address taken; for example: &(x:="abc").
|
seems like is the breaking point... with the recursed function..
eg:
| Code: | g(x) {
IfEqual x,, Return ""
static v
if !v
v = 0
v++
tooltip % v " - " x
z := "w"
if (z := g(SubStr(x,2,1))) = ""
return SubStr(x,1,1)
else
return z
} |
breaks, whereas
| Code: | g(x) {
IfEqual x,, Return ""
static v
if !v
v = 0
v++
tooltip % v " - " x
if (z := f(SubStr(x,2,1))) = ""
return SubStr(x,1,1)
else
return z
} |
works...
ie. Z is not being properly assigned from within an operator ( ) where Z is assigned from a recursed function...
hope this helps.
as can be seen here:
| Code: | g(x) {
IfEqual x,, Return ""
static v
if !v
v = 0
v++
;tooltip % v " - " x
fsee := (z := g(SubStr(x,2,1)))
if (z) = "" {
tooltip % z " is z"
return SubStr(x,1,1)
} else
return z
} |
_________________ Joyce Jamce |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4012 Location: Pittsburgh
|
Posted: Sun Mar 04, 2007 6:26 am Post subject: |
|
|
I can confirm, Joy2DWorld is right. Thanks!
Here are some little shorter scripts for demo.
(1) The problem is not the ternary operator. The following, functionally equivalent code fails, too. | Code: | g(x) {
IfEqual x,, Return
If ((z := g(SubStr(x,2,1))) = "")
Return SubStr(x,1,1)
Else Return z
} | It is the same with automatic increase of precedence: | Code: | | If ("" = z := g(SubStr(x,2,1))) |
The assignment inside an if (..) statement fails, regardless of its role (dummy): | Code: | g(x) {
IfEqual x,, Return
If (z := g(SubStr(x,2,1)))
MsgBox NEVER
Return z = "" ? SubStr(x,1,1) : z
} |
(2) Assignments only to a recursive function fails inside an "if (..)" or ternary op. Assigning a local variable (y) works OK, like a non-recursive function: | Code: | g(x) {
IfEqual x,, Return
y := g(SubStr(x,2,1))
Return (z := SubStr(y,1))) = "" ? SubStr(x,1,1) : z
} |
The final values of the variables can be shown in the tray tip | Code: | g(x) {
IfEqual x,, Return
y := (z := g(SubStr(x,2,1))) = "" ? SubStr(x,1,1) : z
TrayTip,,[%x%] - [%y%] - [%z%]
Return y
} | TrayTip: [xy] – [x] – []
The final values when the function works: | Code: | g(x) {
IfEqual x,, Return
z := g(SubStr(x,2,1))
y := z = "" ? SubStr(x,1,1) : z
TrayTip,,[%x%] - [%y%] - [%z%]
Return y
} | TrayTip: [xy] – [y] – [y] |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Sun Mar 04, 2007 10:30 pm Post subject: |
|
|
I believe this has been fixed in today's 1.0.46.09; but please let me know if you have any more problems with it.
This was actually broken by the following optimization in 1.0.46.06: "Improved performance when assigning large strings returned from user-defined functions." That optimization is still present but it no longer applies when the result of a recursive function-call is assigned to one of that function's own local variables.
Thanks for the detailed analysis; it made fixing this easier. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4012 Location: Pittsburgh
|
Posted: Sun Mar 04, 2007 11:35 pm Post subject: |
|
|
| Yes, it is fixed in AHK 1.0.46.09. -Thanks, Chris! |
|
| 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
|