Returning Variable Value

LiveCode is the premier environment for creating multi-platform solutions for all major operating systems - Windows, Mac OS X, Linux, the Web, Server environments and Mobile platforms. Brand new to LiveCode? Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
bjb007
Posts: 313
Joined: Fri Dec 28, 2007 4:56 am

Returning Variable Value

Post by bjb007 » Wed Sep 10, 2008 4:00 pm

I've spent a couple of days trying to figure
out how to preserve the value of a variable
cCount which I want to use in the following
code.

dString is like this -
3,1,2,1,3,3,3,3,3,2,2,1,3,1,2,2,1,1,3

Want to code to:

Get item 1 (3 in this case) and look for first
occurrence of either of the other two numbers
(1 and 2 in this case).

Item 2 is 1 so this cycle is done.

The next number to consider is item 3 (2) and
look for next 1 or 3. Item 4 is 1 so second cycle done.

Next number to consider is item 5 (3) so will look for 1 or 2.

Neither 1 nor 2 will be found by look1 so go to look2
and so on (up to look5 if necessary) which returns "Failed".

Most of this works but I haven't been able to figure out
a way to return vCount to the repeat loop in the mouseUp
handler so that the next item use is the one after the last
one found e.g. last found at item 10 so want to use
item 11 for next search.

Using a variable for the value of i and incrementing it works
while going down but on the way back (up) at the mouseUp
handler the value is lost for some reason.

Have tried using "return vCount" and a few other things
without success.

Code: Select all

pseudo-code...
----------------------
on mouseUp

put 1 into vCount

repeat with i = vCount to number of items in dString
  get look1(vCount)
end repeat

end mouseUp
----------------------
function look1 vCount

if item vCount+1 of dString = item vCount of dString then
  ...
  add 1 to vCount 
  exit look1
else
 add 1 to vCount --- = 2
 get look2(vCount)
 exit look1
end if

end look1
---------------------
function look2 vCount

if item i + 2 of dString = item i of dString then
  ...do things
  add 1 to vCount --- = 3
  exit look2
else
  add 1 to vCount
  get look3(vCount)
  exit look2 
end if

end look2
---------------------
function look3 vCount

if item i + 3 of dString = item i of dString then
  ...do things
  add 1 to vCount
  exit look3
else
 add 1 to vCount
 get look4(vCount)
 exit look3
end if

end look3
---------------------
function look4 vCount

if item i + 4 of dString = item i of dString then
  ...do things
  add 1 to vCount
  exit look4
else
  add 1 to vCount
  get look5(vCount)
  exit look4
end if

end look4
---------------------
function look5 vCount

if item i + 5 of dString = item i of dString then
  ...do things
  add 1 to vCount
  exit look5
else
  add 1 to vCount
  exit look5
end if

end look5      

Probably haven't explained this very well
but any ideas appreciated. Only other thing
to add is that the mysterious system variable "it"
seems to increment sometimes but haven't
tried using it since I don't know what its value
represents.
Life is just a bowl of cherries.

BvG
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 1239
Joined: Sat Apr 08, 2006 1:10 pm
Contact:

Post by BvG » Wed Sep 10, 2008 7:01 pm

I am not sure I understand your explanation, it's hard to distinguish between item numbers and numbers in your example data. Why don't you try to make an example with chars in the data (a,b,c)?

Said that, this is what I guess:
  • You want to repeat over data
  • Your data contains three different entries (1,2,3), in a unknown order
  • You want to perform some action whenever a condition is met
  • The condition is true when you find a data item that is different from the last data item (For example, last item was "1", now find "2" or "3")
  • After five tries without finding "1", you want to abort with a failure
based on the guess, I suggest this code (untested):

Code: Select all

on mouseUp
  put item 1 of dString into prevItem
  put 0 into failedCounter
  repeat for each item theItem in item 2 to -1 of dString
    if failedCounter >= 5 then
      --do your failure handling here
      exit repeat
    end if
    if prevItem <> theItem then
      --do your action here
      put theItem into prevItem
      if theItem = 1 then
        put 1 into failedCounter --maybe should be 0?
      else
        add one to failedCounter
      end if
    end if
  end repeat
end mouseUp
Various teststacks and stuff:
http://bjoernke.com

Chat with other RunRev developers:
chat.freenode.net:6666 #livecode

BvG
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 1239
Joined: Sat Apr 08, 2006 1:10 pm
Contact:

Post by BvG » Wed Sep 10, 2008 7:09 pm

Oh, as for preserving Vars between handlers, there's lots of things you can do, so I won't go into too much depth for each (read them up in the pdf that Rev has as documentation). They're ordered in the frequency I normally chose them (most used to least used).
  1. Use a script local variable
  2. Use functions and pass data from them using "return"
  3. Use a custom property
  4. Use a global variable
  5. Use a handler and pass data using "return" via "the result"
Note that 2 and 5 are mostly the same thing, and 1 and 4 are similar too.
Various teststacks and stuff:
http://bjoernke.com

Chat with other RunRev developers:
chat.freenode.net:6666 #livecode

bangkok
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 937
Joined: Fri Aug 15, 2008 7:15 am

Post by bangkok » Wed Sep 10, 2008 9:05 pm

BvG wrote:Oh, as for preserving Vars between handlers, there's lots of things you can do, so I won't go into too much depth for each (read them up in the pdf that Rev has as documentation). They're ordered in the frequency I normally chose them (most used to least used).
  1. Use a script local variable
  2. Use functions and pass data from them using "return"
  3. Use a custom property
  4. Use a global variable
  5. Use a handler and pass data using "return" via "the result"
.
The question asked is way beyond my skills ... but from an intellectual point of view could we say that using invisible fields... is a sixth way for preserving vars between handlers ?

Furthermore, you say that globals are almost at the bottom of the list.

If I remember my Hypercard times... globals had like bad reputation. It was considered I don't know, like dirty or missy, or too easy (compared to a function returning datas for instance), am I right ?

Why ?

I mean with a Macintosh with 512 Ko of Ram, it was maybe justified. But nowadays ? With the memory orgy we have ? :D

Could you share your opinion on this question ? (sorry to hijack BJB's thread )

TEDennis
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 41
Joined: Tue Apr 11, 2006 12:36 am

Post by TEDennis » Wed Sep 10, 2008 10:37 pm

Try this for a more generic approach. Note that I added a final "1,0" to cause the error condition. It looks better without the testing code, but it's there for you to verify the solution.

Code: Select all

constant cItems = "3,1,2,1,3,3,3,3,3,2,2,1,3,1,2,2,1,1,3,1,0"

on mouseUp
   set the itemDelimiter to comma
   -- Build array of allowable values
   put empty into tArray
   put "2,3" into tArray["1"]
   put "1,3" into tArray["2"]
   put "1,2"  into tArray["3"]
   put 1 into tOffset
   put (number of items in cItems) into tOffsetMax
   put empty into tTesting -- Create empty string for test purposes
   repeat while tOffset < tOffsetMax
      -- Set up current key and maximum length string to search
      put item tOffset of cItems into tKey
      put item (tOffset + 1) to (tOffset + 5) of cItems into tItems
      -- Set up lookup values
      put tArray[tKey] into tValues
      -- Determine offset of both lookup values
      put itemOffset(item 1 of tValues, tItems) into tOffset1
      put itemOffset(item 2 of tValues, tItems) into tOffset2
      switch 
         case ((tOffset1 = 0) and (tOffset2 = 0))
            -- Do error case
            put cr & "ERROR" && tOffset && item tOffset of cItems after tTesting -- Testing
            -- Exit repeat loop
            put tOffsetMax into tOffsetFound
         break
            -- At least one of the two tValues was found
         case (tOffset1 = 0) -- First of tValues not found
            put tOffset2 into tOffsetFound
            -- Do case where return value = second of tValues 
            put cr & "2nd" && tOffset && item tOffset of cItems && item (tOffset + tOffsetFound) of cItems after tTesting -- Testing
         break
         case (tOffset2 = 0) -- Second of tValues not found
            put tOffset1 into tOffsetFound
            -- Do  case where return value = first of tValues
            put cr & "1st" && tOffset && item tOffset of cItems && item (tOffset + tOffsetFound) of cItems after tTesting -- Testing
         break
         case (tOffset1 < tOffset2) -- First of tValues was found before second of tValues
            put tOffset1 into tOffsetFound
            -- Do case where return value = first of tValues
            put cr & "1st" && tOffset && item tOffset of cItems && item (tOffset + tOffsetFound) of cItems after tTesting -- Testing
         break
         default
            put tOffset2 into tOffsetFound
            -- Do case where return value = second of tValues
            put cr & "2nd" && tOffset && item tOffset of cItems && item (tOffset + tOffsetFound) of cItems after tTesting -- Testing
      end switch
      put (tOffset + tOffsetFound + 1) into tOffset
   end repeat
   put tTesting
end mouseUp

bjb007
Posts: 313
Joined: Fri Dec 28, 2007 4:56 am

Returning Variable Value

Post by bjb007 » Wed Sep 10, 2008 11:59 pm

Thanks to all who replied.

I didn't put in the code sample that
I made vCount a global.

Also need to be able to do different
calculations depending on which
step finds the required number which
is why I separated them into look1,look2 etc.
and to make the code understandable
to myself.

From the suggested methods I've tried

2. Use functions and pass data from them using "return"
4. Use a global variable

and a few variations thereof but the result is
always that vCount doesn't keep the value
from look1 etc. when it returns to the
"repeat with" loop - which is something that
I expected a global to do.

Will take a while to try your suggestions.
Life is just a bowl of cherries.

bjb007
Posts: 313
Joined: Fri Dec 28, 2007 4:56 am

Returning Variable Value

Post by bjb007 » Thu Sep 11, 2008 2:19 am

I've changed the string to use A,B and C
as suggested and posted my test stack as
"Passing Variables" in Rev Online under
user bjb007
Life is just a bowl of cherries.

bjb007
Posts: 313
Joined: Fri Dec 28, 2007 4:56 am

Returning Variable Value

Post by bjb007 » Thu Sep 11, 2008 8:22 am

I've been trying to find a clue as to why
the declared global doesn't retain a value
which seems to me to be the purpose of
a global variable.

The docs say:
* If you declare a global command in a script, but outside any handlers in the script, the global can be used by any handler that comes
after the global declaration in that script. You don't need to declare such a global again in the handler itself.
So perhaps functions aren't included in the
scope of a global unless the definition of a
"handler" includes functions.

Anyone have the official definition of a "handler"?
Life is just a bowl of cherries.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Post by bn » Thu Sep 11, 2008 1:07 pm

hi bjb007,

I changed your script a little:
you might want to make a new button in your stack and compare
some of the problems came from using vCount as a global variable and at the same time as a parameter, Rev treated the parameter differently and hence the value 1 in the mouseUp handler

Once you declare the variable as global, you dont have to send it as a parameter. Same goes for function, in your case you dont need a function so I changed that to a command, the command has access to the global variable.

I tried to stick to your original script so it is easier for you to see the difference. I am not shure that the script does exactly what you want but it should get you started and you can use the structure to adapt the script.

Code: Select all

--> all handlers
 
----Code
-- dont global i, if you inadvertently use i in another handler
--  you confuse your increment counter i to no end bn
-- global i,theString,vCount -- bn
global theString,vCount
global lookFor1,lookFor2
------------------------------------------------------
on mouseUp
    
    send "mouseUp" to button "btnClear"
    put 1 into vCount
    put field fldtheString into theString --- testing only
    
    repeat with i = vCount to number of items in theString
        put item vCount of theString into field fldItemv
        put vCount into field fldvCount0
        look1
        
        -- you advance vCount as a counter but you have i = 1 to x as another counter
        -- you just want to check the number of items in theString so exit the repeat loop bn
        if vCount > the number of items of theString then exit repeat
        ---------
        wait 150 milliseconds  -- to make changes visible, delete later
        ---------
    end repeat
    
end mouseup
--------------------------------------------------------
on look1
    
    put item vCount of theString into field fldItemv
    add 1 to vCount ---item 2
    if item vCount of theString = A then
        --find next B or C
        --   if item vCount of theString = B or item vCount of theString = C then -- your original code bn
        if item vCount + 1 of theString = B or item vCount of theString = C then
            add 1 to vCount  --used items 1 & 2 so next test on item 3
            put vCount into field fldvCount1
            
            ---exit look1
        else
            add 1 to vCount ---not found in item 2 so try item 3
            put vCount into field fldvCount1
             
            put B into lookFor1
            put C into lookFor2
            look2
            
            ---exit look1
        end if
         
    end if
    
    if item vCount of theString = B then
        ---put it into field fldit1
        --find next A or C
        put vCount into field fldvCount1
        if item vCount+1 of theString = A or item vCount+1 of theString = C then
            add 2 to vCount
            put item vCount of theString into field fldItemv
            put vCount into field fldvCount1 ---should be 3
            
            ---exit look1
        else
            add 1 to vCount
            put vCount into field fldvCount1
            put vCount into field fldvCount1
            put A into lookFor1
            put C into lookFor2
            look2
            
            ----exit look2
        end if
    end if
    
    if item vCount of theString = C then
        put it into field fldit1
        --find next A or B
        put vCount into field fldvCount1
        if item vCount+1 of theString = A or item vCount+1 of theString = B then
            add 1 to vCount
            put item vCount of theString into field fldItemv --should be 3
            put vCount into field fldvCount1
            ---exit look1
        else
            put vCount into field fldvCount1
            add 1 to vCount
            put A into lookFor1
            put B into lookFor2
            look2
             
            ---exit look1
        end if
    end if
    
    if item vCount of theString = 0 then
        add 1 to vCount
        
    end if
    
end look1
---------------------------------------------------
on look2
    
    put item vCount of theString into field fldItemv
    --find next x or x
    ---put it into field fldit2
    put vCount into field fldvCount2
    if item vCount of theString = lookFor1 or item vCount of theString = lookFor2 then
        add 1 to vCount
        put vCount into field fldvCount2
        ---return vCount
        -- exit look2 -- no need to exit because of the if clause bn
    else
        ---put vCount into field fldvCount2
        add 1 to vCount
        put vCount into field fldvCount3
         
        --get look3(vCount)
    end if
     
end look2
----------------------------------------------------
good luck

Bernd

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Post by bn » Thu Sep 11, 2008 2:15 pm

Hi bjb007,

some remarks regarding local, global variables and custom properties
everybody develops his own coding style eventually

for all persistent variables dont forget to initialise them i.e. give them an initial value that you control, even if it may seem to be redundant (of course not, when you reuse the actual value). It has happened to me often that I forgot that and had a hard time to debug the script. In my experience especially true for global variables, this is the main reason I avoid them.

I prefer local variables when it is only one script with as many handlers as you wish to use a persistent variable. Like in

Code: Select all

local tCounter
on mouseUp
    add 1 to tCounter
    put tCounter
end mouseUp
Whenever you start a stack tCounter is empty and then it increments 1 for every mouseUp. If you make two buttons with the same script tCounter stays with each script and you have two different increments.
If you do the same with two button but use a global variable as in

Code: Select all

global tCounter
on mouseUp
     add 1 to tCounter
     put tCounter
end mouseUp
you increment tCounter by 1 for every mouseUp regardless of the button you click.
If you want variable that is persistent between restarts of the stack then use a custom property. Every object in Rev can have a custom property. You create a custom property by putting something into it. Again two buttons. The syntax is a little different.

Code: Select all

on mouseUp
    set the cpCounter of this stack to the cpCounter of this stack + 1
    put the cpCounter of this stack
end mouseUp
I called it cpCounter to remind me that it is a custom property, you choose the name you want.
now after restarting your stack after saving it first you will find the last value of the cpCounter and add to it. Just remember that you have to code: set the xxx of xxx to x instead of put x into y
You can see the custom properties and their values of an object in the inspector, just look for custom properties.
I dont put variables into fields for temporary storage since it slows things down.

FWIW

cheers

Bernd

bjb007
Posts: 313
Joined: Fri Dec 28, 2007 4:56 am

Returning Variable Value

Post by bjb007 » Fri Sep 12, 2008 12:47 am

Bernd

Really appreciate you taking the time
to help me with this.

It's usually something simple that trips
me up - as in this case.
Life is just a bowl of cherries.

bjb007
Posts: 313
Joined: Fri Dec 28, 2007 4:56 am

Returning Variable Value

Post by bjb007 » Fri Sep 12, 2008 3:12 am

Been looking at the "on" control structure
which I haven't used (or seen referred to)
before.

As this was only added to Rev 2.8.1 I guess
I'm not the only one who hasn't come across
it.

Makes me wonder if I would have been able
to do what I want to do with Rev prior to 2.8.1.

Still can't understand the workings of the Rev
"global" which doesn't seem to work the
way it does in other languages.
Life is just a bowl of cherries.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Post by bn » Fri Sep 12, 2008 10:34 am

Hi bjb007,

look up custom command in the pdf 'Revolution User guide' that comes with Rev.

Commands or as you put it "on" control structure is as old as Rev, actually it is as old as Hypercard. Other envirionments might call it subroutine or something like that. It is very useful, actually the work horses of Rev. Usually they just do something and dont return a value as functions do. However the way the commands are used in your example the line between function and command is a little blurred since you have the globals and instead of returning a value like in a function you set global variables that you access from the calling command handler.

Regarding global variables: The main advantage is that they are persistent and can (after beeing declared in a script) be accessed from any handler of any stack that is currently open. That to me is also its disatvantage, you have to be careful which handler in which script writes to the global.



regards

Bernd

Post Reply