Skip to content

Instantly share code, notes, and snippets.

@FreeBirdLjj
Last active July 14, 2024 17:46
Show Gist options
  • Save FreeBirdLjj/6303864 to your computer and use it in GitHub Desktop.
Save FreeBirdLjj/6303864 to your computer and use it in GitHub Desktop.
A way to write switch-case statements in lua.
print "Hello, switch"
-- If the default case does not have to be handled, we can use the following auxiliary function:
local function switch(value)
-- Handing `cases` to the returned function allows the `switch()` function to be used with a syntax closer to c code (see the example below).
-- This is because lua allows the parentheses around a table type argument to be omitted if it is the only argument.
return function(cases)
-- The default case is achieved through the metatable mechanism of lua tables (the `__index` operation).
setmetatable(cases, cases)
local f = cases[value]
if f then
f()
end
end
end
-- Suppose we want to write the equivalent lua code of the following c code:
-- switch (a) {
-- case 1:
-- printf("Case 1.\n");
-- break;
-- case 2:
-- printf("Case 2.\n");
-- break;
-- case 3:
-- printf("Case 3.\n");
-- break;
-- default:
-- printf("Case default.\n");
-- }
local x = 2
switch (x) {
[1] = function() -- for case 1
print "Case 1."
end,
[2] = function() -- for case 2
print "Case 2."
end,
[3] = function() -- for case 3
print "Case 3."
end,
__index = function() -- for case default, can be omitted if not needed
print "Case default."
end
}
@Core-commits
Copy link

Useful

@srijan-paul
Copy link

I use this small function:

_G.switch = function(param, case_table)
    local case = case_table[param]
    if case then return case() end
    local def = case_table['default']
    return def and def() or nil
end

usage:

switch(a, { 
        [1] = function()	-- for case 1
		print "Case 1."
	end,
	[2] = function()	-- for case 2
		print "Case 2."
	end,
	[3] = function()	-- for case 3
		print "Case 3."
	end
})

@LingleDev
Copy link

noice.

@MatteoKrsticDev
Copy link

really cool ad usefull

@itzKiwiSky
Copy link

super usefull, thx

@mystery-z
Copy link

Didn't know this was a thing, helped a lot

@gitcrane
Copy link

This looks great. Can you add some comments to your code to help novices like me understand the lua chunk?

@AnoRebel
Copy link

Awesome, thanks

@Davemehari
Copy link

Thank you.

@Davemehari
Copy link

@switch.lua Thank you.

@sleeptightAnsiC
Copy link

sleeptightAnsiC commented Jul 13, 2024

The small problem with this technique is that it cannot mimic case-fall-through
so for example, one cannot easily port following C code

switch (a) {
case 1:
        printf("Case 1.\n");
        break;
case 2:
case 3:
default:
        printf("Case 2, 3 or default.\n");
}

I don't think there is any sane and simple solution in said case

@FreeBirdLjj
Copy link
Author

Hi @sleeptightAnsiC, I guess you can try the following code as a solution:

local function fallthrough(next_case)
	coroutine.yield("fallthrough", next_case)
end

local function switch(value)
	return function(cases)
		setmetatable(cases, cases)
		repeat
			local f = cases[value]
			if f then
				local act, next_case = coroutine.wrap(f)()
				if act == "fallthrough" then
					value = next_case
				else
					break
				end
			end
		until f == nil
	end
end

-- Suppose we want to write the equivalent lua code of the following c code:
-- switch (a) {
-- case 1:
--   printf("Case 1.\n");
--   break;
-- case 2:
-- case 3:
-- default:
--   printf("Case 2, 3 or default.\n");
-- }
for _, v in ipairs {1, 2, 3, 4} do
	switch (v) {
		[1] = function()
			print "Case 1."
		end,
		[2] = function() fallthrough(3)	end,
		[3] = function() fallthrough(0 --[[ any default value ]]) end,
		__index = function()	-- for case default
			print "Case 2, 3 or default."
		end
	}
end

@sleeptightAnsiC
Copy link

Hey @FreeBirdLjj,

Gosh... Lua shocks me everyday with its meta-programming capabilities. This indeed works.
I wonder about performance penalty of said approach as it uses coroutine?

Using fallthrough here kinda skyrockets the complexity, since every falling case N must explicitly call fallthrough N+1 and adding/removing cases becomes complicated, so not sure if this is a great solution. Maybe something like this [code bellow] would be better in a long run.

-- `switch` is defined in a same way as in the first example

local case_1 = function ()
	print "Case 1."
end

local case_23d = function()
	print "Case 2, 3 or default."
end

for _, x in ipairs {1, 2, 3, 4} do
	switch (x) {
		[1] = case_1,
		[2] = case_23d,
		[3] = case_23d,
		__index = case_23d,
	}
end

Thanks for your answer though, I haven't thought this would be even possible.

@sleeptightAnsiC
Copy link

sleeptightAnsiC commented Jul 14, 2024

Also, I just realized that I use a simple Lua idiom that basically works like switch-case (not exactly, but it's very similar). I'll leave it there, I hope someone may find it useful:

print "Hello, switch"
local x = 2
local result =
	   x == 1 and "Case 1."
	or x == 2 and "Case 2."
	or x == 3 and "Case 3."
	or "Case default."
print(result)

This removes the need of using metatable entirely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment