[{"data":1,"prerenderedAt":3800},["ShallowReactive",2],{"page-\u002Fscala\u002F07-case-classes-and-pattern-matching":3},{"id":4,"title":5,"body":6,"description":3793,"extension":3794,"meta":3795,"navigation":94,"path":3796,"seo":3797,"stem":3798,"__hash__":3799},"content\u002Fscala\u002F07-case-classes-and-pattern-matching.md","Scala — Case Classes, ADTs & Advanced Pattern Matching",{"type":7,"value":8,"toc":3774},"minimark",[9,14,19,432,436,895,899,1398,1405,1866,1882,2193,2197,2423,2431,2840,2852,3103,3110,3424,3428,3442,3526,3538,3575,3594,3598,3616,3628,3641,3666,3670,3679,3770],[10,11,13],"h1",{"id":12},"_07-case-classes-adts-advanced-pattern-matching","07 — Case Classes, ADTs & Advanced Pattern Matching",[15,16,18],"h2",{"id":17},"case-class-internals-what-gets-generated","Case Class Internals — What Gets Generated",[20,21,23],"code-wrapper",{"language":22},"scala",[24,25,29],"pre",{"className":26,"code":27,"language":22,"meta":28,"style":28},"language-scala shiki shiki-themes github-light github-dark","\u002F\u002F case class generates (Scala 3):\n\u002F\u002F   1. apply() — factory method on companion object (no 'new' needed)\n\u002F\u002F   2. unapply() — extractor for pattern matching → Option[Tuple]\n\u002F\u002F   3. copy() — shallow copy with named param defaults for modification\n\u002F\u002F   4. equals() — field-by-field comparison via productElementNames + productIterator\n\u002F\u002F   5. hashCode() — MurmurHash3.productHash (consistent with equals)\n\u002F\u002F   6. toString() — \"ClassName(field1, field2, ...)\"\n\u002F\u002F   7. productPrefix, productArity, productElement, productIterator\n\u002F\u002F   8. The class itself is FINAL (can't subclass a case class)\n\nfinal case class User(id: Long, name: String, email: String, roles: List[String]):\n  \u002F\u002F You can add methods — they don't interfere with generated ones\n  def isAdmin: Boolean = roles.contains(\"admin\")\n  def withRole(role: String): User = copy(roles = roles :+ role)\n\n\u002F\u002F copy() — the immutable update pattern. Creates a new instance with modified fields.\nval alice = User(1, \"Alice\", \"alice@x.com\", List(\"user\"))\nval aliceAdmin = alice.copy(roles = alice.roles :+ \"admin\")  \u002F\u002F new User, old one unchanged\n\u002F\u002F copy is SHALLOW — List[String] is shared by reference (fine, List is immutable)\n\n\u002F\u002F ❌ ANTI-PATTERN: case class with mutable fields\ncase class BadConfig(var timeout: Int)     \u002F\u002F equals\u002FhashCode depend on mutable state!\nval cfg = BadConfig(5000)\nval set = Set(cfg)\ncfg.timeout = 10000\nset.contains(cfg)                          \u002F\u002F → false! hashCode changed, wrong bucket\n\u002F\u002F ✅ CORRECT: use copy for updates, keep case classes immutable\n","",[30,31,32,41,47,53,59,65,71,77,83,89,96,168,174,202,243,248,254,295,324,330,335,341,371,390,406,417,426],"code",{"__ignoreMap":28},[33,34,37],"span",{"class":35,"line":36},"line",1,[33,38,40],{"class":39},"sdCPZ","\u002F\u002F case class generates (Scala 3):\n",[33,42,44],{"class":35,"line":43},2,[33,45,46],{"class":39},"\u002F\u002F   1. apply() — factory method on companion object (no 'new' needed)\n",[33,48,50],{"class":35,"line":49},3,[33,51,52],{"class":39},"\u002F\u002F   2. unapply() — extractor for pattern matching → Option[Tuple]\n",[33,54,56],{"class":35,"line":55},4,[33,57,58],{"class":39},"\u002F\u002F   3. copy() — shallow copy with named param defaults for modification\n",[33,60,62],{"class":35,"line":61},5,[33,63,64],{"class":39},"\u002F\u002F   4. equals() — field-by-field comparison via productElementNames + productIterator\n",[33,66,68],{"class":35,"line":67},6,[33,69,70],{"class":39},"\u002F\u002F   5. hashCode() — MurmurHash3.productHash (consistent with equals)\n",[33,72,74],{"class":35,"line":73},7,[33,75,76],{"class":39},"\u002F\u002F   6. toString() — \"ClassName(field1, field2, ...)\"\n",[33,78,80],{"class":35,"line":79},8,[33,81,82],{"class":39},"\u002F\u002F   7. productPrefix, productArity, productElement, productIterator\n",[33,84,86],{"class":35,"line":85},9,[33,87,88],{"class":39},"\u002F\u002F   8. The class itself is FINAL (can't subclass a case class)\n",[33,90,92],{"class":35,"line":91},10,[33,93,95],{"emptyLinePlaceholder":94},true,"\n",[33,97,99,103,106,109,113,117,121,124,127,130,133,135,138,140,143,145,147,149,152,154,157,160,162,165],{"class":35,"line":98},11,[33,100,102],{"class":101},"svdQ7","final",[33,104,105],{"class":101}," case",[33,107,108],{"class":101}," class",[33,110,112],{"class":111},"sIsaT"," User",[33,114,116],{"class":115},"ssxIu","(",[33,118,120],{"class":119},"sCrzJ","id",[33,122,123],{"class":115},": ",[33,125,126],{"class":111},"Long",[33,128,129],{"class":115},", ",[33,131,132],{"class":119},"name",[33,134,123],{"class":115},[33,136,137],{"class":111},"String",[33,139,129],{"class":115},[33,141,142],{"class":119},"email",[33,144,123],{"class":115},[33,146,137],{"class":111},[33,148,129],{"class":115},[33,150,151],{"class":119},"roles",[33,153,123],{"class":115},[33,155,156],{"class":111},"List",[33,158,159],{"class":115},"[",[33,161,137],{"class":111},[33,163,164],{"class":115},"])",[33,166,167],{"class":101},":\n",[33,169,171],{"class":35,"line":170},12,[33,172,173],{"class":39},"  \u002F\u002F You can add methods — they don't interfere with generated ones\n",[33,175,177,180,183,186,189,192,195,199],{"class":35,"line":176},13,[33,178,179],{"class":101},"  def",[33,181,182],{"class":111}," isAdmin",[33,184,185],{"class":101},":",[33,187,188],{"class":111}," Boolean",[33,190,191],{"class":101}," =",[33,193,194],{"class":115}," roles.contains(",[33,196,198],{"class":197},"sJ6F3","\"admin\"",[33,200,201],{"class":115},")\n",[33,203,205,207,210,212,215,217,219,222,224,226,228,231,234,237,240],{"class":35,"line":204},14,[33,206,179],{"class":101},[33,208,209],{"class":111}," withRole",[33,211,116],{"class":115},[33,213,214],{"class":119},"role",[33,216,123],{"class":115},[33,218,137],{"class":111},[33,220,221],{"class":115},")",[33,223,185],{"class":101},[33,225,112],{"class":111},[33,227,191],{"class":101},[33,229,230],{"class":115}," copy(roles ",[33,232,233],{"class":101},"=",[33,235,236],{"class":115}," roles ",[33,238,239],{"class":101},":+",[33,241,242],{"class":115}," role)\n",[33,244,246],{"class":35,"line":245},15,[33,247,95],{"emptyLinePlaceholder":94},[33,249,251],{"class":35,"line":250},16,[33,252,253],{"class":39},"\u002F\u002F copy() — the immutable update pattern. Creates a new instance with modified fields.\n",[33,255,257,260,263,265,267,269,273,275,278,280,283,285,287,289,292],{"class":35,"line":256},17,[33,258,259],{"class":101},"val",[33,261,262],{"class":119}," alice",[33,264,191],{"class":101},[33,266,112],{"class":111},[33,268,116],{"class":115},[33,270,272],{"class":271},"snvgF","1",[33,274,129],{"class":115},[33,276,277],{"class":197},"\"Alice\"",[33,279,129],{"class":115},[33,281,282],{"class":197},"\"alice@x.com\"",[33,284,129],{"class":115},[33,286,156],{"class":111},[33,288,116],{"class":115},[33,290,291],{"class":197},"\"user\"",[33,293,294],{"class":115},"))\n",[33,296,298,300,303,305,308,310,313,315,318,321],{"class":35,"line":297},18,[33,299,259],{"class":101},[33,301,302],{"class":119}," aliceAdmin",[33,304,191],{"class":101},[33,306,307],{"class":115}," alice.copy(roles ",[33,309,233],{"class":101},[33,311,312],{"class":115}," alice.roles ",[33,314,239],{"class":101},[33,316,317],{"class":197}," \"admin\"",[33,319,320],{"class":115},")  ",[33,322,323],{"class":39},"\u002F\u002F new User, old one unchanged\n",[33,325,327],{"class":35,"line":326},19,[33,328,329],{"class":39},"\u002F\u002F copy is SHALLOW — List[String] is shared by reference (fine, List is immutable)\n",[33,331,333],{"class":35,"line":332},20,[33,334,95],{"emptyLinePlaceholder":94},[33,336,338],{"class":35,"line":337},21,[33,339,340],{"class":39},"\u002F\u002F ❌ ANTI-PATTERN: case class with mutable fields\n",[33,342,344,347,349,352,354,357,360,362,365,368],{"class":35,"line":343},22,[33,345,346],{"class":101},"case",[33,348,108],{"class":101},[33,350,351],{"class":111}," BadConfig",[33,353,116],{"class":115},[33,355,356],{"class":101},"var",[33,358,359],{"class":119}," timeout",[33,361,185],{"class":101},[33,363,364],{"class":111}," Int",[33,366,367],{"class":115},")     ",[33,369,370],{"class":39},"\u002F\u002F equals\u002FhashCode depend on mutable state!\n",[33,372,374,376,379,381,383,385,388],{"class":35,"line":373},23,[33,375,259],{"class":101},[33,377,378],{"class":119}," cfg",[33,380,191],{"class":101},[33,382,351],{"class":111},[33,384,116],{"class":115},[33,386,387],{"class":271},"5000",[33,389,201],{"class":115},[33,391,393,395,398,400,403],{"class":35,"line":392},24,[33,394,259],{"class":101},[33,396,397],{"class":119}," set",[33,399,191],{"class":101},[33,401,402],{"class":111}," Set",[33,404,405],{"class":115},"(cfg)\n",[33,407,409,412,414],{"class":35,"line":408},25,[33,410,411],{"class":115},"cfg.timeout ",[33,413,233],{"class":101},[33,415,416],{"class":271}," 10000\n",[33,418,420,423],{"class":35,"line":419},26,[33,421,422],{"class":115},"set.contains(cfg)                          ",[33,424,425],{"class":39},"\u002F\u002F → false! hashCode changed, wrong bucket\n",[33,427,429],{"class":35,"line":428},27,[33,430,431],{"class":39},"\u002F\u002F ✅ CORRECT: use copy for updates, keep case classes immutable\n",[15,433,435],{"id":434},"adt-design-sealed-hierarchies-for-domain-modeling","ADT Design — Sealed Hierarchies for Domain Modeling",[20,437,438],{"language":22},[24,439,441],{"className":26,"code":440,"language":22,"meta":28,"style":28},"\u002F\u002F Algebraic Data Type: sealed hierarchy where each variant is a case class.\n\u002F\u002F The compiler enforces exhaustiveness — adding a variant breaks all consumers.\n\nsealed trait Event:\n  def userId: Long\n  def timestamp: Long\n\nobject Event:\n  \u002F\u002F \"Sum type\" — Event is ONE of these variants\n  case class PageView(userId: Long, timestamp: Long, path: String, duration: Int) extends Event\n  case class Click(userId: Long, timestamp: Long, target: String, x: Int, y: Int) extends Event\n  case class Purchase(userId: Long, timestamp: Long, orderId: Long, amount: BigDecimal) extends Event\n  case class SessionEnd(userId: Long, timestamp: Long, sessionId: String) extends Event\n\n\u002F\u002F \"Product type\" — each variant has fields (the \"product\" of their types)\n\n\u002F\u002F Exhaustive handler — compiler verifies all 4 cases are covered\ndef toJson(e: Event): String = e match\n  case PageView(uid, ts, path, dur) => s\"\"\"{\"type\":\"pv\",\"uid\":$uid,\"path\":\"$path\",\"dur\":$dur}\"\"\"\n  case Click(uid, ts, target, x, y) => s\"\"\"{\"type\":\"click\",\"uid\":$uid,\"target\":\"$target\"}\"\"\"\n  case Purchase(uid, ts, orderId, amount) => s\"\"\"{\"type\":\"purchase\",\"uid\":$uid,\"amt\":$amount}\"\"\"\n  case SessionEnd(uid, ts, sessionId) => s\"\"\"{\"type\":\"end\",\"uid\":$uid,\"sid\":\"$sessionId\"}\"\"\"\n\n\u002F\u002F Adding Event.Signup → ALL match expressions fail to compile → forced to handle\n\u002F\u002F This is the #1 safety mechanism in Scala domain modeling.\n",[30,442,443,448,453,457,470,482,493,497,506,511,567,625,675,715,719,724,728,733,766,802,829,855,881,885,890],{"__ignoreMap":28},[33,444,445],{"class":35,"line":36},[33,446,447],{"class":39},"\u002F\u002F Algebraic Data Type: sealed hierarchy where each variant is a case class.\n",[33,449,450],{"class":35,"line":43},[33,451,452],{"class":39},"\u002F\u002F The compiler enforces exhaustiveness — adding a variant breaks all consumers.\n",[33,454,455],{"class":35,"line":49},[33,456,95],{"emptyLinePlaceholder":94},[33,458,459,462,465,468],{"class":35,"line":55},[33,460,461],{"class":101},"sealed",[33,463,464],{"class":101}," trait",[33,466,467],{"class":111}," Event",[33,469,167],{"class":101},[33,471,472,474,477,479],{"class":35,"line":61},[33,473,179],{"class":101},[33,475,476],{"class":111}," userId",[33,478,185],{"class":101},[33,480,481],{"class":111}," Long\n",[33,483,484,486,489,491],{"class":35,"line":67},[33,485,179],{"class":101},[33,487,488],{"class":111}," timestamp",[33,490,185],{"class":101},[33,492,481],{"class":111},[33,494,495],{"class":35,"line":73},[33,496,95],{"emptyLinePlaceholder":94},[33,498,499,502,504],{"class":35,"line":79},[33,500,501],{"class":101},"object",[33,503,467],{"class":111},[33,505,167],{"class":101},[33,507,508],{"class":35,"line":85},[33,509,510],{"class":39},"  \u002F\u002F \"Sum type\" — Event is ONE of these variants\n",[33,512,513,516,518,521,523,526,528,530,532,535,537,539,541,544,546,548,550,553,555,558,561,564],{"class":35,"line":91},[33,514,515],{"class":101},"  case",[33,517,108],{"class":101},[33,519,520],{"class":111}," PageView",[33,522,116],{"class":115},[33,524,525],{"class":119},"userId",[33,527,123],{"class":115},[33,529,126],{"class":111},[33,531,129],{"class":115},[33,533,534],{"class":119},"timestamp",[33,536,123],{"class":115},[33,538,126],{"class":111},[33,540,129],{"class":115},[33,542,543],{"class":119},"path",[33,545,123],{"class":115},[33,547,137],{"class":111},[33,549,129],{"class":115},[33,551,552],{"class":119},"duration",[33,554,123],{"class":115},[33,556,557],{"class":111},"Int",[33,559,560],{"class":115},") ",[33,562,563],{"class":101},"extends",[33,565,566],{"class":111}," Event\n",[33,568,569,571,573,576,578,580,582,584,586,588,590,592,594,597,599,601,603,606,608,610,612,615,617,619,621,623],{"class":35,"line":98},[33,570,515],{"class":101},[33,572,108],{"class":101},[33,574,575],{"class":111}," Click",[33,577,116],{"class":115},[33,579,525],{"class":119},[33,581,123],{"class":115},[33,583,126],{"class":111},[33,585,129],{"class":115},[33,587,534],{"class":119},[33,589,123],{"class":115},[33,591,126],{"class":111},[33,593,129],{"class":115},[33,595,596],{"class":119},"target",[33,598,123],{"class":115},[33,600,137],{"class":111},[33,602,129],{"class":115},[33,604,605],{"class":119},"x",[33,607,123],{"class":115},[33,609,557],{"class":111},[33,611,129],{"class":115},[33,613,614],{"class":119},"y",[33,616,123],{"class":115},[33,618,557],{"class":111},[33,620,560],{"class":115},[33,622,563],{"class":101},[33,624,566],{"class":111},[33,626,627,629,631,634,636,638,640,642,644,646,648,650,652,655,657,659,661,664,666,669,671,673],{"class":35,"line":170},[33,628,515],{"class":101},[33,630,108],{"class":101},[33,632,633],{"class":111}," Purchase",[33,635,116],{"class":115},[33,637,525],{"class":119},[33,639,123],{"class":115},[33,641,126],{"class":111},[33,643,129],{"class":115},[33,645,534],{"class":119},[33,647,123],{"class":115},[33,649,126],{"class":111},[33,651,129],{"class":115},[33,653,654],{"class":119},"orderId",[33,656,123],{"class":115},[33,658,126],{"class":111},[33,660,129],{"class":115},[33,662,663],{"class":119},"amount",[33,665,123],{"class":115},[33,667,668],{"class":111},"BigDecimal",[33,670,560],{"class":115},[33,672,563],{"class":101},[33,674,566],{"class":111},[33,676,677,679,681,684,686,688,690,692,694,696,698,700,702,705,707,709,711,713],{"class":35,"line":176},[33,678,515],{"class":101},[33,680,108],{"class":101},[33,682,683],{"class":111}," SessionEnd",[33,685,116],{"class":115},[33,687,525],{"class":119},[33,689,123],{"class":115},[33,691,126],{"class":111},[33,693,129],{"class":115},[33,695,534],{"class":119},[33,697,123],{"class":115},[33,699,126],{"class":111},[33,701,129],{"class":115},[33,703,704],{"class":119},"sessionId",[33,706,123],{"class":115},[33,708,137],{"class":111},[33,710,560],{"class":115},[33,712,563],{"class":101},[33,714,566],{"class":111},[33,716,717],{"class":35,"line":204},[33,718,95],{"emptyLinePlaceholder":94},[33,720,721],{"class":35,"line":245},[33,722,723],{"class":39},"\u002F\u002F \"Product type\" — each variant has fields (the \"product\" of their types)\n",[33,725,726],{"class":35,"line":250},[33,727,95],{"emptyLinePlaceholder":94},[33,729,730],{"class":35,"line":256},[33,731,732],{"class":39},"\u002F\u002F Exhaustive handler — compiler verifies all 4 cases are covered\n",[33,734,735,738,741,743,746,748,751,753,755,758,760,763],{"class":35,"line":297},[33,736,737],{"class":101},"def",[33,739,740],{"class":111}," toJson",[33,742,116],{"class":115},[33,744,745],{"class":119},"e",[33,747,123],{"class":115},[33,749,750],{"class":111},"Event",[33,752,221],{"class":115},[33,754,185],{"class":101},[33,756,757],{"class":111}," String",[33,759,191],{"class":101},[33,761,762],{"class":115}," e ",[33,764,765],{"class":101},"match\n",[33,767,768,770,772,775,778,781,784,787,790,793,796,799],{"class":35,"line":326},[33,769,515],{"class":101},[33,771,520],{"class":111},[33,773,774],{"class":115},"(uid, ts, path, dur) ",[33,776,777],{"class":101},"=>",[33,779,780],{"class":101}," s",[33,782,783],{"class":197},"\"\"\"{\"type\":\"pv\",\"uid\":",[33,785,786],{"class":115},"$uid",[33,788,789],{"class":197},",\"path\":\"",[33,791,792],{"class":115},"$path",[33,794,795],{"class":197},"\",\"dur\":",[33,797,798],{"class":115},"$dur",[33,800,801],{"class":197},"}\"\"\"\n",[33,803,804,806,808,811,813,815,818,820,823,826],{"class":35,"line":332},[33,805,515],{"class":101},[33,807,575],{"class":111},[33,809,810],{"class":115},"(uid, ts, target, x, y) ",[33,812,777],{"class":101},[33,814,780],{"class":101},[33,816,817],{"class":197},"\"\"\"{\"type\":\"click\",\"uid\":",[33,819,786],{"class":115},[33,821,822],{"class":197},",\"target\":\"",[33,824,825],{"class":115},"$target",[33,827,828],{"class":197},"\"}\"\"\"\n",[33,830,831,833,835,838,840,842,845,847,850,853],{"class":35,"line":337},[33,832,515],{"class":101},[33,834,633],{"class":111},[33,836,837],{"class":115},"(uid, ts, orderId, amount) ",[33,839,777],{"class":101},[33,841,780],{"class":101},[33,843,844],{"class":197},"\"\"\"{\"type\":\"purchase\",\"uid\":",[33,846,786],{"class":115},[33,848,849],{"class":197},",\"amt\":",[33,851,852],{"class":115},"$amount",[33,854,801],{"class":197},[33,856,857,859,861,864,866,868,871,873,876,879],{"class":35,"line":343},[33,858,515],{"class":101},[33,860,683],{"class":111},[33,862,863],{"class":115},"(uid, ts, sessionId) ",[33,865,777],{"class":101},[33,867,780],{"class":101},[33,869,870],{"class":197},"\"\"\"{\"type\":\"end\",\"uid\":",[33,872,786],{"class":115},[33,874,875],{"class":197},",\"sid\":\"",[33,877,878],{"class":115},"$sessionId",[33,880,828],{"class":197},[33,882,883],{"class":35,"line":373},[33,884,95],{"emptyLinePlaceholder":94},[33,886,887],{"class":35,"line":392},[33,888,889],{"class":39},"\u002F\u002F Adding Event.Signup → ALL match expressions fail to compile → forced to handle\n",[33,891,892],{"class":35,"line":408},[33,893,894],{"class":39},"\u002F\u002F This is the #1 safety mechanism in Scala domain modeling.\n",[15,896,898],{"id":897},"recursive-adts-tree-structures","Recursive ADTs — Tree Structures",[20,900,901],{"language":22},[24,902,904],{"className":26,"code":903,"language":22,"meta":28,"style":28},"\u002F\u002F Recursive sealed ADT — compiler handles recursion in pattern matching\nsealed trait Json\nobject Json:\n  case object Null extends Json\n  case class Bool(value: Boolean) extends Json\n  case class Num(value: BigDecimal) extends Json\n  case class Str(value: String) extends Json\n  case class Arr(items: List[Json]) extends Json\n  case class Obj(fields: List[(String, Json)]) extends Json\n\n\u002F\u002F Recursive traversal with pattern matching — NO @tailrec (not tail-recursive)\ndef stringify(json: Json): String = json match\n  case Null        => \"null\"\n  case Bool(b)     => b.toString\n  case Num(n)      => n.toString\n  case Str(s)      => s\"\"\"\"${s.replace(\"\\\"\", \"\\\\\\\"\")}\"\"\"\"\n  case Arr(items)  => items.map(stringify).mkString(\"[\", \",\", \"]\")     \u002F\u002F recursive calls\n  case Obj(fields) => fields.map { case (k, v) => s\"\"\"\"$k\":${stringify(v)}\"\"\" }.mkString(\"{\", \",\", \"}\")\n\n\u002F\u002F For deep nesting, this WILL stack overflow. Use a trampoline or iterative approach:\n@tailrec\ndef stringifyIter(json: Json, stack: List[Json] = Nil, acc: StringBuilder = StringBuilder()): String =\n  json match\n    case Null => ???  \u002F\u002F complex — use Cats' IO or a proper stack-machine parser for production\n    case _ => ???\n",[30,905,906,911,920,929,944,969,992,1015,1045,1079,1083,1088,1117,1129,1143,1157,1199,1231,1285,1289,1294,1302,1363,1370,1386],{"__ignoreMap":28},[33,907,908],{"class":35,"line":36},[33,909,910],{"class":39},"\u002F\u002F Recursive sealed ADT — compiler handles recursion in pattern matching\n",[33,912,913,915,917],{"class":35,"line":43},[33,914,461],{"class":101},[33,916,464],{"class":101},[33,918,919],{"class":111}," Json\n",[33,921,922,924,927],{"class":35,"line":49},[33,923,501],{"class":101},[33,925,926],{"class":111}," Json",[33,928,167],{"class":101},[33,930,931,933,936,939,942],{"class":35,"line":55},[33,932,515],{"class":101},[33,934,935],{"class":101}," object",[33,937,938],{"class":111}," Null",[33,940,941],{"class":101}," extends",[33,943,919],{"class":111},[33,945,946,948,950,953,955,958,960,963,965,967],{"class":35,"line":61},[33,947,515],{"class":101},[33,949,108],{"class":101},[33,951,952],{"class":111}," Bool",[33,954,116],{"class":115},[33,956,957],{"class":119},"value",[33,959,123],{"class":115},[33,961,962],{"class":111},"Boolean",[33,964,560],{"class":115},[33,966,563],{"class":101},[33,968,919],{"class":111},[33,970,971,973,975,978,980,982,984,986,988,990],{"class":35,"line":67},[33,972,515],{"class":101},[33,974,108],{"class":101},[33,976,977],{"class":111}," Num",[33,979,116],{"class":115},[33,981,957],{"class":119},[33,983,123],{"class":115},[33,985,668],{"class":111},[33,987,560],{"class":115},[33,989,563],{"class":101},[33,991,919],{"class":111},[33,993,994,996,998,1001,1003,1005,1007,1009,1011,1013],{"class":35,"line":73},[33,995,515],{"class":101},[33,997,108],{"class":101},[33,999,1000],{"class":111}," Str",[33,1002,116],{"class":115},[33,1004,957],{"class":119},[33,1006,123],{"class":115},[33,1008,137],{"class":111},[33,1010,560],{"class":115},[33,1012,563],{"class":101},[33,1014,919],{"class":111},[33,1016,1017,1019,1021,1024,1026,1029,1031,1033,1035,1038,1041,1043],{"class":35,"line":79},[33,1018,515],{"class":101},[33,1020,108],{"class":101},[33,1022,1023],{"class":111}," Arr",[33,1025,116],{"class":115},[33,1027,1028],{"class":119},"items",[33,1030,123],{"class":115},[33,1032,156],{"class":111},[33,1034,159],{"class":115},[33,1036,1037],{"class":111},"Json",[33,1039,1040],{"class":115},"]) ",[33,1042,563],{"class":101},[33,1044,919],{"class":111},[33,1046,1047,1049,1051,1054,1056,1059,1061,1063,1066,1068,1070,1072,1075,1077],{"class":35,"line":85},[33,1048,515],{"class":101},[33,1050,108],{"class":101},[33,1052,1053],{"class":111}," Obj",[33,1055,116],{"class":115},[33,1057,1058],{"class":119},"fields",[33,1060,123],{"class":115},[33,1062,156],{"class":111},[33,1064,1065],{"class":115},"[(",[33,1067,137],{"class":111},[33,1069,129],{"class":115},[33,1071,1037],{"class":111},[33,1073,1074],{"class":115},")]) ",[33,1076,563],{"class":101},[33,1078,919],{"class":111},[33,1080,1081],{"class":35,"line":91},[33,1082,95],{"emptyLinePlaceholder":94},[33,1084,1085],{"class":35,"line":98},[33,1086,1087],{"class":39},"\u002F\u002F Recursive traversal with pattern matching — NO @tailrec (not tail-recursive)\n",[33,1089,1090,1092,1095,1097,1100,1102,1104,1106,1108,1110,1112,1115],{"class":35,"line":170},[33,1091,737],{"class":101},[33,1093,1094],{"class":111}," stringify",[33,1096,116],{"class":115},[33,1098,1099],{"class":119},"json",[33,1101,123],{"class":115},[33,1103,1037],{"class":111},[33,1105,221],{"class":115},[33,1107,185],{"class":101},[33,1109,757],{"class":111},[33,1111,191],{"class":101},[33,1113,1114],{"class":115}," json ",[33,1116,765],{"class":101},[33,1118,1119,1121,1123,1126],{"class":35,"line":176},[33,1120,515],{"class":101},[33,1122,938],{"class":111},[33,1124,1125],{"class":101},"        =>",[33,1127,1128],{"class":197}," \"null\"\n",[33,1130,1131,1133,1135,1138,1140],{"class":35,"line":204},[33,1132,515],{"class":101},[33,1134,952],{"class":111},[33,1136,1137],{"class":115},"(b)     ",[33,1139,777],{"class":101},[33,1141,1142],{"class":115}," b.toString\n",[33,1144,1145,1147,1149,1152,1154],{"class":35,"line":245},[33,1146,515],{"class":101},[33,1148,977],{"class":111},[33,1150,1151],{"class":115},"(n)      ",[33,1153,777],{"class":101},[33,1155,1156],{"class":115}," n.toString\n",[33,1158,1159,1161,1163,1166,1168,1170,1173,1176,1179,1182,1184,1186,1188,1191,1193,1196],{"class":35,"line":250},[33,1160,515],{"class":101},[33,1162,1000],{"class":111},[33,1164,1165],{"class":115},"(s)      ",[33,1167,777],{"class":101},[33,1169,780],{"class":101},[33,1171,1172],{"class":197},"\"\"\"\"",[33,1174,1175],{"class":115},"${s.replace(",[33,1177,1178],{"class":197},"\"",[33,1180,1181],{"class":271},"\\\"",[33,1183,1178],{"class":197},[33,1185,129],{"class":115},[33,1187,1178],{"class":197},[33,1189,1190],{"class":271},"\\\\\\\"",[33,1192,1178],{"class":197},[33,1194,1195],{"class":115},")}",[33,1197,1198],{"class":197},"\"\"\"\"\n",[33,1200,1201,1203,1205,1208,1210,1213,1216,1218,1221,1223,1226,1228],{"class":35,"line":256},[33,1202,515],{"class":101},[33,1204,1023],{"class":111},[33,1206,1207],{"class":115},"(items)  ",[33,1209,777],{"class":101},[33,1211,1212],{"class":115}," items.map(stringify).mkString(",[33,1214,1215],{"class":197},"\"[\"",[33,1217,129],{"class":115},[33,1219,1220],{"class":197},"\",\"",[33,1222,129],{"class":115},[33,1224,1225],{"class":197},"\"]\"",[33,1227,367],{"class":115},[33,1229,1230],{"class":39},"\u002F\u002F recursive calls\n",[33,1232,1233,1235,1237,1240,1242,1245,1247,1250,1252,1254,1256,1259,1262,1265,1268,1271,1274,1276,1278,1280,1283],{"class":35,"line":297},[33,1234,515],{"class":101},[33,1236,1053],{"class":111},[33,1238,1239],{"class":115},"(fields) ",[33,1241,777],{"class":101},[33,1243,1244],{"class":115}," fields.map { ",[33,1246,346],{"class":101},[33,1248,1249],{"class":115}," (k, v) ",[33,1251,777],{"class":101},[33,1253,780],{"class":101},[33,1255,1172],{"class":197},[33,1257,1258],{"class":115},"$k",[33,1260,1261],{"class":197},"\":",[33,1263,1264],{"class":115},"${stringify(v)}",[33,1266,1267],{"class":197},"\"\"\"",[33,1269,1270],{"class":115}," }.mkString(",[33,1272,1273],{"class":197},"\"{\"",[33,1275,129],{"class":115},[33,1277,1220],{"class":197},[33,1279,129],{"class":115},[33,1281,1282],{"class":197},"\"}\"",[33,1284,201],{"class":115},[33,1286,1287],{"class":35,"line":326},[33,1288,95],{"emptyLinePlaceholder":94},[33,1290,1291],{"class":35,"line":332},[33,1292,1293],{"class":39},"\u002F\u002F For deep nesting, this WILL stack overflow. Use a trampoline or iterative approach:\n",[33,1295,1296,1299],{"class":35,"line":337},[33,1297,1298],{"class":101},"@",[33,1300,1301],{"class":115},"tailrec\n",[33,1303,1304,1306,1309,1311,1313,1315,1317,1319,1322,1324,1326,1328,1330,1333,1335,1338,1340,1343,1345,1348,1350,1353,1356,1358,1360],{"class":35,"line":343},[33,1305,737],{"class":101},[33,1307,1308],{"class":111}," stringifyIter",[33,1310,116],{"class":115},[33,1312,1099],{"class":119},[33,1314,123],{"class":115},[33,1316,1037],{"class":111},[33,1318,129],{"class":115},[33,1320,1321],{"class":119},"stack",[33,1323,123],{"class":115},[33,1325,156],{"class":111},[33,1327,159],{"class":115},[33,1329,1037],{"class":111},[33,1331,1332],{"class":115},"] ",[33,1334,233],{"class":101},[33,1336,1337],{"class":111}," Nil",[33,1339,129],{"class":115},[33,1341,1342],{"class":119},"acc",[33,1344,123],{"class":115},[33,1346,1347],{"class":111},"StringBuilder",[33,1349,191],{"class":101},[33,1351,1352],{"class":111}," StringBuilder",[33,1354,1355],{"class":115},"())",[33,1357,185],{"class":101},[33,1359,757],{"class":111},[33,1361,1362],{"class":101}," =\n",[33,1364,1365,1368],{"class":35,"line":373},[33,1366,1367],{"class":115},"  json ",[33,1369,765],{"class":101},[33,1371,1372,1375,1377,1380,1383],{"class":35,"line":392},[33,1373,1374],{"class":101},"    case",[33,1376,938],{"class":111},[33,1378,1379],{"class":101}," =>",[33,1381,1382],{"class":101}," ???",[33,1384,1385],{"class":39},"  \u002F\u002F complex — use Cats' IO or a proper stack-machine parser for production\n",[33,1387,1388,1390,1393,1395],{"class":35,"line":408},[33,1389,1374],{"class":101},[33,1391,1392],{"class":115}," _ ",[33,1394,777],{"class":101},[33,1396,1397],{"class":101}," ???\n",[15,1399,1401,1402,1404],{"id":1400},"pattern-matching-guards-alternatives-and-binding","Pattern Matching — Guards, Alternatives, and ",[30,1403,1298],{}," Binding",[20,1406,1407],{"language":22},[24,1408,1410],{"className":26,"code":1409,"language":22,"meta":28,"style":28},"sealed trait Shape\ncase class Circle(radius: Double) extends Shape\ncase class Rectangle(width: Double, height: Double) extends Shape\ncase class Triangle(a: Double, b: Double, c: Double) extends Shape\n\ndef classify(s: Shape): String = s match\n  \u002F\u002F @ binding — capture the whole value AND destructure fields\n  case c @ Circle(r) if r > 100 => s\"huge circle: $c\"     \u002F\u002F c is the full Circle object\n\n  \u002F\u002F Alternative patterns — match multiple shapes in one case\n  case Rectangle(w, h) | Triangle(a, b, c) if area(s) > 1000 => \"large non-circle\"\n\n  \u002F\u002F Guard with field computation\n  case Rectangle(w, h) if math.abs(w - h) \u003C 0.001 => \"square\"  \u002F\u002F near-square rectangle\n\n  \u002F\u002F Exhaustive fallback (sealed → no catch-all needed, but can add for safety)\n  case other => s\"shape: $other\"\n\ndef area(s: Shape): Double = s match\n  case Circle(r) => math.Pi * r * r\n  case Rectangle(w, h) => w * h\n  case Triangle(a, b, c) =>\n    val s = (a + b + c) \u002F 2\n    math.sqrt(s * (s - a) * (s - b) * (s - c))  \u002F\u002F Heron's formula\n",[30,1411,1412,1421,1446,1479,1521,1525,1555,1560,1601,1605,1610,1642,1646,1651,1684,1688,1693,1713,1717,1745,1772,1790,1801,1830],{"__ignoreMap":28},[33,1413,1414,1416,1418],{"class":35,"line":36},[33,1415,461],{"class":101},[33,1417,464],{"class":101},[33,1419,1420],{"class":111}," Shape\n",[33,1422,1423,1425,1427,1430,1432,1435,1437,1440,1442,1444],{"class":35,"line":43},[33,1424,346],{"class":101},[33,1426,108],{"class":101},[33,1428,1429],{"class":111}," Circle",[33,1431,116],{"class":115},[33,1433,1434],{"class":119},"radius",[33,1436,123],{"class":115},[33,1438,1439],{"class":111},"Double",[33,1441,560],{"class":115},[33,1443,563],{"class":101},[33,1445,1420],{"class":111},[33,1447,1448,1450,1452,1455,1457,1460,1462,1464,1466,1469,1471,1473,1475,1477],{"class":35,"line":49},[33,1449,346],{"class":101},[33,1451,108],{"class":101},[33,1453,1454],{"class":111}," Rectangle",[33,1456,116],{"class":115},[33,1458,1459],{"class":119},"width",[33,1461,123],{"class":115},[33,1463,1439],{"class":111},[33,1465,129],{"class":115},[33,1467,1468],{"class":119},"height",[33,1470,123],{"class":115},[33,1472,1439],{"class":111},[33,1474,560],{"class":115},[33,1476,563],{"class":101},[33,1478,1420],{"class":111},[33,1480,1481,1483,1485,1488,1490,1493,1495,1497,1499,1502,1504,1506,1508,1511,1513,1515,1517,1519],{"class":35,"line":55},[33,1482,346],{"class":101},[33,1484,108],{"class":101},[33,1486,1487],{"class":111}," Triangle",[33,1489,116],{"class":115},[33,1491,1492],{"class":119},"a",[33,1494,123],{"class":115},[33,1496,1439],{"class":111},[33,1498,129],{"class":115},[33,1500,1501],{"class":119},"b",[33,1503,123],{"class":115},[33,1505,1439],{"class":111},[33,1507,129],{"class":115},[33,1509,1510],{"class":119},"c",[33,1512,123],{"class":115},[33,1514,1439],{"class":111},[33,1516,560],{"class":115},[33,1518,563],{"class":101},[33,1520,1420],{"class":111},[33,1522,1523],{"class":35,"line":61},[33,1524,95],{"emptyLinePlaceholder":94},[33,1526,1527,1529,1532,1534,1537,1539,1542,1544,1546,1548,1550,1553],{"class":35,"line":67},[33,1528,737],{"class":101},[33,1530,1531],{"class":111}," classify",[33,1533,116],{"class":115},[33,1535,1536],{"class":119},"s",[33,1538,123],{"class":115},[33,1540,1541],{"class":111},"Shape",[33,1543,221],{"class":115},[33,1545,185],{"class":101},[33,1547,757],{"class":111},[33,1549,191],{"class":101},[33,1551,1552],{"class":115}," s ",[33,1554,765],{"class":101},[33,1556,1557],{"class":35,"line":73},[33,1558,1559],{"class":39},"  \u002F\u002F @ binding — capture the whole value AND destructure fields\n",[33,1561,1562,1564,1567,1569,1571,1574,1577,1580,1583,1586,1588,1590,1593,1596,1598],{"class":35,"line":79},[33,1563,515],{"class":101},[33,1565,1566],{"class":115}," c ",[33,1568,1298],{"class":101},[33,1570,1429],{"class":111},[33,1572,1573],{"class":115},"(r) ",[33,1575,1576],{"class":101},"if",[33,1578,1579],{"class":115}," r ",[33,1581,1582],{"class":101},">",[33,1584,1585],{"class":271}," 100",[33,1587,1379],{"class":101},[33,1589,780],{"class":101},[33,1591,1592],{"class":197},"\"huge circle: ",[33,1594,1595],{"class":115},"$c",[33,1597,1178],{"class":197},[33,1599,1600],{"class":39},"     \u002F\u002F c is the full Circle object\n",[33,1602,1603],{"class":35,"line":85},[33,1604,95],{"emptyLinePlaceholder":94},[33,1606,1607],{"class":35,"line":91},[33,1608,1609],{"class":39},"  \u002F\u002F Alternative patterns — match multiple shapes in one case\n",[33,1611,1612,1614,1616,1619,1622,1624,1627,1629,1632,1634,1637,1639],{"class":35,"line":98},[33,1613,515],{"class":101},[33,1615,1454],{"class":111},[33,1617,1618],{"class":115},"(w, h) ",[33,1620,1621],{"class":101},"|",[33,1623,1487],{"class":111},[33,1625,1626],{"class":115},"(a, b, c) ",[33,1628,1576],{"class":101},[33,1630,1631],{"class":115}," area(s) ",[33,1633,1582],{"class":101},[33,1635,1636],{"class":271}," 1000",[33,1638,1379],{"class":101},[33,1640,1641],{"class":197}," \"large non-circle\"\n",[33,1643,1644],{"class":35,"line":170},[33,1645,95],{"emptyLinePlaceholder":94},[33,1647,1648],{"class":35,"line":176},[33,1649,1650],{"class":39},"  \u002F\u002F Guard with field computation\n",[33,1652,1653,1655,1657,1659,1661,1664,1667,1670,1673,1676,1678,1681],{"class":35,"line":204},[33,1654,515],{"class":101},[33,1656,1454],{"class":111},[33,1658,1618],{"class":115},[33,1660,1576],{"class":101},[33,1662,1663],{"class":115}," math.abs(w ",[33,1665,1666],{"class":101},"-",[33,1668,1669],{"class":115}," h) ",[33,1671,1672],{"class":101},"\u003C",[33,1674,1675],{"class":271}," 0.001",[33,1677,1379],{"class":101},[33,1679,1680],{"class":197}," \"square\"",[33,1682,1683],{"class":39},"  \u002F\u002F near-square rectangle\n",[33,1685,1686],{"class":35,"line":245},[33,1687,95],{"emptyLinePlaceholder":94},[33,1689,1690],{"class":35,"line":250},[33,1691,1692],{"class":39},"  \u002F\u002F Exhaustive fallback (sealed → no catch-all needed, but can add for safety)\n",[33,1694,1695,1697,1700,1702,1704,1707,1710],{"class":35,"line":256},[33,1696,515],{"class":101},[33,1698,1699],{"class":115}," other ",[33,1701,777],{"class":101},[33,1703,780],{"class":101},[33,1705,1706],{"class":197},"\"shape: ",[33,1708,1709],{"class":115},"$other",[33,1711,1712],{"class":197},"\"\n",[33,1714,1715],{"class":35,"line":297},[33,1716,95],{"emptyLinePlaceholder":94},[33,1718,1719,1721,1724,1726,1728,1730,1732,1734,1736,1739,1741,1743],{"class":35,"line":326},[33,1720,737],{"class":101},[33,1722,1723],{"class":111}," area",[33,1725,116],{"class":115},[33,1727,1536],{"class":119},[33,1729,123],{"class":115},[33,1731,1541],{"class":111},[33,1733,221],{"class":115},[33,1735,185],{"class":101},[33,1737,1738],{"class":111}," Double",[33,1740,191],{"class":101},[33,1742,1552],{"class":115},[33,1744,765],{"class":101},[33,1746,1747,1749,1751,1753,1755,1758,1761,1764,1766,1769],{"class":35,"line":332},[33,1748,515],{"class":101},[33,1750,1429],{"class":111},[33,1752,1573],{"class":115},[33,1754,777],{"class":101},[33,1756,1757],{"class":115}," math.",[33,1759,1760],{"class":111},"Pi",[33,1762,1763],{"class":101}," *",[33,1765,1579],{"class":115},[33,1767,1768],{"class":101},"*",[33,1770,1771],{"class":115}," r\n",[33,1773,1774,1776,1778,1780,1782,1785,1787],{"class":35,"line":337},[33,1775,515],{"class":101},[33,1777,1454],{"class":111},[33,1779,1618],{"class":115},[33,1781,777],{"class":101},[33,1783,1784],{"class":115}," w ",[33,1786,1768],{"class":101},[33,1788,1789],{"class":115}," h\n",[33,1791,1792,1794,1796,1798],{"class":35,"line":343},[33,1793,515],{"class":101},[33,1795,1487],{"class":111},[33,1797,1626],{"class":115},[33,1799,1800],{"class":101},"=>\n",[33,1802,1803,1806,1808,1810,1813,1816,1819,1821,1824,1827],{"class":35,"line":373},[33,1804,1805],{"class":101},"    val",[33,1807,780],{"class":119},[33,1809,191],{"class":101},[33,1811,1812],{"class":115}," (a ",[33,1814,1815],{"class":101},"+",[33,1817,1818],{"class":115}," b ",[33,1820,1815],{"class":101},[33,1822,1823],{"class":115}," c) ",[33,1825,1826],{"class":101},"\u002F",[33,1828,1829],{"class":271}," 2\n",[33,1831,1832,1835,1837,1840,1842,1845,1847,1849,1851,1854,1856,1858,1860,1863],{"class":35,"line":392},[33,1833,1834],{"class":115},"    math.sqrt(s ",[33,1836,1768],{"class":101},[33,1838,1839],{"class":115}," (s ",[33,1841,1666],{"class":101},[33,1843,1844],{"class":115}," a) ",[33,1846,1768],{"class":101},[33,1848,1839],{"class":115},[33,1850,1666],{"class":101},[33,1852,1853],{"class":115}," b) ",[33,1855,1768],{"class":101},[33,1857,1839],{"class":115},[33,1859,1666],{"class":101},[33,1861,1862],{"class":115}," c))  ",[33,1864,1865],{"class":39},"\u002F\u002F Heron's formula\n",[15,1867,1869,1870,129,1873,129,1876,129,1879],{"id":1868},"collection-patterns-nil-_-unapplyseq","Collection Patterns — ",[30,1871,1872],{},"::",[30,1874,1875],{},"Nil",[30,1877,1878],{},"_*",[30,1880,1881],{},"unapplySeq",[20,1883,1884],{"language":22},[24,1885,1887],{"className":26,"code":1886,"language":22,"meta":28,"style":28},"val list = List(1, 2, 3, 4, 5)\n\nlist match\n  case Nil           => \"empty\"\n  case head :: Nil   => s\"single: $head\"          \u002F\u002F List(x) also works\n  case a :: b :: Nil => s\"pair: $a, $b\"           \u002F\u002F List(a, b)\n  case head :: tail  => s\"head=$head, tail=$tail\" \u002F\u002F non-empty with rest\n  case _             => \"shouldn't reach (sealed List)\"\n\n\u002F\u002F _* — match variable number of remaining elements (via unapplySeq)\nlist match\n  case List(first, second, rest @ _*) => s\"first=$first, second=$second, rest=${rest.toList}\"\n  \u002F\u002F rest is Seq[Int] of remaining elements → List(3, 4, 5)\n\n\u002F\u002F Fixed-size pattern + rest\nList(1, 2, 3, 4) match\n  case List(a, b, _*) => s\"first two: $a, $b\"     \u002F\u002F matches, ignores rest\n\n\u002F\u002F ❌ PITFALL: List(1, 2, 3) match { case List(a, b) => ... } — DOESN'T match!\n\u002F\u002F List(a, b) requires EXACTLY 2 elements. Use a :: b :: _ for \"at least 2\".\n",[30,1888,1889,1927,1931,1938,1950,1977,2012,2043,2055,2059,2064,2070,2110,2115,2119,2124,2148,2179,2183,2188],{"__ignoreMap":28},[33,1890,1891,1893,1896,1898,1901,1903,1905,1907,1910,1912,1915,1917,1920,1922,1925],{"class":35,"line":36},[33,1892,259],{"class":101},[33,1894,1895],{"class":119}," list",[33,1897,191],{"class":101},[33,1899,1900],{"class":111}," List",[33,1902,116],{"class":115},[33,1904,272],{"class":271},[33,1906,129],{"class":115},[33,1908,1909],{"class":271},"2",[33,1911,129],{"class":115},[33,1913,1914],{"class":271},"3",[33,1916,129],{"class":115},[33,1918,1919],{"class":271},"4",[33,1921,129],{"class":115},[33,1923,1924],{"class":271},"5",[33,1926,201],{"class":115},[33,1928,1929],{"class":35,"line":43},[33,1930,95],{"emptyLinePlaceholder":94},[33,1932,1933,1936],{"class":35,"line":49},[33,1934,1935],{"class":115},"list ",[33,1937,765],{"class":101},[33,1939,1940,1942,1944,1947],{"class":35,"line":55},[33,1941,515],{"class":101},[33,1943,1337],{"class":111},[33,1945,1946],{"class":101},"           =>",[33,1948,1949],{"class":197}," \"empty\"\n",[33,1951,1952,1954,1957,1959,1961,1964,1966,1969,1972,1974],{"class":35,"line":61},[33,1953,515],{"class":101},[33,1955,1956],{"class":115}," head ",[33,1958,1872],{"class":101},[33,1960,1337],{"class":111},[33,1962,1963],{"class":101},"   =>",[33,1965,780],{"class":101},[33,1967,1968],{"class":197},"\"single: ",[33,1970,1971],{"class":115},"$head",[33,1973,1178],{"class":197},[33,1975,1976],{"class":39},"          \u002F\u002F List(x) also works\n",[33,1978,1979,1981,1984,1986,1988,1990,1992,1994,1996,1999,2002,2004,2007,2009],{"class":35,"line":67},[33,1980,515],{"class":101},[33,1982,1983],{"class":115}," a ",[33,1985,1872],{"class":101},[33,1987,1818],{"class":115},[33,1989,1872],{"class":101},[33,1991,1337],{"class":111},[33,1993,1379],{"class":101},[33,1995,780],{"class":101},[33,1997,1998],{"class":197},"\"pair: ",[33,2000,2001],{"class":115},"$a",[33,2003,129],{"class":197},[33,2005,2006],{"class":115},"$b",[33,2008,1178],{"class":197},[33,2010,2011],{"class":39},"           \u002F\u002F List(a, b)\n",[33,2013,2014,2016,2018,2020,2023,2025,2027,2030,2032,2035,2038,2040],{"class":35,"line":73},[33,2015,515],{"class":101},[33,2017,1956],{"class":115},[33,2019,1872],{"class":101},[33,2021,2022],{"class":115}," tail  ",[33,2024,777],{"class":101},[33,2026,780],{"class":101},[33,2028,2029],{"class":197},"\"head=",[33,2031,1971],{"class":115},[33,2033,2034],{"class":197},", tail=",[33,2036,2037],{"class":115},"$tail",[33,2039,1178],{"class":197},[33,2041,2042],{"class":39}," \u002F\u002F non-empty with rest\n",[33,2044,2045,2047,2050,2052],{"class":35,"line":79},[33,2046,515],{"class":101},[33,2048,2049],{"class":115}," _             ",[33,2051,777],{"class":101},[33,2053,2054],{"class":197}," \"shouldn't reach (sealed List)\"\n",[33,2056,2057],{"class":35,"line":85},[33,2058,95],{"emptyLinePlaceholder":94},[33,2060,2061],{"class":35,"line":91},[33,2062,2063],{"class":39},"\u002F\u002F _* — match variable number of remaining elements (via unapplySeq)\n",[33,2065,2066,2068],{"class":35,"line":98},[33,2067,1935],{"class":115},[33,2069,765],{"class":101},[33,2071,2072,2074,2076,2079,2081,2084,2086,2088,2090,2093,2096,2099,2102,2105,2108],{"class":35,"line":170},[33,2073,515],{"class":101},[33,2075,1900],{"class":111},[33,2077,2078],{"class":115},"(first, second, rest ",[33,2080,1298],{"class":101},[33,2082,2083],{"class":101}," _*",[33,2085,560],{"class":115},[33,2087,777],{"class":101},[33,2089,780],{"class":101},[33,2091,2092],{"class":197},"\"first=",[33,2094,2095],{"class":115},"$first",[33,2097,2098],{"class":197},", second=",[33,2100,2101],{"class":115},"$second",[33,2103,2104],{"class":197},", rest=",[33,2106,2107],{"class":115},"${rest.toList}",[33,2109,1712],{"class":197},[33,2111,2112],{"class":35,"line":176},[33,2113,2114],{"class":39},"  \u002F\u002F rest is Seq[Int] of remaining elements → List(3, 4, 5)\n",[33,2116,2117],{"class":35,"line":204},[33,2118,95],{"emptyLinePlaceholder":94},[33,2120,2121],{"class":35,"line":245},[33,2122,2123],{"class":39},"\u002F\u002F Fixed-size pattern + rest\n",[33,2125,2126,2128,2130,2132,2134,2136,2138,2140,2142,2144,2146],{"class":35,"line":250},[33,2127,156],{"class":111},[33,2129,116],{"class":115},[33,2131,272],{"class":271},[33,2133,129],{"class":115},[33,2135,1909],{"class":271},[33,2137,129],{"class":115},[33,2139,1914],{"class":271},[33,2141,129],{"class":115},[33,2143,1919],{"class":271},[33,2145,560],{"class":115},[33,2147,765],{"class":101},[33,2149,2150,2152,2154,2157,2159,2161,2163,2165,2168,2170,2172,2174,2176],{"class":35,"line":256},[33,2151,515],{"class":101},[33,2153,1900],{"class":111},[33,2155,2156],{"class":115},"(a, b, ",[33,2158,1878],{"class":101},[33,2160,560],{"class":115},[33,2162,777],{"class":101},[33,2164,780],{"class":101},[33,2166,2167],{"class":197},"\"first two: ",[33,2169,2001],{"class":115},[33,2171,129],{"class":197},[33,2173,2006],{"class":115},[33,2175,1178],{"class":197},[33,2177,2178],{"class":39},"     \u002F\u002F matches, ignores rest\n",[33,2180,2181],{"class":35,"line":297},[33,2182,95],{"emptyLinePlaceholder":94},[33,2184,2185],{"class":35,"line":326},[33,2186,2187],{"class":39},"\u002F\u002F ❌ PITFALL: List(1, 2, 3) match { case List(a, b) => ... } — DOESN'T match!\n",[33,2189,2190],{"class":35,"line":332},[33,2191,2192],{"class":39},"\u002F\u002F List(a, b) requires EXACTLY 2 elements. Use a :: b :: _ for \"at least 2\".\n",[15,2194,2196],{"id":2195},"regex-patterns-in-match","Regex Patterns in Match",[20,2198,2199],{"language":22},[24,2200,2202],{"className":26,"code":2201,"language":22,"meta":28,"style":28},"import scala.util.matching.Regex\n\n\u002F\u002F Regex extractor — unapplySeq returns matched groups as a List\nval logPattern: Regex = \"\"\"(\\d{4}-\\d{2}-\\d{2}) (\\w+) (.+)\"\"\".r\n\ndef parseLog(line: String): Option[(String, String, String)] = line match\n  case logPattern(date, level, msg) => Some((date, level, msg))  \u002F\u002F groups bound to names\n  case _                            => None\n\nparseLog(\"2024-01-15 ERROR Something broke\")  \u002F\u002F → Some((\"2024-01-15\", \"ERROR\", \"Something broke\"))\n\n\u002F\u002F Regex with variable groups — use unapplySeq with _*\nval kvPattern: Regex = \"\"\"(\\w+)=(\\w+)\"\"\".r\nval line = \"name=Alice age=30 role=admin\"\nval pairs = kvPattern.findAllMatchIn(line).map(m => (m.group(1), m.group(2))).toMap\n\u002F\u002F → Map(\"name\" -> \"Alice\", \"age\" -> \"30\", \"role\" -> \"admin\")\n",[30,2203,2204,2228,2232,2237,2257,2261,2305,2323,2335,2339,2352,2356,2361,2379,2391,2418],{"__ignoreMap":28},[33,2205,2206,2209,2212,2215,2218,2220,2223,2225],{"class":35,"line":36},[33,2207,2208],{"class":101},"import",[33,2210,2211],{"class":111}," scala",[33,2213,2214],{"class":115},".",[33,2216,2217],{"class":111},"util",[33,2219,2214],{"class":115},[33,2221,2222],{"class":111},"matching",[33,2224,2214],{"class":115},[33,2226,2227],{"class":111},"Regex\n",[33,2229,2230],{"class":35,"line":43},[33,2231,95],{"emptyLinePlaceholder":94},[33,2233,2234],{"class":35,"line":49},[33,2235,2236],{"class":39},"\u002F\u002F Regex extractor — unapplySeq returns matched groups as a List\n",[33,2238,2239,2241,2244,2246,2249,2251,2254],{"class":35,"line":55},[33,2240,259],{"class":101},[33,2242,2243],{"class":119}," logPattern",[33,2245,185],{"class":101},[33,2247,2248],{"class":111}," Regex",[33,2250,191],{"class":101},[33,2252,2253],{"class":197}," \"\"\"(\\d{4}-\\d{2}-\\d{2}) (\\w+) (.+)\"\"\"",[33,2255,2256],{"class":115},".r\n",[33,2258,2259],{"class":35,"line":61},[33,2260,95],{"emptyLinePlaceholder":94},[33,2262,2263,2265,2268,2270,2272,2274,2276,2278,2280,2283,2285,2287,2289,2291,2293,2295,2298,2300,2303],{"class":35,"line":67},[33,2264,737],{"class":101},[33,2266,2267],{"class":111}," parseLog",[33,2269,116],{"class":115},[33,2271,35],{"class":119},[33,2273,123],{"class":115},[33,2275,137],{"class":111},[33,2277,221],{"class":115},[33,2279,185],{"class":101},[33,2281,2282],{"class":111}," Option",[33,2284,1065],{"class":115},[33,2286,137],{"class":111},[33,2288,129],{"class":115},[33,2290,137],{"class":111},[33,2292,129],{"class":115},[33,2294,137],{"class":111},[33,2296,2297],{"class":115},")] ",[33,2299,233],{"class":101},[33,2301,2302],{"class":115}," line ",[33,2304,765],{"class":101},[33,2306,2307,2309,2312,2314,2317,2320],{"class":35,"line":73},[33,2308,515],{"class":101},[33,2310,2311],{"class":115}," logPattern(date, level, msg) ",[33,2313,777],{"class":101},[33,2315,2316],{"class":111}," Some",[33,2318,2319],{"class":115},"((date, level, msg))  ",[33,2321,2322],{"class":39},"\u002F\u002F groups bound to names\n",[33,2324,2325,2327,2330,2332],{"class":35,"line":79},[33,2326,515],{"class":101},[33,2328,2329],{"class":115}," _                            ",[33,2331,777],{"class":101},[33,2333,2334],{"class":111}," None\n",[33,2336,2337],{"class":35,"line":85},[33,2338,95],{"emptyLinePlaceholder":94},[33,2340,2341,2344,2347,2349],{"class":35,"line":91},[33,2342,2343],{"class":115},"parseLog(",[33,2345,2346],{"class":197},"\"2024-01-15 ERROR Something broke\"",[33,2348,320],{"class":115},[33,2350,2351],{"class":39},"\u002F\u002F → Some((\"2024-01-15\", \"ERROR\", \"Something broke\"))\n",[33,2353,2354],{"class":35,"line":98},[33,2355,95],{"emptyLinePlaceholder":94},[33,2357,2358],{"class":35,"line":170},[33,2359,2360],{"class":39},"\u002F\u002F Regex with variable groups — use unapplySeq with _*\n",[33,2362,2363,2365,2368,2370,2372,2374,2377],{"class":35,"line":176},[33,2364,259],{"class":101},[33,2366,2367],{"class":119}," kvPattern",[33,2369,185],{"class":101},[33,2371,2248],{"class":111},[33,2373,191],{"class":101},[33,2375,2376],{"class":197}," \"\"\"(\\w+)=(\\w+)\"\"\"",[33,2378,2256],{"class":115},[33,2380,2381,2383,2386,2388],{"class":35,"line":204},[33,2382,259],{"class":101},[33,2384,2385],{"class":119}," line",[33,2387,191],{"class":101},[33,2389,2390],{"class":197}," \"name=Alice age=30 role=admin\"\n",[33,2392,2393,2395,2398,2400,2403,2405,2408,2410,2413,2415],{"class":35,"line":245},[33,2394,259],{"class":101},[33,2396,2397],{"class":119}," pairs",[33,2399,191],{"class":101},[33,2401,2402],{"class":115}," kvPattern.findAllMatchIn(line).map(m ",[33,2404,777],{"class":101},[33,2406,2407],{"class":115}," (m.group(",[33,2409,272],{"class":271},[33,2411,2412],{"class":115},"), m.group(",[33,2414,1909],{"class":271},[33,2416,2417],{"class":115},"))).toMap\n",[33,2419,2420],{"class":35,"line":250},[33,2421,2422],{"class":39},"\u002F\u002F → Map(\"name\" -> \"Alice\", \"age\" -> \"30\", \"role\" -> \"admin\")\n",[15,2424,2426,2427,2430],{"id":2425},"custom-extractors-unapply-with-state","Custom Extractors — ",[30,2428,2429],{},"unapply"," with State",[20,2432,2433],{"language":22},[24,2434,2436],{"className":26,"code":2435,"language":22,"meta":28,"style":28},"\u002F\u002F Extractor that validates and transforms — not just destructuring\nobject Email:\n  def unapply(s: String): Option[(String, String)] =\n    val at = s.indexOf('@')\n    if at > 0 && s.indexOf('.', at) > at then\n      Some((s.take(at), s.drop(at + 1)))   \u002F\u002F (local-part, domain)\n    else\n      None\n\ndef classify(s: String): String = s match\n  case Email(local, domain) if domain.endsWith(\".com\") => s\"commercial: $local@$domain\"\n  case Email(local, domain) => s\"other: $local@$domain\"\n  case _ => \"not an email\"\n\nclassify(\"alice@example.com\")   \u002F\u002F → \"commercial: alice@example.com\"\nclassify(\"bob@not-email\")       \u002F\u002F → \"not an email\"\n\n\u002F\u002F Extractor from a type — for pattern matching on opaque types\nobject PositiveInt:\n  def unapply(n: Int): Option[Int] = if n > 0 then Some(n) else None\n\ndef process(n: Int): String = n match\n  case PositiveInt(x) => s\"positive: $x\"\n  case 0              => \"zero\"\n  case _              => \"negative\"\n",[30,2437,2438,2443,2452,2486,2503,2534,2553,2558,2563,2567,2593,2629,2652,2663,2667,2681,2694,2698,2703,2712,2764,2768,2795,2816,2828],{"__ignoreMap":28},[33,2439,2440],{"class":35,"line":36},[33,2441,2442],{"class":39},"\u002F\u002F Extractor that validates and transforms — not just destructuring\n",[33,2444,2445,2447,2450],{"class":35,"line":43},[33,2446,501],{"class":101},[33,2448,2449],{"class":111}," Email",[33,2451,167],{"class":101},[33,2453,2454,2456,2459,2461,2463,2465,2467,2469,2471,2473,2475,2477,2479,2481,2483],{"class":35,"line":49},[33,2455,179],{"class":101},[33,2457,2458],{"class":111}," unapply",[33,2460,116],{"class":115},[33,2462,1536],{"class":119},[33,2464,123],{"class":115},[33,2466,137],{"class":111},[33,2468,221],{"class":115},[33,2470,185],{"class":101},[33,2472,2282],{"class":111},[33,2474,1065],{"class":115},[33,2476,137],{"class":111},[33,2478,129],{"class":115},[33,2480,137],{"class":111},[33,2482,2297],{"class":115},[33,2484,2485],{"class":101},"=\n",[33,2487,2488,2490,2493,2495,2498,2501],{"class":35,"line":55},[33,2489,1805],{"class":101},[33,2491,2492],{"class":119}," at",[33,2494,191],{"class":101},[33,2496,2497],{"class":115}," s.indexOf(",[33,2499,2500],{"class":271},"'@'",[33,2502,201],{"class":115},[33,2504,2505,2508,2511,2513,2516,2519,2521,2524,2527,2529,2531],{"class":35,"line":61},[33,2506,2507],{"class":101},"    if",[33,2509,2510],{"class":115}," at ",[33,2512,1582],{"class":101},[33,2514,2515],{"class":271}," 0",[33,2517,2518],{"class":101}," &&",[33,2520,2497],{"class":115},[33,2522,2523],{"class":271},"'.'",[33,2525,2526],{"class":115},", at) ",[33,2528,1582],{"class":101},[33,2530,2510],{"class":115},[33,2532,2533],{"class":101},"then\n",[33,2535,2536,2539,2542,2544,2547,2550],{"class":35,"line":67},[33,2537,2538],{"class":111},"      Some",[33,2540,2541],{"class":115},"((s.take(at), s.drop(at ",[33,2543,1815],{"class":101},[33,2545,2546],{"class":271}," 1",[33,2548,2549],{"class":115},")))   ",[33,2551,2552],{"class":39},"\u002F\u002F (local-part, domain)\n",[33,2554,2555],{"class":35,"line":73},[33,2556,2557],{"class":101},"    else\n",[33,2559,2560],{"class":35,"line":79},[33,2561,2562],{"class":111},"      None\n",[33,2564,2565],{"class":35,"line":85},[33,2566,95],{"emptyLinePlaceholder":94},[33,2568,2569,2571,2573,2575,2577,2579,2581,2583,2585,2587,2589,2591],{"class":35,"line":91},[33,2570,737],{"class":101},[33,2572,1531],{"class":111},[33,2574,116],{"class":115},[33,2576,1536],{"class":119},[33,2578,123],{"class":115},[33,2580,137],{"class":111},[33,2582,221],{"class":115},[33,2584,185],{"class":101},[33,2586,757],{"class":111},[33,2588,191],{"class":101},[33,2590,1552],{"class":115},[33,2592,765],{"class":101},[33,2594,2595,2597,2599,2602,2604,2607,2610,2612,2614,2616,2619,2622,2624,2627],{"class":35,"line":98},[33,2596,515],{"class":101},[33,2598,2449],{"class":111},[33,2600,2601],{"class":115},"(local, domain) ",[33,2603,1576],{"class":101},[33,2605,2606],{"class":115}," domain.endsWith(",[33,2608,2609],{"class":197},"\".com\"",[33,2611,560],{"class":115},[33,2613,777],{"class":101},[33,2615,780],{"class":101},[33,2617,2618],{"class":197},"\"commercial: ",[33,2620,2621],{"class":115},"$local",[33,2623,1298],{"class":197},[33,2625,2626],{"class":115},"$domain",[33,2628,1712],{"class":197},[33,2630,2631,2633,2635,2637,2639,2641,2644,2646,2648,2650],{"class":35,"line":170},[33,2632,515],{"class":101},[33,2634,2449],{"class":111},[33,2636,2601],{"class":115},[33,2638,777],{"class":101},[33,2640,780],{"class":101},[33,2642,2643],{"class":197},"\"other: ",[33,2645,2621],{"class":115},[33,2647,1298],{"class":197},[33,2649,2626],{"class":115},[33,2651,1712],{"class":197},[33,2653,2654,2656,2658,2660],{"class":35,"line":176},[33,2655,515],{"class":101},[33,2657,1392],{"class":115},[33,2659,777],{"class":101},[33,2661,2662],{"class":197}," \"not an email\"\n",[33,2664,2665],{"class":35,"line":204},[33,2666,95],{"emptyLinePlaceholder":94},[33,2668,2669,2672,2675,2678],{"class":35,"line":245},[33,2670,2671],{"class":115},"classify(",[33,2673,2674],{"class":197},"\"alice@example.com\"",[33,2676,2677],{"class":115},")   ",[33,2679,2680],{"class":39},"\u002F\u002F → \"commercial: alice@example.com\"\n",[33,2682,2683,2685,2688,2691],{"class":35,"line":250},[33,2684,2671],{"class":115},[33,2686,2687],{"class":197},"\"bob@not-email\"",[33,2689,2690],{"class":115},")       ",[33,2692,2693],{"class":39},"\u002F\u002F → \"not an email\"\n",[33,2695,2696],{"class":35,"line":256},[33,2697,95],{"emptyLinePlaceholder":94},[33,2699,2700],{"class":35,"line":297},[33,2701,2702],{"class":39},"\u002F\u002F Extractor from a type — for pattern matching on opaque types\n",[33,2704,2705,2707,2710],{"class":35,"line":326},[33,2706,501],{"class":101},[33,2708,2709],{"class":111}," PositiveInt",[33,2711,167],{"class":101},[33,2713,2714,2716,2718,2720,2723,2725,2727,2729,2731,2733,2735,2737,2739,2741,2744,2747,2749,2751,2754,2756,2759,2762],{"class":35,"line":332},[33,2715,179],{"class":101},[33,2717,2458],{"class":111},[33,2719,116],{"class":115},[33,2721,2722],{"class":119},"n",[33,2724,123],{"class":115},[33,2726,557],{"class":111},[33,2728,221],{"class":115},[33,2730,185],{"class":101},[33,2732,2282],{"class":111},[33,2734,159],{"class":115},[33,2736,557],{"class":111},[33,2738,1332],{"class":115},[33,2740,233],{"class":101},[33,2742,2743],{"class":101}," if",[33,2745,2746],{"class":115}," n ",[33,2748,1582],{"class":101},[33,2750,2515],{"class":271},[33,2752,2753],{"class":101}," then",[33,2755,2316],{"class":111},[33,2757,2758],{"class":115},"(n) ",[33,2760,2761],{"class":101},"else",[33,2763,2334],{"class":111},[33,2765,2766],{"class":35,"line":337},[33,2767,95],{"emptyLinePlaceholder":94},[33,2769,2770,2772,2775,2777,2779,2781,2783,2785,2787,2789,2791,2793],{"class":35,"line":343},[33,2771,737],{"class":101},[33,2773,2774],{"class":111}," process",[33,2776,116],{"class":115},[33,2778,2722],{"class":119},[33,2780,123],{"class":115},[33,2782,557],{"class":111},[33,2784,221],{"class":115},[33,2786,185],{"class":101},[33,2788,757],{"class":111},[33,2790,191],{"class":101},[33,2792,2746],{"class":115},[33,2794,765],{"class":101},[33,2796,2797,2799,2801,2804,2806,2808,2811,2814],{"class":35,"line":373},[33,2798,515],{"class":101},[33,2800,2709],{"class":111},[33,2802,2803],{"class":115},"(x) ",[33,2805,777],{"class":101},[33,2807,780],{"class":101},[33,2809,2810],{"class":197},"\"positive: ",[33,2812,2813],{"class":115},"$x",[33,2815,1712],{"class":197},[33,2817,2818,2820,2822,2825],{"class":35,"line":392},[33,2819,515],{"class":101},[33,2821,2515],{"class":271},[33,2823,2824],{"class":101},"              =>",[33,2826,2827],{"class":197}," \"zero\"\n",[33,2829,2830,2832,2835,2837],{"class":35,"line":408},[33,2831,515],{"class":101},[33,2833,2834],{"class":115}," _              ",[33,2836,777],{"class":101},[33,2838,2839],{"class":197}," \"negative\"\n",[15,2841,2843,2844,2847,2848,2851],{"id":2842},"quasi-pattern-matching-with-as-and-scala-3","Quasi-Pattern Matching with ",[30,2845,2846],{},"as"," and ",[30,2849,2850],{},":?"," (Scala 3)",[20,2853,2854],{"language":22},[24,2855,2857],{"className":26,"code":2856,"language":22,"meta":28,"style":28},"\u002F\u002F Scala 3: type test in pattern without binding\ndef handle(x: Any): String = x match\n  case s: String => s\"string of length ${s.length}\"\n  case i: Int if i > 0 => s\"positive int: $i\"\n  case arr: Array[?] => s\"array of size ${arr.length}\"  \u002F\u002F [?] = wildcard, avoids unchecked warning\n  case _ => \"unknown\"\n\n\u002F\u002F Scala 3: inline match — match on an expression inline (no match block)\nval result = x match\n  case _: String => \"str\"\n  case _ => \"other\"\n\n\u002F\u002F Or even inline in a for-comprehension:\nfor\n  s \u003C- list.collect { case s: String => s }  \u002F\u002F collect filters + casts in one pass\n  if s.length > 3\nyield s.toUpperCase\n",[30,2858,2859,2864,2893,2915,2947,2981,2992,2996,3001,3014,3030,3041,3045,3050,3055,3082,3095],{"__ignoreMap":28},[33,2860,2861],{"class":35,"line":36},[33,2862,2863],{"class":39},"\u002F\u002F Scala 3: type test in pattern without binding\n",[33,2865,2866,2868,2871,2873,2875,2877,2880,2882,2884,2886,2888,2891],{"class":35,"line":43},[33,2867,737],{"class":101},[33,2869,2870],{"class":111}," handle",[33,2872,116],{"class":115},[33,2874,605],{"class":119},[33,2876,123],{"class":115},[33,2878,2879],{"class":111},"Any",[33,2881,221],{"class":115},[33,2883,185],{"class":101},[33,2885,757],{"class":111},[33,2887,191],{"class":101},[33,2889,2890],{"class":115}," x ",[33,2892,765],{"class":101},[33,2894,2895,2897,2899,2901,2903,2905,2907,2910,2913],{"class":35,"line":49},[33,2896,515],{"class":101},[33,2898,780],{"class":119},[33,2900,123],{"class":115},[33,2902,137],{"class":111},[33,2904,1379],{"class":101},[33,2906,780],{"class":101},[33,2908,2909],{"class":197},"\"string of length ",[33,2911,2912],{"class":115},"${s.length}",[33,2914,1712],{"class":197},[33,2916,2917,2919,2922,2924,2926,2928,2931,2933,2935,2937,2939,2942,2945],{"class":35,"line":55},[33,2918,515],{"class":101},[33,2920,2921],{"class":119}," i",[33,2923,123],{"class":115},[33,2925,557],{"class":111},[33,2927,2743],{"class":101},[33,2929,2930],{"class":115}," i ",[33,2932,1582],{"class":101},[33,2934,2515],{"class":271},[33,2936,1379],{"class":101},[33,2938,780],{"class":101},[33,2940,2941],{"class":197},"\"positive int: ",[33,2943,2944],{"class":115},"$i",[33,2946,1712],{"class":197},[33,2948,2949,2951,2954,2956,2959,2961,2964,2966,2968,2970,2973,2976,2978],{"class":35,"line":61},[33,2950,515],{"class":101},[33,2952,2953],{"class":119}," arr",[33,2955,123],{"class":115},[33,2957,2958],{"class":111},"Array",[33,2960,159],{"class":115},[33,2962,2963],{"class":101},"?",[33,2965,1332],{"class":115},[33,2967,777],{"class":101},[33,2969,780],{"class":101},[33,2971,2972],{"class":197},"\"array of size ",[33,2974,2975],{"class":115},"${arr.length}",[33,2977,1178],{"class":197},[33,2979,2980],{"class":39},"  \u002F\u002F [?] = wildcard, avoids unchecked warning\n",[33,2982,2983,2985,2987,2989],{"class":35,"line":67},[33,2984,515],{"class":101},[33,2986,1392],{"class":115},[33,2988,777],{"class":101},[33,2990,2991],{"class":197}," \"unknown\"\n",[33,2993,2994],{"class":35,"line":73},[33,2995,95],{"emptyLinePlaceholder":94},[33,2997,2998],{"class":35,"line":79},[33,2999,3000],{"class":39},"\u002F\u002F Scala 3: inline match — match on an expression inline (no match block)\n",[33,3002,3003,3005,3008,3010,3012],{"class":35,"line":85},[33,3004,259],{"class":101},[33,3006,3007],{"class":119}," result",[33,3009,191],{"class":101},[33,3011,2890],{"class":115},[33,3013,765],{"class":101},[33,3015,3016,3018,3021,3023,3025,3027],{"class":35,"line":91},[33,3017,515],{"class":101},[33,3019,3020],{"class":119}," _",[33,3022,123],{"class":115},[33,3024,137],{"class":111},[33,3026,1379],{"class":101},[33,3028,3029],{"class":197}," \"str\"\n",[33,3031,3032,3034,3036,3038],{"class":35,"line":98},[33,3033,515],{"class":101},[33,3035,1392],{"class":115},[33,3037,777],{"class":101},[33,3039,3040],{"class":197}," \"other\"\n",[33,3042,3043],{"class":35,"line":170},[33,3044,95],{"emptyLinePlaceholder":94},[33,3046,3047],{"class":35,"line":176},[33,3048,3049],{"class":39},"\u002F\u002F Or even inline in a for-comprehension:\n",[33,3051,3052],{"class":35,"line":204},[33,3053,3054],{"class":101},"for\n",[33,3056,3057,3060,3063,3066,3068,3070,3072,3074,3076,3079],{"class":35,"line":245},[33,3058,3059],{"class":115},"  s ",[33,3061,3062],{"class":101},"\u003C-",[33,3064,3065],{"class":115}," list.collect { ",[33,3067,346],{"class":101},[33,3069,780],{"class":119},[33,3071,123],{"class":115},[33,3073,137],{"class":111},[33,3075,1379],{"class":101},[33,3077,3078],{"class":115}," s }  ",[33,3080,3081],{"class":39},"\u002F\u002F collect filters + casts in one pass\n",[33,3083,3084,3087,3090,3092],{"class":35,"line":250},[33,3085,3086],{"class":101},"  if",[33,3088,3089],{"class":115}," s.length ",[33,3091,1582],{"class":101},[33,3093,3094],{"class":271}," 3\n",[33,3096,3097,3100],{"class":35,"line":256},[33,3098,3099],{"class":101},"yield",[33,3101,3102],{"class":115}," s.toUpperCase\n",[15,3104,3106,3109],{"id":3105},"copy-and-named-updates-immutable-data-evolution",[30,3107,3108],{},"copy"," and Named Updates — Immutable Data Evolution",[20,3111,3112],{"language":22},[24,3113,3115],{"className":26,"code":3114,"language":22,"meta":28,"style":28},"\u002F\u002F Nested immutable update — the classic pain point, solved with copy chains\nfinal case class Address(street: String, city: String, zip: String)\nfinal case class Company(name: String, address: Address)\nfinal case class Employee(name: String, company: Company)\n\nval emp = Employee(\"Alice\", Company(\"Acme\", Address(\"123 Main\", \"NYC\", \"10001\")))\n\n\u002F\u002F ❌ VERBOSE: nested copy chains\nval moved = emp.copy(\n  company = emp.company.copy(\n    address = emp.company.address.copy(\n      city = \"San Francisco\"\n    )\n  )\n)\n\n\u002F\u002F ✅ BETTER: use a lens library (Monocle) or just write a helper\ndef updateCity(e: Employee, city: String): Employee =\n  e.copy(company = e.company.copy(address = e.company.address.copy(city = city)))\n\n\u002F\u002F For deeply nested immutable data, consider:\n\u002F\u002F   1. Flatter data structures (normalize like a DB)\n\u002F\u002F   2. Monocle lenses: emp.focus(_.company.address.city).replace(\"SF\")\n\u002F\u002F   3. Mutable builders for construction, freeze to case class for storage\n",[30,3116,3117,3122,3162,3193,3224,3228,3274,3278,3283,3295,3305,3315,3325,3330,3335,3339,3343,3348,3380,3400,3404,3409,3414,3419],{"__ignoreMap":28},[33,3118,3119],{"class":35,"line":36},[33,3120,3121],{"class":39},"\u002F\u002F Nested immutable update — the classic pain point, solved with copy chains\n",[33,3123,3124,3126,3128,3130,3133,3135,3138,3140,3142,3144,3147,3149,3151,3153,3156,3158,3160],{"class":35,"line":43},[33,3125,102],{"class":101},[33,3127,105],{"class":101},[33,3129,108],{"class":101},[33,3131,3132],{"class":111}," Address",[33,3134,116],{"class":115},[33,3136,3137],{"class":119},"street",[33,3139,123],{"class":115},[33,3141,137],{"class":111},[33,3143,129],{"class":115},[33,3145,3146],{"class":119},"city",[33,3148,123],{"class":115},[33,3150,137],{"class":111},[33,3152,129],{"class":115},[33,3154,3155],{"class":119},"zip",[33,3157,123],{"class":115},[33,3159,137],{"class":111},[33,3161,201],{"class":115},[33,3163,3164,3166,3168,3170,3173,3175,3177,3179,3181,3183,3186,3188,3191],{"class":35,"line":49},[33,3165,102],{"class":101},[33,3167,105],{"class":101},[33,3169,108],{"class":101},[33,3171,3172],{"class":111}," Company",[33,3174,116],{"class":115},[33,3176,132],{"class":119},[33,3178,123],{"class":115},[33,3180,137],{"class":111},[33,3182,129],{"class":115},[33,3184,3185],{"class":119},"address",[33,3187,123],{"class":115},[33,3189,3190],{"class":111},"Address",[33,3192,201],{"class":115},[33,3194,3195,3197,3199,3201,3204,3206,3208,3210,3212,3214,3217,3219,3222],{"class":35,"line":55},[33,3196,102],{"class":101},[33,3198,105],{"class":101},[33,3200,108],{"class":101},[33,3202,3203],{"class":111}," Employee",[33,3205,116],{"class":115},[33,3207,132],{"class":119},[33,3209,123],{"class":115},[33,3211,137],{"class":111},[33,3213,129],{"class":115},[33,3215,3216],{"class":119},"company",[33,3218,123],{"class":115},[33,3220,3221],{"class":111},"Company",[33,3223,201],{"class":115},[33,3225,3226],{"class":35,"line":61},[33,3227,95],{"emptyLinePlaceholder":94},[33,3229,3230,3232,3235,3237,3239,3241,3243,3245,3247,3249,3252,3254,3256,3258,3261,3263,3266,3268,3271],{"class":35,"line":67},[33,3231,259],{"class":101},[33,3233,3234],{"class":119}," emp",[33,3236,191],{"class":101},[33,3238,3203],{"class":111},[33,3240,116],{"class":115},[33,3242,277],{"class":197},[33,3244,129],{"class":115},[33,3246,3221],{"class":111},[33,3248,116],{"class":115},[33,3250,3251],{"class":197},"\"Acme\"",[33,3253,129],{"class":115},[33,3255,3190],{"class":111},[33,3257,116],{"class":115},[33,3259,3260],{"class":197},"\"123 Main\"",[33,3262,129],{"class":115},[33,3264,3265],{"class":197},"\"NYC\"",[33,3267,129],{"class":115},[33,3269,3270],{"class":197},"\"10001\"",[33,3272,3273],{"class":115},")))\n",[33,3275,3276],{"class":35,"line":73},[33,3277,95],{"emptyLinePlaceholder":94},[33,3279,3280],{"class":35,"line":79},[33,3281,3282],{"class":39},"\u002F\u002F ❌ VERBOSE: nested copy chains\n",[33,3284,3285,3287,3290,3292],{"class":35,"line":85},[33,3286,259],{"class":101},[33,3288,3289],{"class":119}," moved",[33,3291,191],{"class":101},[33,3293,3294],{"class":115}," emp.copy(\n",[33,3296,3297,3300,3302],{"class":35,"line":91},[33,3298,3299],{"class":115},"  company ",[33,3301,233],{"class":101},[33,3303,3304],{"class":115}," emp.company.copy(\n",[33,3306,3307,3310,3312],{"class":35,"line":98},[33,3308,3309],{"class":115},"    address ",[33,3311,233],{"class":101},[33,3313,3314],{"class":115}," emp.company.address.copy(\n",[33,3316,3317,3320,3322],{"class":35,"line":170},[33,3318,3319],{"class":115},"      city ",[33,3321,233],{"class":101},[33,3323,3324],{"class":197}," \"San Francisco\"\n",[33,3326,3327],{"class":35,"line":176},[33,3328,3329],{"class":115},"    )\n",[33,3331,3332],{"class":35,"line":204},[33,3333,3334],{"class":115},"  )\n",[33,3336,3337],{"class":35,"line":245},[33,3338,201],{"class":115},[33,3340,3341],{"class":35,"line":250},[33,3342,95],{"emptyLinePlaceholder":94},[33,3344,3345],{"class":35,"line":256},[33,3346,3347],{"class":39},"\u002F\u002F ✅ BETTER: use a lens library (Monocle) or just write a helper\n",[33,3349,3350,3352,3355,3357,3359,3361,3364,3366,3368,3370,3372,3374,3376,3378],{"class":35,"line":297},[33,3351,737],{"class":101},[33,3353,3354],{"class":111}," updateCity",[33,3356,116],{"class":115},[33,3358,745],{"class":119},[33,3360,123],{"class":115},[33,3362,3363],{"class":111},"Employee",[33,3365,129],{"class":115},[33,3367,3146],{"class":119},[33,3369,123],{"class":115},[33,3371,137],{"class":111},[33,3373,221],{"class":115},[33,3375,185],{"class":101},[33,3377,3203],{"class":111},[33,3379,1362],{"class":101},[33,3381,3382,3385,3387,3390,3392,3395,3397],{"class":35,"line":326},[33,3383,3384],{"class":115},"  e.copy(company ",[33,3386,233],{"class":101},[33,3388,3389],{"class":115}," e.company.copy(address ",[33,3391,233],{"class":101},[33,3393,3394],{"class":115}," e.company.address.copy(city ",[33,3396,233],{"class":101},[33,3398,3399],{"class":115}," city)))\n",[33,3401,3402],{"class":35,"line":332},[33,3403,95],{"emptyLinePlaceholder":94},[33,3405,3406],{"class":35,"line":337},[33,3407,3408],{"class":39},"\u002F\u002F For deeply nested immutable data, consider:\n",[33,3410,3411],{"class":35,"line":343},[33,3412,3413],{"class":39},"\u002F\u002F   1. Flatter data structures (normalize like a DB)\n",[33,3415,3416],{"class":35,"line":373},[33,3417,3418],{"class":39},"\u002F\u002F   2. Monocle lenses: emp.focus(_.company.address.city).replace(\"SF\")\n",[33,3420,3421],{"class":35,"line":392},[33,3422,3423],{"class":39},"\u002F\u002F   3. Mutable builders for construction, freeze to case class for storage\n",[15,3425,3427],{"id":3426},"tips-tricks","💡 Tips & Tricks",[3429,3430,3431,3438,3439,3441],"p",{},[3432,3433,3434,3437],"strong",{},[30,3435,3436],{},"case object"," for singleton variants",": When an ADT case has no fields, use ",[30,3440,3436],{}," — it's a singleton, zero allocation per use.",[20,3443,3444],{"language":22},[24,3445,3447],{"className":26,"code":3446,"language":22,"meta":28,"style":28},"sealed trait Maybe[+T]\ncase object Nothing extends Maybe[Nothing]  \u002F\u002F singleton — no allocation\ncase class Just[T](value: T) extends Maybe[T]\n",[30,3448,3449,3468,3492],{"__ignoreMap":28},[33,3450,3451,3453,3455,3458,3460,3462,3465],{"class":35,"line":36},[33,3452,461],{"class":101},[33,3454,464],{"class":101},[33,3456,3457],{"class":111}," Maybe",[33,3459,159],{"class":115},[33,3461,1815],{"class":101},[33,3463,3464],{"class":111},"T",[33,3466,3467],{"class":115},"]\n",[33,3469,3470,3472,3474,3477,3479,3481,3483,3486,3489],{"class":35,"line":43},[33,3471,346],{"class":101},[33,3473,935],{"class":101},[33,3475,3476],{"class":111}," Nothing",[33,3478,941],{"class":101},[33,3480,3457],{"class":111},[33,3482,159],{"class":115},[33,3484,3485],{"class":111},"Nothing",[33,3487,3488],{"class":115},"]  ",[33,3490,3491],{"class":39},"\u002F\u002F singleton — no allocation\n",[33,3493,3494,3496,3498,3501,3503,3505,3508,3510,3512,3514,3516,3518,3520,3522,3524],{"class":35,"line":49},[33,3495,346],{"class":101},[33,3497,108],{"class":101},[33,3499,3500],{"class":111}," Just",[33,3502,159],{"class":115},[33,3504,3464],{"class":111},[33,3506,3507],{"class":115},"](",[33,3509,957],{"class":119},[33,3511,123],{"class":115},[33,3513,3464],{"class":111},[33,3515,560],{"class":115},[33,3517,563],{"class":101},[33,3519,3457],{"class":111},[33,3521,159],{"class":115},[33,3523,3464],{"class":111},[33,3525,3467],{"class":115},[3429,3527,3528,3534,3535,3537],{},[3432,3529,3530,3533],{},[30,3531,3532],{},"productElementNames"," for reflective serialization",": Scala 3 case classes expose field names via ",[30,3536,3532],{}," — use for generic JSON\u002FDB serialization without reflection.",[20,3539,3540],{"language":22},[24,3541,3543],{"className":26,"code":3542,"language":22,"meta":28,"style":28},"val names = alice.productElementNames.toVector  \u002F\u002F → Vector(\"id\", \"name\", \"email\", \"roles\")\nval values = alice.productIterator.toVector     \u002F\u002F → Vector(1L, \"Alice\", \"alice@x.com\", List(\"user\"))\n",[30,3544,3545,3560],{"__ignoreMap":28},[33,3546,3547,3549,3552,3554,3557],{"class":35,"line":36},[33,3548,259],{"class":101},[33,3550,3551],{"class":119}," names",[33,3553,191],{"class":101},[33,3555,3556],{"class":115}," alice.productElementNames.toVector  ",[33,3558,3559],{"class":39},"\u002F\u002F → Vector(\"id\", \"name\", \"email\", \"roles\")\n",[33,3561,3562,3564,3567,3569,3572],{"class":35,"line":43},[33,3563,259],{"class":101},[33,3565,3566],{"class":119}," values",[33,3568,191],{"class":101},[33,3570,3571],{"class":115}," alice.productIterator.toVector     ",[33,3573,3574],{"class":39},"\u002F\u002F → Vector(1L, \"Alice\", \"alice@x.com\", List(\"user\"))\n",[3429,3576,3577,3585,3586,3581,3588,3590,3591,2214],{},[3432,3578,3579,3581,3582,3584],{},[30,3580,2429],{}," returning ",[30,3583,962],{}," for guard-like extractors",": When you only need a yes\u002Fno match (no captured values), ",[30,3587,2429],{},[30,3589,962],{}," is cleaner than ",[30,3592,3593],{},"Option[Unit]",[15,3595,3597],{"id":3596},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[3429,3599,3600,123,3603,3606,3607,2847,3609,3611,3612,3615],{},[3432,3601,3602],{},"Type erasure in pattern matching",[30,3604,3605],{},"case m: Map[String, Int]"," — the ",[30,3608,137],{},[30,3610,557],{}," are erased. The match will succeed for ANY ",[30,3613,3614],{},"Map",", regardless of key\u002Fvalue types. Use element-level checks instead.",[3429,3617,3618,3624,3625,3627],{},[3432,3619,3620,3623],{},[30,3621,3622],{},"case _"," after sealed match hides future variants",": If you add ",[30,3626,3622],{}," to a sealed match, the compiler CANNOT warn you about missing new variants. The catch-all silently handles them.",[3429,3629,3630,3636,3637,3640],{},[3432,3631,3632,3633,3635],{},"Case class ",[30,3634,3108],{}," is shallow",": Nested mutable fields (e.g., ",[30,3638,3639],{},"case class C(buf: mutable.ArrayBuffer[Int])",") share the same buffer between original and copy — mutating one affects the other.",[3429,3642,3643,123,3654,3657,3658,3661,3662,3665],{},[3432,3644,3645,3648,3649,1826,3652],{},[30,3646,3647],{},"equals"," on case class with ",[30,3650,3651],{},"Float",[30,3653,1439],{},[30,3655,3656],{},"Float.NaN != Float.NaN",", so ",[30,3659,3660],{},"case class Point(x: Float)"," — two ",[30,3663,3664],{},"Point(NaN)"," are NOT equal. This is IEEE 754 semantics, not a Scala bug.",[15,3667,3669],{"id":3668},"quick-quiz","🧠 Quick Quiz",[3429,3671,3672,3673,2847,3676,2963],{},"What's the difference between ",[30,3674,3675],{},"case head :: tail =>",[30,3677,3678],{},"case head +: tail =>",[3680,3681,3682,3686,3691,3727,3748],"details",{},[3683,3684,3685],"summary",{},"Answer",[3429,3687,3688,3689,185],{},"They're functionally identical for ",[30,3690,156],{},[3692,3693,3694,3715],"ul",{},[3695,3696,3697,3699,3700,3703,3704,3706,3707,3710,3711,3714],"li",{},[30,3698,1872],{}," is the cons operator — ",[30,3701,3702],{},"head :: tail"," is a pattern that matches a non-empty ",[30,3705,156],{},", binding ",[30,3708,3709],{},"head"," to the first element and ",[30,3712,3713],{},"tail"," to the rest.",[3695,3716,3717,3720,3721,3724,3725,2214],{},[30,3718,3719],{},"+:"," is the general prepended element pattern — works on ANY ",[30,3722,3723],{},"Seq",", not just ",[30,3726,156],{},[3429,3728,3729,3730,129,3732,3734,3735,3738,3739,3734,3741,3744,3745,2214],{},"For ",[30,3731,156],{},[30,3733,1872],{}," uses ",[30,3736,3737],{},"::.unapply"," (List-specific). ",[30,3740,3719],{},[30,3742,3743],{},"scala.collection.+:.unapply"," which works on any ",[30,3746,3747],{},"SeqOps",[3429,3749,3750,3751,3753,3754,3756,3757,3759,3760,3762,3763,129,3766,3769],{},"Use ",[30,3752,1872],{}," when you specifically mean ",[30,3755,156],{},". Use ",[30,3758,3719],{}," when working with generic ",[30,3761,3723],{}," types where the concrete type might be ",[30,3764,3765],{},"Vector",[30,3767,3768],{},"ArrayBuffer",", etc.",[3771,3772,3773],"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 .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}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);}",{"title":28,"searchDepth":43,"depth":43,"links":3775},[3776,3777,3778,3779,3781,3783,3784,3786,3788,3790,3791,3792],{"id":17,"depth":43,"text":18},{"id":434,"depth":43,"text":435},{"id":897,"depth":43,"text":898},{"id":1400,"depth":43,"text":3780},"Pattern Matching — Guards, Alternatives, and @ Binding",{"id":1868,"depth":43,"text":3782},"Collection Patterns — ::, Nil, _*, unapplySeq",{"id":2195,"depth":43,"text":2196},{"id":2425,"depth":43,"text":3785},"Custom Extractors — unapply with State",{"id":2842,"depth":43,"text":3787},"Quasi-Pattern Matching with as and :? (Scala 3)",{"id":3105,"depth":43,"text":3789},"copy and Named Updates — Immutable Data Evolution",{"id":3426,"depth":43,"text":3427},{"id":3596,"depth":43,"text":3597},{"id":3668,"depth":43,"text":3669},"Production patterns for algebraic data types, exhaustiveness-driven domain modeling, custom extractors, regex patterns, and the compiler's unapplySeq \u002F productElementNames machinery.","md",{},"\u002Fscala\u002F07-case-classes-and-pattern-matching",{"title":5,"description":3793},"scala\u002F07-case-classes-and-pattern-matching","ikMU5hiOihpwK4qlEeqOpPiCQqs4uQPmNo-tNTodMOo",1789924654002]