[{"data":1,"prerenderedAt":3430},["ShallowReactive",2],{"page-\u002Fdart\u002F02-variables-and-data-types":3},{"id":4,"title":5,"body":6,"description":3423,"extension":3424,"meta":3425,"navigation":107,"path":3426,"seo":3427,"stem":3428,"__hash__":3429},"content\u002Fdart\u002F02-variables-and-data-types.md","Dart — Variables, Type System & Memory Semantics",{"type":7,"value":8,"toc":3401},"minimark",[9,13,32,340,347,647,656,908,912,925,1147,1151,1390,1394,1771,1784,2036,2040,2371,2375,2656,2660,2746,2750,2979,2983,2989,3157,3160,3397],[10,11,5],"h1",{"id":12},"dart-variables-type-system-memory-semantics",[14,15,17,21,22,21,25,21,28,31],"h2",{"id":16},"var-final-const-late-allocation-canonicalization",[18,19,20],"code",{},"var"," \u002F ",[18,23,24],{},"final",[18,26,27],{},"const",[18,29,30],{},"late"," — Allocation & Canonicalization",[33,34,36],"code-wrapper",{"language":35},"dart",[37,38,42],"pre",{"className":39,"code":40,"language":35,"meta":41,"style":41},"language-dart shiki shiki-themes github-light github-dark","\u002F\u002F ── var: type inferred at compile time, mutable reference ──\nvar count = 0;           \u002F\u002F inferred as int — the TYPE is fixed, the VALUE is mutable\ncount = 42;              \u002F\u002F ✓ same type, reassignment OK\n\u002F\u002F count = 'hi';         \u002F\u002F ✗ compile error: int expected — inference is not dynamic\n\n\u002F\u002F ── final: single-assignment, value computed at RUNTIME ──\nfinal now = DateTime.now();  \u002F\u002F ✓ evaluated at construction, locked thereafter\n\u002F\u002F now = DateTime.now();     \u002F\u002F ✗ throws: late initialization already happened\n\n\u002F\u002F ── const: compile-time constant, CANONICALIZED across the program ──\nconst pi = 3.14159;          \u002F\u002F the compiler interns this — identical const expressions\nconst pi2 = 3.14159;         \u002F\u002F are the SAME object in memory (identical(pi, pi2) == true)\nconst list = [1, 2, 3];      \u002F\u002F deeply immutable, canonicalized — same instance everywhere\n\u002F\u002F list.add(4);               \u002F\u002F ✗ UnsupportedError: const lists are immutable\n\n\u002F\u002F ── late: non-nullable, assigned before first read, or lazy initializer ──\nlate final String config = _loadConfig();  \u002F\u002F _loadConfig() runs ONLY on first read\n\u002F\u002F Reading `config` before assignment throws LateInitializationError.\n\u002F\u002F With an initializer (above), it's always safe — runs lazily, caches result.\n\nString _loadConfig() {\n  print('Config loaded');  \u002F\u002F runs once, on first access\n  return 'production';\n}\n","",[18,43,44,53,76,93,102,109,115,141,150,155,161,180,198,231,240,245,251,275,281,287,292,303,322,334],{"__ignoreMap":41},[45,46,49],"span",{"class":47,"line":48},"line",1,[45,50,52],{"class":51},"sdCPZ","\u002F\u002F ── var: type inferred at compile time, mutable reference ──\n",[45,54,56,59,63,66,70,73],{"class":47,"line":55},2,[45,57,20],{"class":58},"svdQ7",[45,60,62],{"class":61},"ssxIu"," count ",[45,64,65],{"class":58},"=",[45,67,69],{"class":68},"snvgF"," 0",[45,71,72],{"class":61},";           ",[45,74,75],{"class":51},"\u002F\u002F inferred as int — the TYPE is fixed, the VALUE is mutable\n",[45,77,79,82,84,87,90],{"class":47,"line":78},3,[45,80,81],{"class":61},"count ",[45,83,65],{"class":58},[45,85,86],{"class":68}," 42",[45,88,89],{"class":61},";              ",[45,91,92],{"class":51},"\u002F\u002F ✓ same type, reassignment OK\n",[45,94,96,99],{"class":47,"line":95},4,[45,97,98],{"class":51},"\u002F\u002F count = 'hi';",[45,100,101],{"class":51},"         \u002F\u002F ✗ compile error: int expected — inference is not dynamic\n",[45,103,105],{"class":47,"line":104},5,[45,106,108],{"emptyLinePlaceholder":107},true,"\n",[45,110,112],{"class":47,"line":111},6,[45,113,114],{"class":51},"\u002F\u002F ── final: single-assignment, value computed at RUNTIME ──\n",[45,116,118,120,123,125,128,131,135,138],{"class":47,"line":117},7,[45,119,24],{"class":58},[45,121,122],{"class":61}," now ",[45,124,65],{"class":58},[45,126,127],{"class":68}," DateTime",[45,129,130],{"class":61},".",[45,132,134],{"class":133},"sIsaT","now",[45,136,137],{"class":61},"();  ",[45,139,140],{"class":51},"\u002F\u002F ✓ evaluated at construction, locked thereafter\n",[45,142,144,147],{"class":47,"line":143},8,[45,145,146],{"class":51},"\u002F\u002F now = DateTime.now();",[45,148,149],{"class":51},"     \u002F\u002F ✗ throws: late initialization already happened\n",[45,151,153],{"class":47,"line":152},9,[45,154,108],{"emptyLinePlaceholder":107},[45,156,158],{"class":47,"line":157},10,[45,159,160],{"class":51},"\u002F\u002F ── const: compile-time constant, CANONICALIZED across the program ──\n",[45,162,164,166,169,171,174,177],{"class":47,"line":163},11,[45,165,27],{"class":58},[45,167,168],{"class":61}," pi ",[45,170,65],{"class":58},[45,172,173],{"class":68}," 3.14159",[45,175,176],{"class":61},";          ",[45,178,179],{"class":51},"\u002F\u002F the compiler interns this — identical const expressions\n",[45,181,183,185,188,190,192,195],{"class":47,"line":182},12,[45,184,27],{"class":58},[45,186,187],{"class":61}," pi2 ",[45,189,65],{"class":58},[45,191,173],{"class":68},[45,193,194],{"class":61},";         ",[45,196,197],{"class":51},"\u002F\u002F are the SAME object in memory (identical(pi, pi2) == true)\n",[45,199,201,203,206,208,211,214,217,220,222,225,228],{"class":47,"line":200},13,[45,202,27],{"class":58},[45,204,205],{"class":61}," list ",[45,207,65],{"class":58},[45,209,210],{"class":61}," [",[45,212,213],{"class":68},"1",[45,215,216],{"class":61},", ",[45,218,219],{"class":68},"2",[45,221,216],{"class":61},[45,223,224],{"class":68},"3",[45,226,227],{"class":61},"];      ",[45,229,230],{"class":51},"\u002F\u002F deeply immutable, canonicalized — same instance everywhere\n",[45,232,234,237],{"class":47,"line":233},14,[45,235,236],{"class":51},"\u002F\u002F list.add(4);",[45,238,239],{"class":51},"               \u002F\u002F ✗ UnsupportedError: const lists are immutable\n",[45,241,243],{"class":47,"line":242},15,[45,244,108],{"emptyLinePlaceholder":107},[45,246,248],{"class":47,"line":247},16,[45,249,250],{"class":51},"\u002F\u002F ── late: non-nullable, assigned before first read, or lazy initializer ──\n",[45,252,254,256,259,262,265,267,270,272],{"class":47,"line":253},17,[45,255,30],{"class":58},[45,257,258],{"class":58}," final",[45,260,261],{"class":68}," String",[45,263,264],{"class":61}," config ",[45,266,65],{"class":58},[45,268,269],{"class":133}," _loadConfig",[45,271,137],{"class":61},[45,273,274],{"class":51},"\u002F\u002F _loadConfig() runs ONLY on first read\n",[45,276,278],{"class":47,"line":277},18,[45,279,280],{"class":51},"\u002F\u002F Reading `config` before assignment throws LateInitializationError.\n",[45,282,284],{"class":47,"line":283},19,[45,285,286],{"class":51},"\u002F\u002F With an initializer (above), it's always safe — runs lazily, caches result.\n",[45,288,290],{"class":47,"line":289},20,[45,291,108],{"emptyLinePlaceholder":107},[45,293,295,298,300],{"class":47,"line":294},21,[45,296,297],{"class":68},"String",[45,299,269],{"class":133},[45,301,302],{"class":61},"() {\n",[45,304,306,309,312,316,319],{"class":47,"line":305},22,[45,307,308],{"class":133},"  print",[45,310,311],{"class":61},"(",[45,313,315],{"class":314},"sJ6F3","'Config loaded'",[45,317,318],{"class":61},");  ",[45,320,321],{"class":51},"\u002F\u002F runs once, on first access\n",[45,323,325,328,331],{"class":47,"line":324},23,[45,326,327],{"class":58},"  return",[45,329,330],{"class":314}," 'production'",[45,332,333],{"class":61},";\n",[45,335,337],{"class":47,"line":336},24,[45,338,339],{"class":61},"}\n",[341,342,344,346],"h3",{"id":343},"const-canonicalization-memory-sharing",[18,345,27],{}," Canonicalization — Memory Sharing",[33,348,349],{"language":35},[37,350,352],{"className":39,"code":351,"language":35,"meta":41,"style":41},"\u002F\u002F const objects with identical arguments are the SAME instance (canonicalized).\n\u002F\u002F The compiler deduplicates them — zero allocation at runtime for repeated uses.\nconst a = [1, 2, 3];\nconst b = [1, 2, 3];\nprint(identical(a, b));  \u002F\u002F true — same object in memory (not just equal)\n\n\u002F\u002F This extends to const constructors:\nclass Color {\n  final int r, g, b;\n  const Color(this.r, this.g, this.b);\n}\n\nconst red1 = Color(255, 0, 0);\nconst red2 = Color(255, 0, 0);\nprint(identical(red1, red2));  \u002F\u002F true — canonicalized at compile time\n\n\u002F\u002F Non-const: separate allocations, identity comparison is false.\nfinal red3 = Color(255, 0, 0);\nfinal red4 = Color(255, 0, 0);\nprint(identical(red3, red4));  \u002F\u002F false — distinct heap allocations\nprint(red3 == red4);           \u002F\u002F false (unless == is overridden)\n",[18,353,354,359,364,388,411,427,431,436,447,458,483,487,491,519,544,558,562,567,592,617,631],{"__ignoreMap":41},[45,355,356],{"class":47,"line":48},[45,357,358],{"class":51},"\u002F\u002F const objects with identical arguments are the SAME instance (canonicalized).\n",[45,360,361],{"class":47,"line":55},[45,362,363],{"class":51},"\u002F\u002F The compiler deduplicates them — zero allocation at runtime for repeated uses.\n",[45,365,366,368,371,373,375,377,379,381,383,385],{"class":47,"line":78},[45,367,27],{"class":58},[45,369,370],{"class":61}," a ",[45,372,65],{"class":58},[45,374,210],{"class":61},[45,376,213],{"class":68},[45,378,216],{"class":61},[45,380,219],{"class":68},[45,382,216],{"class":61},[45,384,224],{"class":68},[45,386,387],{"class":61},"];\n",[45,389,390,392,395,397,399,401,403,405,407,409],{"class":47,"line":95},[45,391,27],{"class":58},[45,393,394],{"class":61}," b ",[45,396,65],{"class":58},[45,398,210],{"class":61},[45,400,213],{"class":68},[45,402,216],{"class":61},[45,404,219],{"class":68},[45,406,216],{"class":61},[45,408,224],{"class":68},[45,410,387],{"class":61},[45,412,413,416,418,421,424],{"class":47,"line":104},[45,414,415],{"class":133},"print",[45,417,311],{"class":61},[45,419,420],{"class":133},"identical",[45,422,423],{"class":61},"(a, b));  ",[45,425,426],{"class":51},"\u002F\u002F true — same object in memory (not just equal)\n",[45,428,429],{"class":47,"line":111},[45,430,108],{"emptyLinePlaceholder":107},[45,432,433],{"class":47,"line":117},[45,434,435],{"class":51},"\u002F\u002F This extends to const constructors:\n",[45,437,438,441,444],{"class":47,"line":143},[45,439,440],{"class":58},"class",[45,442,443],{"class":68}," Color",[45,445,446],{"class":61}," {\n",[45,448,449,452,455],{"class":47,"line":152},[45,450,451],{"class":58},"  final",[45,453,454],{"class":68}," int",[45,456,457],{"class":61}," r, g, b;\n",[45,459,460,463,465,467,470,473,475,478,480],{"class":47,"line":157},[45,461,462],{"class":58},"  const",[45,464,443],{"class":68},[45,466,311],{"class":61},[45,468,469],{"class":68},"this",[45,471,472],{"class":61},".r, ",[45,474,469],{"class":68},[45,476,477],{"class":61},".g, ",[45,479,469],{"class":68},[45,481,482],{"class":61},".b);\n",[45,484,485],{"class":47,"line":163},[45,486,339],{"class":61},[45,488,489],{"class":47,"line":182},[45,490,108],{"emptyLinePlaceholder":107},[45,492,493,495,498,500,502,504,507,509,512,514,516],{"class":47,"line":200},[45,494,27],{"class":58},[45,496,497],{"class":61}," red1 ",[45,499,65],{"class":58},[45,501,443],{"class":68},[45,503,311],{"class":61},[45,505,506],{"class":68},"255",[45,508,216],{"class":61},[45,510,511],{"class":68},"0",[45,513,216],{"class":61},[45,515,511],{"class":68},[45,517,518],{"class":61},");\n",[45,520,521,523,526,528,530,532,534,536,538,540,542],{"class":47,"line":233},[45,522,27],{"class":58},[45,524,525],{"class":61}," red2 ",[45,527,65],{"class":58},[45,529,443],{"class":68},[45,531,311],{"class":61},[45,533,506],{"class":68},[45,535,216],{"class":61},[45,537,511],{"class":68},[45,539,216],{"class":61},[45,541,511],{"class":68},[45,543,518],{"class":61},[45,545,546,548,550,552,555],{"class":47,"line":242},[45,547,415],{"class":133},[45,549,311],{"class":61},[45,551,420],{"class":133},[45,553,554],{"class":61},"(red1, red2));  ",[45,556,557],{"class":51},"\u002F\u002F true — canonicalized at compile time\n",[45,559,560],{"class":47,"line":247},[45,561,108],{"emptyLinePlaceholder":107},[45,563,564],{"class":47,"line":253},[45,565,566],{"class":51},"\u002F\u002F Non-const: separate allocations, identity comparison is false.\n",[45,568,569,571,574,576,578,580,582,584,586,588,590],{"class":47,"line":277},[45,570,24],{"class":58},[45,572,573],{"class":61}," red3 ",[45,575,65],{"class":58},[45,577,443],{"class":68},[45,579,311],{"class":61},[45,581,506],{"class":68},[45,583,216],{"class":61},[45,585,511],{"class":68},[45,587,216],{"class":61},[45,589,511],{"class":68},[45,591,518],{"class":61},[45,593,594,596,599,601,603,605,607,609,611,613,615],{"class":47,"line":283},[45,595,24],{"class":58},[45,597,598],{"class":61}," red4 ",[45,600,65],{"class":58},[45,602,443],{"class":68},[45,604,311],{"class":61},[45,606,506],{"class":68},[45,608,216],{"class":61},[45,610,511],{"class":68},[45,612,216],{"class":61},[45,614,511],{"class":68},[45,616,518],{"class":61},[45,618,619,621,623,625,628],{"class":47,"line":289},[45,620,415],{"class":133},[45,622,311],{"class":61},[45,624,420],{"class":133},[45,626,627],{"class":61},"(red3, red4));  ",[45,629,630],{"class":51},"\u002F\u002F false — distinct heap allocations\n",[45,632,633,635,638,641,644],{"class":47,"line":294},[45,634,415],{"class":133},[45,636,637],{"class":61},"(red3 ",[45,639,640],{"class":58},"==",[45,642,643],{"class":61}," red4);           ",[45,645,646],{"class":51},"\u002F\u002F false (unless == is overridden)\n",[341,648,650,652,653,655],{"id":649},"final-vs-const-the-deep-immutability-trap",[18,651,24],{}," vs ",[18,654,27],{}," — The Deep Immutability Trap",[33,657,658],{"language":35},[37,659,661],{"className":39,"code":660,"language":35,"meta":41,"style":41},"\u002F\u002F ❌ Anti-pattern: assuming `final` makes collections immutable.\nfinal list = [1, 2, 3];\nlist.add(4);       \u002F\u002F ✓ `final` locks the REFERENCE, not the contents.\nlist[0] = 99;      \u002F\u002F ✓ mutation is allowed — `final` ≠ immutable.\n\u002F\u002F list = [0];      \u002F\u002F ✗ reassignment is blocked.\n\n\u002F\u002F ✓ Correct: use `const` for compile-time immutable, or List.unmodifiable for runtime.\nconst immutable = [1, 2, 3];     \u002F\u002F deeply immutable, canonicalized\n\u002F\u002F immutable.add(4);              \u002F\u002F ✗ UnsupportedError\n\nfinal readonly = List.unmodifiable([1, 2, 3]);  \u002F\u002F runtime immutability\n\u002F\u002F readonly.add(4);               \u002F\u002F ✗ UnsupportedError — view wrapper throws\n\n\u002F\u002F List.unmodifiable is a VIEW — mutations to the source are visible:\nfinal source = [1, 2, 3];\nfinal view = List.unmodifiable(source);\nsource.add(4);\nprint(view);  \u002F\u002F [1, 2, 3, 4] — the view reflects the source mutation!\n\u002F\u002F For a true immutable copy: List.unmodifiable([...source])\n",[18,662,663,668,690,709,730,738,742,747,774,782,786,822,830,834,839,862,880,893,903],{"__ignoreMap":41},[45,664,665],{"class":47,"line":48},[45,666,667],{"class":51},"\u002F\u002F ❌ Anti-pattern: assuming `final` makes collections immutable.\n",[45,669,670,672,674,676,678,680,682,684,686,688],{"class":47,"line":55},[45,671,24],{"class":58},[45,673,205],{"class":61},[45,675,65],{"class":58},[45,677,210],{"class":61},[45,679,213],{"class":68},[45,681,216],{"class":61},[45,683,219],{"class":68},[45,685,216],{"class":61},[45,687,224],{"class":68},[45,689,387],{"class":61},[45,691,692,695,698,700,703,706],{"class":47,"line":78},[45,693,694],{"class":61},"list.",[45,696,697],{"class":133},"add",[45,699,311],{"class":61},[45,701,702],{"class":68},"4",[45,704,705],{"class":61},");       ",[45,707,708],{"class":51},"\u002F\u002F ✓ `final` locks the REFERENCE, not the contents.\n",[45,710,711,714,716,719,721,724,727],{"class":47,"line":95},[45,712,713],{"class":61},"list[",[45,715,511],{"class":68},[45,717,718],{"class":61},"] ",[45,720,65],{"class":58},[45,722,723],{"class":68}," 99",[45,725,726],{"class":61},";      ",[45,728,729],{"class":51},"\u002F\u002F ✓ mutation is allowed — `final` ≠ immutable.\n",[45,731,732,735],{"class":47,"line":104},[45,733,734],{"class":51},"\u002F\u002F list = [0];",[45,736,737],{"class":51},"      \u002F\u002F ✗ reassignment is blocked.\n",[45,739,740],{"class":47,"line":111},[45,741,108],{"emptyLinePlaceholder":107},[45,743,744],{"class":47,"line":117},[45,745,746],{"class":51},"\u002F\u002F ✓ Correct: use `const` for compile-time immutable, or List.unmodifiable for runtime.\n",[45,748,749,751,754,756,758,760,762,764,766,768,771],{"class":47,"line":143},[45,750,27],{"class":58},[45,752,753],{"class":61}," immutable ",[45,755,65],{"class":58},[45,757,210],{"class":61},[45,759,213],{"class":68},[45,761,216],{"class":61},[45,763,219],{"class":68},[45,765,216],{"class":61},[45,767,224],{"class":68},[45,769,770],{"class":61},"];     ",[45,772,773],{"class":51},"\u002F\u002F deeply immutable, canonicalized\n",[45,775,776,779],{"class":47,"line":152},[45,777,778],{"class":51},"\u002F\u002F immutable.add(4);",[45,780,781],{"class":51},"              \u002F\u002F ✗ UnsupportedError\n",[45,783,784],{"class":47,"line":157},[45,785,108],{"emptyLinePlaceholder":107},[45,787,788,790,793,795,798,800,803,806,808,810,812,814,816,819],{"class":47,"line":163},[45,789,24],{"class":58},[45,791,792],{"class":61}," readonly ",[45,794,65],{"class":58},[45,796,797],{"class":68}," List",[45,799,130],{"class":61},[45,801,802],{"class":133},"unmodifiable",[45,804,805],{"class":61},"([",[45,807,213],{"class":68},[45,809,216],{"class":61},[45,811,219],{"class":68},[45,813,216],{"class":61},[45,815,224],{"class":68},[45,817,818],{"class":61},"]);  ",[45,820,821],{"class":51},"\u002F\u002F runtime immutability\n",[45,823,824,827],{"class":47,"line":182},[45,825,826],{"class":51},"\u002F\u002F readonly.add(4);",[45,828,829],{"class":51},"               \u002F\u002F ✗ UnsupportedError — view wrapper throws\n",[45,831,832],{"class":47,"line":200},[45,833,108],{"emptyLinePlaceholder":107},[45,835,836],{"class":47,"line":233},[45,837,838],{"class":51},"\u002F\u002F List.unmodifiable is a VIEW — mutations to the source are visible:\n",[45,840,841,843,846,848,850,852,854,856,858,860],{"class":47,"line":242},[45,842,24],{"class":58},[45,844,845],{"class":61}," source ",[45,847,65],{"class":58},[45,849,210],{"class":61},[45,851,213],{"class":68},[45,853,216],{"class":61},[45,855,219],{"class":68},[45,857,216],{"class":61},[45,859,224],{"class":68},[45,861,387],{"class":61},[45,863,864,866,869,871,873,875,877],{"class":47,"line":247},[45,865,24],{"class":58},[45,867,868],{"class":61}," view ",[45,870,65],{"class":58},[45,872,797],{"class":68},[45,874,130],{"class":61},[45,876,802],{"class":133},[45,878,879],{"class":61},"(source);\n",[45,881,882,885,887,889,891],{"class":47,"line":253},[45,883,884],{"class":61},"source.",[45,886,697],{"class":133},[45,888,311],{"class":61},[45,890,702],{"class":68},[45,892,518],{"class":61},[45,894,895,897,900],{"class":47,"line":277},[45,896,415],{"class":133},[45,898,899],{"class":61},"(view);  ",[45,901,902],{"class":51},"\u002F\u002F [1, 2, 3, 4] — the view reflects the source mutation!\n",[45,904,905],{"class":47,"line":283},[45,906,907],{"class":51},"\u002F\u002F For a true immutable copy: List.unmodifiable([...source])\n",[14,909,911],{"id":910},"built-in-types-platform-dependent-semantics","Built-in Types — Platform-Dependent Semantics",[341,913,915,916,216,919,216,922],{"id":914},"numbers-int-double-num","Numbers: ",[18,917,918],{},"int",[18,920,921],{},"double",[18,923,924],{},"num",[33,926,927],{"language":35},[37,928,930],{"className":39,"code":929,"language":35,"meta":41,"style":41},"\u002F\u002F ── Native (VM\u002FAOT): int is 64-bit signed, double is IEEE 754 64-bit ──\n\u002F\u002F ── Web (dart2js\u002FDDC): both are JS numbers (IEEE 754 doubles) ──\n\nint max64 = 9223372036854775807;  \u002F\u002F 2^63 - 1 on native\nmax64 + 1;  \u002F\u002F native: wraps to -9223372036854775808 (two's complement, SILENT)\n            \u002F\u002F web: becomes 9223372036854775808.0 (a double, precision lost above 2^53)\n\n\u002F\u002F The web precision trap:\nint big = 1 \u003C\u003C 53;  \u002F\u002F 9007199254740992\nprint(big + 1 == big);  \u002F\u002F native: false | web: true (double can't represent 2^53+1)\n\n\u002F\u002F Use BigInt for arbitrary precision (works on all platforms):\nBigInt huge = BigInt.parse('9223372036854775807') + BigInt.one;\nprint(huge);  \u002F\u002F 9223372036854775808 — exact, no overflow\n\n\u002F\u002F num is the supertype of int and double:\nnum any = 10;     \u002F\u002F can hold int or double\nany = 5.5;        \u002F\u002F ✓\n\u002F\u002F any.abs();     \u002F\u002F ✓ num has abs()\n\u002F\u002F any.toRadixString(16); \u002F\u002F ✗ int-only method — requires `as int` or `is int` check\n",[18,931,932,937,942,946,964,980,985,989,994,1016,1036,1040,1045,1078,1088,1092,1097,1115,1131,1139],{"__ignoreMap":41},[45,933,934],{"class":47,"line":48},[45,935,936],{"class":51},"\u002F\u002F ── Native (VM\u002FAOT): int is 64-bit signed, double is IEEE 754 64-bit ──\n",[45,938,939],{"class":47,"line":55},[45,940,941],{"class":51},"\u002F\u002F ── Web (dart2js\u002FDDC): both are JS numbers (IEEE 754 doubles) ──\n",[45,943,944],{"class":47,"line":78},[45,945,108],{"emptyLinePlaceholder":107},[45,947,948,950,953,955,958,961],{"class":47,"line":95},[45,949,918],{"class":68},[45,951,952],{"class":61}," max64 ",[45,954,65],{"class":58},[45,956,957],{"class":68}," 9223372036854775807",[45,959,960],{"class":61},";  ",[45,962,963],{"class":51},"\u002F\u002F 2^63 - 1 on native\n",[45,965,966,969,972,975,977],{"class":47,"line":104},[45,967,968],{"class":61},"max64 ",[45,970,971],{"class":58},"+",[45,973,974],{"class":68}," 1",[45,976,960],{"class":61},[45,978,979],{"class":51},"\u002F\u002F native: wraps to -9223372036854775808 (two's complement, SILENT)\n",[45,981,982],{"class":47,"line":111},[45,983,984],{"class":51},"            \u002F\u002F web: becomes 9223372036854775808.0 (a double, precision lost above 2^53)\n",[45,986,987],{"class":47,"line":117},[45,988,108],{"emptyLinePlaceholder":107},[45,990,991],{"class":47,"line":143},[45,992,993],{"class":51},"\u002F\u002F The web precision trap:\n",[45,995,996,998,1001,1003,1005,1008,1011,1013],{"class":47,"line":152},[45,997,918],{"class":68},[45,999,1000],{"class":61}," big ",[45,1002,65],{"class":58},[45,1004,974],{"class":68},[45,1006,1007],{"class":58}," \u003C\u003C",[45,1009,1010],{"class":68}," 53",[45,1012,960],{"class":61},[45,1014,1015],{"class":51},"\u002F\u002F 9007199254740992\n",[45,1017,1018,1020,1023,1025,1027,1030,1033],{"class":47,"line":157},[45,1019,415],{"class":133},[45,1021,1022],{"class":61},"(big ",[45,1024,971],{"class":58},[45,1026,974],{"class":68},[45,1028,1029],{"class":58}," ==",[45,1031,1032],{"class":61}," big);  ",[45,1034,1035],{"class":51},"\u002F\u002F native: false | web: true (double can't represent 2^53+1)\n",[45,1037,1038],{"class":47,"line":163},[45,1039,108],{"emptyLinePlaceholder":107},[45,1041,1042],{"class":47,"line":182},[45,1043,1044],{"class":51},"\u002F\u002F Use BigInt for arbitrary precision (works on all platforms):\n",[45,1046,1047,1050,1053,1055,1058,1060,1063,1065,1068,1071,1073,1075],{"class":47,"line":200},[45,1048,1049],{"class":68},"BigInt",[45,1051,1052],{"class":61}," huge ",[45,1054,65],{"class":58},[45,1056,1057],{"class":68}," BigInt",[45,1059,130],{"class":61},[45,1061,1062],{"class":133},"parse",[45,1064,311],{"class":61},[45,1066,1067],{"class":314},"'9223372036854775807'",[45,1069,1070],{"class":61},") ",[45,1072,971],{"class":58},[45,1074,1057],{"class":68},[45,1076,1077],{"class":61},".one;\n",[45,1079,1080,1082,1085],{"class":47,"line":233},[45,1081,415],{"class":133},[45,1083,1084],{"class":61},"(huge);  ",[45,1086,1087],{"class":51},"\u002F\u002F 9223372036854775808 — exact, no overflow\n",[45,1089,1090],{"class":47,"line":242},[45,1091,108],{"emptyLinePlaceholder":107},[45,1093,1094],{"class":47,"line":247},[45,1095,1096],{"class":51},"\u002F\u002F num is the supertype of int and double:\n",[45,1098,1099,1101,1104,1106,1109,1112],{"class":47,"line":253},[45,1100,924],{"class":68},[45,1102,1103],{"class":61}," any ",[45,1105,65],{"class":58},[45,1107,1108],{"class":68}," 10",[45,1110,1111],{"class":61},";     ",[45,1113,1114],{"class":51},"\u002F\u002F can hold int or double\n",[45,1116,1117,1120,1122,1125,1128],{"class":47,"line":277},[45,1118,1119],{"class":61},"any ",[45,1121,65],{"class":58},[45,1123,1124],{"class":68}," 5.5",[45,1126,1127],{"class":61},";        ",[45,1129,1130],{"class":51},"\u002F\u002F ✓\n",[45,1132,1133,1136],{"class":47,"line":283},[45,1134,1135],{"class":51},"\u002F\u002F any.abs();",[45,1137,1138],{"class":51},"     \u002F\u002F ✓ num has abs()\n",[45,1140,1141,1144],{"class":47,"line":289},[45,1142,1143],{"class":51},"\u002F\u002F any.toRadixString(16);",[45,1145,1146],{"class":51}," \u002F\u002F ✗ int-only method — requires `as int` or `is int` check\n",[341,1148,1150],{"id":1149},"integer-division-modulo-sign-semantics","Integer Division & Modulo — Sign Semantics",[33,1152,1153],{"language":35},[37,1154,1156],{"className":39,"code":1155,"language":35,"meta":41,"style":41},"\u002F\u002F `\u002F` ALWAYS returns double, even for int operands:\nprint(7 \u002F 2);    \u002F\u002F 3.5 (double)\nprint(4 \u002F 2);    \u002F\u002F 2.0 (double, NOT int 2)\n\n\u002F\u002F `~\u002F` is integer division (truncates toward ZERO, not floor):\nprint(7 ~\u002F 2);    \u002F\u002F 3\nprint(-7 ~\u002F 2);   \u002F\u002F -3 (truncates toward zero — NOT -4 like Python's floor division)\n\n\u002F\u002F `%` follows the sign of the DIVIDEND (like C, unlike Python):\nprint(7 % 3);     \u002F\u002F 1\nprint(-7 % 3);    \u002F\u002F -1 (Dart: sign of dividend | Python: 2, sign of divisor)\nprint(7 % -3);    \u002F\u002F 1  (sign of dividend)\n\n\u002F\u002F To get Python-style non-negative modulo:\nint pyMod(int a, int n) => ((a % n) + n) % n;\nprint(pyMod(-7, 3));  \u002F\u002F 2\n",[18,1157,1158,1163,1184,1201,1205,1210,1228,1249,1253,1258,1278,1297,1317,1321,1326,1365],{"__ignoreMap":41},[45,1159,1160],{"class":47,"line":48},[45,1161,1162],{"class":51},"\u002F\u002F `\u002F` ALWAYS returns double, even for int operands:\n",[45,1164,1165,1167,1169,1172,1175,1178,1181],{"class":47,"line":55},[45,1166,415],{"class":133},[45,1168,311],{"class":61},[45,1170,1171],{"class":68},"7",[45,1173,1174],{"class":58}," \u002F",[45,1176,1177],{"class":68}," 2",[45,1179,1180],{"class":61},");    ",[45,1182,1183],{"class":51},"\u002F\u002F 3.5 (double)\n",[45,1185,1186,1188,1190,1192,1194,1196,1198],{"class":47,"line":78},[45,1187,415],{"class":133},[45,1189,311],{"class":61},[45,1191,702],{"class":68},[45,1193,1174],{"class":58},[45,1195,1177],{"class":68},[45,1197,1180],{"class":61},[45,1199,1200],{"class":51},"\u002F\u002F 2.0 (double, NOT int 2)\n",[45,1202,1203],{"class":47,"line":95},[45,1204,108],{"emptyLinePlaceholder":107},[45,1206,1207],{"class":47,"line":104},[45,1208,1209],{"class":51},"\u002F\u002F `~\u002F` is integer division (truncates toward ZERO, not floor):\n",[45,1211,1212,1214,1216,1218,1221,1223,1225],{"class":47,"line":111},[45,1213,415],{"class":133},[45,1215,311],{"class":61},[45,1217,1171],{"class":68},[45,1219,1220],{"class":58}," ~\u002F",[45,1222,1177],{"class":68},[45,1224,1180],{"class":61},[45,1226,1227],{"class":51},"\u002F\u002F 3\n",[45,1229,1230,1232,1234,1237,1239,1241,1243,1246],{"class":47,"line":117},[45,1231,415],{"class":133},[45,1233,311],{"class":61},[45,1235,1236],{"class":58},"-",[45,1238,1171],{"class":68},[45,1240,1220],{"class":58},[45,1242,1177],{"class":68},[45,1244,1245],{"class":61},");   ",[45,1247,1248],{"class":51},"\u002F\u002F -3 (truncates toward zero — NOT -4 like Python's floor division)\n",[45,1250,1251],{"class":47,"line":143},[45,1252,108],{"emptyLinePlaceholder":107},[45,1254,1255],{"class":47,"line":152},[45,1256,1257],{"class":51},"\u002F\u002F `%` follows the sign of the DIVIDEND (like C, unlike Python):\n",[45,1259,1260,1262,1264,1266,1269,1272,1275],{"class":47,"line":157},[45,1261,415],{"class":133},[45,1263,311],{"class":61},[45,1265,1171],{"class":68},[45,1267,1268],{"class":58}," %",[45,1270,1271],{"class":68}," 3",[45,1273,1274],{"class":61},");     ",[45,1276,1277],{"class":51},"\u002F\u002F 1\n",[45,1279,1280,1282,1284,1286,1288,1290,1292,1294],{"class":47,"line":163},[45,1281,415],{"class":133},[45,1283,311],{"class":61},[45,1285,1236],{"class":58},[45,1287,1171],{"class":68},[45,1289,1268],{"class":58},[45,1291,1271],{"class":68},[45,1293,1180],{"class":61},[45,1295,1296],{"class":51},"\u002F\u002F -1 (Dart: sign of dividend | Python: 2, sign of divisor)\n",[45,1298,1299,1301,1303,1305,1307,1310,1312,1314],{"class":47,"line":182},[45,1300,415],{"class":133},[45,1302,311],{"class":61},[45,1304,1171],{"class":68},[45,1306,1268],{"class":58},[45,1308,1309],{"class":58}," -",[45,1311,224],{"class":68},[45,1313,1180],{"class":61},[45,1315,1316],{"class":51},"\u002F\u002F 1  (sign of dividend)\n",[45,1318,1319],{"class":47,"line":200},[45,1320,108],{"emptyLinePlaceholder":107},[45,1322,1323],{"class":47,"line":233},[45,1324,1325],{"class":51},"\u002F\u002F To get Python-style non-negative modulo:\n",[45,1327,1328,1330,1333,1335,1337,1340,1342,1345,1348,1351,1354,1356,1358,1360,1362],{"class":47,"line":242},[45,1329,918],{"class":68},[45,1331,1332],{"class":133}," pyMod",[45,1334,311],{"class":61},[45,1336,918],{"class":68},[45,1338,1339],{"class":61}," a, ",[45,1341,918],{"class":68},[45,1343,1344],{"class":61}," n) ",[45,1346,1347],{"class":58},"=>",[45,1349,1350],{"class":61}," ((a ",[45,1352,1353],{"class":58},"%",[45,1355,1344],{"class":61},[45,1357,971],{"class":58},[45,1359,1344],{"class":61},[45,1361,1353],{"class":58},[45,1363,1364],{"class":61}," n;\n",[45,1366,1367,1369,1371,1374,1376,1378,1380,1382,1384,1387],{"class":47,"line":247},[45,1368,415],{"class":133},[45,1370,311],{"class":61},[45,1372,1373],{"class":133},"pyMod",[45,1375,311],{"class":61},[45,1377,1236],{"class":58},[45,1379,1171],{"class":68},[45,1381,216],{"class":61},[45,1383,224],{"class":68},[45,1385,1386],{"class":61},"));  ",[45,1388,1389],{"class":51},"\u002F\u002F 2\n",[341,1391,1393],{"id":1392},"strings-internals-interpolation","Strings — Internals & Interpolation",[33,1395,1396],{"language":35},[37,1397,1399],{"className":39,"code":1398,"language":35,"meta":41,"style":41},"\u002F\u002F Dart strings are sequences of UTF-16 code units (NOT code points \u002F graphemes).\n\u002F\u002F A single emoji may be 2 code units (surrogate pair):\nvar emoji = '🎉';  \u002F\u002F U+1F389\nprint(emoji.length);          \u002F\u002F 2 — two UTF-16 code units\nprint(emoji.runes.length);    \u002F\u002F 1 — one Unicode code point\nprint(emoji.codeUnits.length); \u002F\u002F 2 — code units\n\n\u002F\u002F ❌ Anti-pattern: indexing strings for \"characters\":\nvar s = 'café';\nprint(s[3]);  \u002F\u002F 'é' — works here (1 code unit)\nvar s2 = 'café🎉';\nprint(s2[4]);  \u002F\u002F garbage surrogate — NOT the emoji\nprint(s2[5]);  \u002F\u002F second half of surrogate pair — NOT a character\n\n\u002F\u002F ✓ Correct: use runes for code points, or `characters` package for graphemes:\nfor (var rune in s2.runes) {\n  print(String.fromCharCode(rune));  \u002F\u002F c, a, f, é, 🎉\n}\n\n\u002F\u002F String interpolation calls toString() — override for readable output:\nclass Point {\n  final double x, y;\n  const Point(this.x, this.y);\n  @override\n  String toString() => 'Point($x, $y)';  \u002F\u002F without this: 'Instance of Point'\n}\n\nvar p = Point(1, 2);\nprint('Location: $p');           \u002F\u002F 'Location: Point(1.0, 2.0)'\nprint('Sum: ${p.x + p.y}');     \u002F\u002F 'Sum: 3.0' — ${} for expressions\n",[18,1400,1401,1406,1411,1428,1438,1448,1458,1462,1467,1481,1495,1509,1523,1537,1541,1546,1565,1584,1588,1592,1597,1606,1616,1634,1639,1677,1682,1687,1709,1733],{"__ignoreMap":41},[45,1402,1403],{"class":47,"line":48},[45,1404,1405],{"class":51},"\u002F\u002F Dart strings are sequences of UTF-16 code units (NOT code points \u002F graphemes).\n",[45,1407,1408],{"class":47,"line":55},[45,1409,1410],{"class":51},"\u002F\u002F A single emoji may be 2 code units (surrogate pair):\n",[45,1412,1413,1415,1418,1420,1423,1425],{"class":47,"line":78},[45,1414,20],{"class":58},[45,1416,1417],{"class":61}," emoji ",[45,1419,65],{"class":58},[45,1421,1422],{"class":314}," '🎉'",[45,1424,960],{"class":61},[45,1426,1427],{"class":51},"\u002F\u002F U+1F389\n",[45,1429,1430,1432,1435],{"class":47,"line":95},[45,1431,415],{"class":133},[45,1433,1434],{"class":61},"(emoji.length);          ",[45,1436,1437],{"class":51},"\u002F\u002F 2 — two UTF-16 code units\n",[45,1439,1440,1442,1445],{"class":47,"line":104},[45,1441,415],{"class":133},[45,1443,1444],{"class":61},"(emoji.runes.length);    ",[45,1446,1447],{"class":51},"\u002F\u002F 1 — one Unicode code point\n",[45,1449,1450,1452,1455],{"class":47,"line":111},[45,1451,415],{"class":133},[45,1453,1454],{"class":61},"(emoji.codeUnits.length); ",[45,1456,1457],{"class":51},"\u002F\u002F 2 — code units\n",[45,1459,1460],{"class":47,"line":117},[45,1461,108],{"emptyLinePlaceholder":107},[45,1463,1464],{"class":47,"line":143},[45,1465,1466],{"class":51},"\u002F\u002F ❌ Anti-pattern: indexing strings for \"characters\":\n",[45,1468,1469,1471,1474,1476,1479],{"class":47,"line":152},[45,1470,20],{"class":58},[45,1472,1473],{"class":61}," s ",[45,1475,65],{"class":58},[45,1477,1478],{"class":314}," 'café'",[45,1480,333],{"class":61},[45,1482,1483,1485,1488,1490,1492],{"class":47,"line":157},[45,1484,415],{"class":133},[45,1486,1487],{"class":61},"(s[",[45,1489,224],{"class":68},[45,1491,818],{"class":61},[45,1493,1494],{"class":51},"\u002F\u002F 'é' — works here (1 code unit)\n",[45,1496,1497,1499,1502,1504,1507],{"class":47,"line":163},[45,1498,20],{"class":58},[45,1500,1501],{"class":61}," s2 ",[45,1503,65],{"class":58},[45,1505,1506],{"class":314}," 'café🎉'",[45,1508,333],{"class":61},[45,1510,1511,1513,1516,1518,1520],{"class":47,"line":182},[45,1512,415],{"class":133},[45,1514,1515],{"class":61},"(s2[",[45,1517,702],{"class":68},[45,1519,818],{"class":61},[45,1521,1522],{"class":51},"\u002F\u002F garbage surrogate — NOT the emoji\n",[45,1524,1525,1527,1529,1532,1534],{"class":47,"line":200},[45,1526,415],{"class":133},[45,1528,1515],{"class":61},[45,1530,1531],{"class":68},"5",[45,1533,818],{"class":61},[45,1535,1536],{"class":51},"\u002F\u002F second half of surrogate pair — NOT a character\n",[45,1538,1539],{"class":47,"line":233},[45,1540,108],{"emptyLinePlaceholder":107},[45,1542,1543],{"class":47,"line":242},[45,1544,1545],{"class":51},"\u002F\u002F ✓ Correct: use runes for code points, or `characters` package for graphemes:\n",[45,1547,1548,1551,1554,1556,1559,1562],{"class":47,"line":247},[45,1549,1550],{"class":58},"for",[45,1552,1553],{"class":61}," (",[45,1555,20],{"class":58},[45,1557,1558],{"class":61}," rune ",[45,1560,1561],{"class":58},"in",[45,1563,1564],{"class":61}," s2.runes) {\n",[45,1566,1567,1569,1571,1573,1575,1578,1581],{"class":47,"line":253},[45,1568,308],{"class":133},[45,1570,311],{"class":61},[45,1572,297],{"class":68},[45,1574,130],{"class":61},[45,1576,1577],{"class":133},"fromCharCode",[45,1579,1580],{"class":61},"(rune));  ",[45,1582,1583],{"class":51},"\u002F\u002F c, a, f, é, 🎉\n",[45,1585,1586],{"class":47,"line":277},[45,1587,339],{"class":61},[45,1589,1590],{"class":47,"line":283},[45,1591,108],{"emptyLinePlaceholder":107},[45,1593,1594],{"class":47,"line":289},[45,1595,1596],{"class":51},"\u002F\u002F String interpolation calls toString() — override for readable output:\n",[45,1598,1599,1601,1604],{"class":47,"line":294},[45,1600,440],{"class":58},[45,1602,1603],{"class":68}," Point",[45,1605,446],{"class":61},[45,1607,1608,1610,1613],{"class":47,"line":305},[45,1609,451],{"class":58},[45,1611,1612],{"class":68}," double",[45,1614,1615],{"class":61}," x, y;\n",[45,1617,1618,1620,1622,1624,1626,1629,1631],{"class":47,"line":324},[45,1619,462],{"class":58},[45,1621,1603],{"class":68},[45,1623,311],{"class":61},[45,1625,469],{"class":68},[45,1627,1628],{"class":61},".x, ",[45,1630,469],{"class":68},[45,1632,1633],{"class":61},".y);\n",[45,1635,1636],{"class":47,"line":336},[45,1637,1638],{"class":58},"  @override\n",[45,1640,1642,1645,1648,1651,1653,1656,1659,1662,1664,1666,1669,1672,1674],{"class":47,"line":1641},25,[45,1643,1644],{"class":68},"  String",[45,1646,1647],{"class":133}," toString",[45,1649,1650],{"class":61},"() ",[45,1652,1347],{"class":58},[45,1654,1655],{"class":314}," 'Point(",[45,1657,1658],{"class":314},"$",[45,1660,1661],{"class":68},"x",[45,1663,216],{"class":314},[45,1665,1658],{"class":314},[45,1667,1668],{"class":68},"y",[45,1670,1671],{"class":314},")'",[45,1673,960],{"class":61},[45,1675,1676],{"class":51},"\u002F\u002F without this: 'Instance of Point'\n",[45,1678,1680],{"class":47,"line":1679},26,[45,1681,339],{"class":61},[45,1683,1685],{"class":47,"line":1684},27,[45,1686,108],{"emptyLinePlaceholder":107},[45,1688,1690,1692,1695,1697,1699,1701,1703,1705,1707],{"class":47,"line":1689},28,[45,1691,20],{"class":58},[45,1693,1694],{"class":61}," p ",[45,1696,65],{"class":58},[45,1698,1603],{"class":68},[45,1700,311],{"class":61},[45,1702,213],{"class":68},[45,1704,216],{"class":61},[45,1706,219],{"class":68},[45,1708,518],{"class":61},[45,1710,1712,1714,1716,1719,1721,1724,1727,1730],{"class":47,"line":1711},29,[45,1713,415],{"class":133},[45,1715,311],{"class":61},[45,1717,1718],{"class":314},"'Location: ",[45,1720,1658],{"class":314},[45,1722,1723],{"class":68},"p",[45,1725,1726],{"class":314},"'",[45,1728,1729],{"class":61},");           ",[45,1731,1732],{"class":51},"\u002F\u002F 'Location: Point(1.0, 2.0)'\n",[45,1734,1736,1738,1740,1743,1746,1748,1750,1752,1755,1757,1759,1761,1764,1766,1768],{"class":47,"line":1735},30,[45,1737,415],{"class":133},[45,1739,311],{"class":61},[45,1741,1742],{"class":314},"'Sum: ",[45,1744,1745],{"class":314},"${",[45,1747,1723],{"class":68},[45,1749,130],{"class":314},[45,1751,1661],{"class":68},[45,1753,1754],{"class":314}," + ",[45,1756,1723],{"class":68},[45,1758,130],{"class":314},[45,1760,1668],{"class":68},[45,1762,1763],{"class":314},"}",[45,1765,1726],{"class":314},[45,1767,1274],{"class":61},[45,1769,1770],{"class":51},"\u002F\u002F 'Sum: 3.0' — ${} for expressions\n",[14,1772,1774,652,1777,652,1780,1783],{"id":1773},"object-vs-dynamic-vs-object-type-safety-boundaries",[18,1775,1776],{},"Object",[18,1778,1779],{},"dynamic",[18,1781,1782],{},"Object?"," — Type Safety Boundaries",[33,1785,1786],{"language":35},[37,1787,1789],{"className":39,"code":1788,"language":35,"meta":41,"style":41},"\u002F\u002F ── Object: non-nullable supertype of all non-null types ──\n\u002F\u002F Static type checking is ON — you must cast to access methods.\nObject obj = 'hello';\n\u002F\u002F obj.toUpperCase();  \u002F\u002F ✗ compile error: Object has no toUpperCase\n(obj as String).toUpperCase();  \u002F\u002F ✓ explicit cast — throws if wrong type\nif (obj is String) {\n  obj.toUpperCase();  \u002F\u002F ✓ type promotion: obj is String in this block\n}\n\n\u002F\u002F ── dynamic: disables ALL static type checking ──\n\u002F\u002F Any method call compiles — checked at RUNTIME (NoSuchMethodError if missing).\ndynamic dyn = 'hello';\ndyn.toUpperCase();  \u002F\u002F ✓ compiles, works at runtime\ndyn = 42;\ndyn.toUpperCase();  \u002F\u002F ✓ compiles, throws NoSuchMethodError at runtime (int has no toUpperCase)\ndyn.nonExistent();  \u002F\u002F ✓ compiles, throws at runtime\n\n\u002F\u002F ── Object?: nullable supertype of ALL types (including Null) ──\nObject? maybe = null;  \u002F\u002F ✓\nmaybe = 'hello';       \u002F\u002F ✓\nObject notNull = null; \u002F\u002F ✗ compile error: Object is non-nullable\n\n\u002F\u002F ❌ Anti-pattern: using `dynamic` for \"I don't know the type.\"\n\u002F\u002F It defeats the entire type system — bugs surface at runtime, not compile time.\n\n\u002F\u002F ✓ Correct: use `Object` (non-null, type-safe, must cast) or `Object?` (nullable).\n\u002F\u002F Use `dynamic` ONLY for JSON parsing interop or JS interop — never in APIs.\n",[18,1790,1791,1796,1801,1815,1823,1844,1860,1872,1876,1880,1885,1890,1903,1915,1926,1937,1949,1953,1958,1977,1991,2008,2012,2017,2022,2026,2031],{"__ignoreMap":41},[45,1792,1793],{"class":47,"line":48},[45,1794,1795],{"class":51},"\u002F\u002F ── Object: non-nullable supertype of all non-null types ──\n",[45,1797,1798],{"class":47,"line":55},[45,1799,1800],{"class":51},"\u002F\u002F Static type checking is ON — you must cast to access methods.\n",[45,1802,1803,1805,1808,1810,1813],{"class":47,"line":78},[45,1804,1776],{"class":68},[45,1806,1807],{"class":61}," obj ",[45,1809,65],{"class":58},[45,1811,1812],{"class":314}," 'hello'",[45,1814,333],{"class":61},[45,1816,1817,1820],{"class":47,"line":95},[45,1818,1819],{"class":51},"\u002F\u002F obj.toUpperCase();",[45,1821,1822],{"class":51},"  \u002F\u002F ✗ compile error: Object has no toUpperCase\n",[45,1824,1825,1828,1831,1833,1836,1839,1841],{"class":47,"line":104},[45,1826,1827],{"class":61},"(obj ",[45,1829,1830],{"class":58},"as",[45,1832,261],{"class":68},[45,1834,1835],{"class":61},").",[45,1837,1838],{"class":133},"toUpperCase",[45,1840,137],{"class":61},[45,1842,1843],{"class":51},"\u002F\u002F ✓ explicit cast — throws if wrong type\n",[45,1845,1846,1849,1852,1855,1857],{"class":47,"line":111},[45,1847,1848],{"class":58},"if",[45,1850,1851],{"class":61}," (obj ",[45,1853,1854],{"class":58},"is",[45,1856,261],{"class":68},[45,1858,1859],{"class":61},") {\n",[45,1861,1862,1865,1867,1869],{"class":47,"line":117},[45,1863,1864],{"class":61},"  obj.",[45,1866,1838],{"class":133},[45,1868,137],{"class":61},[45,1870,1871],{"class":51},"\u002F\u002F ✓ type promotion: obj is String in this block\n",[45,1873,1874],{"class":47,"line":143},[45,1875,339],{"class":61},[45,1877,1878],{"class":47,"line":152},[45,1879,108],{"emptyLinePlaceholder":107},[45,1881,1882],{"class":47,"line":157},[45,1883,1884],{"class":51},"\u002F\u002F ── dynamic: disables ALL static type checking ──\n",[45,1886,1887],{"class":47,"line":163},[45,1888,1889],{"class":51},"\u002F\u002F Any method call compiles — checked at RUNTIME (NoSuchMethodError if missing).\n",[45,1891,1892,1894,1897,1899,1901],{"class":47,"line":182},[45,1893,1779],{"class":68},[45,1895,1896],{"class":61}," dyn ",[45,1898,65],{"class":58},[45,1900,1812],{"class":314},[45,1902,333],{"class":61},[45,1904,1905,1908,1910,1912],{"class":47,"line":200},[45,1906,1907],{"class":61},"dyn.",[45,1909,1838],{"class":133},[45,1911,137],{"class":61},[45,1913,1914],{"class":51},"\u002F\u002F ✓ compiles, works at runtime\n",[45,1916,1917,1920,1922,1924],{"class":47,"line":233},[45,1918,1919],{"class":61},"dyn ",[45,1921,65],{"class":58},[45,1923,86],{"class":68},[45,1925,333],{"class":61},[45,1927,1928,1930,1932,1934],{"class":47,"line":242},[45,1929,1907],{"class":61},[45,1931,1838],{"class":133},[45,1933,137],{"class":61},[45,1935,1936],{"class":51},"\u002F\u002F ✓ compiles, throws NoSuchMethodError at runtime (int has no toUpperCase)\n",[45,1938,1939,1941,1944,1946],{"class":47,"line":247},[45,1940,1907],{"class":61},[45,1942,1943],{"class":133},"nonExistent",[45,1945,137],{"class":61},[45,1947,1948],{"class":51},"\u002F\u002F ✓ compiles, throws at runtime\n",[45,1950,1951],{"class":47,"line":253},[45,1952,108],{"emptyLinePlaceholder":107},[45,1954,1955],{"class":47,"line":277},[45,1956,1957],{"class":51},"\u002F\u002F ── Object?: nullable supertype of ALL types (including Null) ──\n",[45,1959,1960,1962,1965,1968,1970,1973,1975],{"class":47,"line":283},[45,1961,1776],{"class":68},[45,1963,1964],{"class":58},"?",[45,1966,1967],{"class":61}," maybe ",[45,1969,65],{"class":58},[45,1971,1972],{"class":68}," null",[45,1974,960],{"class":61},[45,1976,1130],{"class":51},[45,1978,1979,1982,1984,1986,1989],{"class":47,"line":289},[45,1980,1981],{"class":61},"maybe ",[45,1983,65],{"class":58},[45,1985,1812],{"class":314},[45,1987,1988],{"class":61},";       ",[45,1990,1130],{"class":51},[45,1992,1993,1995,1998,2000,2002,2005],{"class":47,"line":294},[45,1994,1776],{"class":68},[45,1996,1997],{"class":61}," notNull ",[45,1999,65],{"class":58},[45,2001,1972],{"class":68},[45,2003,2004],{"class":61},"; ",[45,2006,2007],{"class":51},"\u002F\u002F ✗ compile error: Object is non-nullable\n",[45,2009,2010],{"class":47,"line":305},[45,2011,108],{"emptyLinePlaceholder":107},[45,2013,2014],{"class":47,"line":324},[45,2015,2016],{"class":51},"\u002F\u002F ❌ Anti-pattern: using `dynamic` for \"I don't know the type.\"\n",[45,2018,2019],{"class":47,"line":336},[45,2020,2021],{"class":51},"\u002F\u002F It defeats the entire type system — bugs surface at runtime, not compile time.\n",[45,2023,2024],{"class":47,"line":1641},[45,2025,108],{"emptyLinePlaceholder":107},[45,2027,2028],{"class":47,"line":1679},[45,2029,2030],{"class":51},"\u002F\u002F ✓ Correct: use `Object` (non-null, type-safe, must cast) or `Object?` (nullable).\n",[45,2032,2033],{"class":47,"line":1684},[45,2034,2035],{"class":51},"\u002F\u002F Use `dynamic` ONLY for JSON parsing interop or JS interop — never in APIs.\n",[14,2037,2039],{"id":2038},"type-conversion-safe-parsing-patterns","Type Conversion — Safe Parsing Patterns",[33,2041,2042],{"language":35},[37,2043,2045],{"className":39,"code":2044,"language":35,"meta":41,"style":41},"\u002F\u002F ❌ Anti-pattern: `parse` on untrusted input — throws FormatException.\nint parseUnsafe(String input) => int.parse(input);  \u002F\u002F throws on 'abc'\n\n\u002F\u002F ✓ Correct: `tryParse` returns null on failure — handle explicitly.\nint? parseSafe(String input) => int.tryParse(input);\n\nvoid handleAge(String input) {\n  final age = int.tryParse(input);\n  if (age == null || age \u003C 0 || age > 150) {\n    throw ArgumentError('Invalid age: $input');\n  }\n  \u002F\u002F ... use age\n}\n\n\u002F\u002F double ↔ int conversions:\nprint(3.7.toInt());    \u002F\u002F 3 (truncates toward zero)\nprint(-3.7.toInt());   \u002F\u002F -3 (truncates toward zero, NOT floor)\nprint(3.0.toInt());    \u002F\u002F 3\n\u002F\u002F print(3.7.toInt() == 3.7.floor());  \u002F\u002F false for negatives: toInt=-3, floor=-4\n\n\u002F\u002F toString with formatting:\nprint(3.14159.toStringAsFixed(2));  \u002F\u002F '3.14'\nprint(255.toRadixString(16));       \u002F\u002F 'ff'\nprint(255.toRadixString(2));        \u002F\u002F '11111111'\n",[18,2046,2047,2052,2080,2084,2089,2116,2120,2135,2152,2186,2208,2213,2218,2222,2226,2231,2251,2271,2288,2296,2300,2305,2328,2351],{"__ignoreMap":41},[45,2048,2049],{"class":47,"line":48},[45,2050,2051],{"class":51},"\u002F\u002F ❌ Anti-pattern: `parse` on untrusted input — throws FormatException.\n",[45,2053,2054,2056,2059,2061,2063,2066,2068,2070,2072,2074,2077],{"class":47,"line":55},[45,2055,918],{"class":68},[45,2057,2058],{"class":133}," parseUnsafe",[45,2060,311],{"class":61},[45,2062,297],{"class":68},[45,2064,2065],{"class":61}," input) ",[45,2067,1347],{"class":58},[45,2069,454],{"class":68},[45,2071,130],{"class":61},[45,2073,1062],{"class":133},[45,2075,2076],{"class":61},"(input);  ",[45,2078,2079],{"class":51},"\u002F\u002F throws on 'abc'\n",[45,2081,2082],{"class":47,"line":78},[45,2083,108],{"emptyLinePlaceholder":107},[45,2085,2086],{"class":47,"line":95},[45,2087,2088],{"class":51},"\u002F\u002F ✓ Correct: `tryParse` returns null on failure — handle explicitly.\n",[45,2090,2091,2093,2095,2098,2100,2102,2104,2106,2108,2110,2113],{"class":47,"line":104},[45,2092,918],{"class":68},[45,2094,1964],{"class":58},[45,2096,2097],{"class":133}," parseSafe",[45,2099,311],{"class":61},[45,2101,297],{"class":68},[45,2103,2065],{"class":61},[45,2105,1347],{"class":58},[45,2107,454],{"class":68},[45,2109,130],{"class":61},[45,2111,2112],{"class":133},"tryParse",[45,2114,2115],{"class":61},"(input);\n",[45,2117,2118],{"class":47,"line":111},[45,2119,108],{"emptyLinePlaceholder":107},[45,2121,2122,2125,2128,2130,2132],{"class":47,"line":117},[45,2123,2124],{"class":58},"void",[45,2126,2127],{"class":133}," handleAge",[45,2129,311],{"class":61},[45,2131,297],{"class":68},[45,2133,2134],{"class":61}," input) {\n",[45,2136,2137,2139,2142,2144,2146,2148,2150],{"class":47,"line":143},[45,2138,451],{"class":58},[45,2140,2141],{"class":61}," age ",[45,2143,65],{"class":58},[45,2145,454],{"class":68},[45,2147,130],{"class":61},[45,2149,2112],{"class":133},[45,2151,2115],{"class":61},[45,2153,2154,2157,2160,2162,2164,2167,2169,2172,2174,2176,2178,2181,2184],{"class":47,"line":152},[45,2155,2156],{"class":58},"  if",[45,2158,2159],{"class":61}," (age ",[45,2161,640],{"class":58},[45,2163,1972],{"class":68},[45,2165,2166],{"class":58}," ||",[45,2168,2141],{"class":61},[45,2170,2171],{"class":58},"\u003C",[45,2173,69],{"class":68},[45,2175,2166],{"class":58},[45,2177,2141],{"class":61},[45,2179,2180],{"class":58},">",[45,2182,2183],{"class":68}," 150",[45,2185,1859],{"class":61},[45,2187,2188,2191,2194,2196,2199,2201,2204,2206],{"class":47,"line":157},[45,2189,2190],{"class":58},"    throw",[45,2192,2193],{"class":68}," ArgumentError",[45,2195,311],{"class":61},[45,2197,2198],{"class":314},"'Invalid age: ",[45,2200,1658],{"class":314},[45,2202,2203],{"class":68},"input",[45,2205,1726],{"class":314},[45,2207,518],{"class":61},[45,2209,2210],{"class":47,"line":163},[45,2211,2212],{"class":61},"  }\n",[45,2214,2215],{"class":47,"line":182},[45,2216,2217],{"class":51},"  \u002F\u002F ... use age\n",[45,2219,2220],{"class":47,"line":200},[45,2221,339],{"class":61},[45,2223,2224],{"class":47,"line":233},[45,2225,108],{"emptyLinePlaceholder":107},[45,2227,2228],{"class":47,"line":242},[45,2229,2230],{"class":51},"\u002F\u002F double ↔ int conversions:\n",[45,2232,2233,2235,2237,2240,2242,2245,2248],{"class":47,"line":247},[45,2234,415],{"class":133},[45,2236,311],{"class":61},[45,2238,2239],{"class":68},"3.7",[45,2241,130],{"class":61},[45,2243,2244],{"class":133},"toInt",[45,2246,2247],{"class":61},"());    ",[45,2249,2250],{"class":51},"\u002F\u002F 3 (truncates toward zero)\n",[45,2252,2253,2255,2257,2259,2261,2263,2265,2268],{"class":47,"line":253},[45,2254,415],{"class":133},[45,2256,311],{"class":61},[45,2258,1236],{"class":58},[45,2260,2239],{"class":68},[45,2262,130],{"class":61},[45,2264,2244],{"class":133},[45,2266,2267],{"class":61},"());   ",[45,2269,2270],{"class":51},"\u002F\u002F -3 (truncates toward zero, NOT floor)\n",[45,2272,2273,2275,2277,2280,2282,2284,2286],{"class":47,"line":277},[45,2274,415],{"class":133},[45,2276,311],{"class":61},[45,2278,2279],{"class":68},"3.0",[45,2281,130],{"class":61},[45,2283,2244],{"class":133},[45,2285,2247],{"class":61},[45,2287,1227],{"class":51},[45,2289,2290,2293],{"class":47,"line":283},[45,2291,2292],{"class":51},"\u002F\u002F print(3.7.toInt() == 3.7.floor());",[45,2294,2295],{"class":51},"  \u002F\u002F false for negatives: toInt=-3, floor=-4\n",[45,2297,2298],{"class":47,"line":289},[45,2299,108],{"emptyLinePlaceholder":107},[45,2301,2302],{"class":47,"line":294},[45,2303,2304],{"class":51},"\u002F\u002F toString with formatting:\n",[45,2306,2307,2309,2311,2314,2316,2319,2321,2323,2325],{"class":47,"line":305},[45,2308,415],{"class":133},[45,2310,311],{"class":61},[45,2312,2313],{"class":68},"3.14159",[45,2315,130],{"class":61},[45,2317,2318],{"class":133},"toStringAsFixed",[45,2320,311],{"class":61},[45,2322,219],{"class":68},[45,2324,1386],{"class":61},[45,2326,2327],{"class":51},"\u002F\u002F '3.14'\n",[45,2329,2330,2332,2334,2337,2340,2342,2345,2348],{"class":47,"line":324},[45,2331,415],{"class":133},[45,2333,311],{"class":61},[45,2335,2336],{"class":68},"255.",[45,2338,2339],{"class":133},"toRadixString",[45,2341,311],{"class":61},[45,2343,2344],{"class":68},"16",[45,2346,2347],{"class":61},"));       ",[45,2349,2350],{"class":51},"\u002F\u002F 'ff'\n",[45,2352,2353,2355,2357,2359,2361,2363,2365,2368],{"class":47,"line":336},[45,2354,415],{"class":133},[45,2356,311],{"class":61},[45,2358,2336],{"class":68},[45,2360,2339],{"class":133},[45,2362,311],{"class":61},[45,2364,219],{"class":68},[45,2366,2367],{"class":61},"));        ",[45,2369,2370],{"class":51},"\u002F\u002F '11111111'\n",[14,2372,2374],{"id":2373},"records-dart-3-value-semantic-anonymous-types","Records (Dart 3) — Value-Semantic Anonymous Types",[33,2376,2377],{"language":35},[37,2378,2380],{"className":39,"code":2379,"language":35,"meta":41,"style":41},"\u002F\u002F Records are immutable, value-equal, zero-allocation anonymous aggregates.\n\u002F\u002F Fields are positional by default, named with a label.\n({String name, int age}) user = (name: 'Alice', age: 30);\n(int x, int y) point = (3, 4);\n\n\u002F\u002F Value equality is automatic — no need to override == or hashCode:\nvar a = (x: 1, y: 2);\nvar b = (x: 1, y: 2);\nprint(a == b);  \u002F\u002F true — structural equality, built in\nprint(identical(a, b));  \u002F\u002F false — distinct instances, but equal\n\n\u002F\u002F Destructuring with patterns:\nvar (x, y) = point;  \u002F\u002F x = 3, y = 4\nvar (:name, :age) = user;  \u002F\u002F name = 'Alice', age = 30\n\n\u002F\u002F Use records instead of tiny one-off classes:\n({User user, List\u003CRepo> repos}) fetchProfile(String username) async {\n  \u002F\u002F ... no need to define a Profile class\n  return (user: u, repos: r);\n}\n",[18,2381,2382,2387,2392,2428,2454,2458,2463,2487,2509,2524,2537,2541,2546,2561,2585,2589,2594,2630,2635,2652],{"__ignoreMap":41},[45,2383,2384],{"class":47,"line":48},[45,2385,2386],{"class":51},"\u002F\u002F Records are immutable, value-equal, zero-allocation anonymous aggregates.\n",[45,2388,2389],{"class":47,"line":55},[45,2390,2391],{"class":51},"\u002F\u002F Fields are positional by default, named with a label.\n",[45,2393,2394,2397,2399,2402,2404,2407,2409,2412,2415,2418,2421,2423,2426],{"class":47,"line":78},[45,2395,2396],{"class":61},"({",[45,2398,297],{"class":68},[45,2400,2401],{"class":61}," name, ",[45,2403,918],{"class":68},[45,2405,2406],{"class":61}," age}) user ",[45,2408,65],{"class":58},[45,2410,2411],{"class":61}," (name",[45,2413,2414],{"class":58},":",[45,2416,2417],{"class":314}," 'Alice'",[45,2419,2420],{"class":61},", age",[45,2422,2414],{"class":58},[45,2424,2425],{"class":68}," 30",[45,2427,518],{"class":61},[45,2429,2430,2432,2434,2437,2439,2442,2444,2446,2448,2450,2452],{"class":47,"line":95},[45,2431,311],{"class":61},[45,2433,918],{"class":68},[45,2435,2436],{"class":61}," x, ",[45,2438,918],{"class":68},[45,2440,2441],{"class":61}," y) point ",[45,2443,65],{"class":58},[45,2445,1553],{"class":61},[45,2447,224],{"class":68},[45,2449,216],{"class":61},[45,2451,702],{"class":68},[45,2453,518],{"class":61},[45,2455,2456],{"class":47,"line":104},[45,2457,108],{"emptyLinePlaceholder":107},[45,2459,2460],{"class":47,"line":111},[45,2461,2462],{"class":51},"\u002F\u002F Value equality is automatic — no need to override == or hashCode:\n",[45,2464,2465,2467,2469,2471,2474,2476,2478,2481,2483,2485],{"class":47,"line":117},[45,2466,20],{"class":58},[45,2468,370],{"class":61},[45,2470,65],{"class":58},[45,2472,2473],{"class":61}," (x",[45,2475,2414],{"class":58},[45,2477,974],{"class":68},[45,2479,2480],{"class":61},", y",[45,2482,2414],{"class":58},[45,2484,1177],{"class":68},[45,2486,518],{"class":61},[45,2488,2489,2491,2493,2495,2497,2499,2501,2503,2505,2507],{"class":47,"line":143},[45,2490,20],{"class":58},[45,2492,394],{"class":61},[45,2494,65],{"class":58},[45,2496,2473],{"class":61},[45,2498,2414],{"class":58},[45,2500,974],{"class":68},[45,2502,2480],{"class":61},[45,2504,2414],{"class":58},[45,2506,1177],{"class":68},[45,2508,518],{"class":61},[45,2510,2511,2513,2516,2518,2521],{"class":47,"line":152},[45,2512,415],{"class":133},[45,2514,2515],{"class":61},"(a ",[45,2517,640],{"class":58},[45,2519,2520],{"class":61}," b);  ",[45,2522,2523],{"class":51},"\u002F\u002F true — structural equality, built in\n",[45,2525,2526,2528,2530,2532,2534],{"class":47,"line":157},[45,2527,415],{"class":133},[45,2529,311],{"class":61},[45,2531,420],{"class":133},[45,2533,423],{"class":61},[45,2535,2536],{"class":51},"\u002F\u002F false — distinct instances, but equal\n",[45,2538,2539],{"class":47,"line":163},[45,2540,108],{"emptyLinePlaceholder":107},[45,2542,2543],{"class":47,"line":182},[45,2544,2545],{"class":51},"\u002F\u002F Destructuring with patterns:\n",[45,2547,2548,2550,2553,2555,2558],{"class":47,"line":200},[45,2549,20],{"class":58},[45,2551,2552],{"class":61}," (x, y) ",[45,2554,65],{"class":58},[45,2556,2557],{"class":61}," point;  ",[45,2559,2560],{"class":51},"\u002F\u002F x = 3, y = 4\n",[45,2562,2563,2565,2567,2569,2572,2574,2577,2579,2582],{"class":47,"line":233},[45,2564,20],{"class":58},[45,2566,1553],{"class":61},[45,2568,2414],{"class":58},[45,2570,2571],{"class":61},"name, ",[45,2573,2414],{"class":58},[45,2575,2576],{"class":61},"age) ",[45,2578,65],{"class":58},[45,2580,2581],{"class":61}," user;  ",[45,2583,2584],{"class":51},"\u002F\u002F name = 'Alice', age = 30\n",[45,2586,2587],{"class":47,"line":242},[45,2588,108],{"emptyLinePlaceholder":107},[45,2590,2591],{"class":47,"line":247},[45,2592,2593],{"class":51},"\u002F\u002F Use records instead of tiny one-off classes:\n",[45,2595,2596,2598,2601,2604,2607,2609,2612,2615,2618,2620,2622,2625,2628],{"class":47,"line":253},[45,2597,2396],{"class":61},[45,2599,2600],{"class":68},"User",[45,2602,2603],{"class":61}," user, ",[45,2605,2606],{"class":68},"List",[45,2608,2171],{"class":61},[45,2610,2611],{"class":68},"Repo",[45,2613,2614],{"class":61},"> repos}) ",[45,2616,2617],{"class":133},"fetchProfile",[45,2619,311],{"class":61},[45,2621,297],{"class":68},[45,2623,2624],{"class":61}," username) ",[45,2626,2627],{"class":58},"async",[45,2629,446],{"class":61},[45,2631,2632],{"class":47,"line":277},[45,2633,2634],{"class":51},"  \u002F\u002F ... no need to define a Profile class\n",[45,2636,2637,2639,2642,2644,2647,2649],{"class":47,"line":283},[45,2638,327],{"class":58},[45,2640,2641],{"class":61}," (user",[45,2643,2414],{"class":58},[45,2645,2646],{"class":61}," u, repos",[45,2648,2414],{"class":58},[45,2650,2651],{"class":61}," r);\n",[45,2653,2654],{"class":47,"line":289},[45,2655,339],{"class":61},[14,2657,2659],{"id":2658},"tips-tricks","💡 Tips & Tricks",[2661,2662,2663,2683,2692,2710,2725],"ul",{},[2664,2665,2666,2670,2671,2673,2674,2676,2677,2679,2680,2682],"li",{},[2667,2668,2669],"strong",{},"Performance",": ",[18,2672,27],{}," objects are canonicalized at compile time — using ",[18,2675,27],{}," in hot paths (Flutter widget trees, lookup tables) means zero allocation and zero GC pressure. Prefer ",[18,2678,27],{}," over ",[18,2681,24],{}," when the value is known at compile time.",[2664,2684,2685,2670,2688,2691],{},[2667,2686,2687],{},"Idiom",[18,2689,2690],{},"late final x = expensive()"," defers computation until first read — the initializer runs once and caches. Use for expensive fields that may never be accessed (e.g., a debug-only inspector).",[2664,2693,2694,2670,2696,2679,2698,2700,2701,2703,2704,2706,2707,2709],{},[2667,2695,2687],{},[18,2697,1776],{},[18,2699,1779],{}," for \"any non-null value\" — ",[18,2702,1776],{}," preserves static type checking (you must cast), while ",[18,2705,1779],{}," silently disables it. ",[18,2708,1779],{}," should only appear at JSON\u002FJS interop boundaries.",[2664,2711,2712,2715,2716,2718,2719,2721,2722,2724],{},[2667,2713,2714],{},"Portability",": use ",[18,2717,1049],{}," for integers above 2^53 that must work on web — ",[18,2720,918],{}," on web is a JS double and loses precision. On native, ",[18,2723,918],{}," is 64-bit and safe up to 2^63-1.",[2664,2726,2727,2670,2730,2733,2734,2737,2738,2741,2742,2745],{},[2667,2728,2729],{},"Debug",[18,2731,2732],{},"print(obj)"," calls ",[18,2735,2736],{},"obj.toString()",". Always override ",[18,2739,2740],{},"toString()"," on domain objects — the default ",[18,2743,2744],{},"'Instance of Foo'"," is useless in logs and error messages.",[14,2747,2749],{"id":2748},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2661,2751,2752,2782,2813,2833,2845,2864,2887,2906,2930,2950],{},[2664,2753,2754,2670,2765,216,2768,216,2771,216,2774,2777,2778,2781],{},[2667,2755,2756,2757,2760,2761,2764],{},"Only ",[18,2758,2759],{},"true","\u002F",[18,2762,2763],{},"false"," are boolean",[18,2766,2767],{},"if (0)",[18,2769,2770],{},"if ('')",[18,2772,2773],{},"if (null)",[18,2775,2776],{},"if ([])"," are all compile errors. Dart has no truthy\u002Ffalsy coercion (unlike JS). Only ",[18,2779,2780],{},"if (bool)"," is valid.",[2664,2783,2784,2670,2797,2800,2801,2804,2805,2808,2809,2812],{},[2667,2785,2786,2789,2790,2793,2794],{},[18,2787,2788],{},"{}"," is an empty ",[18,2791,2792],{},"Map",", not a ",[18,2795,2796],{},"Set",[18,2798,2799],{},"var x = {}"," infers ",[18,2802,2803],{},"Map\u003Cdynamic, dynamic>",". Use ",[18,2806,2807],{},"var x = \u003Cint>{}"," or ",[18,2810,2811],{},"Set\u003Cint>()"," for an empty Set.",[2664,2814,2815,2670,2820,2823,2824,2826,2827,2808,2829,2832],{},[2667,2816,2817,2819],{},[18,2818,24],{}," doesn't freeze collections",[18,2821,2822],{},"final list = [1,2,3]; list.add(4)"," works — ",[18,2825,24],{}," locks the reference, not the contents. Use ",[18,2828,27],{},[18,2830,2831],{},"List.unmodifiable([...source])"," for true immutability.",[2664,2834,2835,2841,2842,2844],{},[2667,2836,2837,2840],{},[18,2838,2839],{},"List.unmodifiable"," is a view",": it wraps the source list. Mutating the source is visible through the view. Use ",[18,2843,2831],{}," for an immutable copy.",[2664,2846,2847,2670,2853,2856,2857,2804,2860,2863],{},[2667,2848,2849,2850,2852],{},"Reading a ",[18,2851,30],{}," variable before assignment throws",[18,2854,2855],{},"late int x; print(x);"," → ",[18,2858,2859],{},"LateInitializationError",[18,2861,2862],{},"late final x = initializer"," to guarantee safe lazy initialization.",[2664,2865,2866,2670,2871,2874,2875,2877,2878,2880,2881,2883,2884,130],{},[2667,2867,2868,2870],{},[18,2869,27],{}," requires compile-time-known values",[18,2872,2873],{},"const x = DateTime.now()"," fails. ",[18,2876,24],{}," accepts runtime values. ",[18,2879,27],{}," inside a ",[18,2882,24],{}," context is fine: ",[18,2885,2886],{},"final x = const [1,2,3]",[2664,2888,2889,2670,2894,2897,2898,2901,2902,2905],{},[2667,2890,2891,2893],{},[18,2892,918],{}," on web loses precision above 2^53",[18,2895,2896],{},"int.parse('9007199254740993')"," on web gives ",[18,2899,2900],{},"9007199254740992"," (rounded double). Use ",[18,2903,2904],{},"BigInt.parse"," for exact large integers on web.",[2664,2907,2908,2670,2915,2918,2919,2921,2922,2925,2926,2929],{},[2667,2909,2910,2911,2914],{},"String ",[18,2912,2913],{},".length"," is UTF-16 code units, not characters",[18,2916,2917],{},"'🎉'.length"," is ",[18,2920,219],{}," (surrogate pair). Use ",[18,2923,2924],{},".runes.length"," for code points, or the ",[18,2927,2928],{},"characters"," package for grapheme clusters.",[2664,2931,2932,2670,2939,2942,2943,2945,2946,2949],{},[2667,2933,2934,2935,2938],{},"Integer division ",[18,2936,2937],{},"~\u002F"," truncates toward zero",[18,2940,2941],{},"-7 ~\u002F 2 = -3"," (not -4). ",[18,2944,1353],{}," follows the sign of the dividend: ",[18,2947,2948],{},"-7 % 3 = -1"," (not 2 like Python).",[2664,2951,2952,2670,2959,2918,2962,2965,2966,2969,2970,2808,2973,2976,2977,130],{},[2667,2953,2954,2956,2957],{},[18,2955,2740],{}," on ",[18,2958,924],{},[18,2960,2961],{},"3.0.toString()",[18,2963,2964],{},"'3.0'"," (not ",[18,2967,2968],{},"'3'","). Use ",[18,2971,2972],{},"toInt().toString()",[18,2974,2975],{},"toStringAsFixed(0)"," for ",[18,2978,2968],{},[14,2980,2982],{"id":2981},"spot-the-bug","🧠 Spot the Bug",[1723,2984,2985,2986,2988],{},"A developer caches configuration with ",[18,2987,24],{},", expecting it to be immutable. Another part of the code mutates it:",[33,2990,2991],{"language":35},[37,2992,2994],{"className":39,"code":2993,"language":35,"meta":41,"style":41},"class Config {\n  final Map\u003CString, String> settings = {'env': 'prod', 'debug': 'false'};\n\n  void override(String key, String value) {\n    settings[key] = value;  \u002F\u002F mutates the \"final\" map\n  }\n}\n\nvoid main() {\n  final config = Config();\n  config.override('env', 'dev');\n  print(config.settings['env']);  \u002F\u002F 'dev' — the \"final\" map was mutated!\n}\n",[18,2995,2996,3005,3049,3053,3073,3086,3090,3094,3098,3107,3120,3139,3153],{"__ignoreMap":41},[45,2997,2998,3000,3003],{"class":47,"line":48},[45,2999,440],{"class":58},[45,3001,3002],{"class":68}," Config",[45,3004,446],{"class":61},[45,3006,3007,3009,3012,3014,3016,3018,3020,3023,3025,3028,3031,3033,3036,3038,3041,3043,3046],{"class":47,"line":55},[45,3008,451],{"class":58},[45,3010,3011],{"class":68}," Map",[45,3013,2171],{"class":61},[45,3015,297],{"class":68},[45,3017,216],{"class":61},[45,3019,297],{"class":68},[45,3021,3022],{"class":61},"> settings ",[45,3024,65],{"class":58},[45,3026,3027],{"class":61}," {",[45,3029,3030],{"class":314},"'env'",[45,3032,2414],{"class":58},[45,3034,3035],{"class":314}," 'prod'",[45,3037,216],{"class":61},[45,3039,3040],{"class":314},"'debug'",[45,3042,2414],{"class":58},[45,3044,3045],{"class":314}," 'false'",[45,3047,3048],{"class":61},"};\n",[45,3050,3051],{"class":47,"line":78},[45,3052,108],{"emptyLinePlaceholder":107},[45,3054,3055,3058,3061,3063,3065,3068,3070],{"class":47,"line":95},[45,3056,3057],{"class":58},"  void",[45,3059,3060],{"class":133}," override",[45,3062,311],{"class":61},[45,3064,297],{"class":68},[45,3066,3067],{"class":61}," key, ",[45,3069,297],{"class":68},[45,3071,3072],{"class":61}," value) {\n",[45,3074,3075,3078,3080,3083],{"class":47,"line":104},[45,3076,3077],{"class":61},"    settings[key] ",[45,3079,65],{"class":58},[45,3081,3082],{"class":61}," value;  ",[45,3084,3085],{"class":51},"\u002F\u002F mutates the \"final\" map\n",[45,3087,3088],{"class":47,"line":111},[45,3089,2212],{"class":61},[45,3091,3092],{"class":47,"line":117},[45,3093,339],{"class":61},[45,3095,3096],{"class":47,"line":143},[45,3097,108],{"emptyLinePlaceholder":107},[45,3099,3100,3102,3105],{"class":47,"line":152},[45,3101,2124],{"class":58},[45,3103,3104],{"class":133}," main",[45,3106,302],{"class":61},[45,3108,3109,3111,3113,3115,3117],{"class":47,"line":157},[45,3110,451],{"class":58},[45,3112,264],{"class":61},[45,3114,65],{"class":58},[45,3116,3002],{"class":68},[45,3118,3119],{"class":61},"();\n",[45,3121,3122,3125,3128,3130,3132,3134,3137],{"class":47,"line":163},[45,3123,3124],{"class":61},"  config.",[45,3126,3127],{"class":133},"override",[45,3129,311],{"class":61},[45,3131,3030],{"class":314},[45,3133,216],{"class":61},[45,3135,3136],{"class":314},"'dev'",[45,3138,518],{"class":61},[45,3140,3141,3143,3146,3148,3150],{"class":47,"line":182},[45,3142,308],{"class":133},[45,3144,3145],{"class":61},"(config.settings[",[45,3147,3030],{"class":314},[45,3149,818],{"class":61},[45,3151,3152],{"class":51},"\u002F\u002F 'dev' — the \"final\" map was mutated!\n",[45,3154,3155],{"class":47,"line":200},[45,3156,339],{"class":61},[1723,3158,3159],{},"What's wrong and how to fix it?",[3161,3162,3163,3167,3186,3196,3376],"details",{},[3164,3165,3166],"summary",{},"Answer",[1723,3168,3169,3171,3172,3175,3176,3178,3179,3182,3183,3185],{},[18,3170,24],{}," locks the reference (",[18,3173,3174],{},"settings"," can't be reassigned), but the ",[18,3177,2792],{}," itself is mutable. ",[18,3180,3181],{},"settings[key] = value"," mutates the contents — the \"final\" map is changed. ",[18,3184,24],{}," is not deep immutability.",[1723,3187,3188,3189,3192,3193,3195],{},"The fix — use ",[18,3190,3191],{},"Map.unmodifiable"," (runtime) or ",[18,3194,27],{}," (compile-time):",[37,3197,3199],{"className":39,"code":3198,"language":35,"meta":41,"style":41},"class Config {\n  \u002F\u002F Runtime immutable — throws on any mutation attempt.\n  final Map\u003CString, String> settings = Map.unmodifiable({'env': 'prod', 'debug': 'false'});\n\n  void override(String key, String value) {\n    \u002F\u002F settings[key] = value;  \u002F\u002F ✗ UnsupportedError at runtime\n    throw UnsupportedError('Config is immutable — create a new instance to override.');\n  }\n}\n\n\u002F\u002F Or compile-time immutable (if values are literals):\nclass Config {\n  const Config();\n  static const Map\u003CString, String> settings = {'env': 'prod', 'debug': 'false'};\n}\n",[18,3200,3201,3209,3214,3257,3261,3277,3285,3299,3303,3307,3311,3316,3324,3332,3372],{"__ignoreMap":41},[45,3202,3203,3205,3207],{"class":47,"line":48},[45,3204,440],{"class":58},[45,3206,3002],{"class":68},[45,3208,446],{"class":61},[45,3210,3211],{"class":47,"line":55},[45,3212,3213],{"class":51},"  \u002F\u002F Runtime immutable — throws on any mutation attempt.\n",[45,3215,3216,3218,3220,3222,3224,3226,3228,3230,3232,3234,3236,3238,3240,3242,3244,3246,3248,3250,3252,3254],{"class":47,"line":78},[45,3217,451],{"class":58},[45,3219,3011],{"class":68},[45,3221,2171],{"class":61},[45,3223,297],{"class":68},[45,3225,216],{"class":61},[45,3227,297],{"class":68},[45,3229,3022],{"class":61},[45,3231,65],{"class":58},[45,3233,3011],{"class":68},[45,3235,130],{"class":61},[45,3237,802],{"class":133},[45,3239,2396],{"class":61},[45,3241,3030],{"class":314},[45,3243,2414],{"class":58},[45,3245,3035],{"class":314},[45,3247,216],{"class":61},[45,3249,3040],{"class":314},[45,3251,2414],{"class":58},[45,3253,3045],{"class":314},[45,3255,3256],{"class":61},"});\n",[45,3258,3259],{"class":47,"line":95},[45,3260,108],{"emptyLinePlaceholder":107},[45,3262,3263,3265,3267,3269,3271,3273,3275],{"class":47,"line":104},[45,3264,3057],{"class":58},[45,3266,3060],{"class":133},[45,3268,311],{"class":61},[45,3270,297],{"class":68},[45,3272,3067],{"class":61},[45,3274,297],{"class":68},[45,3276,3072],{"class":61},[45,3278,3279,3282],{"class":47,"line":111},[45,3280,3281],{"class":51},"    \u002F\u002F settings[key] = value;",[45,3283,3284],{"class":51},"  \u002F\u002F ✗ UnsupportedError at runtime\n",[45,3286,3287,3289,3292,3294,3297],{"class":47,"line":117},[45,3288,2190],{"class":58},[45,3290,3291],{"class":68}," UnsupportedError",[45,3293,311],{"class":61},[45,3295,3296],{"class":314},"'Config is immutable — create a new instance to override.'",[45,3298,518],{"class":61},[45,3300,3301],{"class":47,"line":143},[45,3302,2212],{"class":61},[45,3304,3305],{"class":47,"line":152},[45,3306,339],{"class":61},[45,3308,3309],{"class":47,"line":157},[45,3310,108],{"emptyLinePlaceholder":107},[45,3312,3313],{"class":47,"line":163},[45,3314,3315],{"class":51},"\u002F\u002F Or compile-time immutable (if values are literals):\n",[45,3317,3318,3320,3322],{"class":47,"line":182},[45,3319,440],{"class":58},[45,3321,3002],{"class":68},[45,3323,446],{"class":61},[45,3325,3326,3328,3330],{"class":47,"line":200},[45,3327,462],{"class":58},[45,3329,3002],{"class":68},[45,3331,3119],{"class":61},[45,3333,3334,3337,3340,3342,3344,3346,3348,3350,3352,3354,3356,3358,3360,3362,3364,3366,3368,3370],{"class":47,"line":233},[45,3335,3336],{"class":58},"  static",[45,3338,3339],{"class":58}," const",[45,3341,3011],{"class":68},[45,3343,2171],{"class":61},[45,3345,297],{"class":68},[45,3347,216],{"class":61},[45,3349,297],{"class":68},[45,3351,3022],{"class":61},[45,3353,65],{"class":58},[45,3355,3027],{"class":61},[45,3357,3030],{"class":314},[45,3359,2414],{"class":58},[45,3361,3035],{"class":314},[45,3363,216],{"class":61},[45,3365,3040],{"class":314},[45,3367,2414],{"class":58},[45,3369,3045],{"class":314},[45,3371,3048],{"class":61},[45,3373,3374],{"class":47,"line":242},[45,3375,339],{"class":61},[1723,3377,3378,3380,3381,3383,3384,3387,3388,3390,3391,3393,3394,3396],{},[18,3379,24],{}," = single-assignment reference. ",[18,3382,27],{}," = deeply immutable + canonicalized. ",[18,3385,3386],{},"List\u002FMap.unmodifiable"," = runtime immutable view. Choose based on whether the value is known at compile time (",[18,3389,27],{},"), constructed at runtime (",[18,3392,802],{},"), or genuinely mutable (",[18,3395,24],{}," + mutable collection).",[3398,3399,3400],"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 .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html 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":41,"searchDepth":55,"depth":55,"links":3402},[3403,3410,3416,3418,3419,3420,3421,3422],{"id":16,"depth":55,"text":3404,"children":3405},"var \u002F final \u002F const \u002F late — Allocation & Canonicalization",[3406,3408],{"id":343,"depth":78,"text":3407},"const Canonicalization — Memory Sharing",{"id":649,"depth":78,"text":3409},"final vs const — The Deep Immutability Trap",{"id":910,"depth":55,"text":911,"children":3411},[3412,3414,3415],{"id":914,"depth":78,"text":3413},"Numbers: int, double, num",{"id":1149,"depth":78,"text":1150},{"id":1392,"depth":78,"text":1393},{"id":1773,"depth":55,"text":3417},"Object vs dynamic vs Object? — Type Safety Boundaries",{"id":2038,"depth":55,"text":2039},{"id":2373,"depth":55,"text":2374},{"id":2658,"depth":55,"text":2659},{"id":2748,"depth":55,"text":2749},{"id":2981,"depth":55,"text":2982},"Deep-dive into Dart's static type system, const\u002Ffinal\u002Flate memory semantics, canonicalization, platform-dependent int precision, and nullable type algebra. Code-first engineering reference.","md",{},"\u002Fdart\u002F02-variables-and-data-types",{"title":5,"description":3423},"dart\u002F02-variables-and-data-types","Q0qzxAul2GsNDHAf2yyrOrv7M0lvnanpZSOGfLwFG4k",1789924647644]