I keep trying to find answers for this but fail to do so. I wanted to know, what is the do-end block actually used for? It just says values are used when needed in my book so how could I use this?
Do I use it to reduce the scope of local variables by placing a function in a do-end loop and place local variables outside of the function but inside this do-end block and the variables will be seen by the function? But then can the function still be called?
Sorry for being very vague. I hope that makes sense. Maybe an illustrated example might be useful ^^
In it's essence, the “do… end” are just indicators of what code lies within what section of a particular script. whereas the Lua “equivalent” would replace the { and } with do and end, respectively.
A block is the body of a control structure, the body of a function, or a chunk (the file or string with the code where the variable is declared).
There is an implicit return at the end of the Lua functions. As per syntactic reason the return statement should be the last statement of a block or function, before the end keyword.
The do-end blocks have to do with the problem of variable scoping. Essentially, when you use an identifier, what value does it have? For example, what numbers will be printed when we write the following program?
local x = 10 if x > 0 then local x = 17 print(x) end print(x)
When it comes to local variables, Lua uses standard lexical scoping, as is well explained in section 4.2 of the Programming in Lua book. Lexical scope is very useful for a couple of reasons:
The variable scoping is static. You know just by looking at the source code what variables and functions correspond to each identifier in your code. This is opposed to the dynamic scoping you find in Bash or indirect dispatching via method calls or array lookups, where you need to think about the execution flow of the program to know what value you will end up with.
Variable scoping is limited, which helps readability and avoids some bugs:
If you declare a variable only when you are going to need to use it you can declare it and initialize it at the same time. On the other hand, if you declare all your variables at the top of the function then you might end up accidentally using one before you initialize it.
If you define a variable inside an inner scope you can't accidentally use it in outer scopes.
Lexical scoping enables some very expressive idioms when you combine it with nested functions (closures).
Usually, you don't need to worry about specifying variables scopes yourself. Functions, loops and conditionals automatically introduce new scopes and that will normally be enough for giving your variables a well constrained scope. That said, every once in a while, you might want to introduce some extra scopes out of thin air and we can use do-end for that. Programming Lua has the following example where you want to calculate the solutions of a quadratic equation and the computation has some temporaries:
do local a2 = 2*a local d = sqrt(b^2 - 4*a*c) x1 = (-b + d)/a2 x2 = (-b - d)/a2 end -- scope of `a2' and `d' ends here print(x1, x2)
Without the do-end block, a2
and d
could end up being accidentally used after they are not needed anymore:
local a2 = 2*a local d = sqrt(b^2 - 4*a*c) x1 = (-b + d)/a2 x2 = (-b - d)/a2 print(x1, x2) print(a2) -- OOPS! I wanted to say "print(a)"
That said, do-end doesn't need to be used that often. If the code block is small, there is less need to hide the local variables and if the code block is big it often is a better approach to put the code block in a subroutine of its own. The times when I find that do-end shines is when you only need to do the computation once - functions can potentially be called many times but if you use a do-end block you make it clear that you are only running that piece of code once.
Yes, do end
block can be used to limit the scope of variables; to keep the function that uses those variables visible, you have several options
Localize the variable that keeps the function outside of the block:
local func do local a = 0 func = function(inc) a = a + inc return a end end
Use a global function:
do local a = 0 function func(inc) a = a + inc return a end end
Use a method:
local tbl = {} do local a = 0 function tbl:func(inc) a = a + inc return a end end
In all three cases you can still call func()
after the block is closed, but a
is only visible from that function and not anywhere else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With