Page 1 of 2
SWAP
Posted: Sun Nov 22, 2009 5:42 pm
by ukimiku
I'd really appreciate if RevTalk could provide a SWAP command:
for any sort of a,b. The use of a temporary variable each time appears cumbersome and is error-prone.
Regards
Re: SWAP
Posted: Sun Nov 22, 2009 6:14 pm
by BvG
I have no clue what swap might do. I guess you want to put the variables into each other so that "a" contains what "b" contained and vice versa.
for that, there is no existing single line way. But then, if you swap them with each other, why not continue to use the the existing variables? What real world task would such a "swap" operation _need_? I'm really not against (or for) your proposal, just curious because I never had the need for that?
Posted: Sun Nov 22, 2009 8:51 pm
by ukimiku
Real-world application are typically specialized sorting routines where elements get "swapped" (the contents of a becomes the contents of b and vice versa, but you cannot write someting like
since as soon as the interpreter executes the first line, the original contents of b is overwritten. The typical solution is to use a temporary variable to hold one of the contents before the swap takes place, e.g.
Code: Select all
put a into temp
put b into a
put temp into b
which
is needlessly cumbersome. How about only writing
and you're done.
In my case, I wrote an implementation of the Blowfish algorithm. In it, many contents exchanges take place, and the above method (which is called very often, so it takes up a significant amount of time, too) makes the code not only slower and more cumbersome, but also harder to read than just
Other languages have it too. Programming without SWAPI find equally unnverving as programming nested conditionals without ELSEIF.
Hoping to shed some light on the swappin' business...
Regards,
Re:
Posted: Sun Nov 22, 2009 9:50 pm
by sturgis
Can't help with the swap, but what do you mean programming without elseif? If you're referring to runrev it works fine, it's else if not elseif, but same difference.
The following works just fine. Silly example I admit
Code: Select all
on mouseUp
put random(5) into theTest
if theTest = 1 then
put "1" && theTest
else if theTest = 2 then
put "2" && theTest
else if theTest = 3 then
put "3" && theTest
else if theTest = 4 then
put "4" && thetest
else
put "5" && theTest
end if
end mouseUp
ukimiku wrote:Real-world application are typically specialized sorting routines where elements get "swapped" (the contents of a becomes the contents of b and vice versa, but you cannot write someting like
since as soon as the interpreter executes the first line, the original contents of b is overwritten. The typical solution is to use a temporary variable to hold one of the contents before the swap takes place, e.g.
Code: Select all
put a into temp
put b into a
put temp into b
which
is needlessly cumbersome. How about only writing
and you're done.
In my case, I wrote an implementation of the Blowfish algorithm. In it, many contents exchanges take place, and the above method (which is called very often, so it takes up a significant amount of time, too) makes the code not only slower and more cumbersome, but also harder to read than just
Other languages have it too. Programming without SWAPI find equally unnverving as programming nested conditionals without ELSEIF.
Hoping to shed some light on the swappin' business...
Regards,
Re: SWAP
Posted: Sun Nov 22, 2009 9:53 pm
by FourthWorld
Code: Select all
on swap @pA, @pB
get pA
put pB into pA
put it into pB
end swap
Re: SWAP
Posted: Sun Nov 22, 2009 10:09 pm
by sturgis
Or something like this? Yours is more generic though, so I think it would be the way to go.
Code: Select all
local tA,tB
on mouseUp
put 4 into tA
put 5 into tB
swap tA,tB
put tA && tB
end mouseUp
on swap theA,theB
put theA into tB
put theB into tA
end swap
FourthWorld wrote:Code: Select all
on swap @pA, @pB
get pA
put pB into pA
put it into pB
end swap
Posted: Mon Nov 23, 2009 3:42 pm
by ukimiku
@FourthWorld:
thanks for your code. Could you please explain to me the difference between a handler that starts with "on" and a "command" construct? Isn't "on" used to catch messages sent by other handlers? In my mental model of Runtime, if your implementation of SWAP was used in a stack, a message would be added to the pending messages and then processed by the "on swap" handler. Is that correct? If so, would it be much slower than using a "command swap" construct?
Of course, one canwrite such a handler that references object pointers (I find your use of "it" pretty elegant), and I could have written something alike myself, but an in-built SWAP would still be my preference, if only for reasons of execution speed. Also, I wouldn't have to remind myself for each project to copy the SWAP code into my stack.
Regards,
Re: SWAP
Posted: Mon Nov 23, 2009 3:44 pm
by ukimiku
@sturgis:
I know that "else if" works in RevTalk, I concatenated the two words out of habit, I guess. I didn't mean to imply that RevTalk could not realize flat nested else-if-structures.
Regards
Re: SWAP
Posted: Mon Nov 23, 2009 4:43 pm
by FourthWorld
The "@" signs are necessary here, so the variables used will be modified in place in the calling handler.
sturgis wrote:Or something like this? Yours is more generic though, so I think it would be the way to go.
Code: Select all
local tA,tB
on mouseUp
put 4 into tA
put 5 into tB
swap tA,tB
put tA && tB
end mouseUp
on swap theA,theB
put theA into tB
put theB into tA
end swap
FourthWorld wrote:Code: Select all
on swap @pA, @pB
get pA
put pB into pA
put it into pB
end swap
Re:
Posted: Mon Nov 23, 2009 4:53 pm
by FourthWorld
ukimiku wrote:Could you please explain to me the difference between a handler that starts with "on" and a "command" construct?
Only the age of the programmer.
The "command" token was added fairly recently (v3.5?) to differentiate between custom commands and message handlers. Currently they're both functionally identical, but it does indeed make for clearer style to use "command" where appropriate. I've just been typing RevTalk so long that my fingers have old habits.
In my mental model of Runtime, if your implementation of SWAP was used in a stack, a message would be added to the pending messages and then processed by the "on swap" handler. Is that correct? If so, would it be much slower than using a "command swap" construct?
Both should benchmark identically, but if your testing shows a performance difference I'd be very interested to know.
The "pending messages" is a queue for message sent with the "send in <time>" command, so not really the best descriptor here. But your thinking in general is clear: commands and message handlers are conceptually different and the new "command" token helps differentiate between the two, making code a little more readable.
Of course, one canwrite such a handler that references object pointers (I find your use of "it" pretty elegant), and I could have written something alike myself, but an in-built SWAP would still be my preference, if only for reasons of execution speed. Also, I wouldn't have to remind myself for each project to copy the SWAP code into my stack.
I have a long list of things I'd like added to the engine - I post half of them to the RQCC just in case Mark Waddingham finds himself with too much time on his hands.
But with so many priorities there at RunRev, we have to expect that things that can be done in the language will usually take a back seat to things which can't be done without an engine enhancement. So we write our own handlers, and with the speed of the engine you may be pleasantly surprised by how unnoticeable the performance hit is with such things, esp. with simple three-liners like a swap command.
Re: SWAP
Posted: Tue Nov 24, 2009 11:45 am
by ukimiku
Thanks a lot for the time you took to clarify. I now see the difference between "command" an "on" much clearer, and will continue to use "command" where I define my own subroutines, and reserve "on" for message passing and executing, while recognizing that "on" handlers do not process pending messages as sent with the "SEND IN..." (time) command.
I would be very interested in your list of things you'd like to see added to RevTalk!
Kind regards,
Re: SWAP
Posted: Tue Nov 24, 2009 12:12 pm
by SparkOut
ukimiku wrote:while recognizing that "on" handlers do not process pending messages as sent with the "SEND IN..." (time) command.
Hi Mike, that's not quite accurate.
"on..." handlers will deal with messages that are "sent in <time>" just so long as they are sent through the message path to be handled by the right object. Richard's comment:
The "pending messages" is a queue for message sent with the "send in <time>" command, so not really the best descriptor here.
I believe, was meant to refer to your original question
a message would be added to the pending messages and then processed by the "on swap" handler.
In other words, issuing a command (while it does follow the same rules as message handlers) is not conceptually the same (but only "conceptually") as adding a message to the "pending messages". It's a very subtle point, and probably not worth worrying about too much, perhaps when considering adding a command as "private" (which means that only the current script location (eg in a button, or a given card) will have access to the command, rather than it being available via the message path to be called from other places). Just to reiterate, if you put the following handler in the stack script:
Code: Select all
on myHandler
answer "This dialog was brought to you through processing a send in time construct"
end myHandler
and then say, place a button on a card with the script
Code: Select all
on mouseUp
send "myHandler" to this stack in 2000 milliseconds
end mouseUp
Then when you press the button, two seconds later you should get the answer message triggered. Similarly, if you changed the stack script so that it used "command myHandler" instead, you would still get the same answer dialog two seconds after pressing the button.
As mentioned, "command" and "on" are to all intent at the moment, synonyms. For clarity, it is perhaps an advantage to reserve system message handlers to react to "on" and your other commands, well, with "command", if only to help distinguish a message from a command structure that you create (similar to a function) - even though your commands can and do still go through the message path.
Re: SWAP
Posted: Tue Nov 24, 2009 12:34 pm
by bn
ukimiku,
since beside of the trouble of having to write your own swap handler you were concerned about the speed.
If you use Richard's handler
on swap @pA, @pB
get pA
put pB into pA
put it into pB
end swap
and change it to a
private command like in
Code: Select all
private command swap @pA, @pB
get pA
put pB into pA
put it into pB
end swap
and you call this handler many times (I guess > 50000) then you will notice a speed gain because when you put a private command / private function into the same script of the handler that calls it, you save some on the overhead of the message paths. But it can not be called from another script. This is where comand and on potentially differ, you can not write "private on myHandlerName"
I like the private option for handlers that are called very often like in image processing, stepping through pixels and processing intensive stuff like that. Also recursive handlers profit from private.
Why don't you do a little benchmarking of the swap function in the language that provides the swap command and compare it to RunRev? Just do it 100 000 times of more and see what you get. I would be interested in the results.
regards
Bernd
Re: SWAP
Posted: Tue Nov 24, 2009 4:45 pm
by FourthWorld
Bernd, the "private" option is a great tip for performance. I've seen some good speed bumps from using that where I can.
If ukimiku wants to write a quickie benchmark test, the script outlined here might help get him started:
http://revjournal.com/blog.irv?pid=1256139270.452508
Re: SWAP
Posted: Tue Nov 24, 2009 9:02 pm
by ukimiku
Gentlemen, thanks to all of you for thinking with me and for your useful suggestions.
Here goes our benchmark:
I chose to test all three versions of the SWAP, i.e. "private command", "command", and "on". Here are the benchmark results for the following code:
Code: Select all
local tA, tB
on mouseUp
-- Many tasks are so quick they don't show a measurable
-- difference unless they're run multiple times, so we
-- run through the number of iterations specified here:
put 1000000 into tIterations
--
-- TEST 1:
put the millisecs into t
repeat tIterations
swapA tA, tB
end repeat
put the millisecs - t into t1
--
-- TEST 2:
put the millisecs into t
repeat tIterations
swapB tA, tB
end repeat
put the millisecs - t into t2
-- TEST 3:
put the millisecs into t
repeat tIterations
swapC tA, tB
end repeat
put the millisecs - t into t3
--
-- DISPLAY RESULTS:
put t1 && t2 && t3
end mouseUp
private command swapA @pA, @pB
get pA
put pB into pA
put it into pB
end swapA
command swapB @pA, @pB
get pA
put pB into pA
put it into pB
end swapB
on swapC
get pA
put pB into pA
put it into pB
end swapC
For uninitialized tA, tB I obtained the following results:
The "private command" swapA variant used 944 milliseconds for one million swaps
The "command" version used 1848 millisecs
The "on" version was slowest by almost a factor of two, when compared to the "private command", using 2806 millisecs.
Init'ing tA to 1234567890 and tB to -2877166262, everything slowed down a bit:
The "private command" swapA variant used 1205 milliseconds for one million swaps
The "command" version used 1792 millisecs
The "on" version was slowest by almost a factor of 2 1/2, when compared to the "private command", using 2967 millisecs.
Init'ing tA to "Hello Word of Runtime Revolution" and tB to "the script of me", I obtained:
The "private command" swapA variant used 1318 milliseconds for one million swaps
The "command" version used 1891 millisecs
The "on" version was slowest by more than a factor of 2 1/2, when compared to the "private command", using 3287 millisecs.
The results are consistent even if I change the order of the three constructs in the button handler.
I guess I learned a lot today! Thank you.
P.S. And it's not only the age of the programmer...
