[{"data":1,"prerenderedAt":5466},["ShallowReactive",2],{"page-\u002Flua\u002F03-functions":3},{"id":4,"title":5,"body":6,"description":5459,"extension":5460,"meta":5461,"navigation":172,"path":5462,"seo":5463,"stem":5464,"__hash__":5465},"content\u002Flua\u002F03-functions.md","Lua 03 — Functions, Closures, Varargs & TCO",{"type":7,"value":8,"toc":5437},"minimark",[9,14,32,37,432,436,5433],[10,11,13],"h1",{"id":12},"_03-functions-closures-varargs-tco","03 — Functions, Closures, Varargs & TCO",[15,16,17,18,22,23,27,28,31],"p",{},"Functions are first-class values — closures with captured upvalues. Lua optimizes ",[19,20,21],"strong",{},"proper tail calls"," (PTC), meaning ",[24,25,26],"code",{},"return f()"," doesn't grow the call stack. Multiple return values and varargs (",[24,29,30],{},"...",") are core semantics, not afterthoughts. This chapter covers the mechanics that separate \"knowing Lua syntax\" from building state machines, pipelines, and zero-allocation iterators.",[33,34,36],"h2",{"id":35},"declaration-forms-first-class-semantics","Declaration Forms & First-Class Semantics",[38,39,41],"code-wrapper",{"language":40},"lua",[42,43,47],"pre",{"className":44,"code":45,"language":40,"meta":46,"style":46},"language-lua shiki shiki-themes github-light github-dark","-- Syntactic sugar: `local function f() end` is exactly:\nlocal f = function() end  -- but with one difference: the local is visible inside the body\n-- This matters for recursion:\nlocal function fact(n)        -- f is visible to itself (can recurse)\n  if n \u003C= 1 then return 1 end\n  return n * fact(n - 1)       -- fact refers to the local, not a global\nend\n\n-- This FAILS — local not yet defined when function is created:\nlocal fact = function(n)\n  if n \u003C= 1 then return 1 end\n  return n * fact(n - 1)  -- ERROR: fact is nil at call time (local not assigned yet)\nend\n\n-- Method syntax: obj:method() is sugar for obj.method(obj)\nlocal Obj = {}\nfunction Obj:method(x)  -- sugar for: Obj.method = function(self, x)\n  return self, x\nend\nObj:method(42)  -- (Obj, 42) — self = Obj\nObj.method(Obj, 42)  -- equivalent explicit form\n\n-- Functions as values: pass, store, return\nlocal apply = function(f, x) return f(x) end     -- higher-order function\nlocal add = function(a, b) return a + b end\napply(add, 2, 3)  -- 5 (add ignores the extra arg)\n","",[24,48,49,58,85,91,107,134,161,167,174,180,194,213,236,241,246,252,266,287,298,303,324,342,347,353,381,409],{"__ignoreMap":46},[50,51,54],"span",{"class":52,"line":53},"line",1,[50,55,57],{"class":56},"sdCPZ","-- Syntactic sugar: `local function f() end` is exactly:\n",[50,59,61,65,69,72,75,79,82],{"class":52,"line":60},2,[50,62,64],{"class":63},"svdQ7","local",[50,66,68],{"class":67},"sIsaT"," f",[50,70,71],{"class":63}," =",[50,73,74],{"class":63}," function",[50,76,78],{"class":77},"ssxIu","() ",[50,80,81],{"class":63},"end",[50,83,84],{"class":56},"  -- but with one difference: the local is visible inside the body\n",[50,86,88],{"class":52,"line":87},3,[50,89,90],{"class":56},"-- This matters for recursion:\n",[50,92,94,96,98,101,104],{"class":52,"line":93},4,[50,95,64],{"class":63},[50,97,74],{"class":63},[50,99,100],{"class":67}," fact",[50,102,103],{"class":77},"(n)        ",[50,105,106],{"class":56},"-- f is visible to itself (can recurse)\n",[50,108,110,113,116,119,123,126,129,131],{"class":52,"line":109},5,[50,111,112],{"class":63},"  if",[50,114,115],{"class":77}," n ",[50,117,118],{"class":63},"\u003C=",[50,120,122],{"class":121},"snvgF"," 1",[50,124,125],{"class":63}," then",[50,127,128],{"class":63}," return",[50,130,122],{"class":121},[50,132,133],{"class":63}," end\n",[50,135,137,140,142,145,147,150,153,155,158],{"class":52,"line":136},6,[50,138,139],{"class":63},"  return",[50,141,115],{"class":77},[50,143,144],{"class":63},"*",[50,146,100],{"class":121},[50,148,149],{"class":77},"(n ",[50,151,152],{"class":63},"-",[50,154,122],{"class":121},[50,156,157],{"class":77},")       ",[50,159,160],{"class":56},"-- fact refers to the local, not a global\n",[50,162,164],{"class":52,"line":163},7,[50,165,166],{"class":63},"end\n",[50,168,170],{"class":52,"line":169},8,[50,171,173],{"emptyLinePlaceholder":172},true,"\n",[50,175,177],{"class":52,"line":176},9,[50,178,179],{"class":56},"-- This FAILS — local not yet defined when function is created:\n",[50,181,183,185,187,189,191],{"class":52,"line":182},10,[50,184,64],{"class":63},[50,186,100],{"class":67},[50,188,71],{"class":63},[50,190,74],{"class":63},[50,192,193],{"class":77},"(n)\n",[50,195,197,199,201,203,205,207,209,211],{"class":52,"line":196},11,[50,198,112],{"class":63},[50,200,115],{"class":77},[50,202,118],{"class":63},[50,204,122],{"class":121},[50,206,125],{"class":63},[50,208,128],{"class":63},[50,210,122],{"class":121},[50,212,133],{"class":63},[50,214,216,218,220,222,224,226,228,230,233],{"class":52,"line":215},12,[50,217,139],{"class":63},[50,219,115],{"class":77},[50,221,144],{"class":63},[50,223,100],{"class":121},[50,225,149],{"class":77},[50,227,152],{"class":63},[50,229,122],{"class":121},[50,231,232],{"class":77},")  ",[50,234,235],{"class":56},"-- ERROR: fact is nil at call time (local not assigned yet)\n",[50,237,239],{"class":52,"line":238},13,[50,240,166],{"class":63},[50,242,244],{"class":52,"line":243},14,[50,245,173],{"emptyLinePlaceholder":172},[50,247,249],{"class":52,"line":248},15,[50,250,251],{"class":56},"-- Method syntax: obj:method() is sugar for obj.method(obj)\n",[50,253,255,257,260,263],{"class":52,"line":254},16,[50,256,64],{"class":63},[50,258,259],{"class":77}," Obj ",[50,261,262],{"class":63},"=",[50,264,265],{"class":77}," {}\n",[50,267,269,272,275,278,281,284],{"class":52,"line":268},17,[50,270,271],{"class":63},"function",[50,273,274],{"class":67}," Obj",[50,276,277],{"class":77},":",[50,279,280],{"class":67},"method",[50,282,283],{"class":77},"(x)  ",[50,285,286],{"class":56},"-- sugar for: Obj.method = function(self, x)\n",[50,288,290,292,295],{"class":52,"line":289},18,[50,291,139],{"class":63},[50,293,294],{"class":121}," self",[50,296,297],{"class":77},", x\n",[50,299,301],{"class":52,"line":300},19,[50,302,166],{"class":63},[50,304,306,309,311,313,316,319,321],{"class":52,"line":305},20,[50,307,308],{"class":67},"Obj",[50,310,277],{"class":77},[50,312,280],{"class":121},[50,314,315],{"class":77},"(",[50,317,318],{"class":121},"42",[50,320,232],{"class":77},[50,322,323],{"class":56},"-- (Obj, 42) — self = Obj\n",[50,325,327,330,332,335,337,339],{"class":52,"line":326},21,[50,328,329],{"class":77},"Obj.",[50,331,280],{"class":121},[50,333,334],{"class":77},"(Obj, ",[50,336,318],{"class":121},[50,338,232],{"class":77},[50,340,341],{"class":56},"-- equivalent explicit form\n",[50,343,345],{"class":52,"line":344},22,[50,346,173],{"emptyLinePlaceholder":172},[50,348,350],{"class":52,"line":349},23,[50,351,352],{"class":56},"-- Functions as values: pass, store, return\n",[50,354,356,358,361,363,365,368,371,373,376,378],{"class":52,"line":355},24,[50,357,64],{"class":63},[50,359,360],{"class":67}," apply",[50,362,71],{"class":63},[50,364,74],{"class":63},[50,366,367],{"class":77},"(f, x) ",[50,369,370],{"class":63},"return",[50,372,68],{"class":121},[50,374,375],{"class":77},"(x) ",[50,377,81],{"class":63},[50,379,380],{"class":56},"     -- higher-order function\n",[50,382,384,386,389,391,393,396,398,401,404,407],{"class":52,"line":383},25,[50,385,64],{"class":63},[50,387,388],{"class":67}," add",[50,390,71],{"class":63},[50,392,74],{"class":63},[50,394,395],{"class":77},"(a, b) ",[50,397,370],{"class":63},[50,399,400],{"class":77}," a ",[50,402,403],{"class":63},"+",[50,405,406],{"class":77}," b ",[50,408,166],{"class":63},[50,410,412,415,418,421,424,427,429],{"class":52,"line":411},26,[50,413,414],{"class":121},"apply",[50,416,417],{"class":77},"(add, ",[50,419,420],{"class":121},"2",[50,422,423],{"class":77},", ",[50,425,426],{"class":121},"3",[50,428,232],{"class":77},[50,430,431],{"class":56},"-- 5 (add ignores the extra arg)\n",[33,433,435],{"id":434},"multiple-return-values-mrv","Multiple Return Values (MRV)",[38,437,438,838,843,1094,1110,1562,1569,1819,1823,2348,2352,2362,3013,3017,3270,3274,3691,3695,4329,4336,4502,4506,4516,4609,4617,4737,4746,4977,4981,4993,5026,5043,5066,5110,5114],{"language":40},[42,439,441],{"className":44,"code":440,"language":40,"meta":46,"style":46},"-- Functions return multiple values separated by commas\nlocal function minmax(arr)\n  local lo, hi = math.huge, -math.huge\n  for _, v in ipairs(arr) do\n    if v \u003C lo then lo = v end\n    if v > hi then hi = v end\n  end\n  return lo, hi\nend\n\nlocal lo, hi = minmax({3, 1, 4, 1, 5, 9, 2, 6})  -- 1, 9\nlocal only_lo = minmax({3, 1, 4})                 -- 1 (extra discarded)\nlocal t = {minmax({3, 1, 4})}                     -- {1, 4} (all values packed)\nlocal t2 = {minmax({3, 1, 4}), 99}                -- {1, 4, 99}\n\n-- MRV adjustment rules (critical to know):\n-- 1. As the LAST argument in a call\u002Ftable: all values used\n-- 2. NOT the last argument: only first value used (rest discarded)\nprint(minmax({3, 1, 4}), 99)    -- 1  9  99  (all from minmax + 99)\nprint(99, minmax({3, 1, 4}))    -- 99  1      (minmax not last → only first value!)\nlocal t3 = {minmax({3,1,4}), \"end\"}  -- {1, \"end\"} — minmax truncated to 1 value\n",[24,442,443,448,460,480,500,525,547,552,559,563,567,621,650,683,720,724,729,734,739,770,800],{"__ignoreMap":46},[50,444,445],{"class":52,"line":53},[50,446,447],{"class":56},"-- Functions return multiple values separated by commas\n",[50,449,450,452,454,457],{"class":52,"line":60},[50,451,64],{"class":63},[50,453,74],{"class":63},[50,455,456],{"class":67}," minmax",[50,458,459],{"class":77},"(arr)\n",[50,461,462,465,468,470,473,475,477],{"class":52,"line":87},[50,463,464],{"class":63},"  local",[50,466,467],{"class":77}," lo, hi ",[50,469,262],{"class":63},[50,471,472],{"class":121}," math.huge",[50,474,423],{"class":77},[50,476,152],{"class":63},[50,478,479],{"class":121},"math.huge\n",[50,481,482,485,488,491,494,497],{"class":52,"line":93},[50,483,484],{"class":63},"  for",[50,486,487],{"class":77}," _, v ",[50,489,490],{"class":63},"in",[50,492,493],{"class":121}," ipairs",[50,495,496],{"class":77},"(arr) ",[50,498,499],{"class":63},"do\n",[50,501,502,505,508,511,514,517,519,521,523],{"class":52,"line":109},[50,503,504],{"class":63},"    if",[50,506,507],{"class":77}," v ",[50,509,510],{"class":63},"\u003C",[50,512,513],{"class":77}," lo ",[50,515,516],{"class":63},"then",[50,518,513],{"class":77},[50,520,262],{"class":63},[50,522,507],{"class":77},[50,524,166],{"class":63},[50,526,527,529,531,534,537,539,541,543,545],{"class":52,"line":136},[50,528,504],{"class":63},[50,530,507],{"class":77},[50,532,533],{"class":63},">",[50,535,536],{"class":77}," hi ",[50,538,516],{"class":63},[50,540,536],{"class":77},[50,542,262],{"class":63},[50,544,507],{"class":77},[50,546,166],{"class":63},[50,548,549],{"class":52,"line":163},[50,550,551],{"class":63},"  end\n",[50,553,554,556],{"class":52,"line":169},[50,555,139],{"class":63},[50,557,558],{"class":77}," lo, hi\n",[50,560,561],{"class":52,"line":176},[50,562,166],{"class":63},[50,564,565],{"class":52,"line":182},[50,566,173],{"emptyLinePlaceholder":172},[50,568,569,571,573,575,577,580,582,584,587,589,592,594,596,598,601,603,606,608,610,612,615,618],{"class":52,"line":196},[50,570,64],{"class":63},[50,572,467],{"class":77},[50,574,262],{"class":63},[50,576,456],{"class":121},[50,578,579],{"class":77},"({",[50,581,426],{"class":121},[50,583,423],{"class":77},[50,585,586],{"class":121},"1",[50,588,423],{"class":77},[50,590,591],{"class":121},"4",[50,593,423],{"class":77},[50,595,586],{"class":121},[50,597,423],{"class":77},[50,599,600],{"class":121},"5",[50,602,423],{"class":77},[50,604,605],{"class":121},"9",[50,607,423],{"class":77},[50,609,420],{"class":121},[50,611,423],{"class":77},[50,613,614],{"class":121},"6",[50,616,617],{"class":77},"})  ",[50,619,620],{"class":56},"-- 1, 9\n",[50,622,623,625,628,630,632,634,636,638,640,642,644,647],{"class":52,"line":215},[50,624,64],{"class":63},[50,626,627],{"class":77}," only_lo ",[50,629,262],{"class":63},[50,631,456],{"class":121},[50,633,579],{"class":77},[50,635,426],{"class":121},[50,637,423],{"class":77},[50,639,586],{"class":121},[50,641,423],{"class":77},[50,643,591],{"class":121},[50,645,646],{"class":77},"})                 ",[50,648,649],{"class":56},"-- 1 (extra discarded)\n",[50,651,652,654,657,659,662,665,667,669,671,673,675,677,680],{"class":52,"line":238},[50,653,64],{"class":63},[50,655,656],{"class":77}," t ",[50,658,262],{"class":63},[50,660,661],{"class":77}," {",[50,663,664],{"class":121},"minmax",[50,666,579],{"class":77},[50,668,426],{"class":121},[50,670,423],{"class":77},[50,672,586],{"class":121},[50,674,423],{"class":77},[50,676,591],{"class":121},[50,678,679],{"class":77},"})}                     ",[50,681,682],{"class":56},"-- {1, 4} (all values packed)\n",[50,684,685,687,690,692,694,696,698,700,702,704,706,708,711,714,717],{"class":52,"line":243},[50,686,64],{"class":63},[50,688,689],{"class":77}," t2 ",[50,691,262],{"class":63},[50,693,661],{"class":77},[50,695,664],{"class":121},[50,697,579],{"class":77},[50,699,426],{"class":121},[50,701,423],{"class":77},[50,703,586],{"class":121},[50,705,423],{"class":77},[50,707,591],{"class":121},[50,709,710],{"class":77},"}), ",[50,712,713],{"class":121},"99",[50,715,716],{"class":77},"}                ",[50,718,719],{"class":56},"-- {1, 4, 99}\n",[50,721,722],{"class":52,"line":248},[50,723,173],{"emptyLinePlaceholder":172},[50,725,726],{"class":52,"line":254},[50,727,728],{"class":56},"-- MRV adjustment rules (critical to know):\n",[50,730,731],{"class":52,"line":268},[50,732,733],{"class":56},"-- 1. As the LAST argument in a call\u002Ftable: all values used\n",[50,735,736],{"class":52,"line":289},[50,737,738],{"class":56},"-- 2. NOT the last argument: only first value used (rest discarded)\n",[50,740,741,744,746,748,750,752,754,756,758,760,762,764,767],{"class":52,"line":300},[50,742,743],{"class":121},"print",[50,745,315],{"class":77},[50,747,664],{"class":121},[50,749,579],{"class":77},[50,751,426],{"class":121},[50,753,423],{"class":77},[50,755,586],{"class":121},[50,757,423],{"class":77},[50,759,591],{"class":121},[50,761,710],{"class":77},[50,763,713],{"class":121},[50,765,766],{"class":77},")    ",[50,768,769],{"class":56},"-- 1  9  99  (all from minmax + 99)\n",[50,771,772,774,776,778,780,782,784,786,788,790,792,794,797],{"class":52,"line":305},[50,773,743],{"class":121},[50,775,315],{"class":77},[50,777,713],{"class":121},[50,779,423],{"class":77},[50,781,664],{"class":121},[50,783,579],{"class":77},[50,785,426],{"class":121},[50,787,423],{"class":77},[50,789,586],{"class":121},[50,791,423],{"class":77},[50,793,591],{"class":121},[50,795,796],{"class":77},"}))    ",[50,798,799],{"class":56},"-- 99  1      (minmax not last → only first value!)\n",[50,801,802,804,807,809,811,813,815,817,820,822,824,826,828,832,835],{"class":52,"line":326},[50,803,64],{"class":63},[50,805,806],{"class":77}," t3 ",[50,808,262],{"class":63},[50,810,661],{"class":77},[50,812,664],{"class":121},[50,814,579],{"class":77},[50,816,426],{"class":121},[50,818,819],{"class":77},",",[50,821,586],{"class":121},[50,823,819],{"class":77},[50,825,591],{"class":121},[50,827,710],{"class":77},[50,829,831],{"class":830},"sJ6F3","\"end\"",[50,833,834],{"class":77},"}  ",[50,836,837],{"class":56},"-- {1, \"end\"} — minmax truncated to 1 value\n",[839,840,842],"h3",{"id":841},"anti-pattern-mrv-truncation-in-table-constructors","Anti-pattern: MRV truncation in table constructors",[38,844,845],{"language":40},[42,846,848],{"className":44,"code":847,"language":40,"meta":46,"style":46},"-- BAD: when a multi-return call isn't the last element, values are silently lost\nlocal function get_pos() return 10, 20, 30 end\nlocal points = {get_pos(), get_pos(), get_pos()}\n-- Expect: {10,20,30,10,20,30,10,20,30}\n-- Actual: {10,10,10}  — only first value from each call!\n\n-- FIX: wrap each in parens to force single-value, or use table.insert loop\nlocal function collect(...)\n  local out = {}\n  for _, v in ipairs({...}) do\n    -- ... but this has the same problem with MRV inside {...}\n  end\nend\n\n-- Production: use a builder pattern\nlocal points = {}\nlocal function add_point(x, y, z)\n  points[#points + 1] = x\n  points[#points + 1] = y\n  points[#points + 1] = z\nend\nadd_point(get_pos())   -- distributes 10,20,30 into x,y,z → appends 3 values\n",[24,849,850,855,883,909,914,919,923,928,940,951,970,975,979,983,987,992,1002,1014,1037,1056,1075,1079],{"__ignoreMap":46},[50,851,852],{"class":52,"line":53},[50,853,854],{"class":56},"-- BAD: when a multi-return call isn't the last element, values are silently lost\n",[50,856,857,859,861,864,866,868,871,873,876,878,881],{"class":52,"line":60},[50,858,64],{"class":63},[50,860,74],{"class":63},[50,862,863],{"class":67}," get_pos",[50,865,78],{"class":77},[50,867,370],{"class":63},[50,869,870],{"class":121}," 10",[50,872,423],{"class":77},[50,874,875],{"class":121},"20",[50,877,423],{"class":77},[50,879,880],{"class":121},"30",[50,882,133],{"class":63},[50,884,885,887,890,892,894,897,900,902,904,906],{"class":52,"line":87},[50,886,64],{"class":63},[50,888,889],{"class":77}," points ",[50,891,262],{"class":63},[50,893,661],{"class":77},[50,895,896],{"class":121},"get_pos",[50,898,899],{"class":77},"(), ",[50,901,896],{"class":121},[50,903,899],{"class":77},[50,905,896],{"class":121},[50,907,908],{"class":77},"()}\n",[50,910,911],{"class":52,"line":93},[50,912,913],{"class":56},"-- Expect: {10,20,30,10,20,30,10,20,30}\n",[50,915,916],{"class":52,"line":109},[50,917,918],{"class":56},"-- Actual: {10,10,10}  — only first value from each call!\n",[50,920,921],{"class":52,"line":136},[50,922,173],{"emptyLinePlaceholder":172},[50,924,925],{"class":52,"line":163},[50,926,927],{"class":56},"-- FIX: wrap each in parens to force single-value, or use table.insert loop\n",[50,929,930,932,934,937],{"class":52,"line":169},[50,931,64],{"class":63},[50,933,74],{"class":63},[50,935,936],{"class":67}," collect",[50,938,939],{"class":77},"(...)\n",[50,941,942,944,947,949],{"class":52,"line":176},[50,943,464],{"class":63},[50,945,946],{"class":77}," out ",[50,948,262],{"class":63},[50,950,265],{"class":77},[50,952,953,955,957,959,961,963,965,968],{"class":52,"line":182},[50,954,484],{"class":63},[50,956,487],{"class":77},[50,958,490],{"class":63},[50,960,493],{"class":121},[50,962,579],{"class":77},[50,964,30],{"class":121},[50,966,967],{"class":77},"}) ",[50,969,499],{"class":63},[50,971,972],{"class":52,"line":196},[50,973,974],{"class":56},"    -- ... but this has the same problem with MRV inside {...}\n",[50,976,977],{"class":52,"line":215},[50,978,551],{"class":63},[50,980,981],{"class":52,"line":238},[50,982,166],{"class":63},[50,984,985],{"class":52,"line":243},[50,986,173],{"emptyLinePlaceholder":172},[50,988,989],{"class":52,"line":248},[50,990,991],{"class":56},"-- Production: use a builder pattern\n",[50,993,994,996,998,1000],{"class":52,"line":254},[50,995,64],{"class":63},[50,997,889],{"class":77},[50,999,262],{"class":63},[50,1001,265],{"class":77},[50,1003,1004,1006,1008,1011],{"class":52,"line":268},[50,1005,64],{"class":63},[50,1007,74],{"class":63},[50,1009,1010],{"class":67}," add_point",[50,1012,1013],{"class":77},"(x, y, z)\n",[50,1015,1016,1019,1022,1025,1027,1029,1032,1034],{"class":52,"line":289},[50,1017,1018],{"class":77},"  points[",[50,1020,1021],{"class":63},"#",[50,1023,1024],{"class":77},"points ",[50,1026,403],{"class":63},[50,1028,122],{"class":121},[50,1030,1031],{"class":77},"] ",[50,1033,262],{"class":63},[50,1035,1036],{"class":77}," x\n",[50,1038,1039,1041,1043,1045,1047,1049,1051,1053],{"class":52,"line":300},[50,1040,1018],{"class":77},[50,1042,1021],{"class":63},[50,1044,1024],{"class":77},[50,1046,403],{"class":63},[50,1048,122],{"class":121},[50,1050,1031],{"class":77},[50,1052,262],{"class":63},[50,1054,1055],{"class":77}," y\n",[50,1057,1058,1060,1062,1064,1066,1068,1070,1072],{"class":52,"line":305},[50,1059,1018],{"class":77},[50,1061,1021],{"class":63},[50,1063,1024],{"class":77},[50,1065,403],{"class":63},[50,1067,122],{"class":121},[50,1069,1031],{"class":77},[50,1071,262],{"class":63},[50,1073,1074],{"class":77}," z\n",[50,1076,1077],{"class":52,"line":326},[50,1078,166],{"class":63},[50,1080,1081,1084,1086,1088,1091],{"class":52,"line":344},[50,1082,1083],{"class":121},"add_point",[50,1085,315],{"class":77},[50,1087,896],{"class":121},[50,1089,1090],{"class":77},"())   ",[50,1092,1093],{"class":56},"-- distributes 10,20,30 into x,y,z → appends 3 values\n",[33,1095,1097,1098,423,1100,423,1103,1106,1107],{"id":1096},"varargs-select-tablepackunpack","Varargs: ",[24,1099,30],{},[24,1101,1102],{},"select",[24,1104,1105],{},"table.pack","\u002F",[24,1108,1109],{},"unpack",[38,1111,1112],{"language":40},[42,1113,1115],{"className":44,"code":1114,"language":40,"meta":46,"style":46},"-- `...` is a vararg expression. In a function body, it expands to all arguments.\n-- As the last expression in a list, it expands to all values; otherwise just first.\n\nlocal function log(level, ...)\n  -- select(\"#\", ...): count of varargs (zero allocation)\n  -- select(i, ...): returns args i..n (zero allocation — no table created)\n  local n = select(\"#\", ...)\n  if level == \"debug\" then\n    for i = 1, n do\n      io.write(tostring(select(i, ...)), \" \")  -- stream each arg without packing\n    end\n    io.write(\"\\n\")\n  end\nend\n\n-- table.pack (5.2+): packs varargs into a table with .n = count\n-- CRITICAL: preserves trailing nils (which {...} does NOT)\nlocal function safe_pack(...)\n  local t = table.pack(...)\n  -- t.n has the count, even if last args were nil\n  -- t[1], t[2], ... t[t.n] have the values\n  return t\nend\n\nlocal packed = safe_pack(1, nil, 3, nil)\nprint(packed.n)      -- 4 (count preserved)\nprint(packed[2])     -- nil (value is nil, but key exists — distinguish from missing)\n#packed             -- 0 or 3 (undefined — don't use # on packed varargs with nils)\n\n-- table.unpack: the inverse — unpacks a table into values\nlocal args = {10, 20, 30}\nprint(table.unpack(args))  -- 10  20  30\nprint(table.unpack(args, 2, 3))  -- 20  30  (range: start, end)\n\n-- Forwarding varargs:\nlocal function delegate(fn, ...)\n  return fn(...)  -- passes all varargs through, preserves MRV\nend\ndelegate(print, \"a\", \"b\", \"c\")  -- a b c\n",[24,1116,1117,1122,1127,1131,1143,1148,1153,1176,1192,1209,1239,1244,1261,1265,1269,1273,1278,1283,1294,1311,1316,1321,1328,1332,1336,1366,1382,1398,1409,1414,1420,1446,1462,1486,1491,1497,1510,1527,1532],{"__ignoreMap":46},[50,1118,1119],{"class":52,"line":53},[50,1120,1121],{"class":56},"-- `...` is a vararg expression. In a function body, it expands to all arguments.\n",[50,1123,1124],{"class":52,"line":60},[50,1125,1126],{"class":56},"-- As the last expression in a list, it expands to all values; otherwise just first.\n",[50,1128,1129],{"class":52,"line":87},[50,1130,173],{"emptyLinePlaceholder":172},[50,1132,1133,1135,1137,1140],{"class":52,"line":93},[50,1134,64],{"class":63},[50,1136,74],{"class":63},[50,1138,1139],{"class":67}," log",[50,1141,1142],{"class":77},"(level, ...)\n",[50,1144,1145],{"class":52,"line":109},[50,1146,1147],{"class":56},"  -- select(\"#\", ...): count of varargs (zero allocation)\n",[50,1149,1150],{"class":52,"line":136},[50,1151,1152],{"class":56},"  -- select(i, ...): returns args i..n (zero allocation — no table created)\n",[50,1154,1155,1157,1159,1161,1164,1166,1169,1171,1173],{"class":52,"line":163},[50,1156,464],{"class":63},[50,1158,115],{"class":77},[50,1160,262],{"class":63},[50,1162,1163],{"class":121}," select",[50,1165,315],{"class":77},[50,1167,1168],{"class":830},"\"#\"",[50,1170,423],{"class":77},[50,1172,30],{"class":121},[50,1174,1175],{"class":77},")\n",[50,1177,1178,1180,1183,1186,1189],{"class":52,"line":169},[50,1179,112],{"class":63},[50,1181,1182],{"class":77}," level ",[50,1184,1185],{"class":63},"==",[50,1187,1188],{"class":830}," \"debug\" ",[50,1190,1191],{"class":63},"then\n",[50,1193,1194,1197,1200,1202,1204,1207],{"class":52,"line":176},[50,1195,1196],{"class":63},"    for",[50,1198,1199],{"class":77}," i ",[50,1201,262],{"class":63},[50,1203,122],{"class":121},[50,1205,1206],{"class":77},", n ",[50,1208,499],{"class":63},[50,1210,1211,1214,1216,1219,1221,1223,1226,1228,1231,1234,1236],{"class":52,"line":182},[50,1212,1213],{"class":121},"      io.write",[50,1215,315],{"class":77},[50,1217,1218],{"class":121},"tostring",[50,1220,315],{"class":77},[50,1222,1102],{"class":121},[50,1224,1225],{"class":77},"(i, ",[50,1227,30],{"class":121},[50,1229,1230],{"class":77},")), ",[50,1232,1233],{"class":830},"\" \"",[50,1235,232],{"class":77},[50,1237,1238],{"class":56},"-- stream each arg without packing\n",[50,1240,1241],{"class":52,"line":196},[50,1242,1243],{"class":63},"    end\n",[50,1245,1246,1249,1251,1254,1257,1259],{"class":52,"line":215},[50,1247,1248],{"class":121},"    io.write",[50,1250,315],{"class":77},[50,1252,1253],{"class":830},"\"",[50,1255,1256],{"class":121},"\\n",[50,1258,1253],{"class":830},[50,1260,1175],{"class":77},[50,1262,1263],{"class":52,"line":238},[50,1264,551],{"class":63},[50,1266,1267],{"class":52,"line":243},[50,1268,166],{"class":63},[50,1270,1271],{"class":52,"line":248},[50,1272,173],{"emptyLinePlaceholder":172},[50,1274,1275],{"class":52,"line":254},[50,1276,1277],{"class":56},"-- table.pack (5.2+): packs varargs into a table with .n = count\n",[50,1279,1280],{"class":52,"line":268},[50,1281,1282],{"class":56},"-- CRITICAL: preserves trailing nils (which {...} does NOT)\n",[50,1284,1285,1287,1289,1292],{"class":52,"line":289},[50,1286,64],{"class":63},[50,1288,74],{"class":63},[50,1290,1291],{"class":67}," safe_pack",[50,1293,939],{"class":77},[50,1295,1296,1298,1300,1302,1305,1307,1309],{"class":52,"line":300},[50,1297,464],{"class":63},[50,1299,656],{"class":77},[50,1301,262],{"class":63},[50,1303,1304],{"class":121}," table.pack",[50,1306,315],{"class":77},[50,1308,30],{"class":121},[50,1310,1175],{"class":77},[50,1312,1313],{"class":52,"line":305},[50,1314,1315],{"class":56},"  -- t.n has the count, even if last args were nil\n",[50,1317,1318],{"class":52,"line":326},[50,1319,1320],{"class":56},"  -- t[1], t[2], ... t[t.n] have the values\n",[50,1322,1323,1325],{"class":52,"line":344},[50,1324,139],{"class":63},[50,1326,1327],{"class":77}," t\n",[50,1329,1330],{"class":52,"line":349},[50,1331,166],{"class":63},[50,1333,1334],{"class":52,"line":355},[50,1335,173],{"emptyLinePlaceholder":172},[50,1337,1338,1340,1343,1345,1347,1349,1351,1353,1356,1358,1360,1362,1364],{"class":52,"line":383},[50,1339,64],{"class":63},[50,1341,1342],{"class":77}," packed ",[50,1344,262],{"class":63},[50,1346,1291],{"class":121},[50,1348,315],{"class":77},[50,1350,586],{"class":121},[50,1352,423],{"class":77},[50,1354,1355],{"class":121},"nil",[50,1357,423],{"class":77},[50,1359,426],{"class":121},[50,1361,423],{"class":77},[50,1363,1355],{"class":121},[50,1365,1175],{"class":77},[50,1367,1368,1370,1373,1376,1379],{"class":52,"line":411},[50,1369,743],{"class":121},[50,1371,1372],{"class":77},"(packed.",[50,1374,1375],{"class":67},"n",[50,1377,1378],{"class":77},")      ",[50,1380,1381],{"class":56},"-- 4 (count preserved)\n",[50,1383,1385,1387,1390,1392,1395],{"class":52,"line":1384},27,[50,1386,743],{"class":121},[50,1388,1389],{"class":77},"(packed[",[50,1391,420],{"class":121},[50,1393,1394],{"class":77},"])     ",[50,1396,1397],{"class":56},"-- nil (value is nil, but key exists — distinguish from missing)\n",[50,1399,1401,1403,1406],{"class":52,"line":1400},28,[50,1402,1021],{"class":63},[50,1404,1405],{"class":77},"packed             ",[50,1407,1408],{"class":56},"-- 0 or 3 (undefined — don't use # on packed varargs with nils)\n",[50,1410,1412],{"class":52,"line":1411},29,[50,1413,173],{"emptyLinePlaceholder":172},[50,1415,1417],{"class":52,"line":1416},30,[50,1418,1419],{"class":56},"-- table.unpack: the inverse — unpacks a table into values\n",[50,1421,1423,1425,1428,1430,1432,1435,1437,1439,1441,1443],{"class":52,"line":1422},31,[50,1424,64],{"class":63},[50,1426,1427],{"class":77}," args ",[50,1429,262],{"class":63},[50,1431,661],{"class":77},[50,1433,1434],{"class":121},"10",[50,1436,423],{"class":77},[50,1438,875],{"class":121},[50,1440,423],{"class":77},[50,1442,880],{"class":121},[50,1444,1445],{"class":77},"}\n",[50,1447,1449,1451,1453,1456,1459],{"class":52,"line":1448},32,[50,1450,743],{"class":121},[50,1452,315],{"class":77},[50,1454,1455],{"class":121},"table.unpack",[50,1457,1458],{"class":77},"(args))  ",[50,1460,1461],{"class":56},"-- 10  20  30\n",[50,1463,1465,1467,1469,1471,1474,1476,1478,1480,1483],{"class":52,"line":1464},33,[50,1466,743],{"class":121},[50,1468,315],{"class":77},[50,1470,1455],{"class":121},[50,1472,1473],{"class":77},"(args, ",[50,1475,420],{"class":121},[50,1477,423],{"class":77},[50,1479,426],{"class":121},[50,1481,1482],{"class":77},"))  ",[50,1484,1485],{"class":56},"-- 20  30  (range: start, end)\n",[50,1487,1489],{"class":52,"line":1488},34,[50,1490,173],{"emptyLinePlaceholder":172},[50,1492,1494],{"class":52,"line":1493},35,[50,1495,1496],{"class":56},"-- Forwarding varargs:\n",[50,1498,1500,1502,1504,1507],{"class":52,"line":1499},36,[50,1501,64],{"class":63},[50,1503,74],{"class":63},[50,1505,1506],{"class":67}," delegate",[50,1508,1509],{"class":77},"(fn, ...)\n",[50,1511,1513,1515,1518,1520,1522,1524],{"class":52,"line":1512},37,[50,1514,139],{"class":63},[50,1516,1517],{"class":121}," fn",[50,1519,315],{"class":77},[50,1521,30],{"class":121},[50,1523,232],{"class":77},[50,1525,1526],{"class":56},"-- passes all varargs through, preserves MRV\n",[50,1528,1530],{"class":52,"line":1529},38,[50,1531,166],{"class":63},[50,1533,1535,1538,1540,1542,1544,1547,1549,1552,1554,1557,1559],{"class":52,"line":1534},39,[50,1536,1537],{"class":121},"delegate",[50,1539,315],{"class":77},[50,1541,743],{"class":121},[50,1543,423],{"class":77},[50,1545,1546],{"class":830},"\"a\"",[50,1548,423],{"class":77},[50,1550,1551],{"class":830},"\"b\"",[50,1553,423],{"class":77},[50,1555,1556],{"class":830},"\"c\"",[50,1558,232],{"class":77},[50,1560,1561],{"class":56},"-- a b c\n",[839,1563,1565,1566,1568],{"id":1564},"edge-case-nil-in-varargs","Edge case: ",[24,1567,1355],{}," in varargs",[38,1570,1571],{"language":40},[42,1572,1574],{"className":44,"code":1573,"language":40,"meta":46,"style":46},"-- {...} loses trailing nils — you can't tell if the caller passed (1, nil, nil) or (1)\nlocal function bad(...) return #{...} end\nbad(1, nil, nil)  -- 1 (undefined — # sees hole at index 2)\n\n-- table.pack preserves the count via .n\nlocal function good(...)\n  local t = table.pack(...)\n  return t.n      -- 3 (the actual count, including nils)\nend\ngood(1, nil, nil)  -- 3\n\n-- PRODUCTION: robust vararg iteration (handles nils in middle\u002Fend)\nlocal function each_arg(fn, ...)\n  local n = select(\"#\", ...)     -- true count, zero allocation\n  for i = 1, n do\n    fn(select(i, ...))           -- select(i, ...) returns i-th arg (nil if nil)\n  end\nend\neach_arg(print, 1, nil, 3, nil)  -- prints: 1, nil, 3, nil (all 4 args)\n",[24,1575,1576,1581,1608,1630,1634,1639,1650,1666,1678,1682,1704,1708,1713,1724,1748,1762,1781,1785,1789],{"__ignoreMap":46},[50,1577,1578],{"class":52,"line":53},[50,1579,1580],{"class":56},"-- {...} loses trailing nils — you can't tell if the caller passed (1, nil, nil) or (1)\n",[50,1582,1583,1585,1587,1590,1593,1595,1598,1601,1603,1606],{"class":52,"line":60},[50,1584,64],{"class":63},[50,1586,74],{"class":63},[50,1588,1589],{"class":67}," bad",[50,1591,1592],{"class":77},"(...) ",[50,1594,370],{"class":63},[50,1596,1597],{"class":63}," #",[50,1599,1600],{"class":77},"{",[50,1602,30],{"class":121},[50,1604,1605],{"class":77},"} ",[50,1607,166],{"class":63},[50,1609,1610,1613,1615,1617,1619,1621,1623,1625,1627],{"class":52,"line":87},[50,1611,1612],{"class":121},"bad",[50,1614,315],{"class":77},[50,1616,586],{"class":121},[50,1618,423],{"class":77},[50,1620,1355],{"class":121},[50,1622,423],{"class":77},[50,1624,1355],{"class":121},[50,1626,232],{"class":77},[50,1628,1629],{"class":56},"-- 1 (undefined — # sees hole at index 2)\n",[50,1631,1632],{"class":52,"line":93},[50,1633,173],{"emptyLinePlaceholder":172},[50,1635,1636],{"class":52,"line":109},[50,1637,1638],{"class":56},"-- table.pack preserves the count via .n\n",[50,1640,1641,1643,1645,1648],{"class":52,"line":136},[50,1642,64],{"class":63},[50,1644,74],{"class":63},[50,1646,1647],{"class":67}," good",[50,1649,939],{"class":77},[50,1651,1652,1654,1656,1658,1660,1662,1664],{"class":52,"line":163},[50,1653,464],{"class":63},[50,1655,656],{"class":77},[50,1657,262],{"class":63},[50,1659,1304],{"class":121},[50,1661,315],{"class":77},[50,1663,30],{"class":121},[50,1665,1175],{"class":77},[50,1667,1668,1670,1673,1675],{"class":52,"line":169},[50,1669,139],{"class":63},[50,1671,1672],{"class":77}," t.",[50,1674,1375],{"class":67},[50,1676,1677],{"class":56},"      -- 3 (the actual count, including nils)\n",[50,1679,1680],{"class":52,"line":176},[50,1681,166],{"class":63},[50,1683,1684,1687,1689,1691,1693,1695,1697,1699,1701],{"class":52,"line":182},[50,1685,1686],{"class":121},"good",[50,1688,315],{"class":77},[50,1690,586],{"class":121},[50,1692,423],{"class":77},[50,1694,1355],{"class":121},[50,1696,423],{"class":77},[50,1698,1355],{"class":121},[50,1700,232],{"class":77},[50,1702,1703],{"class":56},"-- 3\n",[50,1705,1706],{"class":52,"line":196},[50,1707,173],{"emptyLinePlaceholder":172},[50,1709,1710],{"class":52,"line":215},[50,1711,1712],{"class":56},"-- PRODUCTION: robust vararg iteration (handles nils in middle\u002Fend)\n",[50,1714,1715,1717,1719,1722],{"class":52,"line":238},[50,1716,64],{"class":63},[50,1718,74],{"class":63},[50,1720,1721],{"class":67}," each_arg",[50,1723,1509],{"class":77},[50,1725,1726,1728,1730,1732,1734,1736,1738,1740,1742,1745],{"class":52,"line":243},[50,1727,464],{"class":63},[50,1729,115],{"class":77},[50,1731,262],{"class":63},[50,1733,1163],{"class":121},[50,1735,315],{"class":77},[50,1737,1168],{"class":830},[50,1739,423],{"class":77},[50,1741,30],{"class":121},[50,1743,1744],{"class":77},")     ",[50,1746,1747],{"class":56},"-- true count, zero allocation\n",[50,1749,1750,1752,1754,1756,1758,1760],{"class":52,"line":248},[50,1751,484],{"class":63},[50,1753,1199],{"class":77},[50,1755,262],{"class":63},[50,1757,122],{"class":121},[50,1759,1206],{"class":77},[50,1761,499],{"class":63},[50,1763,1764,1767,1769,1771,1773,1775,1778],{"class":52,"line":254},[50,1765,1766],{"class":121},"    fn",[50,1768,315],{"class":77},[50,1770,1102],{"class":121},[50,1772,1225],{"class":77},[50,1774,30],{"class":121},[50,1776,1777],{"class":77},"))           ",[50,1779,1780],{"class":56},"-- select(i, ...) returns i-th arg (nil if nil)\n",[50,1782,1783],{"class":52,"line":268},[50,1784,551],{"class":63},[50,1786,1787],{"class":52,"line":289},[50,1788,166],{"class":63},[50,1790,1791,1794,1796,1798,1800,1802,1804,1806,1808,1810,1812,1814,1816],{"class":52,"line":300},[50,1792,1793],{"class":121},"each_arg",[50,1795,315],{"class":77},[50,1797,743],{"class":121},[50,1799,423],{"class":77},[50,1801,586],{"class":121},[50,1803,423],{"class":77},[50,1805,1355],{"class":121},[50,1807,423],{"class":77},[50,1809,426],{"class":121},[50,1811,423],{"class":77},[50,1813,1355],{"class":121},[50,1815,232],{"class":77},[50,1817,1818],{"class":56},"-- prints: 1, nil, 3, nil (all 4 args)\n",[33,1820,1822],{"id":1821},"closures-upvalue-mechanics","Closures & Upvalue Mechanics",[38,1824,1825],{"language":40},[42,1826,1828],{"className":44,"code":1827,"language":40,"meta":46,"style":46},"-- A closure = function + upvalues (captured locals from enclosing scope)\n-- Upvalues are heap-allocated cells. Multiple closures can share the same cell.\n\n-- 1. Counter (shared upvalue cell between get\u002Fset)\nlocal function make_counter(initial)\n  local count = initial or 0  -- becomes an upvalue cell\n  return {\n    inc = function() count = count + 1; return count end,\n    dec = function() count = count - 1; return count end,\n    get = function() return count end,\n    reset = function() count = initial or 0 end,\n  }\nend\n\nlocal c = make_counter(10)\nc.inc()  -- 11\nc.inc()  -- 12\nc.get()  -- 12\n-- inc, dec, get, reset all share the SAME count upvalue cell\n\n-- 2. Private state via closure (no metatable needed)\nlocal function create_bank_account(initial_balance)\n  local balance = initial_balance or 0  -- private — not accessible externally\n\n  return {\n    deposit = function(amount)\n      assert(amount > 0, \"must deposit positive amount\")\n      balance = balance + amount\n      return balance\n    end,\n    withdraw = function(amount)\n      assert(amount > 0, \"must withdraw positive amount\")\n      assert(balance >= amount, \"insufficient funds\")\n      balance = balance - amount\n      return balance\n    end,\n    get_balance = function() return balance end,\n  }\n  -- balance is NOT in the returned table — it's an upvalue. True encapsulation.\nend\n\nlocal acc = create_bank_account(100)\nacc.deposit(50)       -- 150\nacc.withdraw(30)      -- 120\nacc.balance           -- nil (can't access private state directly)\n",[24,1829,1830,1835,1840,1844,1849,1861,1882,1889,1921,1950,1969,1993,1998,2002,2006,2023,2037,2048,2059,2064,2068,2073,2085,2104,2108,2114,2126,2145,2159,2167,2174,2185,2202,2220,2232,2238,2244,2263,2267,2272,2277,2282,2301,2320,2337],{"__ignoreMap":46},[50,1831,1832],{"class":52,"line":53},[50,1833,1834],{"class":56},"-- A closure = function + upvalues (captured locals from enclosing scope)\n",[50,1836,1837],{"class":52,"line":60},[50,1838,1839],{"class":56},"-- Upvalues are heap-allocated cells. Multiple closures can share the same cell.\n",[50,1841,1842],{"class":52,"line":87},[50,1843,173],{"emptyLinePlaceholder":172},[50,1845,1846],{"class":52,"line":93},[50,1847,1848],{"class":56},"-- 1. Counter (shared upvalue cell between get\u002Fset)\n",[50,1850,1851,1853,1855,1858],{"class":52,"line":109},[50,1852,64],{"class":63},[50,1854,74],{"class":63},[50,1856,1857],{"class":67}," make_counter",[50,1859,1860],{"class":77},"(initial)\n",[50,1862,1863,1865,1868,1870,1873,1876,1879],{"class":52,"line":136},[50,1864,464],{"class":63},[50,1866,1867],{"class":77}," count ",[50,1869,262],{"class":63},[50,1871,1872],{"class":77}," initial ",[50,1874,1875],{"class":63},"or",[50,1877,1878],{"class":121}," 0",[50,1880,1881],{"class":56},"  -- becomes an upvalue cell\n",[50,1883,1884,1886],{"class":52,"line":163},[50,1885,139],{"class":63},[50,1887,1888],{"class":77}," {\n",[50,1890,1891,1894,1896,1898,1901,1903,1905,1907,1909,1912,1914,1916,1918],{"class":52,"line":169},[50,1892,1893],{"class":67},"    inc",[50,1895,71],{"class":63},[50,1897,74],{"class":63},[50,1899,1900],{"class":77},"() count ",[50,1902,262],{"class":63},[50,1904,1867],{"class":77},[50,1906,403],{"class":63},[50,1908,122],{"class":121},[50,1910,1911],{"class":77},"; ",[50,1913,370],{"class":63},[50,1915,1867],{"class":77},[50,1917,81],{"class":63},[50,1919,1920],{"class":77},",\n",[50,1922,1923,1926,1928,1930,1932,1934,1936,1938,1940,1942,1944,1946,1948],{"class":52,"line":176},[50,1924,1925],{"class":67},"    dec",[50,1927,71],{"class":63},[50,1929,74],{"class":63},[50,1931,1900],{"class":77},[50,1933,262],{"class":63},[50,1935,1867],{"class":77},[50,1937,152],{"class":63},[50,1939,122],{"class":121},[50,1941,1911],{"class":77},[50,1943,370],{"class":63},[50,1945,1867],{"class":77},[50,1947,81],{"class":63},[50,1949,1920],{"class":77},[50,1951,1952,1955,1957,1959,1961,1963,1965,1967],{"class":52,"line":182},[50,1953,1954],{"class":67},"    get",[50,1956,71],{"class":63},[50,1958,74],{"class":63},[50,1960,78],{"class":77},[50,1962,370],{"class":63},[50,1964,1867],{"class":77},[50,1966,81],{"class":63},[50,1968,1920],{"class":77},[50,1970,1971,1974,1976,1978,1980,1982,1984,1986,1988,1991],{"class":52,"line":196},[50,1972,1973],{"class":67},"    reset",[50,1975,71],{"class":63},[50,1977,74],{"class":63},[50,1979,1900],{"class":77},[50,1981,262],{"class":63},[50,1983,1872],{"class":77},[50,1985,1875],{"class":63},[50,1987,1878],{"class":121},[50,1989,1990],{"class":63}," end",[50,1992,1920],{"class":77},[50,1994,1995],{"class":52,"line":215},[50,1996,1997],{"class":77},"  }\n",[50,1999,2000],{"class":52,"line":238},[50,2001,166],{"class":63},[50,2003,2004],{"class":52,"line":243},[50,2005,173],{"emptyLinePlaceholder":172},[50,2007,2008,2010,2013,2015,2017,2019,2021],{"class":52,"line":248},[50,2009,64],{"class":63},[50,2011,2012],{"class":77}," c ",[50,2014,262],{"class":63},[50,2016,1857],{"class":121},[50,2018,315],{"class":77},[50,2020,1434],{"class":121},[50,2022,1175],{"class":77},[50,2024,2025,2028,2031,2034],{"class":52,"line":254},[50,2026,2027],{"class":77},"c.",[50,2029,2030],{"class":121},"inc",[50,2032,2033],{"class":77},"()  ",[50,2035,2036],{"class":56},"-- 11\n",[50,2038,2039,2041,2043,2045],{"class":52,"line":268},[50,2040,2027],{"class":77},[50,2042,2030],{"class":121},[50,2044,2033],{"class":77},[50,2046,2047],{"class":56},"-- 12\n",[50,2049,2050,2052,2055,2057],{"class":52,"line":289},[50,2051,2027],{"class":77},[50,2053,2054],{"class":121},"get",[50,2056,2033],{"class":77},[50,2058,2047],{"class":56},[50,2060,2061],{"class":52,"line":300},[50,2062,2063],{"class":56},"-- inc, dec, get, reset all share the SAME count upvalue cell\n",[50,2065,2066],{"class":52,"line":305},[50,2067,173],{"emptyLinePlaceholder":172},[50,2069,2070],{"class":52,"line":326},[50,2071,2072],{"class":56},"-- 2. Private state via closure (no metatable needed)\n",[50,2074,2075,2077,2079,2082],{"class":52,"line":344},[50,2076,64],{"class":63},[50,2078,74],{"class":63},[50,2080,2081],{"class":67}," create_bank_account",[50,2083,2084],{"class":77},"(initial_balance)\n",[50,2086,2087,2089,2092,2094,2097,2099,2101],{"class":52,"line":349},[50,2088,464],{"class":63},[50,2090,2091],{"class":77}," balance ",[50,2093,262],{"class":63},[50,2095,2096],{"class":77}," initial_balance ",[50,2098,1875],{"class":63},[50,2100,1878],{"class":121},[50,2102,2103],{"class":56},"  -- private — not accessible externally\n",[50,2105,2106],{"class":52,"line":355},[50,2107,173],{"emptyLinePlaceholder":172},[50,2109,2110,2112],{"class":52,"line":383},[50,2111,139],{"class":63},[50,2113,1888],{"class":77},[50,2115,2116,2119,2121,2123],{"class":52,"line":411},[50,2117,2118],{"class":67},"    deposit",[50,2120,71],{"class":63},[50,2122,74],{"class":63},[50,2124,2125],{"class":77},"(amount)\n",[50,2127,2128,2131,2134,2136,2138,2140,2143],{"class":52,"line":1384},[50,2129,2130],{"class":121},"      assert",[50,2132,2133],{"class":77},"(amount ",[50,2135,533],{"class":63},[50,2137,1878],{"class":121},[50,2139,423],{"class":77},[50,2141,2142],{"class":830},"\"must deposit positive amount\"",[50,2144,1175],{"class":77},[50,2146,2147,2150,2152,2154,2156],{"class":52,"line":1400},[50,2148,2149],{"class":77},"      balance ",[50,2151,262],{"class":63},[50,2153,2091],{"class":77},[50,2155,403],{"class":63},[50,2157,2158],{"class":77}," amount\n",[50,2160,2161,2164],{"class":52,"line":1411},[50,2162,2163],{"class":63},"      return",[50,2165,2166],{"class":77}," balance\n",[50,2168,2169,2172],{"class":52,"line":1416},[50,2170,2171],{"class":63},"    end",[50,2173,1920],{"class":77},[50,2175,2176,2179,2181,2183],{"class":52,"line":1422},[50,2177,2178],{"class":67},"    withdraw",[50,2180,71],{"class":63},[50,2182,74],{"class":63},[50,2184,2125],{"class":77},[50,2186,2187,2189,2191,2193,2195,2197,2200],{"class":52,"line":1448},[50,2188,2130],{"class":121},[50,2190,2133],{"class":77},[50,2192,533],{"class":63},[50,2194,1878],{"class":121},[50,2196,423],{"class":77},[50,2198,2199],{"class":830},"\"must withdraw positive amount\"",[50,2201,1175],{"class":77},[50,2203,2204,2206,2209,2212,2215,2218],{"class":52,"line":1464},[50,2205,2130],{"class":121},[50,2207,2208],{"class":77},"(balance ",[50,2210,2211],{"class":63},">=",[50,2213,2214],{"class":77}," amount, ",[50,2216,2217],{"class":830},"\"insufficient funds\"",[50,2219,1175],{"class":77},[50,2221,2222,2224,2226,2228,2230],{"class":52,"line":1488},[50,2223,2149],{"class":77},[50,2225,262],{"class":63},[50,2227,2091],{"class":77},[50,2229,152],{"class":63},[50,2231,2158],{"class":77},[50,2233,2234,2236],{"class":52,"line":1493},[50,2235,2163],{"class":63},[50,2237,2166],{"class":77},[50,2239,2240,2242],{"class":52,"line":1499},[50,2241,2171],{"class":63},[50,2243,1920],{"class":77},[50,2245,2246,2249,2251,2253,2255,2257,2259,2261],{"class":52,"line":1512},[50,2247,2248],{"class":67},"    get_balance",[50,2250,71],{"class":63},[50,2252,74],{"class":63},[50,2254,78],{"class":77},[50,2256,370],{"class":63},[50,2258,2091],{"class":77},[50,2260,81],{"class":63},[50,2262,1920],{"class":77},[50,2264,2265],{"class":52,"line":1529},[50,2266,1997],{"class":77},[50,2268,2269],{"class":52,"line":1534},[50,2270,2271],{"class":56},"  -- balance is NOT in the returned table — it's an upvalue. True encapsulation.\n",[50,2273,2275],{"class":52,"line":2274},40,[50,2276,166],{"class":63},[50,2278,2280],{"class":52,"line":2279},41,[50,2281,173],{"emptyLinePlaceholder":172},[50,2283,2285,2287,2290,2292,2294,2296,2299],{"class":52,"line":2284},42,[50,2286,64],{"class":63},[50,2288,2289],{"class":77}," acc ",[50,2291,262],{"class":63},[50,2293,2081],{"class":121},[50,2295,315],{"class":77},[50,2297,2298],{"class":121},"100",[50,2300,1175],{"class":77},[50,2302,2304,2307,2310,2312,2315,2317],{"class":52,"line":2303},43,[50,2305,2306],{"class":77},"acc.",[50,2308,2309],{"class":121},"deposit",[50,2311,315],{"class":77},[50,2313,2314],{"class":121},"50",[50,2316,157],{"class":77},[50,2318,2319],{"class":56},"-- 150\n",[50,2321,2323,2325,2328,2330,2332,2334],{"class":52,"line":2322},44,[50,2324,2306],{"class":77},[50,2326,2327],{"class":121},"withdraw",[50,2329,315],{"class":77},[50,2331,880],{"class":121},[50,2333,1378],{"class":77},[50,2335,2336],{"class":56},"-- 120\n",[50,2338,2340,2342,2345],{"class":52,"line":2339},45,[50,2341,2306],{"class":77},[50,2343,2344],{"class":67},"balance",[50,2346,2347],{"class":56},"           -- nil (can't access private state directly)\n",[33,2349,2351],{"id":2350},"proper-tail-calls-ptc-state-machines","Proper Tail Calls (PTC) & State Machines",[15,2353,2354,2355,2357,2358,2361],{},"Lua guarantees ",[19,2356,21],{},": ",[24,2359,2360],{},"return f(args)"," does not grow the stack. The caller's frame is replaced. This enables unbounded recursion and actor-style state machines.",[38,2363,2364],{"language":40},[42,2365,2367],{"className":44,"code":2366,"language":40,"meta":46,"style":46},"-- TAIL CALL: `return f()` — no stack growth. Can recurse infinitely.\nlocal function loop(n)\n  if n == 0 then return \"done\" end\n  return loop(n - 1)  -- tail position: caller's frame discarded before entering loop\nend\nloop(100000000)  -- \"done\" — no stack overflow, constant stack space\n\n-- NOT a tail call: anything after the call prevents PTC\nlocal function sum_bad(n, acc)\n  acc = acc or 0\n  if n == 0 then return acc end\n  return 1 + sum_bad(n - 1, acc)  -- +1 after the call → NOT tail → stack grows\nend\n-- sum_bad(1000000)  -- stack overflow!\n\n-- Fix: make it tail-recursive with accumulator\nlocal function sum_good(n, acc)\n  acc = acc or 0\n  if n == 0 then return acc end\n  return sum_good(n - 1, acc + n)  -- tail position: acc + n computed, then tail call\nend\nsum_good(10000000)  -- works — PTC, constant stack\n\n-- State machine via tail calls (no stack growth across state transitions):\nlocal function state_idle(input)\n  if input == \"start\" then return state_running\n  elseif input == \"quit\" then return state_done\n  end\n  return state_idle  -- stay in current state (tail call to self)\nend\n\nlocal function state_running(input)\n  if input == \"pause\" then return state_paused\n  elseif input == \"stop\" then return state_idle\n  elseif input == \"quit\" then return state_done\n  end\n  return state_running\nend\n\nlocal function state_paused(input)\n  if input == \"resume\" then return state_running\n  elseif input == \"stop\" then return state_idle\n  end\n  return state_paused\nend\n\nlocal function state_done(_) return state_done end  -- terminal\n\n-- Run the machine: each transition is a tail call — no stack growth for any path length\nlocal function run_machine(inputs)\n  local state = state_idle\n  for _, input in ipairs(inputs) do\n    state = state(input)  -- tail call: previous state function's frame discarded\n  end\n  return state == state_done and \"terminated\" or \"active\"\nend\n\nprint(run_machine({\"start\", \"pause\", \"resume\", \"stop\", \"quit\"}))  -- \"terminated\"\n",[24,2368,2369,2374,2385,2404,2421,2425,2440,2444,2449,2461,2475,2493,2516,2520,2525,2529,2534,2545,2557,2575,2598,2602,2617,2621,2626,2638,2657,2676,2680,2690,2694,2698,2709,2727,2745,2761,2765,2771,2775,2779,2790,2807,2823,2827,2833,2837,2842,2865,2870,2876,2889,2901,2918,2935,2940,2962,2967,2972],{"__ignoreMap":46},[50,2370,2371],{"class":52,"line":53},[50,2372,2373],{"class":56},"-- TAIL CALL: `return f()` — no stack growth. Can recurse infinitely.\n",[50,2375,2376,2378,2380,2383],{"class":52,"line":60},[50,2377,64],{"class":63},[50,2379,74],{"class":63},[50,2381,2382],{"class":67}," loop",[50,2384,193],{"class":77},[50,2386,2387,2389,2391,2393,2395,2397,2399,2402],{"class":52,"line":87},[50,2388,112],{"class":63},[50,2390,115],{"class":77},[50,2392,1185],{"class":63},[50,2394,1878],{"class":121},[50,2396,125],{"class":63},[50,2398,128],{"class":63},[50,2400,2401],{"class":830}," \"done\" ",[50,2403,166],{"class":63},[50,2405,2406,2408,2410,2412,2414,2416,2418],{"class":52,"line":93},[50,2407,139],{"class":63},[50,2409,2382],{"class":121},[50,2411,149],{"class":77},[50,2413,152],{"class":63},[50,2415,122],{"class":121},[50,2417,232],{"class":77},[50,2419,2420],{"class":56},"-- tail position: caller's frame discarded before entering loop\n",[50,2422,2423],{"class":52,"line":109},[50,2424,166],{"class":63},[50,2426,2427,2430,2432,2435,2437],{"class":52,"line":136},[50,2428,2429],{"class":121},"loop",[50,2431,315],{"class":77},[50,2433,2434],{"class":121},"100000000",[50,2436,232],{"class":77},[50,2438,2439],{"class":56},"-- \"done\" — no stack overflow, constant stack space\n",[50,2441,2442],{"class":52,"line":163},[50,2443,173],{"emptyLinePlaceholder":172},[50,2445,2446],{"class":52,"line":169},[50,2447,2448],{"class":56},"-- NOT a tail call: anything after the call prevents PTC\n",[50,2450,2451,2453,2455,2458],{"class":52,"line":176},[50,2452,64],{"class":63},[50,2454,74],{"class":63},[50,2456,2457],{"class":67}," sum_bad",[50,2459,2460],{"class":77},"(n, acc)\n",[50,2462,2463,2466,2468,2470,2472],{"class":52,"line":182},[50,2464,2465],{"class":77},"  acc ",[50,2467,262],{"class":63},[50,2469,2289],{"class":77},[50,2471,1875],{"class":63},[50,2473,2474],{"class":121}," 0\n",[50,2476,2477,2479,2481,2483,2485,2487,2489,2491],{"class":52,"line":196},[50,2478,112],{"class":63},[50,2480,115],{"class":77},[50,2482,1185],{"class":63},[50,2484,1878],{"class":121},[50,2486,125],{"class":63},[50,2488,128],{"class":63},[50,2490,2289],{"class":77},[50,2492,166],{"class":63},[50,2494,2495,2497,2499,2502,2504,2506,2508,2510,2513],{"class":52,"line":215},[50,2496,139],{"class":63},[50,2498,122],{"class":121},[50,2500,2501],{"class":63}," +",[50,2503,2457],{"class":121},[50,2505,149],{"class":77},[50,2507,152],{"class":63},[50,2509,122],{"class":121},[50,2511,2512],{"class":77},", acc)  ",[50,2514,2515],{"class":56},"-- +1 after the call → NOT tail → stack grows\n",[50,2517,2518],{"class":52,"line":238},[50,2519,166],{"class":63},[50,2521,2522],{"class":52,"line":243},[50,2523,2524],{"class":56},"-- sum_bad(1000000)  -- stack overflow!\n",[50,2526,2527],{"class":52,"line":248},[50,2528,173],{"emptyLinePlaceholder":172},[50,2530,2531],{"class":52,"line":254},[50,2532,2533],{"class":56},"-- Fix: make it tail-recursive with accumulator\n",[50,2535,2536,2538,2540,2543],{"class":52,"line":268},[50,2537,64],{"class":63},[50,2539,74],{"class":63},[50,2541,2542],{"class":67}," sum_good",[50,2544,2460],{"class":77},[50,2546,2547,2549,2551,2553,2555],{"class":52,"line":289},[50,2548,2465],{"class":77},[50,2550,262],{"class":63},[50,2552,2289],{"class":77},[50,2554,1875],{"class":63},[50,2556,2474],{"class":121},[50,2558,2559,2561,2563,2565,2567,2569,2571,2573],{"class":52,"line":300},[50,2560,112],{"class":63},[50,2562,115],{"class":77},[50,2564,1185],{"class":63},[50,2566,1878],{"class":121},[50,2568,125],{"class":63},[50,2570,128],{"class":63},[50,2572,2289],{"class":77},[50,2574,166],{"class":63},[50,2576,2577,2579,2581,2583,2585,2587,2590,2592,2595],{"class":52,"line":305},[50,2578,139],{"class":63},[50,2580,2542],{"class":121},[50,2582,149],{"class":77},[50,2584,152],{"class":63},[50,2586,122],{"class":121},[50,2588,2589],{"class":77},", acc ",[50,2591,403],{"class":63},[50,2593,2594],{"class":77}," n)  ",[50,2596,2597],{"class":56},"-- tail position: acc + n computed, then tail call\n",[50,2599,2600],{"class":52,"line":326},[50,2601,166],{"class":63},[50,2603,2604,2607,2609,2612,2614],{"class":52,"line":344},[50,2605,2606],{"class":121},"sum_good",[50,2608,315],{"class":77},[50,2610,2611],{"class":121},"10000000",[50,2613,232],{"class":77},[50,2615,2616],{"class":56},"-- works — PTC, constant stack\n",[50,2618,2619],{"class":52,"line":349},[50,2620,173],{"emptyLinePlaceholder":172},[50,2622,2623],{"class":52,"line":355},[50,2624,2625],{"class":56},"-- State machine via tail calls (no stack growth across state transitions):\n",[50,2627,2628,2630,2632,2635],{"class":52,"line":383},[50,2629,64],{"class":63},[50,2631,74],{"class":63},[50,2633,2634],{"class":67}," state_idle",[50,2636,2637],{"class":77},"(input)\n",[50,2639,2640,2642,2645,2647,2650,2652,2654],{"class":52,"line":411},[50,2641,112],{"class":63},[50,2643,2644],{"class":77}," input ",[50,2646,1185],{"class":63},[50,2648,2649],{"class":830}," \"start\" ",[50,2651,516],{"class":63},[50,2653,128],{"class":63},[50,2655,2656],{"class":77}," state_running\n",[50,2658,2659,2662,2664,2666,2669,2671,2673],{"class":52,"line":1384},[50,2660,2661],{"class":63},"  elseif",[50,2663,2644],{"class":77},[50,2665,1185],{"class":63},[50,2667,2668],{"class":830}," \"quit\" ",[50,2670,516],{"class":63},[50,2672,128],{"class":63},[50,2674,2675],{"class":77}," state_done\n",[50,2677,2678],{"class":52,"line":1400},[50,2679,551],{"class":63},[50,2681,2682,2684,2687],{"class":52,"line":1411},[50,2683,139],{"class":63},[50,2685,2686],{"class":77}," state_idle  ",[50,2688,2689],{"class":56},"-- stay in current state (tail call to self)\n",[50,2691,2692],{"class":52,"line":1416},[50,2693,166],{"class":63},[50,2695,2696],{"class":52,"line":1422},[50,2697,173],{"emptyLinePlaceholder":172},[50,2699,2700,2702,2704,2707],{"class":52,"line":1448},[50,2701,64],{"class":63},[50,2703,74],{"class":63},[50,2705,2706],{"class":67}," state_running",[50,2708,2637],{"class":77},[50,2710,2711,2713,2715,2717,2720,2722,2724],{"class":52,"line":1464},[50,2712,112],{"class":63},[50,2714,2644],{"class":77},[50,2716,1185],{"class":63},[50,2718,2719],{"class":830}," \"pause\" ",[50,2721,516],{"class":63},[50,2723,128],{"class":63},[50,2725,2726],{"class":77}," state_paused\n",[50,2728,2729,2731,2733,2735,2738,2740,2742],{"class":52,"line":1488},[50,2730,2661],{"class":63},[50,2732,2644],{"class":77},[50,2734,1185],{"class":63},[50,2736,2737],{"class":830}," \"stop\" ",[50,2739,516],{"class":63},[50,2741,128],{"class":63},[50,2743,2744],{"class":77}," state_idle\n",[50,2746,2747,2749,2751,2753,2755,2757,2759],{"class":52,"line":1493},[50,2748,2661],{"class":63},[50,2750,2644],{"class":77},[50,2752,1185],{"class":63},[50,2754,2668],{"class":830},[50,2756,516],{"class":63},[50,2758,128],{"class":63},[50,2760,2675],{"class":77},[50,2762,2763],{"class":52,"line":1499},[50,2764,551],{"class":63},[50,2766,2767,2769],{"class":52,"line":1512},[50,2768,139],{"class":63},[50,2770,2656],{"class":77},[50,2772,2773],{"class":52,"line":1529},[50,2774,166],{"class":63},[50,2776,2777],{"class":52,"line":1534},[50,2778,173],{"emptyLinePlaceholder":172},[50,2780,2781,2783,2785,2788],{"class":52,"line":2274},[50,2782,64],{"class":63},[50,2784,74],{"class":63},[50,2786,2787],{"class":67}," state_paused",[50,2789,2637],{"class":77},[50,2791,2792,2794,2796,2798,2801,2803,2805],{"class":52,"line":2279},[50,2793,112],{"class":63},[50,2795,2644],{"class":77},[50,2797,1185],{"class":63},[50,2799,2800],{"class":830}," \"resume\" ",[50,2802,516],{"class":63},[50,2804,128],{"class":63},[50,2806,2656],{"class":77},[50,2808,2809,2811,2813,2815,2817,2819,2821],{"class":52,"line":2284},[50,2810,2661],{"class":63},[50,2812,2644],{"class":77},[50,2814,1185],{"class":63},[50,2816,2737],{"class":830},[50,2818,516],{"class":63},[50,2820,128],{"class":63},[50,2822,2744],{"class":77},[50,2824,2825],{"class":52,"line":2303},[50,2826,551],{"class":63},[50,2828,2829,2831],{"class":52,"line":2322},[50,2830,139],{"class":63},[50,2832,2726],{"class":77},[50,2834,2835],{"class":52,"line":2339},[50,2836,166],{"class":63},[50,2838,2840],{"class":52,"line":2839},46,[50,2841,173],{"emptyLinePlaceholder":172},[50,2843,2845,2847,2849,2852,2855,2857,2860,2862],{"class":52,"line":2844},47,[50,2846,64],{"class":63},[50,2848,74],{"class":63},[50,2850,2851],{"class":67}," state_done",[50,2853,2854],{"class":77},"(_) ",[50,2856,370],{"class":63},[50,2858,2859],{"class":77}," state_done ",[50,2861,81],{"class":63},[50,2863,2864],{"class":56},"  -- terminal\n",[50,2866,2868],{"class":52,"line":2867},48,[50,2869,173],{"emptyLinePlaceholder":172},[50,2871,2873],{"class":52,"line":2872},49,[50,2874,2875],{"class":56},"-- Run the machine: each transition is a tail call — no stack growth for any path length\n",[50,2877,2879,2881,2883,2886],{"class":52,"line":2878},50,[50,2880,64],{"class":63},[50,2882,74],{"class":63},[50,2884,2885],{"class":67}," run_machine",[50,2887,2888],{"class":77},"(inputs)\n",[50,2890,2892,2894,2897,2899],{"class":52,"line":2891},51,[50,2893,464],{"class":63},[50,2895,2896],{"class":77}," state ",[50,2898,262],{"class":63},[50,2900,2744],{"class":77},[50,2902,2904,2906,2909,2911,2913,2916],{"class":52,"line":2903},52,[50,2905,484],{"class":63},[50,2907,2908],{"class":77}," _, input ",[50,2910,490],{"class":63},[50,2912,493],{"class":121},[50,2914,2915],{"class":77},"(inputs) ",[50,2917,499],{"class":63},[50,2919,2921,2924,2926,2929,2932],{"class":52,"line":2920},53,[50,2922,2923],{"class":77},"    state ",[50,2925,262],{"class":63},[50,2927,2928],{"class":121}," state",[50,2930,2931],{"class":77},"(input)  ",[50,2933,2934],{"class":56},"-- tail call: previous state function's frame discarded\n",[50,2936,2938],{"class":52,"line":2937},54,[50,2939,551],{"class":63},[50,2941,2943,2945,2947,2949,2951,2954,2957,2959],{"class":52,"line":2942},55,[50,2944,139],{"class":63},[50,2946,2896],{"class":77},[50,2948,1185],{"class":63},[50,2950,2859],{"class":77},[50,2952,2953],{"class":63},"and",[50,2955,2956],{"class":830}," \"terminated\" ",[50,2958,1875],{"class":63},[50,2960,2961],{"class":830}," \"active\"\n",[50,2963,2965],{"class":52,"line":2964},56,[50,2966,166],{"class":63},[50,2968,2970],{"class":52,"line":2969},57,[50,2971,173],{"emptyLinePlaceholder":172},[50,2973,2975,2977,2979,2982,2984,2987,2989,2992,2994,2997,2999,3002,3004,3007,3010],{"class":52,"line":2974},58,[50,2976,743],{"class":121},[50,2978,315],{"class":77},[50,2980,2981],{"class":121},"run_machine",[50,2983,579],{"class":77},[50,2985,2986],{"class":830},"\"start\"",[50,2988,423],{"class":77},[50,2990,2991],{"class":830},"\"pause\"",[50,2993,423],{"class":77},[50,2995,2996],{"class":830},"\"resume\"",[50,2998,423],{"class":77},[50,3000,3001],{"class":830},"\"stop\"",[50,3003,423],{"class":77},[50,3005,3006],{"class":830},"\"quit\"",[50,3008,3009],{"class":77},"}))  ",[50,3011,3012],{"class":56},"-- \"terminated\"\n",[839,3014,3016],{"id":3015},"anti-pattern-non-tail-recursion-for-large-inputs","Anti-pattern: non-tail recursion for large inputs",[38,3018,3019],{"language":40},[42,3020,3022],{"className":44,"code":3021,"language":40,"meta":46,"style":46},"-- BAD: naive recursive tree walk — stack overflow on deep trees\nlocal function depth_first_bad(node)\n  process(node)\n  for _, child in ipairs(node.children or {}) do\n    depth_first_bad(child)  -- not tail: process() runs before, loop after\n  end\nend\n-- depth_first_bad(deep_tree) → stack overflow at ~1000-2000 levels (depending on C stack)\n\n-- GOOD: explicit stack (iterative) — handles any depth, same traversal order\nlocal function depth_first_good(root)\n  local stack = {root}\n  while stack[#stack] do  -- while not empty (but careful with # on sparse — see Array in ch02)\n    local node = stack[#stack]\n    stack[#stack] = nil  -- pop\n    process(node)\n    -- push children in reverse for left-to-right traversal\n    local children = node.children or {}\n    for i = #children, 1, -1 do\n      stack[#stack + 1] = children[i]\n    end\n  end\nend\n",[24,3023,3024,3029,3041,3048,3073,3084,3088,3092,3097,3101,3106,3118,3130,3149,3166,3183,3190,3195,3213,3237,3258,3262,3266],{"__ignoreMap":46},[50,3025,3026],{"class":52,"line":53},[50,3027,3028],{"class":56},"-- BAD: naive recursive tree walk — stack overflow on deep trees\n",[50,3030,3031,3033,3035,3038],{"class":52,"line":60},[50,3032,64],{"class":63},[50,3034,74],{"class":63},[50,3036,3037],{"class":67}," depth_first_bad",[50,3039,3040],{"class":77},"(node)\n",[50,3042,3043,3046],{"class":52,"line":87},[50,3044,3045],{"class":121},"  process",[50,3047,3040],{"class":77},[50,3049,3050,3052,3055,3057,3059,3062,3065,3068,3071],{"class":52,"line":93},[50,3051,484],{"class":63},[50,3053,3054],{"class":77}," _, child ",[50,3056,490],{"class":63},[50,3058,493],{"class":121},[50,3060,3061],{"class":77},"(node.",[50,3063,3064],{"class":67},"children",[50,3066,3067],{"class":63}," or",[50,3069,3070],{"class":77}," {}) ",[50,3072,499],{"class":63},[50,3074,3075,3078,3081],{"class":52,"line":109},[50,3076,3077],{"class":121},"    depth_first_bad",[50,3079,3080],{"class":77},"(child)  ",[50,3082,3083],{"class":56},"-- not tail: process() runs before, loop after\n",[50,3085,3086],{"class":52,"line":136},[50,3087,551],{"class":63},[50,3089,3090],{"class":52,"line":163},[50,3091,166],{"class":63},[50,3093,3094],{"class":52,"line":169},[50,3095,3096],{"class":56},"-- depth_first_bad(deep_tree) → stack overflow at ~1000-2000 levels (depending on C stack)\n",[50,3098,3099],{"class":52,"line":176},[50,3100,173],{"emptyLinePlaceholder":172},[50,3102,3103],{"class":52,"line":182},[50,3104,3105],{"class":56},"-- GOOD: explicit stack (iterative) — handles any depth, same traversal order\n",[50,3107,3108,3110,3112,3115],{"class":52,"line":196},[50,3109,64],{"class":63},[50,3111,74],{"class":63},[50,3113,3114],{"class":67}," depth_first_good",[50,3116,3117],{"class":77},"(root)\n",[50,3119,3120,3122,3125,3127],{"class":52,"line":215},[50,3121,464],{"class":63},[50,3123,3124],{"class":77}," stack ",[50,3126,262],{"class":63},[50,3128,3129],{"class":77}," {root}\n",[50,3131,3132,3135,3138,3140,3143,3146],{"class":52,"line":238},[50,3133,3134],{"class":63},"  while",[50,3136,3137],{"class":77}," stack[",[50,3139,1021],{"class":63},[50,3141,3142],{"class":77},"stack] ",[50,3144,3145],{"class":63},"do",[50,3147,3148],{"class":56},"  -- while not empty (but careful with # on sparse — see Array in ch02)\n",[50,3150,3151,3154,3157,3159,3161,3163],{"class":52,"line":243},[50,3152,3153],{"class":63},"    local",[50,3155,3156],{"class":77}," node ",[50,3158,262],{"class":63},[50,3160,3137],{"class":77},[50,3162,1021],{"class":63},[50,3164,3165],{"class":77},"stack]\n",[50,3167,3168,3171,3173,3175,3177,3180],{"class":52,"line":248},[50,3169,3170],{"class":77},"    stack[",[50,3172,1021],{"class":63},[50,3174,3142],{"class":77},[50,3176,262],{"class":63},[50,3178,3179],{"class":121}," nil",[50,3181,3182],{"class":56},"  -- pop\n",[50,3184,3185,3188],{"class":52,"line":254},[50,3186,3187],{"class":121},"    process",[50,3189,3040],{"class":77},[50,3191,3192],{"class":52,"line":268},[50,3193,3194],{"class":56},"    -- push children in reverse for left-to-right traversal\n",[50,3196,3197,3199,3202,3204,3207,3209,3211],{"class":52,"line":289},[50,3198,3153],{"class":63},[50,3200,3201],{"class":77}," children ",[50,3203,262],{"class":63},[50,3205,3206],{"class":77}," node.",[50,3208,3064],{"class":67},[50,3210,3067],{"class":63},[50,3212,265],{"class":77},[50,3214,3215,3217,3219,3221,3223,3226,3228,3230,3232,3234],{"class":52,"line":300},[50,3216,1196],{"class":63},[50,3218,1199],{"class":77},[50,3220,262],{"class":63},[50,3222,1597],{"class":63},[50,3224,3225],{"class":77},"children, ",[50,3227,586],{"class":121},[50,3229,423],{"class":77},[50,3231,152],{"class":63},[50,3233,586],{"class":121},[50,3235,3236],{"class":63}," do\n",[50,3238,3239,3242,3244,3247,3249,3251,3253,3255],{"class":52,"line":305},[50,3240,3241],{"class":77},"      stack[",[50,3243,1021],{"class":63},[50,3245,3246],{"class":77},"stack ",[50,3248,403],{"class":63},[50,3250,122],{"class":121},[50,3252,1031],{"class":77},[50,3254,262],{"class":63},[50,3256,3257],{"class":77}," children[i]\n",[50,3259,3260],{"class":52,"line":326},[50,3261,1243],{"class":63},[50,3263,3264],{"class":52,"line":344},[50,3265,551],{"class":63},[50,3267,3268],{"class":52,"line":349},[50,3269,166],{"class":63},[33,3271,3273],{"id":3272},"named-arguments-option-merging","Named Arguments & Option Merging",[38,3275,3276],{"language":40},[42,3277,3279],{"className":44,"code":3278,"language":40,"meta":46,"style":46},"-- Lua has no named params. Idiom: pass a single table with key-value pairs.\nlocal function create_server(opts)\n  -- Merge with defaults: explicit per-field, NOT table.merge (doesn't exist in stdlib)\n  opts = opts or {}\n  local host = opts.host or \"0.0.0.0\"      -- default\n  local port = opts.port or 8080\n  local tls = opts.tls ~= false and true or false  -- default true unless explicitly false\n  local max_conn = opts.max_conn or 1024\n  -- ... use host, port, tls, max_conn\n  return {host = host, port = port, tls = tls, max_conn = max_conn}\nend\n\nlocal server = create_server {\n  host = \"127.0.0.1\",\n  port = 3000,\n  tls = false,\n}\n-- Notice: no parens needed when the sole argument is a table literal\n\n-- Production: deep merge utility for nested config\nlocal function merge_defaults(opts, defaults)\n  local result = {}\n  for k, v in pairs(defaults) do\n    result[k] = (type(v) == \"table\" and type(opts[k]) == \"table\")\n      and merge_defaults(opts[k], v)  -- deep merge nested tables\n      or (opts[k] ~= nil and opts[k] or v)  -- shallow copy or default\n  end\n  for k, v in pairs(opts) do\n    if defaults[k] == nil then result[k] = v end  -- pass through unknown keys\n  end\n  return result\nend\n",[24,3280,3281,3286,3298,3303,3317,3340,3359,3392,3411,3416,3443,3447,3451,3464,3476,3488,3499,3503,3508,3512,3517,3529,3540,3557,3593,3606,3632,3636,3651,3676,3680,3687],{"__ignoreMap":46},[50,3282,3283],{"class":52,"line":53},[50,3284,3285],{"class":56},"-- Lua has no named params. Idiom: pass a single table with key-value pairs.\n",[50,3287,3288,3290,3292,3295],{"class":52,"line":60},[50,3289,64],{"class":63},[50,3291,74],{"class":63},[50,3293,3294],{"class":67}," create_server",[50,3296,3297],{"class":77},"(opts)\n",[50,3299,3300],{"class":52,"line":87},[50,3301,3302],{"class":56},"  -- Merge with defaults: explicit per-field, NOT table.merge (doesn't exist in stdlib)\n",[50,3304,3305,3308,3310,3313,3315],{"class":52,"line":93},[50,3306,3307],{"class":77},"  opts ",[50,3309,262],{"class":63},[50,3311,3312],{"class":77}," opts ",[50,3314,1875],{"class":63},[50,3316,265],{"class":77},[50,3318,3319,3321,3324,3326,3329,3332,3334,3337],{"class":52,"line":109},[50,3320,464],{"class":63},[50,3322,3323],{"class":77}," host ",[50,3325,262],{"class":63},[50,3327,3328],{"class":77}," opts.",[50,3330,3331],{"class":67},"host",[50,3333,3067],{"class":63},[50,3335,3336],{"class":830}," \"0.0.0.0\"      ",[50,3338,3339],{"class":56},"-- default\n",[50,3341,3342,3344,3347,3349,3351,3354,3356],{"class":52,"line":136},[50,3343,464],{"class":63},[50,3345,3346],{"class":77}," port ",[50,3348,262],{"class":63},[50,3350,3328],{"class":77},[50,3352,3353],{"class":67},"port",[50,3355,3067],{"class":63},[50,3357,3358],{"class":121}," 8080\n",[50,3360,3361,3363,3366,3368,3370,3373,3376,3379,3382,3385,3387,3389],{"class":52,"line":163},[50,3362,464],{"class":63},[50,3364,3365],{"class":77}," tls ",[50,3367,262],{"class":63},[50,3369,3328],{"class":77},[50,3371,3372],{"class":67},"tls",[50,3374,3375],{"class":63}," ~=",[50,3377,3378],{"class":121}," false",[50,3380,3381],{"class":63}," and",[50,3383,3384],{"class":121}," true",[50,3386,3067],{"class":63},[50,3388,3378],{"class":121},[50,3390,3391],{"class":56},"  -- default true unless explicitly false\n",[50,3393,3394,3396,3399,3401,3403,3406,3408],{"class":52,"line":169},[50,3395,464],{"class":63},[50,3397,3398],{"class":77}," max_conn ",[50,3400,262],{"class":63},[50,3402,3328],{"class":77},[50,3404,3405],{"class":67},"max_conn",[50,3407,3067],{"class":63},[50,3409,3410],{"class":121}," 1024\n",[50,3412,3413],{"class":52,"line":176},[50,3414,3415],{"class":56},"  -- ... use host, port, tls, max_conn\n",[50,3417,3418,3420,3423,3425,3428,3430,3433,3435,3438,3440],{"class":52,"line":182},[50,3419,139],{"class":63},[50,3421,3422],{"class":77}," {host ",[50,3424,262],{"class":63},[50,3426,3427],{"class":77}," host, port ",[50,3429,262],{"class":63},[50,3431,3432],{"class":77}," port, tls ",[50,3434,262],{"class":63},[50,3436,3437],{"class":77}," tls, max_conn ",[50,3439,262],{"class":63},[50,3441,3442],{"class":77}," max_conn}\n",[50,3444,3445],{"class":52,"line":196},[50,3446,166],{"class":63},[50,3448,3449],{"class":52,"line":215},[50,3450,173],{"emptyLinePlaceholder":172},[50,3452,3453,3455,3458,3460,3462],{"class":52,"line":238},[50,3454,64],{"class":63},[50,3456,3457],{"class":77}," server ",[50,3459,262],{"class":63},[50,3461,3294],{"class":121},[50,3463,1888],{"class":77},[50,3465,3466,3469,3471,3474],{"class":52,"line":243},[50,3467,3468],{"class":77},"  host ",[50,3470,262],{"class":63},[50,3472,3473],{"class":830}," \"127.0.0.1\"",[50,3475,1920],{"class":77},[50,3477,3478,3481,3483,3486],{"class":52,"line":248},[50,3479,3480],{"class":77},"  port ",[50,3482,262],{"class":63},[50,3484,3485],{"class":121}," 3000",[50,3487,1920],{"class":77},[50,3489,3490,3493,3495,3497],{"class":52,"line":254},[50,3491,3492],{"class":77},"  tls ",[50,3494,262],{"class":63},[50,3496,3378],{"class":121},[50,3498,1920],{"class":77},[50,3500,3501],{"class":52,"line":268},[50,3502,1445],{"class":77},[50,3504,3505],{"class":52,"line":289},[50,3506,3507],{"class":56},"-- Notice: no parens needed when the sole argument is a table literal\n",[50,3509,3510],{"class":52,"line":300},[50,3511,173],{"emptyLinePlaceholder":172},[50,3513,3514],{"class":52,"line":305},[50,3515,3516],{"class":56},"-- Production: deep merge utility for nested config\n",[50,3518,3519,3521,3523,3526],{"class":52,"line":326},[50,3520,64],{"class":63},[50,3522,74],{"class":63},[50,3524,3525],{"class":67}," merge_defaults",[50,3527,3528],{"class":77},"(opts, defaults)\n",[50,3530,3531,3533,3536,3538],{"class":52,"line":344},[50,3532,464],{"class":63},[50,3534,3535],{"class":77}," result ",[50,3537,262],{"class":63},[50,3539,265],{"class":77},[50,3541,3542,3544,3547,3549,3552,3555],{"class":52,"line":349},[50,3543,484],{"class":63},[50,3545,3546],{"class":77}," k, v ",[50,3548,490],{"class":63},[50,3550,3551],{"class":121}," pairs",[50,3553,3554],{"class":77},"(defaults) ",[50,3556,499],{"class":63},[50,3558,3559,3562,3564,3567,3570,3573,3575,3578,3580,3583,3586,3588,3591],{"class":52,"line":355},[50,3560,3561],{"class":77},"    result[k] ",[50,3563,262],{"class":63},[50,3565,3566],{"class":77}," (",[50,3568,3569],{"class":121},"type",[50,3571,3572],{"class":77},"(v) ",[50,3574,1185],{"class":63},[50,3576,3577],{"class":830}," \"table\" ",[50,3579,2953],{"class":63},[50,3581,3582],{"class":121}," type",[50,3584,3585],{"class":77},"(opts[k]) ",[50,3587,1185],{"class":63},[50,3589,3590],{"class":830}," \"table\"",[50,3592,1175],{"class":77},[50,3594,3595,3598,3600,3603],{"class":52,"line":383},[50,3596,3597],{"class":63},"      and",[50,3599,3525],{"class":121},[50,3601,3602],{"class":77},"(opts[k], v)  ",[50,3604,3605],{"class":56},"-- deep merge nested tables\n",[50,3607,3608,3611,3614,3617,3619,3621,3624,3626,3629],{"class":52,"line":411},[50,3609,3610],{"class":63},"      or",[50,3612,3613],{"class":77}," (opts[k] ",[50,3615,3616],{"class":63},"~=",[50,3618,3179],{"class":121},[50,3620,3381],{"class":63},[50,3622,3623],{"class":77}," opts[k] ",[50,3625,1875],{"class":63},[50,3627,3628],{"class":77}," v)  ",[50,3630,3631],{"class":56},"-- shallow copy or default\n",[50,3633,3634],{"class":52,"line":1384},[50,3635,551],{"class":63},[50,3637,3638,3640,3642,3644,3646,3649],{"class":52,"line":1400},[50,3639,484],{"class":63},[50,3641,3546],{"class":77},[50,3643,490],{"class":63},[50,3645,3551],{"class":121},[50,3647,3648],{"class":77},"(opts) ",[50,3650,499],{"class":63},[50,3652,3653,3655,3658,3660,3662,3664,3667,3669,3671,3673],{"class":52,"line":1411},[50,3654,504],{"class":63},[50,3656,3657],{"class":77}," defaults[k] ",[50,3659,1185],{"class":63},[50,3661,3179],{"class":121},[50,3663,125],{"class":63},[50,3665,3666],{"class":77}," result[k] ",[50,3668,262],{"class":63},[50,3670,507],{"class":77},[50,3672,81],{"class":63},[50,3674,3675],{"class":56},"  -- pass through unknown keys\n",[50,3677,3678],{"class":52,"line":1416},[50,3679,551],{"class":63},[50,3681,3682,3684],{"class":52,"line":1422},[50,3683,139],{"class":63},[50,3685,3686],{"class":77}," result\n",[50,3688,3689],{"class":52,"line":1448},[50,3690,166],{"class":63},[33,3692,3694],{"id":3693},"higher-order-functions-functional-patterns","Higher-Order Functions & Functional Patterns",[38,3696,3697],{"language":40},[42,3698,3700],{"className":44,"code":3699,"language":40,"meta":46,"style":46},"-- Memoize: cache results by argument. Uses weak table for auto-eviction.\nlocal function memoize(fn)\n  local cache = setmetatable({}, {__mode = \"v\"})  -- weak values: GC can evict\n  return function(x)\n    if cache[x] ~= nil then return cache[x] end\n    local result = fn(x)\n    cache[x] = result\n    return result\n  end\nend\n\nlocal slow_fib\nslow_fib = memoize(function(n)\n  if n \u003C 2 then return n end\n  return slow_fib(n - 1) + slow_fib(n - 2)  -- recursive calls also hit cache\nend)\nprint(slow_fib(50))  -- fast: each value computed once, O(n) not O(2^n)\n\n-- Compose: right-to-left function composition\nlocal function compose(...)\n  local fns = {...}\n  return function(x)\n    for i = #fns, 1, -1 do\n      x = fns[i](x)\n    end\n    return x\n  end\nend\n\nlocal process = compose(\n  function(s) return s:upper() end,\n  function(s) return s:gsub(\"%s+\", \" \") end,\n  function(s) return s:reverse() end\n)\nprint(process(\"hello   world\"))  -- \"DLROW OLLEH\"\n\n-- Curry: partial application\nlocal function curry(fn, arity)\n  arity = arity or debug.getinfo(fn, \"u\").nparams  -- introspect param count\n  return function(x)\n    if arity \u003C= 1 then return fn(x) end\n    return curry(function(...) return fn(x, ...) end, arity - 1)\n  end\nend\n\nlocal add = function(a, b, c) return a + b + c end\nlocal add_one = curry(add)(1)       -- takes 2 more args\nlocal add_three = add_one(2)       -- takes 1 more arg\nprint(add_three(3))                -- 6\n",[24,3701,3702,3707,3719,3744,3753,3772,3784,3793,3800,3804,3808,3812,3819,3834,3853,3884,3890,3908,3912,3917,3928,3943,3951,3974,3984,3988,3994,3998,4002,4006,4020,4044,4074,4093,4097,4116,4120,4125,4137,4167,4175,4195,4229,4233,4237,4241,4268,4289,4310],{"__ignoreMap":46},[50,3703,3704],{"class":52,"line":53},[50,3705,3706],{"class":56},"-- Memoize: cache results by argument. Uses weak table for auto-eviction.\n",[50,3708,3709,3711,3713,3716],{"class":52,"line":60},[50,3710,64],{"class":63},[50,3712,74],{"class":63},[50,3714,3715],{"class":67}," memoize",[50,3717,3718],{"class":77},"(fn)\n",[50,3720,3721,3723,3726,3728,3731,3734,3736,3739,3741],{"class":52,"line":87},[50,3722,464],{"class":63},[50,3724,3725],{"class":77}," cache ",[50,3727,262],{"class":63},[50,3729,3730],{"class":121}," setmetatable",[50,3732,3733],{"class":77},"({}, {__mode ",[50,3735,262],{"class":63},[50,3737,3738],{"class":830}," \"v\"",[50,3740,617],{"class":77},[50,3742,3743],{"class":56},"-- weak values: GC can evict\n",[50,3745,3746,3748,3750],{"class":52,"line":93},[50,3747,139],{"class":63},[50,3749,74],{"class":63},[50,3751,3752],{"class":77},"(x)\n",[50,3754,3755,3757,3760,3762,3764,3766,3768,3770],{"class":52,"line":109},[50,3756,504],{"class":63},[50,3758,3759],{"class":77}," cache[x] ",[50,3761,3616],{"class":63},[50,3763,3179],{"class":121},[50,3765,125],{"class":63},[50,3767,128],{"class":63},[50,3769,3759],{"class":77},[50,3771,166],{"class":63},[50,3773,3774,3776,3778,3780,3782],{"class":52,"line":136},[50,3775,3153],{"class":63},[50,3777,3535],{"class":77},[50,3779,262],{"class":63},[50,3781,1517],{"class":121},[50,3783,3752],{"class":77},[50,3785,3786,3789,3791],{"class":52,"line":163},[50,3787,3788],{"class":77},"    cache[x] ",[50,3790,262],{"class":63},[50,3792,3686],{"class":77},[50,3794,3795,3798],{"class":52,"line":169},[50,3796,3797],{"class":63},"    return",[50,3799,3686],{"class":77},[50,3801,3802],{"class":52,"line":176},[50,3803,551],{"class":63},[50,3805,3806],{"class":52,"line":182},[50,3807,166],{"class":63},[50,3809,3810],{"class":52,"line":196},[50,3811,173],{"emptyLinePlaceholder":172},[50,3813,3814,3816],{"class":52,"line":215},[50,3815,64],{"class":63},[50,3817,3818],{"class":77}," slow_fib\n",[50,3820,3821,3824,3826,3828,3830,3832],{"class":52,"line":238},[50,3822,3823],{"class":77},"slow_fib ",[50,3825,262],{"class":63},[50,3827,3715],{"class":121},[50,3829,315],{"class":77},[50,3831,271],{"class":63},[50,3833,193],{"class":77},[50,3835,3836,3838,3840,3842,3845,3847,3849,3851],{"class":52,"line":243},[50,3837,112],{"class":63},[50,3839,115],{"class":77},[50,3841,510],{"class":63},[50,3843,3844],{"class":121}," 2",[50,3846,125],{"class":63},[50,3848,128],{"class":63},[50,3850,115],{"class":77},[50,3852,166],{"class":63},[50,3854,3855,3857,3860,3862,3864,3866,3869,3871,3873,3875,3877,3879,3881],{"class":52,"line":248},[50,3856,139],{"class":63},[50,3858,3859],{"class":121}," slow_fib",[50,3861,149],{"class":77},[50,3863,152],{"class":63},[50,3865,122],{"class":121},[50,3867,3868],{"class":77},") ",[50,3870,403],{"class":63},[50,3872,3859],{"class":121},[50,3874,149],{"class":77},[50,3876,152],{"class":63},[50,3878,3844],{"class":121},[50,3880,232],{"class":77},[50,3882,3883],{"class":56},"-- recursive calls also hit cache\n",[50,3885,3886,3888],{"class":52,"line":254},[50,3887,81],{"class":63},[50,3889,1175],{"class":77},[50,3891,3892,3894,3896,3899,3901,3903,3905],{"class":52,"line":268},[50,3893,743],{"class":121},[50,3895,315],{"class":77},[50,3897,3898],{"class":121},"slow_fib",[50,3900,315],{"class":77},[50,3902,2314],{"class":121},[50,3904,1482],{"class":77},[50,3906,3907],{"class":56},"-- fast: each value computed once, O(n) not O(2^n)\n",[50,3909,3910],{"class":52,"line":289},[50,3911,173],{"emptyLinePlaceholder":172},[50,3913,3914],{"class":52,"line":300},[50,3915,3916],{"class":56},"-- Compose: right-to-left function composition\n",[50,3918,3919,3921,3923,3926],{"class":52,"line":305},[50,3920,64],{"class":63},[50,3922,74],{"class":63},[50,3924,3925],{"class":67}," compose",[50,3927,939],{"class":77},[50,3929,3930,3932,3935,3937,3939,3941],{"class":52,"line":326},[50,3931,464],{"class":63},[50,3933,3934],{"class":77}," fns ",[50,3936,262],{"class":63},[50,3938,661],{"class":77},[50,3940,30],{"class":121},[50,3942,1445],{"class":77},[50,3944,3945,3947,3949],{"class":52,"line":344},[50,3946,139],{"class":63},[50,3948,74],{"class":63},[50,3950,3752],{"class":77},[50,3952,3953,3955,3957,3959,3961,3964,3966,3968,3970,3972],{"class":52,"line":349},[50,3954,1196],{"class":63},[50,3956,1199],{"class":77},[50,3958,262],{"class":63},[50,3960,1597],{"class":63},[50,3962,3963],{"class":77},"fns, ",[50,3965,586],{"class":121},[50,3967,423],{"class":77},[50,3969,152],{"class":63},[50,3971,586],{"class":121},[50,3973,3236],{"class":63},[50,3975,3976,3979,3981],{"class":52,"line":355},[50,3977,3978],{"class":77},"      x ",[50,3980,262],{"class":63},[50,3982,3983],{"class":77}," fns[i](x)\n",[50,3985,3986],{"class":52,"line":383},[50,3987,1243],{"class":63},[50,3989,3990,3992],{"class":52,"line":411},[50,3991,3797],{"class":63},[50,3993,1036],{"class":77},[50,3995,3996],{"class":52,"line":1384},[50,3997,551],{"class":63},[50,3999,4000],{"class":52,"line":1400},[50,4001,166],{"class":63},[50,4003,4004],{"class":52,"line":1411},[50,4005,173],{"emptyLinePlaceholder":172},[50,4007,4008,4010,4013,4015,4017],{"class":52,"line":1416},[50,4009,64],{"class":63},[50,4011,4012],{"class":77}," process ",[50,4014,262],{"class":63},[50,4016,3925],{"class":121},[50,4018,4019],{"class":77},"(\n",[50,4021,4022,4025,4028,4030,4033,4035,4038,4040,4042],{"class":52,"line":1422},[50,4023,4024],{"class":63},"  function",[50,4026,4027],{"class":77},"(s) ",[50,4029,370],{"class":63},[50,4031,4032],{"class":67}," s",[50,4034,277],{"class":77},[50,4036,4037],{"class":121},"upper",[50,4039,78],{"class":77},[50,4041,81],{"class":63},[50,4043,1920],{"class":77},[50,4045,4046,4048,4050,4052,4054,4056,4059,4061,4064,4066,4068,4070,4072],{"class":52,"line":1448},[50,4047,4024],{"class":63},[50,4049,4027],{"class":77},[50,4051,370],{"class":63},[50,4053,4032],{"class":67},[50,4055,277],{"class":77},[50,4057,4058],{"class":121},"gsub",[50,4060,315],{"class":77},[50,4062,4063],{"class":830},"\"%s+\"",[50,4065,423],{"class":77},[50,4067,1233],{"class":830},[50,4069,3868],{"class":77},[50,4071,81],{"class":63},[50,4073,1920],{"class":77},[50,4075,4076,4078,4080,4082,4084,4086,4089,4091],{"class":52,"line":1464},[50,4077,4024],{"class":63},[50,4079,4027],{"class":77},[50,4081,370],{"class":63},[50,4083,4032],{"class":67},[50,4085,277],{"class":77},[50,4087,4088],{"class":121},"reverse",[50,4090,78],{"class":77},[50,4092,166],{"class":63},[50,4094,4095],{"class":52,"line":1488},[50,4096,1175],{"class":77},[50,4098,4099,4101,4103,4106,4108,4111,4113],{"class":52,"line":1493},[50,4100,743],{"class":121},[50,4102,315],{"class":77},[50,4104,4105],{"class":121},"process",[50,4107,315],{"class":77},[50,4109,4110],{"class":830},"\"hello   world\"",[50,4112,1482],{"class":77},[50,4114,4115],{"class":56},"-- \"DLROW OLLEH\"\n",[50,4117,4118],{"class":52,"line":1499},[50,4119,173],{"emptyLinePlaceholder":172},[50,4121,4122],{"class":52,"line":1512},[50,4123,4124],{"class":56},"-- Curry: partial application\n",[50,4126,4127,4129,4131,4134],{"class":52,"line":1529},[50,4128,64],{"class":63},[50,4130,74],{"class":63},[50,4132,4133],{"class":67}," curry",[50,4135,4136],{"class":77},"(fn, arity)\n",[50,4138,4139,4142,4144,4147,4149,4152,4155,4158,4161,4164],{"class":52,"line":1534},[50,4140,4141],{"class":77},"  arity ",[50,4143,262],{"class":63},[50,4145,4146],{"class":77}," arity ",[50,4148,1875],{"class":63},[50,4150,4151],{"class":121}," debug.getinfo",[50,4153,4154],{"class":77},"(fn, ",[50,4156,4157],{"class":830},"\"u\"",[50,4159,4160],{"class":77},").",[50,4162,4163],{"class":67},"nparams",[50,4165,4166],{"class":56},"  -- introspect param count\n",[50,4168,4169,4171,4173],{"class":52,"line":2274},[50,4170,139],{"class":63},[50,4172,74],{"class":63},[50,4174,3752],{"class":77},[50,4176,4177,4179,4181,4183,4185,4187,4189,4191,4193],{"class":52,"line":2279},[50,4178,504],{"class":63},[50,4180,4146],{"class":77},[50,4182,118],{"class":63},[50,4184,122],{"class":121},[50,4186,125],{"class":63},[50,4188,128],{"class":63},[50,4190,1517],{"class":121},[50,4192,375],{"class":77},[50,4194,166],{"class":63},[50,4196,4197,4199,4201,4203,4205,4207,4209,4211,4214,4216,4218,4220,4223,4225,4227],{"class":52,"line":2284},[50,4198,3797],{"class":63},[50,4200,4133],{"class":121},[50,4202,315],{"class":77},[50,4204,271],{"class":63},[50,4206,1592],{"class":77},[50,4208,370],{"class":63},[50,4210,1517],{"class":121},[50,4212,4213],{"class":77},"(x, ",[50,4215,30],{"class":121},[50,4217,3868],{"class":77},[50,4219,81],{"class":63},[50,4221,4222],{"class":77},", arity ",[50,4224,152],{"class":63},[50,4226,122],{"class":121},[50,4228,1175],{"class":77},[50,4230,4231],{"class":52,"line":2303},[50,4232,551],{"class":63},[50,4234,4235],{"class":52,"line":2322},[50,4236,166],{"class":63},[50,4238,4239],{"class":52,"line":2339},[50,4240,173],{"emptyLinePlaceholder":172},[50,4242,4243,4245,4247,4249,4251,4254,4256,4258,4260,4262,4264,4266],{"class":52,"line":2839},[50,4244,64],{"class":63},[50,4246,388],{"class":67},[50,4248,71],{"class":63},[50,4250,74],{"class":63},[50,4252,4253],{"class":77},"(a, b, c) ",[50,4255,370],{"class":63},[50,4257,400],{"class":77},[50,4259,403],{"class":63},[50,4261,406],{"class":77},[50,4263,403],{"class":63},[50,4265,2012],{"class":77},[50,4267,166],{"class":63},[50,4269,4270,4272,4275,4277,4279,4282,4284,4286],{"class":52,"line":2844},[50,4271,64],{"class":63},[50,4273,4274],{"class":77}," add_one ",[50,4276,262],{"class":63},[50,4278,4133],{"class":121},[50,4280,4281],{"class":77},"(add)(",[50,4283,586],{"class":121},[50,4285,157],{"class":77},[50,4287,4288],{"class":56},"-- takes 2 more args\n",[50,4290,4291,4293,4296,4298,4301,4303,4305,4307],{"class":52,"line":2867},[50,4292,64],{"class":63},[50,4294,4295],{"class":77}," add_three ",[50,4297,262],{"class":63},[50,4299,4300],{"class":121}," add_one",[50,4302,315],{"class":77},[50,4304,420],{"class":121},[50,4306,157],{"class":77},[50,4308,4309],{"class":56},"-- takes 1 more arg\n",[50,4311,4312,4314,4316,4319,4321,4323,4326],{"class":52,"line":2872},[50,4313,743],{"class":121},[50,4315,315],{"class":77},[50,4317,4318],{"class":121},"add_three",[50,4320,315],{"class":77},[50,4322,426],{"class":121},[50,4324,4325],{"class":77},"))                ",[50,4327,4328],{"class":56},"-- 6\n",[33,4330,4332,4335],{"id":4331},"pcall-with-multiple-return-values",[24,4333,4334],{},"pcall"," with Multiple Return Values",[38,4337,4338],{"language":40},[42,4339,4341],{"className":44,"code":4340,"language":40,"meta":46,"style":46},"-- pcall returns (true, result1, result2, ...) on success, (false, err) on failure\nlocal function safe_divide(a, b)\n  local ok, r1, r2 = pcall(function()\n    return math.floor(a \u002F b), a % b  -- two return values\n  end)\n  if not ok then return nil, r1 end  -- r1 is the error message\n  return r1, r2                     -- quotient, remainder\nend\n\nlocal q, r = safe_divide(17, 5)  -- 3, 2\nlocal q2, err = safe_divide(17, 0)  -- nil, error message\n",[24,4342,4343,4348,4360,4379,4403,4410,4434,4444,4448,4452,4477],{"__ignoreMap":46},[50,4344,4345],{"class":52,"line":53},[50,4346,4347],{"class":56},"-- pcall returns (true, result1, result2, ...) on success, (false, err) on failure\n",[50,4349,4350,4352,4354,4357],{"class":52,"line":60},[50,4351,64],{"class":63},[50,4353,74],{"class":63},[50,4355,4356],{"class":67}," safe_divide",[50,4358,4359],{"class":77},"(a, b)\n",[50,4361,4362,4364,4367,4369,4372,4374,4376],{"class":52,"line":87},[50,4363,464],{"class":63},[50,4365,4366],{"class":77}," ok, r1, r2 ",[50,4368,262],{"class":63},[50,4370,4371],{"class":121}," pcall",[50,4373,315],{"class":77},[50,4375,271],{"class":63},[50,4377,4378],{"class":77},"()\n",[50,4380,4381,4383,4386,4389,4391,4394,4397,4400],{"class":52,"line":93},[50,4382,3797],{"class":63},[50,4384,4385],{"class":121}," math.floor",[50,4387,4388],{"class":77},"(a ",[50,4390,1106],{"class":63},[50,4392,4393],{"class":77}," b), a ",[50,4395,4396],{"class":63},"%",[50,4398,4399],{"class":77}," b  ",[50,4401,4402],{"class":56},"-- two return values\n",[50,4404,4405,4408],{"class":52,"line":109},[50,4406,4407],{"class":63},"  end",[50,4409,1175],{"class":77},[50,4411,4412,4414,4417,4420,4422,4424,4426,4429,4431],{"class":52,"line":136},[50,4413,112],{"class":63},[50,4415,4416],{"class":63}," not",[50,4418,4419],{"class":77}," ok ",[50,4421,516],{"class":63},[50,4423,128],{"class":63},[50,4425,3179],{"class":121},[50,4427,4428],{"class":77},", r1 ",[50,4430,81],{"class":63},[50,4432,4433],{"class":56},"  -- r1 is the error message\n",[50,4435,4436,4438,4441],{"class":52,"line":163},[50,4437,139],{"class":63},[50,4439,4440],{"class":77}," r1, r2                     ",[50,4442,4443],{"class":56},"-- quotient, remainder\n",[50,4445,4446],{"class":52,"line":169},[50,4447,166],{"class":63},[50,4449,4450],{"class":52,"line":176},[50,4451,173],{"emptyLinePlaceholder":172},[50,4453,4454,4456,4459,4461,4463,4465,4468,4470,4472,4474],{"class":52,"line":182},[50,4455,64],{"class":63},[50,4457,4458],{"class":77}," q, r ",[50,4460,262],{"class":63},[50,4462,4356],{"class":121},[50,4464,315],{"class":77},[50,4466,4467],{"class":121},"17",[50,4469,423],{"class":77},[50,4471,600],{"class":121},[50,4473,232],{"class":77},[50,4475,4476],{"class":56},"-- 3, 2\n",[50,4478,4479,4481,4484,4486,4488,4490,4492,4494,4497,4499],{"class":52,"line":196},[50,4480,64],{"class":63},[50,4482,4483],{"class":77}," q2, err ",[50,4485,262],{"class":63},[50,4487,4356],{"class":121},[50,4489,315],{"class":77},[50,4491,4467],{"class":121},[50,4493,423],{"class":77},[50,4495,4496],{"class":121},"0",[50,4498,232],{"class":77},[50,4500,4501],{"class":56},"-- nil, error message\n",[33,4503,4505],{"id":4504},"tips-tricks","💡 Tips & Tricks",[15,4507,4508,4511,4512,4515],{},[19,4509,4510],{},"Localize functions called in hot loops",": Same as with stdlib — ",[24,4513,4514],{},"local fn = expensive"," turns a global\u002Fupvalue chain into a direct local.",[38,4517,4518],{"language":40},[42,4519,4521],{"className":44,"code":4520,"language":40,"meta":46,"style":46},"local function process_items(items)\n  local insert = table.insert  -- localize for the loop\n  local results = {}\n  for _, item in ipairs(items) do\n    insert(results, transform(item))  -- fast: insert is a local upvalue\n  end\n  return results\nend\n",[24,4522,4523,4535,4550,4561,4577,4594,4598,4605],{"__ignoreMap":46},[50,4524,4525,4527,4529,4532],{"class":52,"line":53},[50,4526,64],{"class":63},[50,4528,74],{"class":63},[50,4530,4531],{"class":67}," process_items",[50,4533,4534],{"class":77},"(items)\n",[50,4536,4537,4539,4542,4544,4547],{"class":52,"line":60},[50,4538,464],{"class":63},[50,4540,4541],{"class":77}," insert ",[50,4543,262],{"class":63},[50,4545,4546],{"class":121}," table.insert",[50,4548,4549],{"class":56},"  -- localize for the loop\n",[50,4551,4552,4554,4557,4559],{"class":52,"line":87},[50,4553,464],{"class":63},[50,4555,4556],{"class":77}," results ",[50,4558,262],{"class":63},[50,4560,265],{"class":77},[50,4562,4563,4565,4568,4570,4572,4575],{"class":52,"line":93},[50,4564,484],{"class":63},[50,4566,4567],{"class":77}," _, item ",[50,4569,490],{"class":63},[50,4571,493],{"class":121},[50,4573,4574],{"class":77},"(items) ",[50,4576,499],{"class":63},[50,4578,4579,4582,4585,4588,4591],{"class":52,"line":109},[50,4580,4581],{"class":121},"    insert",[50,4583,4584],{"class":77},"(results, ",[50,4586,4587],{"class":121},"transform",[50,4589,4590],{"class":77},"(item))  ",[50,4592,4593],{"class":56},"-- fast: insert is a local upvalue\n",[50,4595,4596],{"class":52,"line":136},[50,4597,551],{"class":63},[50,4599,4600,4602],{"class":52,"line":163},[50,4601,139],{"class":63},[50,4603,4604],{"class":77}," results\n",[50,4606,4607],{"class":52,"line":169},[50,4608,166],{"class":63},[15,4610,4611,277],{},[19,4612,4613,4616],{},[24,4614,4615],{},"xpcall"," with traceback handler for better error messages",[38,4618,4619],{"language":40},[42,4620,4622],{"className":44,"code":4621,"language":40,"meta":46,"style":46},"local function with_traceback(fn)\n  return xpcall(fn, function(err)\n    return debug.traceback(tostring(err), 2)  -- full stack with the error\n  end)\nend\nlocal ok, result = with_traceback(function()\n  error(\"boom\")\nend)\nif not ok then print(result) end  -- boom\\nstack traceback:\\n\\tfile.lua:N: ...\n",[24,4623,4624,4635,4649,4670,4676,4680,4697,4709,4715],{"__ignoreMap":46},[50,4625,4626,4628,4630,4633],{"class":52,"line":53},[50,4627,64],{"class":63},[50,4629,74],{"class":63},[50,4631,4632],{"class":67}," with_traceback",[50,4634,3718],{"class":77},[50,4636,4637,4639,4642,4644,4646],{"class":52,"line":60},[50,4638,139],{"class":63},[50,4640,4641],{"class":121}," xpcall",[50,4643,4154],{"class":77},[50,4645,271],{"class":63},[50,4647,4648],{"class":77},"(err)\n",[50,4650,4651,4653,4656,4658,4660,4663,4665,4667],{"class":52,"line":87},[50,4652,3797],{"class":63},[50,4654,4655],{"class":121}," debug.traceback",[50,4657,315],{"class":77},[50,4659,1218],{"class":121},[50,4661,4662],{"class":77},"(err), ",[50,4664,420],{"class":121},[50,4666,232],{"class":77},[50,4668,4669],{"class":56},"-- full stack with the error\n",[50,4671,4672,4674],{"class":52,"line":93},[50,4673,4407],{"class":63},[50,4675,1175],{"class":77},[50,4677,4678],{"class":52,"line":109},[50,4679,166],{"class":63},[50,4681,4682,4684,4687,4689,4691,4693,4695],{"class":52,"line":136},[50,4683,64],{"class":63},[50,4685,4686],{"class":77}," ok, result ",[50,4688,262],{"class":63},[50,4690,4632],{"class":121},[50,4692,315],{"class":77},[50,4694,271],{"class":63},[50,4696,4378],{"class":77},[50,4698,4699,4702,4704,4707],{"class":52,"line":163},[50,4700,4701],{"class":121},"  error",[50,4703,315],{"class":77},[50,4705,4706],{"class":830},"\"boom\"",[50,4708,1175],{"class":77},[50,4710,4711,4713],{"class":52,"line":169},[50,4712,81],{"class":63},[50,4714,1175],{"class":77},[50,4716,4717,4720,4722,4724,4726,4729,4732,4734],{"class":52,"line":176},[50,4718,4719],{"class":63},"if",[50,4721,4416],{"class":63},[50,4723,4419],{"class":77},[50,4725,516],{"class":63},[50,4727,4728],{"class":121}," print",[50,4730,4731],{"class":77},"(result) ",[50,4733,81],{"class":63},[50,4735,4736],{"class":56},"  -- boom\\nstack traceback:\\n\\tfile.lua:N: ...\n",[15,4738,4739,277],{},[19,4740,4741,4742,4745],{},"Use ",[24,4743,4744],{},"__call"," metamethod to make table-based objects callable",[38,4747,4748],{"language":40},[42,4749,4751],{"className":44,"code":4750,"language":40,"meta":46,"style":46},"local Iterator = {}\nIterator.__index = Iterator\nIterator.__call = function(self) return self:next() end  -- obj() == obj:next()\nfunction Iterator.new(t) return setmetatable({_t = t, _i = 1}, Iterator) end\nfunction Iterator:next()\n  local v = self._t[self._i]\n  self._i = self._i + 1\n  return v  -- nil when exhausted\nend\nlocal it = Iterator.new({10, 20, 30})\nprint(it())  -- 10\nprint(it())  -- 20\n",[24,4752,4753,4764,4777,4806,4843,4855,4884,4906,4916,4920,4949,4964],{"__ignoreMap":46},[50,4754,4755,4757,4760,4762],{"class":52,"line":53},[50,4756,64],{"class":63},[50,4758,4759],{"class":77}," Iterator ",[50,4761,262],{"class":63},[50,4763,265],{"class":77},[50,4765,4766,4769,4772,4774],{"class":52,"line":60},[50,4767,4768],{"class":77},"Iterator.",[50,4770,4771],{"class":67},"__index",[50,4773,71],{"class":63},[50,4775,4776],{"class":77}," Iterator\n",[50,4778,4779,4781,4783,4785,4787,4790,4792,4794,4796,4799,4801,4803],{"class":52,"line":87},[50,4780,4768],{"class":77},[50,4782,4744],{"class":67},[50,4784,71],{"class":63},[50,4786,74],{"class":63},[50,4788,4789],{"class":77},"(self) ",[50,4791,370],{"class":63},[50,4793,294],{"class":121},[50,4795,277],{"class":77},[50,4797,4798],{"class":121},"next",[50,4800,78],{"class":77},[50,4802,81],{"class":63},[50,4804,4805],{"class":56},"  -- obj() == obj:next()\n",[50,4807,4808,4810,4813,4816,4819,4822,4824,4826,4829,4831,4834,4836,4838,4841],{"class":52,"line":93},[50,4809,271],{"class":63},[50,4811,4812],{"class":67}," Iterator",[50,4814,4815],{"class":77},".",[50,4817,4818],{"class":67},"new",[50,4820,4821],{"class":77},"(t) ",[50,4823,370],{"class":63},[50,4825,3730],{"class":121},[50,4827,4828],{"class":77},"({_t ",[50,4830,262],{"class":63},[50,4832,4833],{"class":77}," t, _i ",[50,4835,262],{"class":63},[50,4837,122],{"class":121},[50,4839,4840],{"class":77},"}, Iterator) ",[50,4842,166],{"class":63},[50,4844,4845,4847,4849,4851,4853],{"class":52,"line":109},[50,4846,271],{"class":63},[50,4848,4812],{"class":67},[50,4850,277],{"class":77},[50,4852,4798],{"class":67},[50,4854,4378],{"class":77},[50,4856,4857,4859,4861,4863,4865,4867,4870,4873,4876,4878,4881],{"class":52,"line":136},[50,4858,464],{"class":63},[50,4860,507],{"class":77},[50,4862,262],{"class":63},[50,4864,294],{"class":121},[50,4866,4815],{"class":77},[50,4868,4869],{"class":67},"_t",[50,4871,4872],{"class":77},"[",[50,4874,4875],{"class":121},"self",[50,4877,4815],{"class":77},[50,4879,4880],{"class":67},"_i",[50,4882,4883],{"class":77},"]\n",[50,4885,4886,4889,4891,4893,4895,4897,4899,4901,4903],{"class":52,"line":163},[50,4887,4888],{"class":121},"  self",[50,4890,4815],{"class":77},[50,4892,4880],{"class":67},[50,4894,71],{"class":63},[50,4896,294],{"class":121},[50,4898,4815],{"class":77},[50,4900,4880],{"class":67},[50,4902,2501],{"class":63},[50,4904,4905],{"class":121}," 1\n",[50,4907,4908,4910,4913],{"class":52,"line":169},[50,4909,139],{"class":63},[50,4911,4912],{"class":77}," v  ",[50,4914,4915],{"class":56},"-- nil when exhausted\n",[50,4917,4918],{"class":52,"line":176},[50,4919,166],{"class":63},[50,4921,4922,4924,4927,4929,4932,4934,4936,4938,4940,4942,4944,4946],{"class":52,"line":182},[50,4923,64],{"class":63},[50,4925,4926],{"class":77}," it ",[50,4928,262],{"class":63},[50,4930,4931],{"class":77}," Iterator.",[50,4933,4818],{"class":121},[50,4935,579],{"class":77},[50,4937,1434],{"class":121},[50,4939,423],{"class":77},[50,4941,875],{"class":121},[50,4943,423],{"class":77},[50,4945,880],{"class":121},[50,4947,4948],{"class":77},"})\n",[50,4950,4951,4953,4955,4958,4961],{"class":52,"line":196},[50,4952,743],{"class":121},[50,4954,315],{"class":77},[50,4956,4957],{"class":121},"it",[50,4959,4960],{"class":77},"())  ",[50,4962,4963],{"class":56},"-- 10\n",[50,4965,4966,4968,4970,4972,4974],{"class":52,"line":215},[50,4967,743],{"class":121},[50,4969,315],{"class":77},[50,4971,4957],{"class":121},[50,4973,4960],{"class":77},[50,4975,4976],{"class":56},"-- 20\n",[33,4978,4980],{"id":4979},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[15,4982,4983,4992],{},[19,4984,4985,4987,4988,4991],{},[24,4986,26],{}," is a tail call; ",[24,4989,4990],{},"return (f())"," is NOT",": Parentheses force single-value and also prevent PTC.",[38,4994,4995],{"language":40},[42,4996,4998],{"className":44,"code":4997,"language":40,"meta":46,"style":46},"return f()     -- tail call: stack frame replaced\nreturn (f())   -- NOT a tail call: extra parens force single-value + prevent PTC\n",[24,4999,5000,5012],{"__ignoreMap":46},[50,5001,5002,5004,5006,5009],{"class":52,"line":53},[50,5003,370],{"class":63},[50,5005,68],{"class":121},[50,5007,5008],{"class":77},"()     ",[50,5010,5011],{"class":56},"-- tail call: stack frame replaced\n",[50,5013,5014,5016,5018,5021,5023],{"class":52,"line":60},[50,5015,370],{"class":63},[50,5017,3566],{"class":77},[50,5019,5020],{"class":121},"f",[50,5022,1090],{"class":77},[50,5024,5025],{"class":56},"-- NOT a tail call: extra parens force single-value + prevent PTC\n",[15,5027,5028,2357,5035,5038,5039,5042],{},[19,5029,5030,5031,5034],{},"Functions have no ",[24,5032,5033],{},".name"," property",[24,5036,5037],{},"function foo() end"," has no built-in name. ",[24,5040,5041],{},"debug.getinfo(f, \"n\").name"," may return nil for anonymous functions.",[15,5044,5045,2357,5051,5054,5055,423,5058,5061,5062,5065],{},[19,5046,5047,5048,5050],{},"Default parameter via ",[24,5049,1875],{}," is dangerous for false\u002Fnil values",[24,5052,5053],{},"function f(x) x = x or default end"," — if caller passes ",[24,5056,5057],{},"false",[24,5059,5060],{},"x"," becomes ",[24,5063,5064],{},"default",". Use explicit nil check:",[38,5067,5068],{"language":40},[42,5069,5071],{"className":44,"code":5070,"language":40,"meta":46,"style":46},"function f(x)\n  if x == nil then x = default end  -- preserves false\nend\n",[24,5072,5073,5081,5106],{"__ignoreMap":46},[50,5074,5075,5077,5079],{"class":52,"line":53},[50,5076,271],{"class":63},[50,5078,68],{"class":67},[50,5080,3752],{"class":77},[50,5082,5083,5085,5088,5090,5092,5094,5096,5098,5101,5103],{"class":52,"line":60},[50,5084,112],{"class":63},[50,5086,5087],{"class":77}," x ",[50,5089,1185],{"class":63},[50,5091,3179],{"class":121},[50,5093,125],{"class":63},[50,5095,5087],{"class":77},[50,5097,262],{"class":63},[50,5099,5100],{"class":77}," default ",[50,5102,81],{"class":63},[50,5104,5105],{"class":56},"  -- preserves false\n",[50,5107,5108],{"class":52,"line":87},[50,5109,166],{"class":63},[33,5111,5113],{"id":5112},"spot-the-bug","🧠 Spot the Bug",[38,5115,5116,5366],{"language":40},[42,5117,5119],{"className":44,"code":5118,"language":40,"meta":46,"style":46},"local function curry2(fn)\n  return function(a)\n    return function(b)\n      return fn(a, b)\n    end\n  end\nend\n\nlocal add = curry2(function(a, b) return a + b end)\nlocal add5 = add(5)\nprint(add5(3))      -- 8\nprint(add5(10))     -- 13\nprint(add(5)(3))    -- 8\n\n-- Now: what does this print?\nlocal results = {}\nfor i = 1, 3 do\n  results[i] = add(i)\nend\nprint(results[1](100), results[2](100), results[3](100))\n",[24,5120,5121,5132,5141,5150,5158,5162,5166,5170,5174,5203,5220,5239,5257,5280,5284,5289,5299,5316,5328,5332],{"__ignoreMap":46},[50,5122,5123,5125,5127,5130],{"class":52,"line":53},[50,5124,64],{"class":63},[50,5126,74],{"class":63},[50,5128,5129],{"class":67}," curry2",[50,5131,3718],{"class":77},[50,5133,5134,5136,5138],{"class":52,"line":60},[50,5135,139],{"class":63},[50,5137,74],{"class":63},[50,5139,5140],{"class":77},"(a)\n",[50,5142,5143,5145,5147],{"class":52,"line":87},[50,5144,3797],{"class":63},[50,5146,74],{"class":63},[50,5148,5149],{"class":77},"(b)\n",[50,5151,5152,5154,5156],{"class":52,"line":93},[50,5153,2163],{"class":63},[50,5155,1517],{"class":121},[50,5157,4359],{"class":77},[50,5159,5160],{"class":52,"line":109},[50,5161,1243],{"class":63},[50,5163,5164],{"class":52,"line":136},[50,5165,551],{"class":63},[50,5167,5168],{"class":52,"line":163},[50,5169,166],{"class":63},[50,5171,5172],{"class":52,"line":169},[50,5173,173],{"emptyLinePlaceholder":172},[50,5175,5176,5178,5181,5183,5185,5187,5189,5191,5193,5195,5197,5199,5201],{"class":52,"line":176},[50,5177,64],{"class":63},[50,5179,5180],{"class":77}," add ",[50,5182,262],{"class":63},[50,5184,5129],{"class":121},[50,5186,315],{"class":77},[50,5188,271],{"class":63},[50,5190,395],{"class":77},[50,5192,370],{"class":63},[50,5194,400],{"class":77},[50,5196,403],{"class":63},[50,5198,406],{"class":77},[50,5200,81],{"class":63},[50,5202,1175],{"class":77},[50,5204,5205,5207,5210,5212,5214,5216,5218],{"class":52,"line":182},[50,5206,64],{"class":63},[50,5208,5209],{"class":77}," add5 ",[50,5211,262],{"class":63},[50,5213,388],{"class":121},[50,5215,315],{"class":77},[50,5217,600],{"class":121},[50,5219,1175],{"class":77},[50,5221,5222,5224,5226,5229,5231,5233,5236],{"class":52,"line":196},[50,5223,743],{"class":121},[50,5225,315],{"class":77},[50,5227,5228],{"class":121},"add5",[50,5230,315],{"class":77},[50,5232,426],{"class":121},[50,5234,5235],{"class":77},"))      ",[50,5237,5238],{"class":56},"-- 8\n",[50,5240,5241,5243,5245,5247,5249,5251,5254],{"class":52,"line":215},[50,5242,743],{"class":121},[50,5244,315],{"class":77},[50,5246,5228],{"class":121},[50,5248,315],{"class":77},[50,5250,1434],{"class":121},[50,5252,5253],{"class":77},"))     ",[50,5255,5256],{"class":56},"-- 13\n",[50,5258,5259,5261,5263,5266,5268,5270,5273,5275,5278],{"class":52,"line":238},[50,5260,743],{"class":121},[50,5262,315],{"class":77},[50,5264,5265],{"class":121},"add",[50,5267,315],{"class":77},[50,5269,600],{"class":121},[50,5271,5272],{"class":77},")(",[50,5274,426],{"class":121},[50,5276,5277],{"class":77},"))    ",[50,5279,5238],{"class":56},[50,5281,5282],{"class":52,"line":243},[50,5283,173],{"emptyLinePlaceholder":172},[50,5285,5286],{"class":52,"line":248},[50,5287,5288],{"class":56},"-- Now: what does this print?\n",[50,5290,5291,5293,5295,5297],{"class":52,"line":254},[50,5292,64],{"class":63},[50,5294,4556],{"class":77},[50,5296,262],{"class":63},[50,5298,265],{"class":77},[50,5300,5301,5304,5306,5308,5310,5312,5314],{"class":52,"line":268},[50,5302,5303],{"class":63},"for",[50,5305,1199],{"class":77},[50,5307,262],{"class":63},[50,5309,122],{"class":121},[50,5311,423],{"class":77},[50,5313,426],{"class":121},[50,5315,3236],{"class":63},[50,5317,5318,5321,5323,5325],{"class":52,"line":289},[50,5319,5320],{"class":77},"  results[i] ",[50,5322,262],{"class":63},[50,5324,388],{"class":121},[50,5326,5327],{"class":77},"(i)\n",[50,5329,5330],{"class":52,"line":300},[50,5331,166],{"class":63},[50,5333,5334,5336,5339,5341,5344,5346,5349,5351,5353,5355,5357,5359,5361,5363],{"class":52,"line":305},[50,5335,743],{"class":121},[50,5337,5338],{"class":77},"(results[",[50,5340,586],{"class":121},[50,5342,5343],{"class":77},"](",[50,5345,2298],{"class":121},[50,5347,5348],{"class":77},"), results[",[50,5350,420],{"class":121},[50,5352,5343],{"class":77},[50,5354,2298],{"class":121},[50,5356,5348],{"class":77},[50,5358,426],{"class":121},[50,5360,5343],{"class":77},[50,5362,2298],{"class":121},[50,5364,5365],{"class":77},"))\n",[5367,5368,5369,5373,5379,5419],"details",{},[5370,5371,5372],"summary",{},"Answer",[15,5374,5375,5376,4815],{},"Prints ",[24,5377,5378],{},"101 102 103",[15,5380,5381,5382,5385,5386,5389,5390,5393,5394,5396,5397,5399,5400,5403,5404,5406,5407,5410,5411,5414,5415,5418],{},"Each ",[24,5383,5384],{},"add(i)"," call creates a ",[19,5387,5388],{},"new closure"," capturing ",[24,5391,5392],{},"i"," at that moment. Since the ",[24,5395,5303],{}," loop creates a fresh ",[24,5398,5392],{}," per iteration, each ",[24,5401,5402],{},"results[i]"," closure captures a different ",[24,5405,5392],{}," value (1, 2, 3 respectively). So ",[24,5408,5409],{},"results[1](100)"," = 1 + 100 = 101, ",[24,5412,5413],{},"results[2](100)"," = 2 + 100 = 102, ",[24,5416,5417],{},"results[3](100)"," = 3 + 100 = 103.",[15,5420,5421,5422,5425,5426,5428,5429,5432],{},"If this had been a ",[24,5423,5424],{},"while"," loop with a shared ",[24,5427,5392],{},", all three would return ",[24,5430,5431],{},"103"," (all capturing the final value 3 — see chapter 02's closure capture gotcha).",[5434,5435,5436],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":46,"searchDepth":60,"depth":60,"links":5438},[5439,5440,5443,5448,5449,5452,5453,5454,5456,5457,5458],{"id":35,"depth":60,"text":36},{"id":434,"depth":60,"text":435,"children":5441},[5442],{"id":841,"depth":87,"text":842},{"id":1096,"depth":60,"text":5444,"children":5445},"Varargs: ..., select, table.pack\u002Funpack",[5446],{"id":1564,"depth":87,"text":5447},"Edge case: nil in varargs",{"id":1821,"depth":60,"text":1822},{"id":2350,"depth":60,"text":2351,"children":5450},[5451],{"id":3015,"depth":87,"text":3016},{"id":3272,"depth":60,"text":3273},{"id":3693,"depth":60,"text":3694},{"id":4331,"depth":60,"text":5455},"pcall with Multiple Return Values",{"id":4504,"depth":60,"text":4505},{"id":4979,"depth":60,"text":4980},{"id":5112,"depth":60,"text":5113},"Deep-dive into first-class functions, multiple return value semantics, varargs via select\u002Fpack\u002Funpack, lexical closures with upvalue cells, proper tail calls for state machines, and functional patterns (memoize, compose, curry) used in production Lua codebases.","md",{},"\u002Flua\u002F03-functions",{"title":5,"description":5459},"lua\u002F03-functions","SEu3huiDKIbZTHfSyB4fs-wjahvJ1E40S3RC9QcXFu4",1789924650278]