Skip to content

Instantly share code, notes, and snippets.

@FreeBirdLjj
Last active November 2, 2024 22:29
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
}
@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.

@RichardFevrier
Copy link

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.

The benefits of using switch-case over if-elif-else is to not repeat the x variable... otherwise there is no point, like in your example.

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