I have been dealing a lot with Lua in the past few months, and I really like most of the features but I\'m still missing something among those:
The first part is answered in the FAQ as slain pointed out.
As for a workaround, you can wrap the body of the loop in a function and return
early from that, e.g.
-- Print the odd numbers from 1 to 99
for a = 1, 99 do
(function()
if a % 2 == 0 then
return
end
print(a)
end)()
end
Or if you want both break
and continue
functionality, have the local function perform the test, e.g.
local a = 1
while (function()
if a > 99 then
return false; -- break
end
if a % 2 == 0 then
return true; -- continue
end
print(a)
return true; -- continue
end)() do
a = a + 1
end
The way that the language manages lexical scope creates issues with including both goto
and continue
. For example,
local a=0
repeat
if f() then
a=1 --change outer a
end
local a=f() -- inner a
until a==0 -- test inner a
The declaration of local a
inside the loop body masks the outer variable named a
, and the scope of that local extends across the condition of the until
statement so the condition is testing the innermost a
.
If continue
existed, it would have to be restricted semantically to be only valid after all of the variables used in the condition have come into scope. This is a difficult condition to document to the user and enforce in the compiler. Various proposals around this issue have been discussed, including the simple answer of disallowing continue
with the repeat ... until
style of loop. So far, none have had a sufficiently compelling use case to get them included in the language.
The work around is generally to invert the condition that would cause a continue
to be executed, and collect the rest of the loop body under that condition. So, the following loop
-- not valid Lua 5.1 (or 5.2)
for k,v in pairs(t) do
if isstring(k) then continue end
-- do something to t[k] when k is not a string
end
could be written
-- valid Lua 5.1 (or 5.2)
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
end
It is clear enough, and usually not a burden unless you have a series of elaborate culls that control the loop operation.
Because it's unnecessary¹. There's very few situations where a dev would need it.
A) When you have a very simple loop, say a 1- or 2-liner, then you can just turn the loop condition around and it's still plenty readable.
B) When you're writing simple procedural code (aka. how we wrote code in the last century), you should also be applying structured programming (aka. how we wrote better code in the last century)
C) If you're writing object-oriented code, your loop body should consist of no more than one or two method calls unless it can be expressed in a one- or two-liner (in which case, see A)
D) If you're writing functional code, just return a plain tail-call for the next iteration.
The only case when you'd want to use a continue
keyword is if you want to code Lua like it's python, which it just isn't.²
Unless A) applies, in which case there's no need for any workarounds, you should be doing Structured, Object-Oriented or Functional programming. Those are the paradigms that Lua was built for, so you'd be fighting against the language if you go out of your way to avoid their patterns.³
Some clarification:
¹ Lua is a very minimalistic language. It tries to have as few features as it can get away with, and a continue
statement isn't an essential feature in that sense.
I think this philosophy of minimalism is captured well by Roberto Ierusalimschy in this 2019 interview:
add that and that and that, put that out, and in the end we understand the final conclusion will not satisfy most people and we will not put all the options everybody wants, so we don’t put anything. In the end, strict mode is a reasonable compromise.
² There seems to be a large ammount of programmers coming to Lua from other languages because whatever program they're trying to script for happens to use it, and many of them want don't seem to want to write anything other than their language of choice, which leads to many questions like "Why doesn't Lua have X feature?"
Matz described a similar situation with Ruby in a recent interview:
The most popular question is: "I’m from the language X community; can’t you introduce a feature from the language X to Ruby?", or something like that. And my usual answer to these requests is… "no, I wouldn’t do that", because we have different language design and different language development policies.
³ There's a few ways to hack your way around this; some users have suggested using goto
, which is a good enough aproximation in most cases, but gets very ugly very quickly and breaks completely with nested loops. Using goto
s also puts you in danger of having a copy of SICP thrown at you whenever you show your code to anybody else.
Again with the inverting, you could simply use the following code:
for k,v in pairs(t) do
if not isstring(k) then
-- do something to t[k] when k is not a string
end
We can achieve it as below, it will skip even numbers
local len = 5
for i = 1, len do
repeat
if i%2 == 0 then break end
print(" i = "..i)
break
until true
end
O/P:
i = 1
i = 3
i = 5