I have to execute the following code:
local filename = dir .. "/" .. base
thousands of times in a loop (it's a recursion that prints a directory tree).
Now, I wonder whether Lua concatenates the 3 strings (dir, "/", base) in one go (i.e., by allocating a string long enough to hold their total lengths) or whether it does this the inefficient way by doing it internally in two steps:
local filename = (dir .. "/") -- step1
.. base -- step2
This last way would be inefficient memory-wise because two strings are allocated instead of just one.
I don't care much about CPU cycles: I care mainly about memory consumption.
Finally, let me generalize the question:
Does Lua allocate only one string, or 4, when it executes the following code?
local result = str1 .. str2 .. str3 .. str4 .. str5
BTW, I know that I could do:
local filename = string.format("%s/%s", dir, base)
But I've yet to benchmark it (memory & CPU wise).
(BTW, I know about table:concat(). This has the added overhead of creating a table so I guess it won't be beneficial in all use cases.)
A bonus question:
In case Lua doesn't optimize the ".." operator, would it be a good idea to define a C function for concatenating strings, e.g. utils.concat(dir, "/", base, ".", extension)?
Although Lua performs a simple optimization on .. usage, you should still be careful to use it in a tight loop, especially when joining very large strings, because this will create lots of garbage and thus impact performance.
The best way to concatenate many strings is with table.concat.
table.concat lets you use a table as a temporary buffer for all the strings to be concatenated and perform the concatenation only when you are done adding strings to the buffer, like in the following silly example:
local buf = {}
for i = 1, 10000 do
buf[#buf+1] = get_a_string_from_somewhere()
end
local final_string = table.concat( buf )
The simple optimization for .. can be seen analyzing the disassembled bytecode of the following script:
-- file "lua_06.lua"
local a = "hello"
local b = "cruel"
local c = "world"
local z = a .. " " .. b .. " " .. c
print(z)
the output of luac -l -p lua_06.lua is the following (for Lua 5.2.2 - edit: the same bytecode is output also in Lua 5.3.6):
main (13 instructions at 003E40A0)
0+ params, 8 slots, 1 upvalue, 4 locals, 5 constants, 0 functions
1 [3] LOADK 0 -1 ; "hello"
2 [4] LOADK 1 -2 ; "cruel"
3 [5] LOADK 2 -3 ; "world"
4 [7] MOVE 3 0
5 [7] LOADK 4 -4 ; " "
6 [7] MOVE 5 1
7 [7] LOADK 6 -4 ; " "
8 [7] MOVE 7 2
9 [7] CONCAT 3 3 7
10 [9] GETTABUP 4 0 -5 ; _ENV "print"
11 [9] MOVE 5 3
12 [9] CALL 4 2 1
13 [9] RETURN 0 1
You can see that only a single CONCAT opcode is generated, although many .. operators are used in the script.
To fully understand when to use table.concat you must know that Lua strings are immutable. This means that whenever you try to concatenate two strings you are indeed creating a new string (unless the resulting string is already interned by the interpreter, but this is usually unlikely). For example, consider the following fragment:
local s = s .. "hello"
and assume that s already contains a huge string (say, 10MB). Executing that statement creates a new string (10MB + 5 characters) and discards the old one. So you have just created a 10MB dead object for the garbage collector to cope with. If you do this repeatedly you end up hogging the garbage collector. This is the real problem with .. and this is the typical use case where it is necessary to collect all the pieces of the final string in a table and to use table.concat on it: this won't avoid the generation of garbage (all the pieces will be garbage after the call to table.concat), but you will greatly reduce unnecessary garbage.
Conclusions
Use .. whenever you concatenate few, possibly short, strings, or you are not in a tight loop. In this case table.concat could give you worse performance because:
you must create a table (which usually you would throw away);
you have to call the function table.concat (the function call overhead impacts performance more than using the built-in .. operator a few times).
Use table.concat, if you need to concatenate many strings, especially if one or more of the following conditions are met:
you must do it in subsequent steps (the .. optimization works only inside the same expression);
you are in a tight loop;
the strings are large (say, several kBs or more).
Note that these are just rules of thumb. Where performance is really paramount you should profile your code.
Anyway Lua is quite fast compared with other scripting languages when dealing with strings, so usually you don't need to care so much.
In your example, whether the .. operator does optimization is hardly a problem for the performance, you don't have to worry about memory or CPU. And there's table.concat for concatenating many strings. (See Programming in Lua) for the use of table.concat.
Back to your question, in this piece of code
local result = str1 .. str2 .. str3 .. str4 .. str5
Lua allocates only one new string, check out this loop from Lua's relevant source in luaV_concat:
do { /* concat all strings */
size_t l = tsvalue(top-i)->len;
memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
tl += l;
} while (--i > 0);
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl));
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
You can see that Lua concatenate n strings in this loop but only pushes back to the stack one string in the end, which is the result string.
BTW, I know about table:concat(). This has the added overhead of creating a table so I guess it won't be beneficial in all use cases.
In this particular use case (and similar ones), you could consider reusing a table if you're concerned with creating lots of garbage tables:
local path = {}
...
-- someplace else, in a loop or function:
path[1], path[2] = dir, base
local filename = table.concat(path, "/")
path[1], path[2] = nil
...
you could even generalize this to a "concat" utility:
local rope = {}
function string_concat(...)
for i = 1, select("#", ...) do rope[i] = select(i, ...) end -- prepare rope
local res = table.concat(rope)
for i = 1, select("#", ...) do rope[i] = nil end -- clear rope
return res
end
Related
I have 26 variables and each of them contain numbers ranging from 1 to 61. I want for each case of 1, each case of 2 etc. the number 1 in a new variable. If there is no 1, the variable should contain 2.
So 26 variables with data like:
1 15 28 39 46 1 12 etc.
And I want 61 variables with:
1 2 1 2 2 1 etc.
I have been reading about creating vectors, loops, do if's etc but I can't find the right way to code it. What I have done is just creating 61 variables and writing
do if V1=1 or V2=1 or (etc until V26).
recode newV1=1.
end if.
exe.
**repeat this for all 61 variables.
recode newV1 to newV61(missing=2).
So this is a lot of code and quite a detour from what I imagine it could be.
Anyone who can help me out with this one? Your help is much appreciated!
noumenal is correct, you could do it with two loops. Another way though is to access the VECTOR using the original value though, writing that as 1, and setting all other values to zero.
To illustrate, first I make some fake data (with 4 original variables instead of 26) named X1 to X4.
*Fake Data.
SET SEED 10.
INPUT PROGRAM.
LOOP Id = 1 TO 20.
END CASE.
END LOOP.
END FILE.
END INPUT PROGRAM.
VECTOR X(4,F2.0).
LOOP #i = 1 TO 4.
COMPUTE X(#i) = TRUNC(RV.UNIFORM(1,62)).
END LOOP.
EXECUTE.
Now what this code does is create four vector sets to go along with each variable, then uses DO REPEAT to actually refer to the VECTOR stub. Then finishes up with RECODE - if it is missing it should be coded a 2.
VECTOR V1_ V2_ V3_ V4_ (61,F1.0).
DO REPEAT orig = X1 TO X4 /V = V1_ V2_ V3_ V4_.
COMPUTE V(orig) = 1.
END REPEAT.
RECODE V1_1 TO V4_61 (SYSMIS = 2).
It is a little painful, as for the original VECTOR command you need to write out all of the stubs, but then you can copy-paste that into the DO REPEAT subcommand (or make a macro to do it for you).
For a more simple illustration, if we have our original variable, say A, that can take on integer values from 1 to 61, and we want to expand to our 61 dummy variables, we would then make a vector and then access the location in that vector.
VECTOR DummyVec(61,F1.0).
COMPUTE DummyVec(A) = 1.
For a record if A = 10, then here DummyVec10 will equal 1, and all the others DummyVec variables will still by system missing by default. No need to use DO IF for 61 values.
The rest of the code is just extra to do it in one swoop for multiple original variables.
This should do it:
do repeat NewV=NewV1 to NewV61/vl=1 to 61.
compute NewV=any(vl,v1 to v26).
end repeat.
EXPLANATION:
This syntax will go through values 1 to 61, for each one checking whether any of the variables v1 to v26 has that value. If any of them do, the right NewV will receive the value of 1. If none of them do, the right NewV will receive the value of 0.
Just make sure v1 to v26 are consecutively ordered in the file. if not, then change to:
compute NewV=any(vl,v1, v2, v3, v4 ..... v26).
You need a nested loop: two loops - one outer and one inner.
Lua code
local var = {}
for i = 1, 10000, 1 do
table.insert ( var, i )
end
var[5] = { some = false, another = 2 }
var[888] = #userdata
var[10000] = {}
var[1] = 1
var[1] = false
1 ) After this, is var still only with array-part, or it has hash-part too?
2 ) Does code
var[10001] = 1
add hash-part to var or it only forces table rehash without adding hash-part ?
3) How it affects on size of table?
Thanks!
The table will only have an array part after both 1 and 2. The reason is that you have a contiguous set of indices. Specifically, you created entries from 1 to 10,001 and Lua will have allocated space for them.
If for example, you had created 1 to 1000 then added 10001, it would have added the last one in the hash part rather than create nil entries for all the entries between.
It doesn't matter what type of data you put in as the value for the entries, Lua is only interested in the indices when deciding between array and hash. The exception here is setting values to nil. This can get a bit complicated but if table space is your primary concern, I don't believe Lua ever reduces the array an hash parts if you nil sets of them out. I could be mistaken on this.
As to the size, Lua uses a doubling strategy. So, after you hit entry 8192, Lua added another 8192 so there was no extra array space created between 10000 and 10001.
BTW Lua doesn't rehash every table addition. When it adds buckets, it gives itself some headroom. I believe it doubles there too. Note, if your data is sparse i.e. you aren't going to fill most of the indices between 1 and your max, then this approach to hashing can be very beneficial for space even if your indices are numbers. The main downside is it means you can't use ipairs across all your entries.
I'm modelling a program's memory accesses using Z3 and I have a doubt about performance that I'd like to share.
I wanted to model on a compact way something like a:
memset(dst, 0, 1000);
My first try was to use the array theory, but that meant to either create a thousand terms like (assert (and (= (select mem 0) 0) (= (select mem 1) 0) ... or a thousand similar stores or a quantified formula:
(forall (x Int) (implies (and (>= x 0) (< x 1000)) (= (select mem x) 0))
But I was told to avoid quantifiers while using arrays.
Next idea was to define a UF:
(define-fun newmemfun ((idx Int)) Int (
ite (and (>= idx 0) (< idx 1000)) 0 (prevmemfun idx)
))
But that means that I need to define a new function for each memory write operation (even for individual store operations, not just multiple stores like memset or memcpy). Which would end up creating a very nested ITE structure that would even save "old" values for a same index. ie:
mem[0] = 1;
mem[0] = 2;
would be:
(ite (= idx 0) 2 (ite (= idx 0) 1 ...
Which is functionally correct but the size of the expression (and I guess the generated AST for it) tends to accumulate very fast and I'm not sure if Z3 is optimized to detect and handle this case.
So, the question is: what would be the most performant way to encode memory operations that can cope with large multiple stores like the example above and individual stores at the same time.
Thanks,
pablo.
PS: non-closed and non-matching parenthesis intended :P.
Without knowing a bit more about your end goal, aside from modeling memory accesses (e.g., are you going to be doing verification, test case generation, etc.?), it's somewhat hard to answer, as you have many options. However, you may have the most flexibility to control performance issues if you rely on one of the APIs. For example, you can define your own memory accesses as follows (link to z3py script: http://rise4fun.com/Z3Py/gO6i ):
address_bits = 7
data_bits = 8
s = Solver()
# mem is a list of length program step, of a list of length 2^address_bits of bitvectors of size 2^data_bits
mem =[]
# modify a single address addr to value at program step step
def modifyAddr(addr, value, step):
mem.append([]) # add new step
for i in range(0,2**address_bits):
mem[step+1].append( BitVec('m' + str(step + 1) + '_' + str(i), data_bits) )
if i != addr:
s.add(mem[step+1][i] == mem[step][i])
else:
s.add(mem[step+1][i] == value)
# set all memory addresses to a specified value at program step step
def memSet(value, step):
mem.append([])
for i in range(0,2**address_bits):
mem[step+1].append( BitVec('m' + str(step + 1) + '_' + str(i), data_bits) )
s.add(mem[step+1][i] == value)
modaddr = 23 # example address
step = -1
# initialize all addresses to 0
memSet(0, step)
step += 1
print s.check()
for i in range(0,step+1): print s.model()[mem[i][modaddr]] # print all step values for modaddr
modifyAddr(modaddr,3,step)
step += 1
print s.check()
for i in range(0,step+1): print s.model()[mem[i][modaddr]]
modifyAddr(modaddr,4,step)
step += 1
print s.check()
for i in range(0,step+1): print s.model()[mem[i][modaddr]]
modifyAddr(modaddr,2**6,step)
step += 1
print s.check()
for i in range(0,step+1): print s.model()[mem[i][modaddr]]
memSet(1,step)
step += 1
print s.check()
for i in range(0,step+1): print s.model()[mem[i][modaddr]]
for a in range(0,2**address_bits): # set all address values to their address number
modifyAddr(a,a,step)
step += 1
print s.check()
print "values for modaddr at all steps"
for i in range(0,step+1): print s.model()[mem[i][modaddr]] # print all values at each step for modaddr
print "values at final step"
for i in range(0,2**address_bits): print s.model()[mem[step][i]] # print all memory addresses at final step
This naive implementation allows you to either (a) set all memory addresses to some value (like your memset), or (b) modify a single memory address, constraining all other addresses to have the same value. For me, it took a few seconds to run and encoded about 128 steps of 128 addresses, so it had around 20000 bitvector expressions of 8 bits each.
Now, depending on what you are doing (e.g., do you allow atomic writes to several addresses like this memset, or do you want to model them all as individual writes?), you could add further functions, like modify a subset of addresses to some values in a program step. This will allow you some flexibility to trade off modeling accuracy for performance (e.g., atomic writes to blocks of memory versus modifying single addresses at a time, which will run into performance problems). Also, nothing about this implementation requires the APIs, you could encode this as an SMT-LIB file as well, but you will probably have more flexibility (e.g., lets say you want to interact with models to constrain future sat checks) if you use one of the APIs.
I have a string passed into a function, I would like to compare the first character of the string against a number.
I.E.
if String(1) = "3" then
When I compile I get:
warning: index for String may assume lower bound of 1
warning: suggested replacement String'First + 1
I would really like to make this right, but when I try "first" it actually grabs a number, not the character.
Is there a better way to do it?
I tried looking up the 'First concept, and the below site explains I'm actually getting the number of the index, not the actual contents: http://en.wikibooks.org/wiki/Ada_Programming/Types/array
For example,
Hello_World : constant String := "Hello World!";
World : constant String := Hello_World (7 .. 11);
Empty_String : constant String := "";
Using 'First I'll get:
Array 'First 'Last 'Length 'Range
Hello_World 1 12 12 1 .. 12
World 7 11 5 7 .. 11
Empty_String 1 0 0 1 .. 0
Based on that information, I can't get H from Hello world (for a comparison like if Hello_World(1) = "H" then)
EDIT:
So the way I initially was doing it was
(insert some variable name instead of string in this case)
String(String'First .. String'First) = "1"
So that works from what I can tell, however, rather then writing all that, I found out that
String(String'First) = '1'
Does the same thing but using char comparison, which makes a lot more sense!
Thanks for all the answers everyone!
Strings are the biggest bugaboo for newbie Ada coders; particularly so for those who are already experts at dealing with strings in Cish languages.
Ada strings (in fact all Ada arrays) are not 0 based like C, or 1-based like Fortran. They are based however the coder felt like it. If someone wants to index their string from 10 ... 200, they can. So really the safest way to acces characters in an Ada string is to use the 'first attribute (or better yet, loop through them using 'range or 'first .. 'last).
In your case it looks like you want to get at only the first character in the string. The easiest and safest way to do that for a string named X is X(X'first).
In pactice you would almost never do that though. Instead you would be looping through the string's 'first...'last looking for something, or just using one of the routines in Ada.Strings.Fixed.
The warning is suggesting you use:
String(String'First + Index)
Instead of just
String(Index)
There's something odd about the code in your question. First off, that you're calling your variable "String" and that it's of type "String". Ada will balk at that right off the bat.
And the warning statements you reproduce for that code fragment don't make sense.
Let's say your variable is actually called "Value", i.e.:
Value : String := "34543";
Value(1) is not the same as Value(Value'First + 1), because Value'First (in this declaration) is 1. So you end up referencing Value(1 + 1). You appear to be experiencing this because of mentioning that you can't reference the 'H' in a "Hello World" string.
Now the warning is valid, in that you're safer using 'First (and 'Last and 'Range) to reference array bounds. But you need to use the proper indexing if you're going to offset from the bound retrieved via 'First, typically using either 0-based or 1-based (in which case you need to offset by 1). Use whichever base is more appropriate and readable in your context.
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:
Why is there no continue?
What workarounds are there for it?
In Lua 5.2 the best workaround is to use goto:
-- prints odd numbers in [|1,10|]
for i=1,10 do
if i % 2 == 0 then goto continue end
print(i)
::continue::
end
This is supported in LuaJIT since version 2.0.1
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.
You can wrap loop body in additional repeat until true and then use do break end inside for effect of continue. Naturally, you'll need to set up additional flags if you also intend to really break out of loop as well.
This will loop 5 times, printing 1, 2, and 3 each time.
for idx = 1, 5 do
repeat
print(1)
print(2)
print(3)
do break end -- goes to next iteration of for
print(4)
print(5)
until true
end
This construction even translates to literal one opcode JMP in Lua bytecode!
$ luac -l continue.lua
main <continue.lua:0,0> (22 instructions, 88 bytes at 0x23c9530)
0+ params, 6 slots, 0 upvalues, 4 locals, 6 constants, 0 functions
1 [1] LOADK 0 -1 ; 1
2 [1] LOADK 1 -2 ; 3
3 [1] LOADK 2 -1 ; 1
4 [1] FORPREP 0 16 ; to 21
5 [3] GETGLOBAL 4 -3 ; print
6 [3] LOADK 5 -1 ; 1
7 [3] CALL 4 2 1
8 [4] GETGLOBAL 4 -3 ; print
9 [4] LOADK 5 -4 ; 2
10 [4] CALL 4 2 1
11 [5] GETGLOBAL 4 -3 ; print
12 [5] LOADK 5 -2 ; 3
13 [5] CALL 4 2 1
14 [6] JMP 6 ; to 21 -- Here it is! If you remove do break end from code, result will only differ by this single line.
15 [7] GETGLOBAL 4 -3 ; print
16 [7] LOADK 5 -5 ; 4
17 [7] CALL 4 2 1
18 [8] GETGLOBAL 4 -3 ; print
19 [8] LOADK 5 -6 ; 5
20 [8] CALL 4 2 1
21 [1] FORLOOP 0 -17 ; to 5
22 [10] RETURN 0 1
Straight from the designer of Lua himself:
Our main concern with "continue" is that there are several other control structures that (in our view) are more or less as important as "continue" and may even replace it. (E.g., break with labels [as in Java] or even a more generic goto.) "continue" does not seem more special than other control-structure mechanisms, except that it is present in more languages. (Perl actually has two "continue" statements, "next" and "redo". Both are useful.)
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
I've never used Lua before, but I Googled it and came up with this:
http://www.luafaq.org/
Check question 1.26.
This is a common complaint. The Lua authors felt that continue was only one of a number of possible new control flow mechanisms (the fact that it cannot work with the scope rules of repeat/until was a secondary factor.)
In Lua 5.2, there is a goto statement which can be easily used to do the same job.
Lua is lightweight scripting language which want to smaller as possible. For example, many unary operation such as pre/post increment is not available
Instead of continue, you can use goto like
arr = {1,2,3,45,6,7,8}
for key,val in ipairs(arr) do
if val > 6 then
goto skip_to_next
end
# perform some calculation
::skip_to_next::
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
We encountered this scenario many times and we simply use a flag to simulate continue. We try to avoid the use of goto statements as well.
Example: The code intends to print the statements from i=1 to i=10 except i=3. In addition it also prints "loop start", loop end", "if start", and "if end" to simulate other nested statements that exist in your code.
size = 10
for i=1, size do
print("loop start")
if whatever then
print("if start")
if (i == 3) then
print("i is 3")
--continue
end
print(j)
print("if end")
end
print("loop end")
end
is achieved by enclosing all remaining statements until the end scope of the loop with a test flag.
size = 10
for i=1, size do
print("loop start")
local continue = false; -- initialize flag at the start of the loop
if whatever then
print("if start")
if (i == 3) then
print("i is 3")
continue = true
end
if continue==false then -- test flag
print(j)
print("if end")
end
end
if (continue==false) then -- test flag
print("loop end")
end
end
I'm not saying that this is the best approach but it works perfectly to us.
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
Why is there no continue?
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.²
What workarounds are there for it?
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 number 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 gotos also puts you in danger of having a copy of SICP thrown at you whenever you show your code to anybody else.