lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Jun 12, 2014, at 9:20 PM, Andrew Starks <andrew.starks@trms.com> wrote:

> On Thursday, June 12, 2014, Paige DePol <lual@serfnet.org> wrote:
> 
>> My switch patch uses a Lua table to store the case values, it is a fairly trivial process, add a key to the table and set the value to the program counter offset of the jumpto point. I also check each jumpto point against each jumpto statement, however, I do not need to analyse the case values in any way, just add them to the table. I will note that each switch statement does require the use of a table, so there is extra resource usage there.
>> 
>> The advantage of the switch statement is twofold, nicer syntax than a table full of functions plus the ability to utilise fall-through. If you look through the Lua source you will see that fall-through is actually used a fair amount of times.
>> 
>> Compare the two code samples (first sample by Coda Highland):
>> 
>> 
>> local t
>> t = {
>>     'one' = function() stuff() t.two() end,
>>     'two' = function() otherstuff() end,
>>     'three' = function() morestuff() end,
>>     'four'  = function() yetmore() t.five() end,
>>     'five'  = function() otherthings() end,
>> }
>> t[var]()
>> 
>> 
>> switch var
>>     case one
>>       stuff()
>>     case two
>>       otherstuff()
>>       break
>>     case three
>>       morestuff()
>>       break
>>     case four
>>       yetmore()
>>     case five
>>       otherthings()
>> end
>> 
>> 
>> Which would you rather maintain? Personally, I find the syntax of the switch statement considerably easier to look at and mentally parse. Plus with the switch statement you also have the ability to use the `else` (aka `default`) block in case `var` is not in your switch. That would require additional code in the first example to handle.
>> 
>> Another detriment to using the table-of-functions method is that you are essentially creating a closure for each case value, should you be using this form of switch in a tight loop you have now added a closure call (or more to implement fall-through) to each iteration of the loop, whereas with a proper switch statement you only do a single table lookup for each iteration.
>> 
>> Here is the results of running the above code[1] in a tight loop a million times each, averaged over 5 runs:
>> 
>> >>>>> switch.lunia: 0.4462178s
>> >>>>> table.lunia: 0.9022026s
>> 
>> As you can see the switch is more efficient than the table-of-functions method. Granted, we are talking less than a second for a million iterations of a loop, however, when running Lua code in time-criticial situations[2] you typically want every performance gain you can get! ;)
>> 
>> ~pmd
>> 
>> [1] Code was run on vanilla Lua codebase with only my switch patch[3] applied.
>> 
>> [2] For example, video games, or the person on this list who is running Lua code between individual video frames!
>> 
>> [3] https://github.com/FizzyPop/lua-patches/tree/master/joint-patches/jump-table%2Bif-shct%2Bcont-loop
> 
> 
> Is it easy for you to compare this to plain old if-else? 


Yes, on the page for the switch patch there are benchmarks comparing switch to if/else:

==== file ====   == 3 ==    == 6 ==    == 13 ==   == 26 ==   = Rand =
azGifelse.lua:   1.79187s   2.04329s   2.84767s   4.31683s   3.13985s
azGswitch.lua:   1.56020s   1.54594s   1.57489s   1.54292s   1.84061s
azLifelse.lua:   1.14142s   1.26719s   1.55459s   2.09323s   1.89476s
azLswitch.lua:   1.07550s   1.08567s   1.09610s   1.08649s   1.44026s

The files with 'G' use global variables, the files with 'L' use local variables.

As you can see the switch statements take constant time (single table lookup) regardless of the number of entries present.

~pmd