[{"data":1,"prerenderedAt":3035},["ShallowReactive",2],{"page-\u002Fdart\u002F03-operators-and-expressions":3},{"id":4,"title":5,"body":6,"description":3028,"extension":3029,"meta":3030,"navigation":112,"path":3031,"seo":3032,"stem":3033,"__hash__":3034},"content\u002Fdart\u002F03-operators-and-expressions.md","Dart — Operators, Promotion Rules & Expression Semantics",{"type":7,"value":8,"toc":3014},"minimark",[9,13,18,315,323,816,820,1491,1499,1769,1773,2226,2230,2458,2462,2559,2563,2766,2770,2774,2861,2864,3010],[10,11,5],"h1",{"id":12},"dart-operators-promotion-rules-expression-semantics",[14,15,17],"h2",{"id":16},"null-aware-operator-chains-production-patterns","Null-Aware Operator Chains — Production Patterns",[19,20,22],"code-wrapper",{"language":21},"dart",[23,24,28],"pre",{"className":25,"code":26,"language":21,"meta":27,"style":27},"language-dart shiki shiki-themes github-light github-dark","\u002F\u002F Deep null navigation — each `?.` short-circuits the rest of the chain.\n\u002F\u002F If any link is null, the entire expression evaluates to null (no method call).\nString? city = user?.address?.city?.toUpperCase();\n\u002F\u002F Equivalent verbose form:\n\u002F\u002F String? city = (user != null && user.address != null && user.address.city != null)\n\u002F\u002F     ? user.address.city.toUpperCase() : null;\n\n\u002F\u002F ??= for lazy cache initialization — right side evaluated ONLY on cache miss:\nfinal cache = \u003CString, expensive>{};\nT compute\u003CT>(String key, T Function() loader) =>\n    cache.putIfAbsent(key, loader) as T;  \u002F\u002F putIfAbsent: loader runs only if key missing\n\n\u002F\u002F ?? for defaults — right side evaluated only if left is null:\nString displayName = user?.name ?? 'Anonymous';\nint pageSize = settings?.pageSize ?? 20;\n\n\u002F\u002F Combining: null-safe read with default and transformation:\nString label = (user?.nickname ?? user?.name ?? 'Unknown').toUpperCase();\n","",[29,30,31,40,46,89,95,101,107,114,120,145,178,202,207,213,240,266,271,277],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sdCPZ","\u002F\u002F Deep null navigation — each `?.` short-circuits the rest of the chain.\n",[32,41,43],{"class":34,"line":42},2,[32,44,45],{"class":38},"\u002F\u002F If any link is null, the entire expression evaluates to null (no method call).\n",[32,47,49,53,57,61,64,67,69,72,74,77,79,82,86],{"class":34,"line":48},3,[32,50,52],{"class":51},"snvgF","String",[32,54,56],{"class":55},"svdQ7","?",[32,58,60],{"class":59},"ssxIu"," city ",[32,62,63],{"class":55},"=",[32,65,66],{"class":59}," user",[32,68,56],{"class":55},[32,70,71],{"class":59},".address",[32,73,56],{"class":55},[32,75,76],{"class":59},".city",[32,78,56],{"class":55},[32,80,81],{"class":59},".",[32,83,85],{"class":84},"sIsaT","toUpperCase",[32,87,88],{"class":59},"();\n",[32,90,92],{"class":34,"line":91},4,[32,93,94],{"class":38},"\u002F\u002F Equivalent verbose form:\n",[32,96,98],{"class":34,"line":97},5,[32,99,100],{"class":38},"\u002F\u002F String? city = (user != null && user.address != null && user.address.city != null)\n",[32,102,104],{"class":34,"line":103},6,[32,105,106],{"class":38},"\u002F\u002F     ? user.address.city.toUpperCase() : null;\n",[32,108,110],{"class":34,"line":109},7,[32,111,113],{"emptyLinePlaceholder":112},true,"\n",[32,115,117],{"class":34,"line":116},8,[32,118,119],{"class":38},"\u002F\u002F ??= for lazy cache initialization — right side evaluated ONLY on cache miss:\n",[32,121,123,126,129,131,134,136,139,142],{"class":34,"line":122},9,[32,124,125],{"class":55},"final",[32,127,128],{"class":59}," cache ",[32,130,63],{"class":55},[32,132,133],{"class":55}," \u003C",[32,135,52],{"class":51},[32,137,138],{"class":59},", expensive",[32,140,141],{"class":55},">",[32,143,144],{"class":59},"{};\n",[32,146,148,151,154,157,159,162,164,167,169,172,175],{"class":34,"line":147},10,[32,149,150],{"class":51},"T",[32,152,153],{"class":84}," compute",[32,155,156],{"class":59},"\u003C",[32,158,150],{"class":51},[32,160,161],{"class":59},">(",[32,163,52],{"class":51},[32,165,166],{"class":59}," key, ",[32,168,150],{"class":51},[32,170,171],{"class":51}," Function",[32,173,174],{"class":59},"() loader) ",[32,176,177],{"class":55},"=>\n",[32,179,181,184,187,190,193,196,199],{"class":34,"line":180},11,[32,182,183],{"class":59},"    cache.",[32,185,186],{"class":84},"putIfAbsent",[32,188,189],{"class":59},"(key, loader) ",[32,191,192],{"class":55},"as",[32,194,195],{"class":51}," T",[32,197,198],{"class":59},";  ",[32,200,201],{"class":38},"\u002F\u002F putIfAbsent: loader runs only if key missing\n",[32,203,205],{"class":34,"line":204},12,[32,206,113],{"emptyLinePlaceholder":112},[32,208,210],{"class":34,"line":209},13,[32,211,212],{"class":38},"\u002F\u002F ?? for defaults — right side evaluated only if left is null:\n",[32,214,216,218,221,223,225,227,230,233,237],{"class":34,"line":215},14,[32,217,52],{"class":51},[32,219,220],{"class":59}," displayName ",[32,222,63],{"class":55},[32,224,66],{"class":59},[32,226,56],{"class":55},[32,228,229],{"class":59},".name ",[32,231,232],{"class":55},"??",[32,234,236],{"class":235},"sJ6F3"," 'Anonymous'",[32,238,239],{"class":59},";\n",[32,241,243,246,249,251,254,256,259,261,264],{"class":34,"line":242},15,[32,244,245],{"class":51},"int",[32,247,248],{"class":59}," pageSize ",[32,250,63],{"class":55},[32,252,253],{"class":59}," settings",[32,255,56],{"class":55},[32,257,258],{"class":59},".pageSize ",[32,260,232],{"class":55},[32,262,263],{"class":51}," 20",[32,265,239],{"class":59},[32,267,269],{"class":34,"line":268},16,[32,270,113],{"emptyLinePlaceholder":112},[32,272,274],{"class":34,"line":273},17,[32,275,276],{"class":38},"\u002F\u002F Combining: null-safe read with default and transformation:\n",[32,278,280,282,285,287,290,292,295,297,299,301,303,305,308,311,313],{"class":34,"line":279},18,[32,281,52],{"class":51},[32,283,284],{"class":59}," label ",[32,286,63],{"class":55},[32,288,289],{"class":59}," (user",[32,291,56],{"class":55},[32,293,294],{"class":59},".nickname ",[32,296,232],{"class":55},[32,298,66],{"class":59},[32,300,56],{"class":55},[32,302,229],{"class":59},[32,304,232],{"class":55},[32,306,307],{"class":235}," 'Unknown'",[32,309,310],{"class":59},").",[32,312,85],{"class":84},[32,314,88],{"class":59},[316,317,319,322],"h3",{"id":318},"the-null-assertion-trap",[29,320,321],{},"!"," — The Null Assertion Trap",[19,324,325],{"language":21},[23,326,328],{"className":25,"code":327,"language":21,"meta":27,"style":27},"\u002F\u002F ❌ Anti-pattern: using `!` to \"silence\" the null-safety compiler.\nString? getInput() => maybeNull() ? 'hello' : null;\n\nvoid bad() {\n  String name = getInput()!;  \u002F\u002F compiles, but throws TypeError at runtime if null\n  print(name.length);\n}\n\n\u002F\u002F ✓ Correct: handle null explicitly — never use `!` on untrusted sources.\nvoid good() {\n  final name = getInput();\n  if (name != null) {\n    print(name.length);  \u002F\u002F type promotion: name is String here (no `!` needed)\n  } else {\n    print('No input');\n  }\n}\n\n\u002F\u002F Acceptable `!` use: framework invariants where the framework guarantees non-null.\n\u002F\u002F Example: Flutter widget parameters after initState.\nclass MyWidget extends StatefulWidget {\n  const MyWidget({super.key, required this.tag});\n  final String tag;\n  @override\n  State\u003CMyWidget> createState() => _MyWidgetState();\n}\n\nclass _MyWidgetState extends State\u003CMyWidget> {\n  late StreamSubscription _sub;  \u002F\u002F `late` is safer than `!` for \"assigned in initState\"\n\n  @override\n  void initState() {\n    super.initState();\n    _sub = someStream.listen((event) {\n      print('${widget.tag}: $event');  \u002F\u002F `widget` is always non-null in State\n    });\n  }\n\n  @override\n  void dispose() {\n    _sub.cancel();  \u002F\u002F always assigned before dispose if initState ran\n    super.dispose();\n  }\n}\n",[29,329,330,335,368,372,383,405,413,418,422,427,436,449,465,476,487,500,505,509,513,519,525,542,568,579,585,611,616,621,640,655,660,665,676,689,706,748,754,759,764,769,779,794,806,811],{"__ignoreMap":27},[32,331,332],{"class":34,"line":35},[32,333,334],{"class":38},"\u002F\u002F ❌ Anti-pattern: using `!` to \"silence\" the null-safety compiler.\n",[32,336,337,339,341,344,347,350,353,355,357,360,363,366],{"class":34,"line":42},[32,338,52],{"class":51},[32,340,56],{"class":55},[32,342,343],{"class":84}," getInput",[32,345,346],{"class":59},"() ",[32,348,349],{"class":55},"=>",[32,351,352],{"class":84}," maybeNull",[32,354,346],{"class":59},[32,356,56],{"class":55},[32,358,359],{"class":235}," 'hello'",[32,361,362],{"class":55}," :",[32,364,365],{"class":51}," null",[32,367,239],{"class":59},[32,369,370],{"class":34,"line":48},[32,371,113],{"emptyLinePlaceholder":112},[32,373,374,377,380],{"class":34,"line":91},[32,375,376],{"class":55},"void",[32,378,379],{"class":84}," bad",[32,381,382],{"class":59},"() {\n",[32,384,385,388,391,393,395,398,400,402],{"class":34,"line":97},[32,386,387],{"class":51},"  String",[32,389,390],{"class":59}," name ",[32,392,63],{"class":55},[32,394,343],{"class":84},[32,396,397],{"class":59},"()",[32,399,321],{"class":55},[32,401,198],{"class":59},[32,403,404],{"class":38},"\u002F\u002F compiles, but throws TypeError at runtime if null\n",[32,406,407,410],{"class":34,"line":103},[32,408,409],{"class":84},"  print",[32,411,412],{"class":59},"(name.length);\n",[32,414,415],{"class":34,"line":109},[32,416,417],{"class":59},"}\n",[32,419,420],{"class":34,"line":116},[32,421,113],{"emptyLinePlaceholder":112},[32,423,424],{"class":34,"line":122},[32,425,426],{"class":38},"\u002F\u002F ✓ Correct: handle null explicitly — never use `!` on untrusted sources.\n",[32,428,429,431,434],{"class":34,"line":147},[32,430,376],{"class":55},[32,432,433],{"class":84}," good",[32,435,382],{"class":59},[32,437,438,441,443,445,447],{"class":34,"line":180},[32,439,440],{"class":55},"  final",[32,442,390],{"class":59},[32,444,63],{"class":55},[32,446,343],{"class":84},[32,448,88],{"class":59},[32,450,451,454,457,460,462],{"class":34,"line":204},[32,452,453],{"class":55},"  if",[32,455,456],{"class":59}," (name ",[32,458,459],{"class":55},"!=",[32,461,365],{"class":51},[32,463,464],{"class":59},") {\n",[32,466,467,470,473],{"class":34,"line":209},[32,468,469],{"class":84},"    print",[32,471,472],{"class":59},"(name.length);  ",[32,474,475],{"class":38},"\u002F\u002F type promotion: name is String here (no `!` needed)\n",[32,477,478,481,484],{"class":34,"line":215},[32,479,480],{"class":59},"  } ",[32,482,483],{"class":55},"else",[32,485,486],{"class":59}," {\n",[32,488,489,491,494,497],{"class":34,"line":242},[32,490,469],{"class":84},[32,492,493],{"class":59},"(",[32,495,496],{"class":235},"'No input'",[32,498,499],{"class":59},");\n",[32,501,502],{"class":34,"line":268},[32,503,504],{"class":59},"  }\n",[32,506,507],{"class":34,"line":273},[32,508,417],{"class":59},[32,510,511],{"class":34,"line":279},[32,512,113],{"emptyLinePlaceholder":112},[32,514,516],{"class":34,"line":515},19,[32,517,518],{"class":38},"\u002F\u002F Acceptable `!` use: framework invariants where the framework guarantees non-null.\n",[32,520,522],{"class":34,"line":521},20,[32,523,524],{"class":38},"\u002F\u002F Example: Flutter widget parameters after initState.\n",[32,526,528,531,534,537,540],{"class":34,"line":527},21,[32,529,530],{"class":55},"class",[32,532,533],{"class":51}," MyWidget",[32,535,536],{"class":55}," extends",[32,538,539],{"class":51}," StatefulWidget",[32,541,486],{"class":59},[32,543,545,548,550,553,556,559,562,565],{"class":34,"line":544},22,[32,546,547],{"class":55},"  const",[32,549,533],{"class":51},[32,551,552],{"class":59},"({",[32,554,555],{"class":51},"super",[32,557,558],{"class":59},".key, ",[32,560,561],{"class":55},"required",[32,563,564],{"class":51}," this",[32,566,567],{"class":59},".tag});\n",[32,569,571,573,576],{"class":34,"line":570},23,[32,572,440],{"class":55},[32,574,575],{"class":51}," String",[32,577,578],{"class":59}," tag;\n",[32,580,582],{"class":34,"line":581},24,[32,583,584],{"class":55},"  @override\n",[32,586,588,591,593,596,599,602,604,606,609],{"class":34,"line":587},25,[32,589,590],{"class":51},"  State",[32,592,156],{"class":59},[32,594,595],{"class":51},"MyWidget",[32,597,598],{"class":59},"> ",[32,600,601],{"class":84},"createState",[32,603,346],{"class":59},[32,605,349],{"class":55},[32,607,608],{"class":51}," _MyWidgetState",[32,610,88],{"class":59},[32,612,614],{"class":34,"line":613},26,[32,615,417],{"class":59},[32,617,619],{"class":34,"line":618},27,[32,620,113],{"emptyLinePlaceholder":112},[32,622,624,626,628,630,633,635,637],{"class":34,"line":623},28,[32,625,530],{"class":55},[32,627,608],{"class":51},[32,629,536],{"class":55},[32,631,632],{"class":51}," State",[32,634,156],{"class":59},[32,636,595],{"class":51},[32,638,639],{"class":59},"> {\n",[32,641,643,646,649,652],{"class":34,"line":642},29,[32,644,645],{"class":55},"  late",[32,647,648],{"class":51}," StreamSubscription",[32,650,651],{"class":59}," _sub;  ",[32,653,654],{"class":38},"\u002F\u002F `late` is safer than `!` for \"assigned in initState\"\n",[32,656,658],{"class":34,"line":657},30,[32,659,113],{"emptyLinePlaceholder":112},[32,661,663],{"class":34,"line":662},31,[32,664,584],{"class":55},[32,666,668,671,674],{"class":34,"line":667},32,[32,669,670],{"class":55},"  void",[32,672,673],{"class":84}," initState",[32,675,382],{"class":59},[32,677,679,682,684,687],{"class":34,"line":678},33,[32,680,681],{"class":51},"    super",[32,683,81],{"class":59},[32,685,686],{"class":84},"initState",[32,688,88],{"class":59},[32,690,692,695,697,700,703],{"class":34,"line":691},34,[32,693,694],{"class":59},"    _sub ",[32,696,63],{"class":55},[32,698,699],{"class":59}," someStream.",[32,701,702],{"class":84},"listen",[32,704,705],{"class":59},"((event) {\n",[32,707,709,712,714,717,720,723,725,728,731,734,737,740,742,745],{"class":34,"line":708},35,[32,710,711],{"class":84},"      print",[32,713,493],{"class":59},[32,715,716],{"class":235},"'",[32,718,719],{"class":235},"${",[32,721,722],{"class":51},"widget",[32,724,81],{"class":235},[32,726,727],{"class":51},"tag",[32,729,730],{"class":235},"}",[32,732,733],{"class":235},": ",[32,735,736],{"class":235},"$",[32,738,739],{"class":51},"event",[32,741,716],{"class":235},[32,743,744],{"class":59},");  ",[32,746,747],{"class":38},"\u002F\u002F `widget` is always non-null in State\n",[32,749,751],{"class":34,"line":750},36,[32,752,753],{"class":59},"    });\n",[32,755,757],{"class":34,"line":756},37,[32,758,504],{"class":59},[32,760,762],{"class":34,"line":761},38,[32,763,113],{"emptyLinePlaceholder":112},[32,765,767],{"class":34,"line":766},39,[32,768,584],{"class":55},[32,770,772,774,777],{"class":34,"line":771},40,[32,773,670],{"class":55},[32,775,776],{"class":84}," dispose",[32,778,382],{"class":59},[32,780,782,785,788,791],{"class":34,"line":781},41,[32,783,784],{"class":59},"    _sub.",[32,786,787],{"class":84},"cancel",[32,789,790],{"class":59},"();  ",[32,792,793],{"class":38},"\u002F\u002F always assigned before dispose if initState ran\n",[32,795,797,799,801,804],{"class":34,"line":796},42,[32,798,681],{"class":51},[32,800,81],{"class":59},[32,802,803],{"class":84},"dispose",[32,805,88],{"class":59},[32,807,809],{"class":34,"line":808},43,[32,810,504],{"class":59},[32,812,814],{"class":34,"line":813},44,[32,815,417],{"class":59},[14,817,819],{"id":818},"type-promotion-the-closure-field-trap","Type Promotion — The Closure & Field Trap",[19,821,822],{"language":21},[23,823,825],{"className":25,"code":824,"language":21,"meta":27,"style":27},"\u002F\u002F Type promotion works for LOCAL variables only — not fields, not across closures,\n\u002F\u002F not across `await` gaps. This is the #1 source of \"why is the compiler mad at me.\"\n\n\u002F\u002F ✓ Local variable: promotion works inside `if (x != null)`.\nvoid localPromotion() {\n  String? name = getInput();\n  if (name != null) {\n    print(name.length);  \u002F\u002F promoted to String — no `!` needed\n  }\n}\n\n\u002F\u002F ❌ Class field: promotion does NOT work — the field is shared mutable state.\nclass Service {\n  String? _cached;\n\n  void use() {\n    if (_cached != null) {\n      \u002F\u002F print(_cached.length);  \u002F\u002F ✗ compile error: _cached is still String?\n      \u002F\u002F The compiler can't promote because between the check and the use,\n      \u002F\u002F another method or callback could set _cached = null.\n    }\n  }\n}\n\n\u002F\u002F ✓ Fix for fields: copy to a local, then promote the local.\nclass ServiceFixed {\n  String? _cached;\n\n  void use() {\n    final cached = _cached;  \u002F\u002F local copy — immutable snapshot\n    if (cached != null) {\n      print(cached.length);  \u002F\u002F ✓ promoted to String — local can't be mutated externally\n    }\n  }\n}\n\n\u002F\u002F ❌ Across closures: promotion doesn't cross function boundaries.\nvoid closureTrap() {\n  String? name = getInput();\n  if (name != null) {\n    final callback = () {\n      \u002F\u002F print(name.length);  \u002F\u002F ✗ not promoted inside the closure\n      \u002F\u002F The closure could execute later, after `name` was set to null.\n    };\n    callback();\n  }\n}\n\n\u002F\u002F ✓ Fix: capture in a final local before the closure.\nvoid closureFixed() {\n  final name = getInput();\n  if (name != null) {\n    final captured = name;  \u002F\u002F final local — immutable, promotion-safe\n    final callback = () {\n      print(captured.length);  \u002F\u002F ✓ captured is non-nullable String\n    };\n    callback();\n  }\n}\n\n\u002F\u002F ❌ Across `await`: promotion is invalidated after an await gap.\nFuture\u003Cvoid> awaitGap() async {\n  String? name = getInput();\n  if (name != null) {\n    await Future.delayed(Duration.zero);  \u002F\u002F yields to event loop\n    \u002F\u002F print(name.length);  \u002F\u002F ✗ not promoted after await\n    \u002F\u002F Another async task could have set name = null during the await.\n  }\n}\n\n\u002F\u002F ✓ Fix: capture before await.\nFuture\u003Cvoid> awaitFixed() async {\n  final name = getInput();\n  if (name != null) {\n    final captured = name;  \u002F\u002F snapshot before yielding\n    await Future.delayed(Duration.zero);\n    print(captured.length);  \u002F\u002F ✓ captured is non-nullable\n  }\n}\n",[29,826,827,832,837,841,846,855,869,881,890,894,898,902,907,916,925,929,938,952,960,965,970,975,979,983,987,992,1001,1009,1013,1021,1037,1050,1060,1064,1068,1072,1076,1081,1090,1104,1116,1128,1136,1141,1146,1154,1159,1164,1169,1175,1185,1198,1211,1227,1238,1249,1254,1261,1266,1271,1276,1282,1304,1319,1332,1357,1366,1372,1377,1382,1387,1393,1413,1426,1439,1453,1471,1481,1486],{"__ignoreMap":27},[32,828,829],{"class":34,"line":35},[32,830,831],{"class":38},"\u002F\u002F Type promotion works for LOCAL variables only — not fields, not across closures,\n",[32,833,834],{"class":34,"line":42},[32,835,836],{"class":38},"\u002F\u002F not across `await` gaps. This is the #1 source of \"why is the compiler mad at me.\"\n",[32,838,839],{"class":34,"line":48},[32,840,113],{"emptyLinePlaceholder":112},[32,842,843],{"class":34,"line":91},[32,844,845],{"class":38},"\u002F\u002F ✓ Local variable: promotion works inside `if (x != null)`.\n",[32,847,848,850,853],{"class":34,"line":97},[32,849,376],{"class":55},[32,851,852],{"class":84}," localPromotion",[32,854,382],{"class":59},[32,856,857,859,861,863,865,867],{"class":34,"line":103},[32,858,387],{"class":51},[32,860,56],{"class":55},[32,862,390],{"class":59},[32,864,63],{"class":55},[32,866,343],{"class":84},[32,868,88],{"class":59},[32,870,871,873,875,877,879],{"class":34,"line":109},[32,872,453],{"class":55},[32,874,456],{"class":59},[32,876,459],{"class":55},[32,878,365],{"class":51},[32,880,464],{"class":59},[32,882,883,885,887],{"class":34,"line":116},[32,884,469],{"class":84},[32,886,472],{"class":59},[32,888,889],{"class":38},"\u002F\u002F promoted to String — no `!` needed\n",[32,891,892],{"class":34,"line":122},[32,893,504],{"class":59},[32,895,896],{"class":34,"line":147},[32,897,417],{"class":59},[32,899,900],{"class":34,"line":180},[32,901,113],{"emptyLinePlaceholder":112},[32,903,904],{"class":34,"line":204},[32,905,906],{"class":38},"\u002F\u002F ❌ Class field: promotion does NOT work — the field is shared mutable state.\n",[32,908,909,911,914],{"class":34,"line":209},[32,910,530],{"class":55},[32,912,913],{"class":51}," Service",[32,915,486],{"class":59},[32,917,918,920,922],{"class":34,"line":215},[32,919,387],{"class":51},[32,921,56],{"class":55},[32,923,924],{"class":59}," _cached;\n",[32,926,927],{"class":34,"line":242},[32,928,113],{"emptyLinePlaceholder":112},[32,930,931,933,936],{"class":34,"line":268},[32,932,670],{"class":55},[32,934,935],{"class":84}," use",[32,937,382],{"class":59},[32,939,940,943,946,948,950],{"class":34,"line":273},[32,941,942],{"class":55},"    if",[32,944,945],{"class":59}," (_cached ",[32,947,459],{"class":55},[32,949,365],{"class":51},[32,951,464],{"class":59},[32,953,954,957],{"class":34,"line":279},[32,955,956],{"class":38},"      \u002F\u002F print(_cached.length);",[32,958,959],{"class":38},"  \u002F\u002F ✗ compile error: _cached is still String?\n",[32,961,962],{"class":34,"line":515},[32,963,964],{"class":38},"      \u002F\u002F The compiler can't promote because between the check and the use,\n",[32,966,967],{"class":34,"line":521},[32,968,969],{"class":38},"      \u002F\u002F another method or callback could set _cached = null.\n",[32,971,972],{"class":34,"line":527},[32,973,974],{"class":59},"    }\n",[32,976,977],{"class":34,"line":544},[32,978,504],{"class":59},[32,980,981],{"class":34,"line":570},[32,982,417],{"class":59},[32,984,985],{"class":34,"line":581},[32,986,113],{"emptyLinePlaceholder":112},[32,988,989],{"class":34,"line":587},[32,990,991],{"class":38},"\u002F\u002F ✓ Fix for fields: copy to a local, then promote the local.\n",[32,993,994,996,999],{"class":34,"line":613},[32,995,530],{"class":55},[32,997,998],{"class":51}," ServiceFixed",[32,1000,486],{"class":59},[32,1002,1003,1005,1007],{"class":34,"line":618},[32,1004,387],{"class":51},[32,1006,56],{"class":55},[32,1008,924],{"class":59},[32,1010,1011],{"class":34,"line":623},[32,1012,113],{"emptyLinePlaceholder":112},[32,1014,1015,1017,1019],{"class":34,"line":642},[32,1016,670],{"class":55},[32,1018,935],{"class":84},[32,1020,382],{"class":59},[32,1022,1023,1026,1029,1031,1034],{"class":34,"line":657},[32,1024,1025],{"class":55},"    final",[32,1027,1028],{"class":59}," cached ",[32,1030,63],{"class":55},[32,1032,1033],{"class":59}," _cached;  ",[32,1035,1036],{"class":38},"\u002F\u002F local copy — immutable snapshot\n",[32,1038,1039,1041,1044,1046,1048],{"class":34,"line":662},[32,1040,942],{"class":55},[32,1042,1043],{"class":59}," (cached ",[32,1045,459],{"class":55},[32,1047,365],{"class":51},[32,1049,464],{"class":59},[32,1051,1052,1054,1057],{"class":34,"line":667},[32,1053,711],{"class":84},[32,1055,1056],{"class":59},"(cached.length);  ",[32,1058,1059],{"class":38},"\u002F\u002F ✓ promoted to String — local can't be mutated externally\n",[32,1061,1062],{"class":34,"line":678},[32,1063,974],{"class":59},[32,1065,1066],{"class":34,"line":691},[32,1067,504],{"class":59},[32,1069,1070],{"class":34,"line":708},[32,1071,417],{"class":59},[32,1073,1074],{"class":34,"line":750},[32,1075,113],{"emptyLinePlaceholder":112},[32,1077,1078],{"class":34,"line":756},[32,1079,1080],{"class":38},"\u002F\u002F ❌ Across closures: promotion doesn't cross function boundaries.\n",[32,1082,1083,1085,1088],{"class":34,"line":761},[32,1084,376],{"class":55},[32,1086,1087],{"class":84}," closureTrap",[32,1089,382],{"class":59},[32,1091,1092,1094,1096,1098,1100,1102],{"class":34,"line":766},[32,1093,387],{"class":51},[32,1095,56],{"class":55},[32,1097,390],{"class":59},[32,1099,63],{"class":55},[32,1101,343],{"class":84},[32,1103,88],{"class":59},[32,1105,1106,1108,1110,1112,1114],{"class":34,"line":771},[32,1107,453],{"class":55},[32,1109,456],{"class":59},[32,1111,459],{"class":55},[32,1113,365],{"class":51},[32,1115,464],{"class":59},[32,1117,1118,1120,1123,1125],{"class":34,"line":781},[32,1119,1025],{"class":55},[32,1121,1122],{"class":59}," callback ",[32,1124,63],{"class":55},[32,1126,1127],{"class":59}," () {\n",[32,1129,1130,1133],{"class":34,"line":796},[32,1131,1132],{"class":38},"      \u002F\u002F print(name.length);",[32,1134,1135],{"class":38},"  \u002F\u002F ✗ not promoted inside the closure\n",[32,1137,1138],{"class":34,"line":808},[32,1139,1140],{"class":38},"      \u002F\u002F The closure could execute later, after `name` was set to null.\n",[32,1142,1143],{"class":34,"line":813},[32,1144,1145],{"class":59},"    };\n",[32,1147,1149,1152],{"class":34,"line":1148},45,[32,1150,1151],{"class":84},"    callback",[32,1153,88],{"class":59},[32,1155,1157],{"class":34,"line":1156},46,[32,1158,504],{"class":59},[32,1160,1162],{"class":34,"line":1161},47,[32,1163,417],{"class":59},[32,1165,1167],{"class":34,"line":1166},48,[32,1168,113],{"emptyLinePlaceholder":112},[32,1170,1172],{"class":34,"line":1171},49,[32,1173,1174],{"class":38},"\u002F\u002F ✓ Fix: capture in a final local before the closure.\n",[32,1176,1178,1180,1183],{"class":34,"line":1177},50,[32,1179,376],{"class":55},[32,1181,1182],{"class":84}," closureFixed",[32,1184,382],{"class":59},[32,1186,1188,1190,1192,1194,1196],{"class":34,"line":1187},51,[32,1189,440],{"class":55},[32,1191,390],{"class":59},[32,1193,63],{"class":55},[32,1195,343],{"class":84},[32,1197,88],{"class":59},[32,1199,1201,1203,1205,1207,1209],{"class":34,"line":1200},52,[32,1202,453],{"class":55},[32,1204,456],{"class":59},[32,1206,459],{"class":55},[32,1208,365],{"class":51},[32,1210,464],{"class":59},[32,1212,1214,1216,1219,1221,1224],{"class":34,"line":1213},53,[32,1215,1025],{"class":55},[32,1217,1218],{"class":59}," captured ",[32,1220,63],{"class":55},[32,1222,1223],{"class":59}," name;  ",[32,1225,1226],{"class":38},"\u002F\u002F final local — immutable, promotion-safe\n",[32,1228,1230,1232,1234,1236],{"class":34,"line":1229},54,[32,1231,1025],{"class":55},[32,1233,1122],{"class":59},[32,1235,63],{"class":55},[32,1237,1127],{"class":59},[32,1239,1241,1243,1246],{"class":34,"line":1240},55,[32,1242,711],{"class":84},[32,1244,1245],{"class":59},"(captured.length);  ",[32,1247,1248],{"class":38},"\u002F\u002F ✓ captured is non-nullable String\n",[32,1250,1252],{"class":34,"line":1251},56,[32,1253,1145],{"class":59},[32,1255,1257,1259],{"class":34,"line":1256},57,[32,1258,1151],{"class":84},[32,1260,88],{"class":59},[32,1262,1264],{"class":34,"line":1263},58,[32,1265,504],{"class":59},[32,1267,1269],{"class":34,"line":1268},59,[32,1270,417],{"class":59},[32,1272,1274],{"class":34,"line":1273},60,[32,1275,113],{"emptyLinePlaceholder":112},[32,1277,1279],{"class":34,"line":1278},61,[32,1280,1281],{"class":38},"\u002F\u002F ❌ Across `await`: promotion is invalidated after an await gap.\n",[32,1283,1285,1288,1290,1292,1294,1297,1299,1302],{"class":34,"line":1284},62,[32,1286,1287],{"class":51},"Future",[32,1289,156],{"class":59},[32,1291,376],{"class":55},[32,1293,598],{"class":59},[32,1295,1296],{"class":84},"awaitGap",[32,1298,346],{"class":59},[32,1300,1301],{"class":55},"async",[32,1303,486],{"class":59},[32,1305,1307,1309,1311,1313,1315,1317],{"class":34,"line":1306},63,[32,1308,387],{"class":51},[32,1310,56],{"class":55},[32,1312,390],{"class":59},[32,1314,63],{"class":55},[32,1316,343],{"class":84},[32,1318,88],{"class":59},[32,1320,1322,1324,1326,1328,1330],{"class":34,"line":1321},64,[32,1323,453],{"class":55},[32,1325,456],{"class":59},[32,1327,459],{"class":55},[32,1329,365],{"class":51},[32,1331,464],{"class":59},[32,1333,1335,1338,1341,1343,1346,1348,1351,1354],{"class":34,"line":1334},65,[32,1336,1337],{"class":55},"    await",[32,1339,1340],{"class":51}," Future",[32,1342,81],{"class":59},[32,1344,1345],{"class":84},"delayed",[32,1347,493],{"class":59},[32,1349,1350],{"class":51},"Duration",[32,1352,1353],{"class":59},".zero);  ",[32,1355,1356],{"class":38},"\u002F\u002F yields to event loop\n",[32,1358,1360,1363],{"class":34,"line":1359},66,[32,1361,1362],{"class":38},"    \u002F\u002F print(name.length);",[32,1364,1365],{"class":38},"  \u002F\u002F ✗ not promoted after await\n",[32,1367,1369],{"class":34,"line":1368},67,[32,1370,1371],{"class":38},"    \u002F\u002F Another async task could have set name = null during the await.\n",[32,1373,1375],{"class":34,"line":1374},68,[32,1376,504],{"class":59},[32,1378,1380],{"class":34,"line":1379},69,[32,1381,417],{"class":59},[32,1383,1385],{"class":34,"line":1384},70,[32,1386,113],{"emptyLinePlaceholder":112},[32,1388,1390],{"class":34,"line":1389},71,[32,1391,1392],{"class":38},"\u002F\u002F ✓ Fix: capture before await.\n",[32,1394,1396,1398,1400,1402,1404,1407,1409,1411],{"class":34,"line":1395},72,[32,1397,1287],{"class":51},[32,1399,156],{"class":59},[32,1401,376],{"class":55},[32,1403,598],{"class":59},[32,1405,1406],{"class":84},"awaitFixed",[32,1408,346],{"class":59},[32,1410,1301],{"class":55},[32,1412,486],{"class":59},[32,1414,1416,1418,1420,1422,1424],{"class":34,"line":1415},73,[32,1417,440],{"class":55},[32,1419,390],{"class":59},[32,1421,63],{"class":55},[32,1423,343],{"class":84},[32,1425,88],{"class":59},[32,1427,1429,1431,1433,1435,1437],{"class":34,"line":1428},74,[32,1430,453],{"class":55},[32,1432,456],{"class":59},[32,1434,459],{"class":55},[32,1436,365],{"class":51},[32,1438,464],{"class":59},[32,1440,1442,1444,1446,1448,1450],{"class":34,"line":1441},75,[32,1443,1025],{"class":55},[32,1445,1218],{"class":59},[32,1447,63],{"class":55},[32,1449,1223],{"class":59},[32,1451,1452],{"class":38},"\u002F\u002F snapshot before yielding\n",[32,1454,1456,1458,1460,1462,1464,1466,1468],{"class":34,"line":1455},76,[32,1457,1337],{"class":55},[32,1459,1340],{"class":51},[32,1461,81],{"class":59},[32,1463,1345],{"class":84},[32,1465,493],{"class":59},[32,1467,1350],{"class":51},[32,1469,1470],{"class":59},".zero);\n",[32,1472,1474,1476,1478],{"class":34,"line":1473},77,[32,1475,469],{"class":84},[32,1477,1245],{"class":59},[32,1479,1480],{"class":38},"\u002F\u002F ✓ captured is non-nullable\n",[32,1482,1484],{"class":34,"line":1483},78,[32,1485,504],{"class":59},[32,1487,1489],{"class":34,"line":1488},79,[32,1490,417],{"class":59},[14,1492,1494,1495,1498],{"id":1493},"cascade-fluent-configuration","Cascade (",[29,1496,1497],{},"..",") — Fluent Configuration",[19,1500,1501],{"language":21},[23,1502,1504],{"className":25,"code":1503,"language":21,"meta":27,"style":27},"\u002F\u002F `..` returns the LEFT-HAND object (not the method result), enabling fluent chains.\n\u002F\u002F Contrast with `.` which returns the method's return value.\n\n\u002F\u002F ❌ Without cascade — verbose, repeated variable name:\nvar paint = Paint();\npaint.color = Colors.red;\npaint.strokeWidth = 2.0;\npaint.style = PaintingStyle.fill;\n\n\u002F\u002F ✓ With cascade — one expression, fluent configuration:\nvar paint = Paint()\n  ..color = Colors.red\n  ..strokeWidth = 2.0\n  ..style = PaintingStyle.fill;\n\n\u002F\u002F Cascade with methods that return void — the cascade still returns the object:\nvar list = \u003Cint>[]\n  ..add(1)\n  ..add(2)\n  ..add(3);  \u002F\u002F list is [1, 2, 3] — add() returns void, but cascade returns list\n\n\u002F\u002F ❌ Anti-pattern: confusing cascade with method chaining.\n\u002F\u002F list.add(1).add(2)  \u002F\u002F ✗ add() returns void, can't chain with `.`\n\n\u002F\u002F Null-aware cascade (`?..`) — cascades only if non-null:\nPaint? maybePaint;\nmaybePaint?..color = Colors.red..strokeWidth = 2.0;\n\u002F\u002F If maybePaint is null, the entire cascade is a no-op (no null error).\n",[29,1505,1506,1511,1516,1520,1525,1540,1553,1565,1578,1582,1587,1600,1612,1622,1633,1637,1642,1660,1676,1689,1705,1709,1714,1722,1726,1731,1741,1764],{"__ignoreMap":27},[32,1507,1508],{"class":34,"line":35},[32,1509,1510],{"class":38},"\u002F\u002F `..` returns the LEFT-HAND object (not the method result), enabling fluent chains.\n",[32,1512,1513],{"class":34,"line":42},[32,1514,1515],{"class":38},"\u002F\u002F Contrast with `.` which returns the method's return value.\n",[32,1517,1518],{"class":34,"line":48},[32,1519,113],{"emptyLinePlaceholder":112},[32,1521,1522],{"class":34,"line":91},[32,1523,1524],{"class":38},"\u002F\u002F ❌ Without cascade — verbose, repeated variable name:\n",[32,1526,1527,1530,1533,1535,1538],{"class":34,"line":97},[32,1528,1529],{"class":55},"var",[32,1531,1532],{"class":59}," paint ",[32,1534,63],{"class":55},[32,1536,1537],{"class":51}," Paint",[32,1539,88],{"class":59},[32,1541,1542,1545,1547,1550],{"class":34,"line":103},[32,1543,1544],{"class":59},"paint.color ",[32,1546,63],{"class":55},[32,1548,1549],{"class":51}," Colors",[32,1551,1552],{"class":59},".red;\n",[32,1554,1555,1558,1560,1563],{"class":34,"line":109},[32,1556,1557],{"class":59},"paint.strokeWidth ",[32,1559,63],{"class":55},[32,1561,1562],{"class":51}," 2.0",[32,1564,239],{"class":59},[32,1566,1567,1570,1572,1575],{"class":34,"line":116},[32,1568,1569],{"class":59},"paint.style ",[32,1571,63],{"class":55},[32,1573,1574],{"class":51}," PaintingStyle",[32,1576,1577],{"class":59},".fill;\n",[32,1579,1580],{"class":34,"line":122},[32,1581,113],{"emptyLinePlaceholder":112},[32,1583,1584],{"class":34,"line":147},[32,1585,1586],{"class":38},"\u002F\u002F ✓ With cascade — one expression, fluent configuration:\n",[32,1588,1589,1591,1593,1595,1597],{"class":34,"line":180},[32,1590,1529],{"class":55},[32,1592,1532],{"class":59},[32,1594,63],{"class":55},[32,1596,1537],{"class":51},[32,1598,1599],{"class":59},"()\n",[32,1601,1602,1605,1607,1609],{"class":34,"line":204},[32,1603,1604],{"class":59},"  ..color ",[32,1606,63],{"class":55},[32,1608,1549],{"class":51},[32,1610,1611],{"class":59},".red\n",[32,1613,1614,1617,1619],{"class":34,"line":209},[32,1615,1616],{"class":59},"  ..strokeWidth ",[32,1618,63],{"class":55},[32,1620,1621],{"class":51}," 2.0\n",[32,1623,1624,1627,1629,1631],{"class":34,"line":215},[32,1625,1626],{"class":59},"  ..style ",[32,1628,63],{"class":55},[32,1630,1574],{"class":51},[32,1632,1577],{"class":59},[32,1634,1635],{"class":34,"line":242},[32,1636,113],{"emptyLinePlaceholder":112},[32,1638,1639],{"class":34,"line":268},[32,1640,1641],{"class":38},"\u002F\u002F Cascade with methods that return void — the cascade still returns the object:\n",[32,1643,1644,1646,1649,1651,1653,1655,1657],{"class":34,"line":273},[32,1645,1529],{"class":55},[32,1647,1648],{"class":59}," list ",[32,1650,63],{"class":55},[32,1652,133],{"class":55},[32,1654,245],{"class":51},[32,1656,141],{"class":55},[32,1658,1659],{"class":59},"[]\n",[32,1661,1662,1665,1668,1670,1673],{"class":34,"line":279},[32,1663,1664],{"class":59},"  ..",[32,1666,1667],{"class":84},"add",[32,1669,493],{"class":59},[32,1671,1672],{"class":51},"1",[32,1674,1675],{"class":59},")\n",[32,1677,1678,1680,1682,1684,1687],{"class":34,"line":515},[32,1679,1664],{"class":59},[32,1681,1667],{"class":84},[32,1683,493],{"class":59},[32,1685,1686],{"class":51},"2",[32,1688,1675],{"class":59},[32,1690,1691,1693,1695,1697,1700,1702],{"class":34,"line":521},[32,1692,1664],{"class":59},[32,1694,1667],{"class":84},[32,1696,493],{"class":59},[32,1698,1699],{"class":51},"3",[32,1701,744],{"class":59},[32,1703,1704],{"class":38},"\u002F\u002F list is [1, 2, 3] — add() returns void, but cascade returns list\n",[32,1706,1707],{"class":34,"line":527},[32,1708,113],{"emptyLinePlaceholder":112},[32,1710,1711],{"class":34,"line":544},[32,1712,1713],{"class":38},"\u002F\u002F ❌ Anti-pattern: confusing cascade with method chaining.\n",[32,1715,1716,1719],{"class":34,"line":570},[32,1717,1718],{"class":38},"\u002F\u002F list.add(1).add(2)",[32,1720,1721],{"class":38},"  \u002F\u002F ✗ add() returns void, can't chain with `.`\n",[32,1723,1724],{"class":34,"line":581},[32,1725,113],{"emptyLinePlaceholder":112},[32,1727,1728],{"class":34,"line":587},[32,1729,1730],{"class":38},"\u002F\u002F Null-aware cascade (`?..`) — cascades only if non-null:\n",[32,1732,1733,1736,1738],{"class":34,"line":613},[32,1734,1735],{"class":51},"Paint",[32,1737,56],{"class":55},[32,1739,1740],{"class":59}," maybePaint;\n",[32,1742,1743,1746,1748,1751,1753,1755,1758,1760,1762],{"class":34,"line":618},[32,1744,1745],{"class":59},"maybePaint",[32,1747,56],{"class":55},[32,1749,1750],{"class":59},"..color ",[32,1752,63],{"class":55},[32,1754,1549],{"class":51},[32,1756,1757],{"class":59},".red..strokeWidth ",[32,1759,63],{"class":55},[32,1761,1562],{"class":51},[32,1763,239],{"class":59},[32,1765,1766],{"class":34,"line":623},[32,1767,1768],{"class":38},"\u002F\u002F If maybePaint is null, the entire cascade is a no-op (no null error).\n",[14,1770,1772],{"id":1771},"equality-identity-collection-semantics","Equality & Identity — Collection Semantics",[19,1774,1775],{"language":21},[23,1776,1778],{"className":25,"code":1777,"language":21,"meta":27,"style":27},"\u002F\u002F `==` for built-in collections is IDENTITY (same instance), not value equality.\nprint([1, 2] == [1, 2]);  \u002F\u002F false — different instances\nprint({'a': 1} == {'a': 1});  \u002F\u002F false\nprint({1, 2} == {1, 2});  \u002F\u002F false\n\n\u002F\u002F ❌ Anti-pattern: using `==` to compare collections.\nbool isSame(List\u003Cint> a, List\u003Cint> b) => a == b;  \u002F\u002F almost always false\n\n\u002F\u002F ✓ Correct: use listEquals (Flutter) or DeepCollectionEquality (collection package).\nimport 'package:flutter\u002Ffoundation.dart';\nprint(listEquals([1, 2], [1, 2]));  \u002F\u002F true\n\nimport 'package:collection\u002Fcollection.dart';\nconst eq = DeepCollectionEquality();\nprint(eq.equals([1, 2], [1, 2]));  \u002F\u002F true\nprint(eq.equals({'a': 1}, {'a': 1}));  \u002F\u002F true\n\n\u002F\u002F For your own classes, override == and hashCode together (consistency required):\nclass Point {\n  final double x, y;\n  const Point(this.x, this.y);\n\n  @override\n  bool operator ==(Object other) =>\n      other is Point && x == other.x && y == other.y;\n\n  @override\n  int get hashCode => Object.hash(x, y);  \u002F\u002F consistent with ==\n}\n\u002F\u002F Equal objects MUST have equal hashes (HashMap\u002FSet contract).\n",[29,1779,1780,1785,1821,1856,1884,1888,1893,1935,1939,1944,1954,1986,1990,1999,2014,2044,2074,2078,2083,2092,2102,2121,2125,2129,2150,2182,2186,2190,2217,2221],{"__ignoreMap":27},[32,1781,1782],{"class":34,"line":35},[32,1783,1784],{"class":38},"\u002F\u002F `==` for built-in collections is IDENTITY (same instance), not value equality.\n",[32,1786,1787,1790,1793,1795,1798,1800,1803,1806,1809,1811,1813,1815,1818],{"class":34,"line":42},[32,1788,1789],{"class":84},"print",[32,1791,1792],{"class":59},"([",[32,1794,1672],{"class":51},[32,1796,1797],{"class":59},", ",[32,1799,1686],{"class":51},[32,1801,1802],{"class":59},"] ",[32,1804,1805],{"class":55},"==",[32,1807,1808],{"class":59}," [",[32,1810,1672],{"class":51},[32,1812,1797],{"class":59},[32,1814,1686],{"class":51},[32,1816,1817],{"class":59},"]);  ",[32,1819,1820],{"class":38},"\u002F\u002F false — different instances\n",[32,1822,1823,1825,1827,1830,1833,1836,1839,1841,1844,1846,1848,1850,1853],{"class":34,"line":48},[32,1824,1789],{"class":84},[32,1826,552],{"class":59},[32,1828,1829],{"class":235},"'a'",[32,1831,1832],{"class":55},":",[32,1834,1835],{"class":51}," 1",[32,1837,1838],{"class":59},"} ",[32,1840,1805],{"class":55},[32,1842,1843],{"class":59}," {",[32,1845,1829],{"class":235},[32,1847,1832],{"class":55},[32,1849,1835],{"class":51},[32,1851,1852],{"class":59},"});  ",[32,1854,1855],{"class":38},"\u002F\u002F false\n",[32,1857,1858,1860,1862,1864,1866,1868,1870,1872,1874,1876,1878,1880,1882],{"class":34,"line":91},[32,1859,1789],{"class":84},[32,1861,552],{"class":59},[32,1863,1672],{"class":51},[32,1865,1797],{"class":59},[32,1867,1686],{"class":51},[32,1869,1838],{"class":59},[32,1871,1805],{"class":55},[32,1873,1843],{"class":59},[32,1875,1672],{"class":51},[32,1877,1797],{"class":59},[32,1879,1686],{"class":51},[32,1881,1852],{"class":59},[32,1883,1855],{"class":38},[32,1885,1886],{"class":34,"line":97},[32,1887,113],{"emptyLinePlaceholder":112},[32,1889,1890],{"class":34,"line":103},[32,1891,1892],{"class":38},"\u002F\u002F ❌ Anti-pattern: using `==` to compare collections.\n",[32,1894,1895,1898,1901,1903,1906,1908,1910,1913,1915,1917,1919,1922,1924,1927,1929,1932],{"class":34,"line":109},[32,1896,1897],{"class":51},"bool",[32,1899,1900],{"class":84}," isSame",[32,1902,493],{"class":59},[32,1904,1905],{"class":51},"List",[32,1907,156],{"class":59},[32,1909,245],{"class":51},[32,1911,1912],{"class":59},"> a, ",[32,1914,1905],{"class":51},[32,1916,156],{"class":59},[32,1918,245],{"class":51},[32,1920,1921],{"class":59},"> b) ",[32,1923,349],{"class":55},[32,1925,1926],{"class":59}," a ",[32,1928,1805],{"class":55},[32,1930,1931],{"class":59}," b;  ",[32,1933,1934],{"class":38},"\u002F\u002F almost always false\n",[32,1936,1937],{"class":34,"line":116},[32,1938,113],{"emptyLinePlaceholder":112},[32,1940,1941],{"class":34,"line":122},[32,1942,1943],{"class":38},"\u002F\u002F ✓ Correct: use listEquals (Flutter) or DeepCollectionEquality (collection package).\n",[32,1945,1946,1949,1952],{"class":34,"line":147},[32,1947,1948],{"class":55},"import",[32,1950,1951],{"class":235}," 'package:flutter\u002Ffoundation.dart'",[32,1953,239],{"class":59},[32,1955,1956,1958,1960,1963,1965,1967,1969,1971,1974,1976,1978,1980,1983],{"class":34,"line":180},[32,1957,1789],{"class":84},[32,1959,493],{"class":59},[32,1961,1962],{"class":84},"listEquals",[32,1964,1792],{"class":59},[32,1966,1672],{"class":51},[32,1968,1797],{"class":59},[32,1970,1686],{"class":51},[32,1972,1973],{"class":59},"], [",[32,1975,1672],{"class":51},[32,1977,1797],{"class":59},[32,1979,1686],{"class":51},[32,1981,1982],{"class":59},"]));  ",[32,1984,1985],{"class":38},"\u002F\u002F true\n",[32,1987,1988],{"class":34,"line":204},[32,1989,113],{"emptyLinePlaceholder":112},[32,1991,1992,1994,1997],{"class":34,"line":209},[32,1993,1948],{"class":55},[32,1995,1996],{"class":235}," 'package:collection\u002Fcollection.dart'",[32,1998,239],{"class":59},[32,2000,2001,2004,2007,2009,2012],{"class":34,"line":215},[32,2002,2003],{"class":55},"const",[32,2005,2006],{"class":59}," eq ",[32,2008,63],{"class":55},[32,2010,2011],{"class":51}," DeepCollectionEquality",[32,2013,88],{"class":59},[32,2015,2016,2018,2021,2024,2026,2028,2030,2032,2034,2036,2038,2040,2042],{"class":34,"line":242},[32,2017,1789],{"class":84},[32,2019,2020],{"class":59},"(eq.",[32,2022,2023],{"class":84},"equals",[32,2025,1792],{"class":59},[32,2027,1672],{"class":51},[32,2029,1797],{"class":59},[32,2031,1686],{"class":51},[32,2033,1973],{"class":59},[32,2035,1672],{"class":51},[32,2037,1797],{"class":59},[32,2039,1686],{"class":51},[32,2041,1982],{"class":59},[32,2043,1985],{"class":38},[32,2045,2046,2048,2050,2052,2054,2056,2058,2060,2063,2065,2067,2069,2072],{"class":34,"line":268},[32,2047,1789],{"class":84},[32,2049,2020],{"class":59},[32,2051,2023],{"class":84},[32,2053,552],{"class":59},[32,2055,1829],{"class":235},[32,2057,1832],{"class":55},[32,2059,1835],{"class":51},[32,2061,2062],{"class":59},"}, {",[32,2064,1829],{"class":235},[32,2066,1832],{"class":55},[32,2068,1835],{"class":51},[32,2070,2071],{"class":59},"}));  ",[32,2073,1985],{"class":38},[32,2075,2076],{"class":34,"line":273},[32,2077,113],{"emptyLinePlaceholder":112},[32,2079,2080],{"class":34,"line":279},[32,2081,2082],{"class":38},"\u002F\u002F For your own classes, override == and hashCode together (consistency required):\n",[32,2084,2085,2087,2090],{"class":34,"line":515},[32,2086,530],{"class":55},[32,2088,2089],{"class":51}," Point",[32,2091,486],{"class":59},[32,2093,2094,2096,2099],{"class":34,"line":521},[32,2095,440],{"class":55},[32,2097,2098],{"class":51}," double",[32,2100,2101],{"class":59}," x, y;\n",[32,2103,2104,2106,2108,2110,2113,2116,2118],{"class":34,"line":527},[32,2105,547],{"class":55},[32,2107,2089],{"class":51},[32,2109,493],{"class":59},[32,2111,2112],{"class":51},"this",[32,2114,2115],{"class":59},".x, ",[32,2117,2112],{"class":51},[32,2119,2120],{"class":59},".y);\n",[32,2122,2123],{"class":34,"line":544},[32,2124,113],{"emptyLinePlaceholder":112},[32,2126,2127],{"class":34,"line":570},[32,2128,584],{"class":55},[32,2130,2131,2134,2137,2140,2142,2145,2148],{"class":34,"line":581},[32,2132,2133],{"class":51},"  bool",[32,2135,2136],{"class":55}," operator",[32,2138,2139],{"class":55}," ==",[32,2141,493],{"class":59},[32,2143,2144],{"class":51},"Object",[32,2146,2147],{"class":59}," other) ",[32,2149,177],{"class":55},[32,2151,2152,2155,2158,2160,2163,2166,2168,2171,2174,2177,2179],{"class":34,"line":587},[32,2153,2154],{"class":59},"      other ",[32,2156,2157],{"class":55},"is",[32,2159,2089],{"class":51},[32,2161,2162],{"class":55}," &&",[32,2164,2165],{"class":59}," x ",[32,2167,1805],{"class":55},[32,2169,2170],{"class":59}," other.x ",[32,2172,2173],{"class":55},"&&",[32,2175,2176],{"class":59}," y ",[32,2178,1805],{"class":55},[32,2180,2181],{"class":59}," other.y;\n",[32,2183,2184],{"class":34,"line":613},[32,2185,113],{"emptyLinePlaceholder":112},[32,2187,2188],{"class":34,"line":618},[32,2189,584],{"class":55},[32,2191,2192,2195,2198,2201,2203,2206,2208,2211,2214],{"class":34,"line":623},[32,2193,2194],{"class":51},"  int",[32,2196,2197],{"class":55}," get",[32,2199,2200],{"class":59}," hashCode ",[32,2202,349],{"class":55},[32,2204,2205],{"class":51}," Object",[32,2207,81],{"class":59},[32,2209,2210],{"class":84},"hash",[32,2212,2213],{"class":59},"(x, y);  ",[32,2215,2216],{"class":38},"\u002F\u002F consistent with ==\n",[32,2218,2219],{"class":34,"line":642},[32,2220,417],{"class":59},[32,2222,2223],{"class":34,"line":657},[32,2224,2225],{"class":38},"\u002F\u002F Equal objects MUST have equal hashes (HashMap\u002FSet contract).\n",[14,2227,2229],{"id":2228},"overflow-bitwise-native-vs-web","Overflow & Bitwise — Native vs Web",[19,2231,2232],{"language":21},[23,2233,2235],{"className":25,"code":2234,"language":21,"meta":27,"style":27},"\u002F\u002F Native (VM\u002FAOT): int is 64-bit signed, overflow wraps silently (two's complement).\n\u002F\u002F No exception, no warning — the value just wraps.\nint max = 9223372036854775807;  \u002F\u002F 2^63 - 1\nprint(max + 1);  \u002F\u002F -9223372036854775808 (wrapped to min int64)\n\n\u002F\u002F Web: int is a JS double — no wrap, but precision loss above 2^53.\nprint(1 \u003C\u003C 62);  \u002F\u002F native: 4611686018427387904 | web: 4611686018427388000 (rounded)\n\n\u002F\u002F Bitwise operators on int:\nprint(0b1100 & 0b1010);  \u002F\u002F 8  (1000 — AND)\nprint(0b1100 | 0b1010);  \u002F\u002F 14 (1110 — OR)\nprint(0b1100 ^ 0b1010);  \u002F\u002F 6  (0110 — XOR)\nprint(~0b1100);          \u002F\u002F -13 (bitwise NOT — two's complement)\nprint(1 \u003C\u003C 60);          \u002F\u002F native: 1152921504606846976 | web: 1152921504606847000\n\n\u002F\u002F >>>= (unsigned right shift) — Dart 3+ for logical shift (fills with zeros):\nint v = -1;  \u002F\u002F all bits set (0xFFFFFFFFFFFFFFFF on 64-bit)\nprint(v >> 1);   \u002F\u002F -1 (arithmetic shift — sign bit preserved)\nprint(v >>> 1);  \u002F\u002F 9223372036854775807 (logical shift — zeros fill from left)\n",[29,2236,2237,2242,2247,2264,2281,2285,2290,2309,2313,2318,2334,2348,2362,2377,2396,2400,2405,2424,2442],{"__ignoreMap":27},[32,2238,2239],{"class":34,"line":35},[32,2240,2241],{"class":38},"\u002F\u002F Native (VM\u002FAOT): int is 64-bit signed, overflow wraps silently (two's complement).\n",[32,2243,2244],{"class":34,"line":42},[32,2245,2246],{"class":38},"\u002F\u002F No exception, no warning — the value just wraps.\n",[32,2248,2249,2251,2254,2256,2259,2261],{"class":34,"line":48},[32,2250,245],{"class":51},[32,2252,2253],{"class":59}," max ",[32,2255,63],{"class":55},[32,2257,2258],{"class":51}," 9223372036854775807",[32,2260,198],{"class":59},[32,2262,2263],{"class":38},"\u002F\u002F 2^63 - 1\n",[32,2265,2266,2268,2271,2274,2276,2278],{"class":34,"line":91},[32,2267,1789],{"class":84},[32,2269,2270],{"class":59},"(max ",[32,2272,2273],{"class":55},"+",[32,2275,1835],{"class":51},[32,2277,744],{"class":59},[32,2279,2280],{"class":38},"\u002F\u002F -9223372036854775808 (wrapped to min int64)\n",[32,2282,2283],{"class":34,"line":97},[32,2284,113],{"emptyLinePlaceholder":112},[32,2286,2287],{"class":34,"line":103},[32,2288,2289],{"class":38},"\u002F\u002F Web: int is a JS double — no wrap, but precision loss above 2^53.\n",[32,2291,2292,2294,2296,2298,2301,2304,2306],{"class":34,"line":109},[32,2293,1789],{"class":84},[32,2295,493],{"class":59},[32,2297,1672],{"class":51},[32,2299,2300],{"class":55}," \u003C\u003C",[32,2302,2303],{"class":51}," 62",[32,2305,744],{"class":59},[32,2307,2308],{"class":38},"\u002F\u002F native: 4611686018427387904 | web: 4611686018427388000 (rounded)\n",[32,2310,2311],{"class":34,"line":116},[32,2312,113],{"emptyLinePlaceholder":112},[32,2314,2315],{"class":34,"line":122},[32,2316,2317],{"class":38},"\u002F\u002F Bitwise operators on int:\n",[32,2319,2320,2322,2325,2328,2331],{"class":34,"line":147},[32,2321,1789],{"class":84},[32,2323,2324],{"class":59},"(0b1100 ",[32,2326,2327],{"class":55},"&",[32,2329,2330],{"class":59}," 0b1010);  ",[32,2332,2333],{"class":38},"\u002F\u002F 8  (1000 — AND)\n",[32,2335,2336,2338,2340,2343,2345],{"class":34,"line":180},[32,2337,1789],{"class":84},[32,2339,2324],{"class":59},[32,2341,2342],{"class":55},"|",[32,2344,2330],{"class":59},[32,2346,2347],{"class":38},"\u002F\u002F 14 (1110 — OR)\n",[32,2349,2350,2352,2354,2357,2359],{"class":34,"line":204},[32,2351,1789],{"class":84},[32,2353,2324],{"class":59},[32,2355,2356],{"class":55},"^",[32,2358,2330],{"class":59},[32,2360,2361],{"class":38},"\u002F\u002F 6  (0110 — XOR)\n",[32,2363,2364,2366,2368,2371,2374],{"class":34,"line":209},[32,2365,1789],{"class":84},[32,2367,493],{"class":59},[32,2369,2370],{"class":55},"~",[32,2372,2373],{"class":59},"0b1100);          ",[32,2375,2376],{"class":38},"\u002F\u002F -13 (bitwise NOT — two's complement)\n",[32,2378,2379,2381,2383,2385,2387,2390,2393],{"class":34,"line":215},[32,2380,1789],{"class":84},[32,2382,493],{"class":59},[32,2384,1672],{"class":51},[32,2386,2300],{"class":55},[32,2388,2389],{"class":51}," 60",[32,2391,2392],{"class":59},");          ",[32,2394,2395],{"class":38},"\u002F\u002F native: 1152921504606846976 | web: 1152921504606847000\n",[32,2397,2398],{"class":34,"line":242},[32,2399,113],{"emptyLinePlaceholder":112},[32,2401,2402],{"class":34,"line":268},[32,2403,2404],{"class":38},"\u002F\u002F >>>= (unsigned right shift) — Dart 3+ for logical shift (fills with zeros):\n",[32,2406,2407,2409,2412,2414,2417,2419,2421],{"class":34,"line":273},[32,2408,245],{"class":51},[32,2410,2411],{"class":59}," v ",[32,2413,63],{"class":55},[32,2415,2416],{"class":55}," -",[32,2418,1672],{"class":51},[32,2420,198],{"class":59},[32,2422,2423],{"class":38},"\u002F\u002F all bits set (0xFFFFFFFFFFFFFFFF on 64-bit)\n",[32,2425,2426,2428,2431,2434,2436,2439],{"class":34,"line":279},[32,2427,1789],{"class":84},[32,2429,2430],{"class":59},"(v ",[32,2432,2433],{"class":55},">>",[32,2435,1835],{"class":51},[32,2437,2438],{"class":59},");   ",[32,2440,2441],{"class":38},"\u002F\u002F -1 (arithmetic shift — sign bit preserved)\n",[32,2443,2444,2446,2448,2451,2453,2455],{"class":34,"line":515},[32,2445,1789],{"class":84},[32,2447,2430],{"class":59},[32,2449,2450],{"class":55},">>>",[32,2452,1835],{"class":51},[32,2454,744],{"class":59},[32,2456,2457],{"class":38},"\u002F\u002F 9223372036854775807 (logical shift — zeros fill from left)\n",[14,2459,2461],{"id":2460},"tips-tricks","💡 Tips & Tricks",[2463,2464,2465,2484,2503,2520,2532],"ul",{},[2466,2467,2468,733,2472,2475,2476,2479,2480,2483],"li",{},[2469,2470,2471],"strong",{},"Idiom",[29,2473,2474],{},"??="," for lazy memoization — ",[29,2477,2478],{},"cache[key] ??= compute(key)"," runs ",[29,2481,2482],{},"compute"," only on a cache miss. The right side is evaluated only if the left is null. Zero-overhead if cached.",[2466,2485,2486,733,2488,2491,2492,2495,2496,2499,2500,81],{},[2469,2487,2471],{},[29,2489,2490],{},"?."," chains for deep null navigation — ",[29,2493,2494],{},"user?.address?.city"," short-circuits at the first null, no nested ",[29,2497,2498],{},"if"," checks. Returns nullable type; follow with ",[29,2501,2502],{},"?? default",[2466,2504,2505,733,2508,2511,2512,2515,2516,2519],{},[2469,2506,2507],{},"Performance",[29,2509,2510],{},"~\u002F"," for integer division is a single VM op — ",[29,2513,2514],{},"(a \u002F b).toInt()"," does float division then truncation (two ops, potential precision loss on web). Prefer ",[29,2517,2518],{},"~\u002F%"," for integer math.",[2466,2521,2522,2524,2525,2527,2528,2531],{},[2469,2523,2471],{},": cascade (",[29,2526,1497],{},") for fluent object setup — ",[29,2529,2530],{},"Paint()..color = red..strokeWidth = 2"," is one expression. Use for configuring objects with many setters (Paint, TextStyle, TextEditingController).",[2466,2533,2534,733,2537,2540,2541,2544,2545,2548,2549,2552,2553,2555,2556,2558],{},[2469,2535,2536],{},"Debug",[29,2538,2539],{},"identical(a, b)"," checks reference equality (same object in memory). ",[29,2542,2543],{},"a == b"," checks value equality (calls ",[29,2546,2547],{},"operator ==","). Use ",[29,2550,2551],{},"identical"," to verify ",[29,2554,2003],{}," canonicalization; use ",[29,2557,1805],{}," for domain equality.",[14,2560,2562],{"id":2561},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2463,2564,2565,2594,2613,2645,2660,2675,2695,2716,2733,2751],{},[2466,2566,2567,733,2576,2579,2580,2583,2584,2586,2587,2589,2590,2593],{},[2469,2568,2569,2572,2573],{},[29,2570,2571],{},"\u002F"," always returns ",[29,2574,2575],{},"double",[29,2577,2578],{},"4 \u002F 2"," is ",[29,2581,2582],{},"2.0"," (double), not ",[29,2585,1686],{}," (int). Use ",[29,2588,2510],{}," for integer division. Assigning ",[29,2591,2592],{},"int x = 4 \u002F 2"," is a compile error (type mismatch).",[2466,2595,2596,733,2602,2605,2606,2608,2609,2612],{},[2469,2597,2598,2601],{},[29,2599,2600],{},"%"," follows the dividend's sign",[29,2603,2604],{},"-7 % 3 = -1"," (Dart\u002FC\u002FJava), not ",[29,2607,1686],{}," (Python\u002Fmathematical modulo). Use ",[29,2610,2611],{},"((a % n) + n) % n"," for non-negative modulo.",[2466,2614,2615,733,2623,2626,2627,2630,2631,2634,2635,2638,2639,2641,2642,2644],{},[2469,2616,2617,2619,2620,2622],{},[29,2618,2157],{}," promotes, ",[29,2621,192],{}," throws",[29,2624,2625],{},"if (x is String) { x.length }"," promotes safely. ",[29,2628,2629],{},"x as String"," throws ",[29,2632,2633],{},"TypeError"," if ",[29,2636,2637],{},"x"," isn't a String. Use ",[29,2640,2157],{}," for checks, ",[29,2643,192],{}," only when certain.",[2466,2646,2647,733,2650,2653,2654,2656,2657,81],{},[2469,2648,2649],{},"Type promotion doesn't apply to fields",[29,2651,2652],{},"if (this.x != null) { x.length }"," — ",[29,2655,2637],{}," is still nullable. Copy to a local: ",[29,2658,2659],{},"final x = this.x; if (x != null) { x.length; }",[2466,2661,2662,2668,2669,2671,2672,81],{},[2469,2663,2664,2665],{},"Promotion is invalidated after ",[29,2666,2667],{},"await",": a nullable local checked before ",[29,2670,2667],{}," is not promoted after. Snapshot it: ",[29,2673,2674],{},"final captured = x; if (captured != null) { await ...; captured.length; }",[2466,2676,2677,733,2682,2579,2685,2688,2689,1797,2691,2694],{},[2469,2678,2679,2681],{},[29,2680,1805],{}," for collections is identity",[29,2683,2684],{},"[1,2] == [1,2]",[29,2686,2687],{},"false",". Use ",[29,2690,1962],{},[29,2692,2693],{},"DeepCollectionEquality",", or records (which have structural equality).",[2466,2696,2697,733,2704,2707,2708,1797,2711,2713,2714,81],{},[2469,2698,2699,2630,2701,2703],{},[29,2700,321],{},[29,2702,2633],{}," at runtime",[29,2705,2706],{},"null!"," crashes. It defeats null safety — use only on framework invariants. Prefer ",[29,2709,2710],{},"if (x != null)",[29,2712,232],{},", or ",[29,2715,2490],{},[2466,2717,2718,733,2721,2724,2725,2728,2729,2732],{},[2469,2719,2720],{},"Integer overflow wraps silently on native",[29,2722,2723],{},"9223372036854775807 + 1"," wraps to ",[29,2726,2727],{},"minInt64",". No exception. Use ",[29,2730,2731],{},"BigInt"," for overflow-safe arithmetic.",[2466,2734,2735,733,2740,2743,2744,2747,2748,2750],{},[2469,2736,2737,2739],{},[29,2738,245],{}," on web loses precision above 2^53",[29,2741,2742],{},"int.parse('9007199254740993')"," gives ",[29,2745,2746],{},"9007199254740992"," on web (double rounding). Use ",[29,2749,2731],{}," for exact large integers.",[2466,2752,2753,733,2758,2761,2762,2765],{},[2469,2754,2755,2757],{},[29,2756,2370],{}," (bitwise NOT) on a positive int gives a negative int",[29,2759,2760],{},"~5 = -6"," (two's complement). ",[29,2763,2764],{},"~0 = -1",". This is standard two's complement behavior, not a bug.",[14,2767,2769],{"id":2768},"spot-the-bug","🧠 Spot the Bug",[2771,2772,2773],"p",{},"A developer checks a nullable field for null, then uses it inside a closure, but the compiler rejects it:",[19,2775,2776],{"language":21},[23,2777,2779],{"className":25,"code":2778,"language":21,"meta":27,"style":27},"class Cache {\n  String? _value;\n\n  void process() {\n    if (_value != null) {\n      Future(() {\n        print(_value.length);  \u002F\u002F ✗ compile error: _value is String?\n      });\n    }\n  }\n}\n",[29,2780,2781,2790,2799,2803,2812,2825,2833,2844,2849,2853,2857],{"__ignoreMap":27},[32,2782,2783,2785,2788],{"class":34,"line":35},[32,2784,530],{"class":55},[32,2786,2787],{"class":51}," Cache",[32,2789,486],{"class":59},[32,2791,2792,2794,2796],{"class":34,"line":42},[32,2793,387],{"class":51},[32,2795,56],{"class":55},[32,2797,2798],{"class":59}," _value;\n",[32,2800,2801],{"class":34,"line":48},[32,2802,113],{"emptyLinePlaceholder":112},[32,2804,2805,2807,2810],{"class":34,"line":91},[32,2806,670],{"class":55},[32,2808,2809],{"class":84}," process",[32,2811,382],{"class":59},[32,2813,2814,2816,2819,2821,2823],{"class":34,"line":97},[32,2815,942],{"class":55},[32,2817,2818],{"class":59}," (_value ",[32,2820,459],{"class":55},[32,2822,365],{"class":51},[32,2824,464],{"class":59},[32,2826,2827,2830],{"class":34,"line":103},[32,2828,2829],{"class":51},"      Future",[32,2831,2832],{"class":59},"(() {\n",[32,2834,2835,2838,2841],{"class":34,"line":109},[32,2836,2837],{"class":84},"        print",[32,2839,2840],{"class":59},"(_value.length);  ",[32,2842,2843],{"class":38},"\u002F\u002F ✗ compile error: _value is String?\n",[32,2845,2846],{"class":34,"line":116},[32,2847,2848],{"class":59},"      });\n",[32,2850,2851],{"class":34,"line":122},[32,2852,974],{"class":59},[32,2854,2855],{"class":34,"line":147},[32,2856,504],{"class":59},[32,2858,2859],{"class":34,"line":180},[32,2860,417],{"class":59},[2771,2862,2863],{},"Two problems — what are they?",[2865,2866,2867,2871,2903,2906,2999],"details",{},[2868,2869,2870],"summary",{},"Answer",[2872,2873,2874,2890],"ol",{},[2466,2875,2876,733,2879,2882,2883,2886,2887,2889],{},[2469,2877,2878],{},"Fields don't promote",[29,2880,2881],{},"if (_value != null)"," does not promote ",[29,2884,2885],{},"_value"," to ",[29,2888,52],{}," because it's a class field — the compiler can't guarantee it won't be mutated between the check and the use.",[2466,2891,2892,2895,2896,2899,2900,2902],{},[2469,2893,2894],{},"Closure + async gap",": even if promotion worked for fields, it doesn't cross into the ",[29,2897,2898],{},"Future(() { ... })"," closure. The closure executes asynchronously, and ",[29,2901,2885],{}," could be null by then.",[2771,2904,2905],{},"The fix — snapshot to a final local, then use the local inside the closure:",[23,2907,2909],{"className":25,"code":2908,"language":21,"meta":27,"style":27},"class Cache {\n  String? _value;\n\n  void process() {\n    final value = _value;  \u002F\u002F immutable local snapshot\n    if (value != null) {\n      Future(() {\n        print(value.length);  \u002F\u002F ✓ value is promoted to String (final local, no async mutation)\n      });\n    }\n  }\n}\n",[29,2910,2911,2919,2927,2931,2939,2954,2967,2973,2983,2987,2991,2995],{"__ignoreMap":27},[32,2912,2913,2915,2917],{"class":34,"line":35},[32,2914,530],{"class":55},[32,2916,2787],{"class":51},[32,2918,486],{"class":59},[32,2920,2921,2923,2925],{"class":34,"line":42},[32,2922,387],{"class":51},[32,2924,56],{"class":55},[32,2926,2798],{"class":59},[32,2928,2929],{"class":34,"line":48},[32,2930,113],{"emptyLinePlaceholder":112},[32,2932,2933,2935,2937],{"class":34,"line":91},[32,2934,670],{"class":55},[32,2936,2809],{"class":84},[32,2938,382],{"class":59},[32,2940,2941,2943,2946,2948,2951],{"class":34,"line":97},[32,2942,1025],{"class":55},[32,2944,2945],{"class":59}," value ",[32,2947,63],{"class":55},[32,2949,2950],{"class":59}," _value;  ",[32,2952,2953],{"class":38},"\u002F\u002F immutable local snapshot\n",[32,2955,2956,2958,2961,2963,2965],{"class":34,"line":103},[32,2957,942],{"class":55},[32,2959,2960],{"class":59}," (value ",[32,2962,459],{"class":55},[32,2964,365],{"class":51},[32,2966,464],{"class":59},[32,2968,2969,2971],{"class":34,"line":109},[32,2970,2829],{"class":51},[32,2972,2832],{"class":59},[32,2974,2975,2977,2980],{"class":34,"line":116},[32,2976,2837],{"class":84},[32,2978,2979],{"class":59},"(value.length);  ",[32,2981,2982],{"class":38},"\u002F\u002F ✓ value is promoted to String (final local, no async mutation)\n",[32,2984,2985],{"class":34,"line":122},[32,2986,2848],{"class":59},[32,2988,2989],{"class":34,"line":147},[32,2990,974],{"class":59},[32,2992,2993],{"class":34,"line":180},[32,2994,504],{"class":59},[32,2996,2997],{"class":34,"line":204},[32,2998,417],{"class":59},[2771,3000,3001,3002,2579,3005,3007,3008,81],{},"The local ",[29,3003,3004],{},"value",[29,3006,125],{}," — it can't be reassigned, so the promotion holds inside the closure. The snapshot captures the value at check time, making it immune to concurrent mutation of ",[29,3009,2885],{},[3011,3012,3013],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}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":27,"searchDepth":42,"depth":42,"links":3015},[3016,3020,3021,3023,3024,3025,3026,3027],{"id":16,"depth":42,"text":17,"children":3017},[3018],{"id":318,"depth":48,"text":3019},"! — The Null Assertion Trap",{"id":818,"depth":42,"text":819},{"id":1493,"depth":42,"text":3022},"Cascade (..) — Fluent Configuration",{"id":1771,"depth":42,"text":1772},{"id":2228,"depth":42,"text":2229},{"id":2460,"depth":42,"text":2461},{"id":2561,"depth":42,"text":2562},{"id":2768,"depth":42,"text":2769},"Deep-dive into Dart's operator semantics, null-aware operator chains, type promotion rules across closures and async gaps, cascade mechanics, and overflow behavior. Code-first engineering reference.","md",{},"\u002Fdart\u002F03-operators-and-expressions",{"title":5,"description":3028},"dart\u002F03-operators-and-expressions","lK_fD5eTu9JEYS9p14sqzYQCGhx4PaJVYiYRh5MFddc",1789924647657]