[{"data":1,"prerenderedAt":25126},["ShallowReactive",2],{"chapter-lessons-ch18-polymorphism-many-forms":3},[4,60,524,950,1212,1428,1648,1916,2095,2271,2440,2632,2840,3086,3318,3562,3769,4044,4196,4333,4447,4672,5030,5287,5549,5758,6032,6402,6673,7043,7322,7661,7970,8368,8663,9025,9262,9512,9962,10208,10542,10919,11225,11542,12094,12520,13124,13418,13550,14263,14836,15205,15493,15781,16269,16580,16901,17202,17543,17944,18326,18747,19230,19685,20135,20372,20803,21020,21227,21518,21813,22366,22577,22800,22913,23405,23754,24026,24371,24401,24426,24451,24476,24501,24526,24551,24576,24601,24626,24651,24676,24701,24726,24751,24776,24801,24826,24851,24876,24901,24926,24951,24976,25001,25026,25051,25076,25101],{"id":5,"title":6,"body":7,"description":17,"extension":51,"meta":52,"navigation":55,"path":56,"seo":57,"stem":58,"__hash__":59},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.1-why-java-for-frc.md","Why Java for FRC?",{"type":8,"value":9,"toc":47},"minimark",[10,14,18],[11,12,6],"h1",{"id":13},"why-java-for-frc",[15,16,17],"p",{},"Java is one of the most popular languages in the world, and the standard for most FRC teams.",[19,20,21,29,35,41],"ul",{},[22,23,24,28],"li",{},[25,26,27],"strong",{},"Static Typing:"," Catch errors at compile-time before they reach the robot.",[22,30,31,34],{},[25,32,33],{},"Object-Oriented:"," Perfect for modeling physical systems like motors and sensors.",[22,36,37,40],{},[25,38,39],{},"Performance:"," The JVM (Java Virtual Machine) is fast enough for real-time control loops.",[22,42,43,46],{},[25,44,45],{},"Ecosystem:"," Access to WPILib, thousands of libraries, and years of documentation.",{"title":48,"searchDepth":49,"depth":49,"links":50},"",2,[],"md",{"outlineRef":53,"status":54},"1.1 — Why Java for FRC?","existing — deck's original motivational slide, pulled verbatim. Intro only — no exercise, no CSA source; 1.2 is where the real lesson content starts.",true,"\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1-why-java-for-frc",{"title":6,"description":17},"shockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.1-why-java-for-frc","BUSgek9NWwnfapsWxxhcfsj7bzHRV2q-TYfyDERCsMY",{"id":61,"title":62,"body":63,"description":48,"extension":51,"meta":517,"navigation":55,"path":520,"seo":521,"stem":522,"__hash__":523},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.2-intro-to-algorithms-programming-and-compilers.md","Intro to Algorithms, Programming & Compilers",{"type":8,"value":64,"toc":506},[65,68,73,80,87,91,103,154,172,176,187,196,199,213,217,227,230,252,265,269,287,290,333,347,351,373,380,384,394,409,413,447,451,491,502],[11,66,62],{"id":67},"intro-to-algorithms-programming-compilers",[69,70,72],"h2",{"id":71},"algorithms","Algorithms",[15,74,75,76,79],{},"An algorithm is just a set of ordered steps to solve a problem — a recipe, directions to a house, and a Java program are all algorithms. Steps run in order, one at a time — this is called ",[25,77,78],{},"sequencing",".",[15,81,82,83,86],{},"Before writing real code, it helps to plan the steps first: in plain English, a diagram, or ",[25,84,85],{},"pseudocode"," (simplified fake-code written on paper, not run by anything). Getting the steps straight on paper first is what turns a half-formed idea into code that actually works.",[69,88,90],{"id":89},"your-first-java-program","Your First Java Program",[15,92,93,94,98,99,102],{},"Every Java program lives inside a ",[95,96,97],"code",{},"class",", and every class you run needs a ",[95,100,101],{},"main"," method — that's where the program starts running.",[104,105,109],"pre",{"className":106,"code":107,"language":108,"meta":48,"style":48},"language-java shiki shiki-themes github-light github-dark","public class MyClass\n{\n    public static void main(String[] args)\n    {\n        System.out.println(\"Hi there!\");\n    }\n}\n","java",[95,110,111,119,124,130,136,142,148],{"__ignoreMap":48},[112,113,116],"span",{"class":114,"line":115},"line",1,[112,117,118],{},"public class MyClass\n",[112,120,121],{"class":114,"line":49},[112,122,123],{},"{\n",[112,125,127],{"class":114,"line":126},3,[112,128,129],{},"    public static void main(String[] args)\n",[112,131,133],{"class":114,"line":132},4,[112,134,135],{},"    {\n",[112,137,139],{"class":114,"line":138},5,[112,140,141],{},"        System.out.println(\"Hi there!\");\n",[112,143,145],{"class":114,"line":144},6,[112,146,147],{},"    }\n",[112,149,151],{"class":114,"line":150},7,[112,152,153],{},"}\n",[15,155,156,157,160,161,164,165,168,169,79],{},"Every open curly brace ",[95,158,159],{},"{"," needs a matching close ",[95,162,163],{},"}",". The file itself has to be named the same as the class — ",[95,166,167],{},"MyClass.java"," for ",[95,170,171],{},"public class MyClass",[69,173,175],{"id":174},"every-statement-ends-with-a-semicolon","Every Statement Ends With a Semicolon",[15,177,178,179,182,183,186],{},"Each individual instruction is a ",[25,180,181],{},"statement",", and every statement ends with ",[95,184,185],{},";"," — think of it like a period ending a sentence.",[104,188,190],{"className":106,"code":189,"language":108,"meta":48,"style":48},"System.out.println(\"Hi there!\");\n",[95,191,192],{"__ignoreMap":48},[112,193,194],{"class":114,"line":115},[112,195,189],{},[15,197,198],{},"Miss it, and the program won't compile. This is one of the most common mistakes when you're starting out — expect it, don't stress about it.",[15,200,201,202,204,205,207,208,210,211,79],{},"Not everything ends in ",[95,203,185],{},". A line that opens a block, like the ",[95,206,97],{}," or ",[95,209,101],{}," line above, has no semicolon before its ",[95,212,159],{},[69,214,216],{"id":215},"compiling-how-your-code-actually-runs","Compiling: How Your Code Actually Runs",[15,218,219,220,223,224,79],{},"Computers don't understand Java directly. A ",[25,221,222],{},"compiler"," checks your code for mistakes and translates it into something the computer can run. If it finds a mistake, it stops and tells you — that's a ",[25,225,226],{},"syntax error",[15,228,229],{},"For this course, you have two ways to write and run your code:",[19,231,232,246],{},[22,233,234,237,238,245],{},[25,235,236],{},"Use your own IDE",", like ",[239,240,244],"a",{"href":241,"rel":242},"https:\u002F\u002Fcode.visualstudio.com\u002F",[243],"nofollow","VS Code"," with the Java extension — genuinely how most FRC teams write real robot code, so it's good practice either way. Write and run it there, then copy your finished code into this course's checker when an exercise asks for it.",[22,247,248,251],{},[25,249,250],{},"Use this course's built-in checker directly"," — no copying needed. This part of the course is still being built, so it's not ready yet.",[15,253,254,255,260,261],{},"For now, the first option is what actually works: write and run your code in a real IDE (or an online one, like ",[239,256,259],{"href":257,"rel":258},"https:\u002F\u002Freplit.com\u002F",[243],"Replit","), then paste the result in when an exercise asks for it. ",[262,263,264],"em",{},"(This section will get an update once the built-in checker exists.)",[69,266,268],{"id":267},"keywords-and-naming","Keywords and Naming",[15,270,271,272,275,276,278,279,282,283,286],{},"Words like ",[95,273,274],{},"public",", ",[95,277,97],{},", and ",[95,280,281],{},"void"," are ",[25,284,285],{},"keywords"," — reserved words with a fixed meaning in Java. Keywords are always lowercase.",[15,288,289],{},"Everything else — every name you pick yourself — follows one of three styles:",[19,291,292,304,320],{},[22,293,294,297,298,275,301,79],{},[25,295,296],{},"lowerCamelCase"," — variables and methods start lowercase, then capitalize each new word: ",[95,299,300],{},"motorSpeed",[95,302,303],{},"calculateTotal()",[22,305,306,309,310,275,313,316,317,79],{},[25,307,308],{},"PascalCase"," (also called UpperCamelCase) — classes and interfaces capitalize every word, including the first: ",[95,311,312],{},"System",[95,314,315],{},"String",", or a class you write yourself like ",[95,318,319],{},"Drivetrain",[22,321,322,325,326,275,329,332],{},[25,323,324],{},"SCREAMING_SNAKE_CASE"," — constants (values that never change) are all uppercase with underscores between words: ",[95,327,328],{},"MAX_SPEED",[95,330,331],{},"PI",". You'll see this style starting in Ch.23.",[15,334,335,336,339,340,342,343,346],{},"That's why ",[95,337,338],{},"System.out.println(...)"," looks the way it does: ",[95,341,312],{}," is a class, so it's PascalCase. ",[95,344,345],{},"println"," is a method — here it's just one word, so there's no second word to capitalize, but it still starts lowercase like every method name does.",[69,348,350],{"id":349},"syntax-errors-vs-run-time-errors","Syntax Errors vs. Run-Time Errors",[19,352,353,367],{},[22,354,355,356,358,359,361,362,207,364,79],{},"A ",[25,357,226],{}," is caught by the compiler, before your program ever runs — a missing ",[95,360,185],{},", an unmatched ",[95,363,159],{},[95,365,366],{},"\"",[22,368,355,369,372],{},[25,370,371],{},"run-time error"," happens while the program is running, after it already compiled — like dividing by zero.",[15,374,375,376,379],{},"Both are normal. Finding and fixing errors is called ",[25,377,378],{},"debugging"," — informally, an error is a \"bug.\" If you're stuck, explaining your code line-by-line out loud — even to an inanimate object, a real technique called \"rubber duck debugging\" — often reveals the problem before you finish explaining it.",[69,381,383],{"id":382},"comments","Comments",[15,385,386,389,390,393],{},[95,387,388],{},"\u002F\u002F"," starts a comment that runs to the end of the line; ",[95,391,392],{},"\u002F* ... *\u002F"," comments out everything in between, even across multiple lines. The compiler ignores comments completely — they exist to explain your code to yourself and your teammates.",[104,395,397],{"className":106,"code":396,"language":108,"meta":48,"style":48},"\u002F\u002F this line is ignored by the compiler\nint score = 10; \u002F\u002F so is this part, after the \u002F\u002F\n",[95,398,399,404],{"__ignoreMap":48},[112,400,401],{"class":114,"line":115},[112,402,403],{},"\u002F\u002F this line is ignored by the compiler\n",[112,405,406],{"class":114,"line":49},[112,407,408],{},"int score = 10; \u002F\u002F so is this part, after the \u002F\u002F\n",[69,410,412],{"id":411},"common-pitfalls","Common Pitfalls",[19,414,415,421,437],{},[22,416,417,420],{},[25,418,419],{},"Missing a semicolon."," The single most common first error — check the end of the line the compiler points at, and the line just before it.",[22,422,423,426,427,429,430,275,432,275,434,436],{},[25,424,425],{},"Mismatched capitalization."," ",[95,428,312],{}," is capitalized (it's a class); ",[95,431,274],{},[95,433,97],{},[95,435,281],{}," are not (they're keywords). Java is case-sensitive everywhere.",[22,438,439,442,443,446],{},[25,440,441],{},"Trusting the error's line number completely."," The compiler tells you where it ",[262,444,445],{},"noticed"," the problem, which is sometimes a line or two after where the actual mistake is.",[69,448,450],{"id":449},"key-takeaways","Key Takeaways",[19,452,453,456,459,468,473,476,479,482],{},[22,454,455],{},"An algorithm is an ordered set of steps, run one at a time (sequencing) — you already use these outside of code.",[22,457,458],{},"Planning steps in plain English or pseudocode before coding turns a half-formed idea into working code.",[22,460,461,462,464,465,467],{},"Every Java program has a ",[95,463,97],{},", and a ",[95,466,101],{}," method where it starts running.",[22,469,470,471,79],{},"Every statement ends with ",[95,472,185],{},[22,474,475],{},"Three naming styles: lowerCamelCase (variables\u002Fmethods), PascalCase (classes\u002Finterfaces), SCREAMING_SNAKE_CASE (constants).",[22,477,478],{},"A compiler checks your code and translates it to run; a syntax error is a mistake it catches before your program ever runs.",[22,480,481],{},"Write and run code in a real IDE (like VS Code) or an online one, then paste it in when an exercise asks for it.",[22,483,484,486,487,490],{},[95,485,388],{}," and ",[95,488,489],{},"\u002F* *\u002F"," are comments — the compiler ignores them completely.",[15,492,493,494,497,498,501],{},"Derived from ",[95,495,496],{},"csawesome-2026",": ",[95,499,500],{},"unit-1-using-objects-and-methods\u002F1.01-introduction-to-algorithms-programming-and-compilers.md"," (CSA 1.1)",[503,504,505],"style",{},"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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":48,"searchDepth":49,"depth":49,"links":507},[508,509,510,511,512,513,514,515,516],{"id":71,"depth":49,"text":72},{"id":89,"depth":49,"text":90},{"id":174,"depth":49,"text":175},{"id":215,"depth":49,"text":216},{"id":267,"depth":49,"text":268},{"id":349,"depth":49,"text":350},{"id":382,"depth":49,"text":383},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":518,"status":519},"1.2 — Intro to Algorithms, Programming and Compilers (CSA 1.1)","new — authored lesson (fuller depth than the teaser slide)","\u002Fshockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F2-intro-to-algorithms-programming-and-compilers",{"title":62,"description":48},"shockwave-curriculum\u002Flessons\u002Fch01-why-java-for-frc\u002F1.2-intro-to-algorithms-programming-and-compilers","-WgvplAPHEn-4UBBQHKep6AHbMI5skLy0On23tx0Cn8",{"id":525,"title":526,"body":527,"description":48,"extension":51,"meta":944,"navigation":55,"path":946,"seo":947,"stem":948,"__hash__":949},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.1-variables-and-data-types.md","Variables & Data Types",{"type":8,"value":528,"toc":936},[529,532,536,543,546,614,617,644,663,667,670,679,688,697,714,717,726,739,746,750,757,772,787,791,826,828,872,874,926,934],[11,530,526],{"id":531},"variables-data-types",[69,533,535],{"id":534},"primitive-types-a-small-fixed-list","Primitive Types: a Small, Fixed List",[15,537,538,539,542],{},"Java has exactly 8 ",[25,540,541],{},"primitive types"," — the only types built directly into the language. A primitive variable holds its value directly, with nothing more underneath it.",[15,544,545],{},"The ones you'll use constantly in FRC code:",[19,547,548,561,576,586,602],{},[22,549,550,553,554,207,557,560],{},[95,551,552],{},"int"," — a whole number, like ",[95,555,556],{},"5",[95,558,559],{},"-12",". CAN IDs, ports, loop counters.",[22,562,563,566,567,569,570,497,573,79],{},[95,564,565],{},"long"," — a bigger whole number, for values too large for ",[95,568,552],{}," (like a timestamp). Written with an ",[95,571,572],{},"L",[95,574,575],{},"100L",[22,577,578,581,582,585],{},[95,579,580],{},"double"," — a decimal number, like ",[95,583,584],{},"0.85",". Almost anything measured — speed, distance, voltage.",[22,587,588,591,592,497,595,598,599,601],{},[95,589,590],{},"float"," — a smaller, less precise decimal number. Written with an ",[95,593,594],{},"f",[95,596,597],{},"1.5f",". Most FRC code (including WPILib itself) prefers ",[95,600,580],{}," instead.",[22,603,604,607,608,207,611,79],{},[95,605,606],{},"boolean"," — only ever ",[95,609,610],{},"true",[95,612,613],{},"false",[15,615,616],{},"The rest exist too, but you'll rarely reach for them directly:",[19,618,619,631],{},[22,620,621,275,624,627,628,630],{},[95,622,623],{},"byte",[95,625,626],{},"short"," — smaller whole numbers than ",[95,629,552],{},". Rarely needed.",[22,632,633,636,637,640,641,643],{},[95,634,635],{},"char"," — one single character, like ",[95,638,639],{},"'A'",". You won't use this much on its own, but it's worth knowing: this is what ",[95,642,315],{}," is actually built from underneath.",[15,645,646,647,650,651,653,654,656,657,659,660,662],{},"That's the full list — nothing else in Java is a primitive. ",[25,648,649],{},"Everything else is built out of these 8",", most obviously ",[95,652,315],{},", which is really a sequence of ",[95,655,635],{},"s glued together. Later, when you write your own classes (starting in Ch.7), those will be built by bundling primitives together — a robot subsystem might combine a ",[95,658,580],{}," for speed, a ",[95,661,606],{}," for \"is it ready,\" and more, all wrapped into one object. Keep this in the back of your mind going forward: every new type you meet is either one of this fixed list, or something built on top of it.",[69,664,666],{"id":665},"declaring-and-assigning","Declaring and Assigning",[15,668,669],{},"To create a variable, write its type, then its name, then a semicolon:",[104,671,673],{"className":106,"code":672,"language":108,"meta":48,"style":48},"int motorSpeed;\n",[95,674,675],{"__ignoreMap":48},[112,676,677],{"class":114,"line":115},[112,678,672],{},[15,680,681,683,684,687],{},[95,682,300],{}," now exists, but it doesn't hold a value yet. Give it one with ",[95,685,686],{},"=",":",[104,689,691],{"className":106,"code":690,"language":108,"meta":48,"style":48},"motorSpeed = 5;\n",[95,692,693],{"__ignoreMap":48},[112,694,695],{"class":114,"line":115},[112,696,690],{},[15,698,699,700,707,708,710,711,713],{},"Read that line as: ",[25,701,702,704,705,79],{},[95,703,300],{}," gets assigned the value ",[95,706,556],{}," Not \"motorSpeed equals 5\" — ",[95,709,686],{}," in code isn't the same as ",[95,712,686],{}," in math class. It's an instruction: take what's on the right, and store it in the box on the left.",[15,715,716],{},"Usually you do both steps at once:",[104,718,720],{"className":106,"code":719,"language":108,"meta":48,"style":48},"int motorSpeed = 5;\n",[95,721,722],{"__ignoreMap":48},[112,723,724],{"class":114,"line":115},[112,725,719],{},[15,727,728,729],{},"Read this the same way: ",[25,730,731,733,734,736,737,79],{},[95,732,300],{},", of type ",[95,735,552],{},", is assigned the value ",[95,738,556],{},[15,740,741,742,745],{},"A variable declared inside a method body, like everything here, is called a ",[25,743,744],{},"local variable"," — it only exists inside that method. (Java has other kinds of variables too — you'll meet those once classes and methods are on the table, starting in Ch.7.)",[69,747,749],{"id":748},"naming-variables-camelcase","Naming Variables (camelCase)",[15,751,752,753,756],{},"A name must start with a letter and can't contain spaces. Java's style — you'll see this in every piece of code from here on — is ",[25,754,755],{},"camelCase",": start lowercase, then capitalize the first letter of each new word.",[104,758,760],{"className":106,"code":759,"language":108,"meta":48,"style":48},"double maxSpeed = 0.85;   \u002F\u002F not max_speed, not MaxSpeed\nboolean isReady = false;\n",[95,761,762,767],{"__ignoreMap":48},[112,763,764],{"class":114,"line":115},[112,765,766],{},"double maxSpeed = 0.85;   \u002F\u002F not max_speed, not MaxSpeed\n",[112,768,769],{"class":114,"line":49},[112,770,771],{},"boolean isReady = false;\n",[15,773,774,775,778,779,782,783,786],{},"Pick a name that says what the value ",[262,776,777],{},"is",". ",[95,780,781],{},"speed"," tells you something; ",[95,784,785],{},"x"," doesn't.",[69,788,790],{"id":789},"worked-example","Worked Example",[104,792,794],{"className":106,"code":793,"language":108,"meta":48,"style":48},"int motorSpeed = 5;         \u002F\u002F a whole number — no decimal needed here\ndouble maxOutput = 0.85;    \u002F\u002F a percentage like 85% — needs a decimal\nboolean isReady = false;    \u002F\u002F only ever true or false\nString robotName = \"Titan\"; \u002F\u002F text, built out of primitives under the hood\n\nSystem.out.println(\"Robot \" + robotName + \" is set to speed \" + motorSpeed);\n",[95,795,796,801,806,811,816,821],{"__ignoreMap":48},[112,797,798],{"class":114,"line":115},[112,799,800],{},"int motorSpeed = 5;         \u002F\u002F a whole number — no decimal needed here\n",[112,802,803],{"class":114,"line":49},[112,804,805],{},"double maxOutput = 0.85;    \u002F\u002F a percentage like 85% — needs a decimal\n",[112,807,808],{"class":114,"line":126},[112,809,810],{},"boolean isReady = false;    \u002F\u002F only ever true or false\n",[112,812,813],{"class":114,"line":132},[112,814,815],{},"String robotName = \"Titan\"; \u002F\u002F text, built out of primitives under the hood\n",[112,817,818],{"class":114,"line":138},[112,819,820],{"emptyLinePlaceholder":55},"\n",[112,822,823],{"class":114,"line":144},[112,824,825],{},"System.out.println(\"Robot \" + robotName + \" is set to speed \" + motorSpeed);\n",[69,827,412],{"id":411},[19,829,830,849,860],{},[22,831,832,426,835,838,839,841,842,845,846,79],{},[25,833,834],{},"Never put a variable's name inside quotes.",[95,836,837],{},"System.out.println(\"motorSpeed\")"," prints the literal word ",[95,840,300],{},", not the number stored in it. Only actual words\u002Fsentences go inside ",[95,843,844],{},"\"\"","; variables get attached with ",[95,847,848],{},"+",[22,850,851,426,854,486,856,859],{},[25,852,853],{},"Case matters.",[95,855,300],{},[95,857,858],{},"motorspeed"," are two different variables to Java. This doesn't cause an error you'll notice right away — it just quietly breaks something.",[22,861,862,865,866,868,869,871],{},[25,863,864],{},"Match the type to the value."," If a value has a decimal point, it needs ",[95,867,580],{},", not ",[95,870,552],{}," — otherwise Java throws away everything after the decimal point.",[69,873,450],{"id":449},[19,875,876,897,909,912,917,923],{},[22,877,878,879,275,881,275,883,275,885,275,887,889,890,275,892,275,894,896],{},"Java has exactly 8 primitive types. ",[95,880,552],{},[95,882,565],{},[95,884,580],{},[95,886,590],{},[95,888,606],{}," are the common ones in FRC code; ",[95,891,623],{},[95,893,626],{},[95,895,635],{}," exist but are rarely used directly.",[22,898,899,900,902,903,905,906,908],{},"Everything else (",[95,901,315],{},", and every class you'll write) is built out of these 8 — ",[95,904,315],{}," is a sequence of ",[95,907,635],{},"s.",[22,910,911],{},"A variable is a named box that holds a value, and that value can change.",[22,913,914,916],{},[95,915,686],{}," means \"gets assigned,\" not \"equals.\"",[22,918,919,920,922],{},"A variable declared inside a method is a ",[25,921,744],{}," — it only exists in that method. There are other kinds too, covered starting in Ch.7.",[22,924,925],{},"Variable names use camelCase and should describe what the value is.",[15,927,493,928,497,930,933],{},[95,929,496],{},[95,931,932],{},"unit-1-using-objects-and-methods\u002F1.02-variables-and-data-types.md"," (CSA 1.2)",[503,935,505],{},{"title":48,"searchDepth":49,"depth":49,"links":937},[938,939,940,941,942,943],{"id":534,"depth":49,"text":535},{"id":665,"depth":49,"text":666},{"id":748,"depth":49,"text":749},{"id":789,"depth":49,"text":790},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":945,"status":519},"2.1 — Variables and Data Types (CSA 1.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F1-variables-and-data-types",{"title":526,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.1-variables-and-data-types","pUoSWuN63dMtmV3RR4MlTEZxA3wR-0F7YG0Ph105R8o",{"id":951,"title":952,"body":953,"description":48,"extension":51,"meta":1206,"navigation":55,"path":1208,"seo":1209,"stem":1210,"__hash__":1211},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.2-expressions-and-output.md","Expressions & Output",{"type":8,"value":954,"toc":1197},[955,958,962,965,979,999,1003,1012,1021,1030,1039,1043,1059,1074,1082,1095,1120,1122,1153,1155,1187,1195],[11,956,952],{"id":957},"expressions-output",[69,959,961],{"id":960},"printing-output","Printing Output",[15,963,964],{},"Two ways to print in Java:",[19,966,967,973],{},[22,968,969,972],{},[95,970,971],{},"System.out.println(value)"," — prints, then moves to a new line.",[22,974,975,978],{},[95,976,977],{},"System.out.print(value)"," — prints, and stays on the same line.",[104,980,982],{"className":106,"code":981,"language":108,"meta":48,"style":48},"System.out.print(\"Score: \");\nSystem.out.println(24);\n\u002F\u002F Output: Score: 24\n",[95,983,984,989,994],{"__ignoreMap":48},[112,985,986],{"class":114,"line":115},[112,987,988],{},"System.out.print(\"Score: \");\n",[112,990,991],{"class":114,"line":49},[112,992,993],{},"System.out.println(24);\n",[112,995,996],{"class":114,"line":126},[112,997,998],{},"\u002F\u002F Output: Score: 24\n",[69,1000,1002],{"id":1001},"math-expressions","Math Expressions",[15,1004,1005,1008,1009],{},[95,1006,1007],{},"+ - * \u002F"," work the same way you'd expect, with one big exception: ",[25,1010,1011],{},"dividing two whole numbers throws away the decimal part.",[104,1013,1015],{"className":106,"code":1014,"language":108,"meta":48,"style":48},"System.out.println(7 \u002F 2); \u002F\u002F prints 3, not 3.5\n",[95,1016,1017],{"__ignoreMap":48},[112,1018,1019],{"class":114,"line":115},[112,1020,1014],{},[15,1022,1023,1024,1027,1028,687],{},"This is called ",[25,1025,1026],{},"truncating division",", and it's the single most common source of \"wrong answer, no error message\" bugs you'll run into. If you want the decimal part, at least one of the two numbers needs to be a ",[95,1029,580],{},[104,1031,1033],{"className":106,"code":1032,"language":108,"meta":48,"style":48},"System.out.println(7.0 \u002F 2); \u002F\u002F prints 3.5\n",[95,1034,1035],{"__ignoreMap":48},[112,1036,1037],{"class":114,"line":115},[112,1038,1032],{},[69,1040,1042],{"id":1041},"order-of-operations","Order of Operations",[15,1044,1045,1046,486,1049,1052,1053,486,1055,1058],{},"Same rules as math class: ",[95,1047,1048],{},"*",[95,1050,1051],{},"\u002F"," happen before ",[95,1054,848],{},[95,1056,1057],{},"-",". Parentheses override that.",[104,1060,1062],{"className":106,"code":1061,"language":108,"meta":48,"style":48},"System.out.println(2 + 3 * 2);   \u002F\u002F 8\nSystem.out.println((2 + 3) * 2); \u002F\u002F 10\n",[95,1063,1064,1069],{"__ignoreMap":48},[112,1065,1066],{"class":114,"line":115},[112,1067,1068],{},"System.out.println(2 + 3 * 2);   \u002F\u002F 8\n",[112,1070,1071],{"class":114,"line":49},[112,1072,1073],{},"System.out.println((2 + 3) * 2); \u002F\u002F 10\n",[69,1075,1077,1078,1081],{"id":1076},"the-remainder-operator","The Remainder Operator (",[95,1079,1080],{},"%",")",[15,1083,1084,1086,1087,1090,1091,1094],{},[95,1085,1080],{}," gives you what's left over after dividing. ",[95,1088,1089],{},"5 % 2"," is ",[95,1092,1093],{},"1",", because 2 fits into 5 twice, with 1 left over.",[104,1096,1098],{"className":106,"code":1097,"language":108,"meta":48,"style":48},"int totalSeconds = 150;\nSystem.out.println(totalSeconds \u002F 60); \u002F\u002F 2 — whole minutes\nSystem.out.println(totalSeconds % 60); \u002F\u002F 30 — leftover seconds\n\u002F\u002F 150 seconds = 2 minutes, 30 seconds\n",[95,1099,1100,1105,1110,1115],{"__ignoreMap":48},[112,1101,1102],{"class":114,"line":115},[112,1103,1104],{},"int totalSeconds = 150;\n",[112,1106,1107],{"class":114,"line":49},[112,1108,1109],{},"System.out.println(totalSeconds \u002F 60); \u002F\u002F 2 — whole minutes\n",[112,1111,1112],{"class":114,"line":126},[112,1113,1114],{},"System.out.println(totalSeconds % 60); \u002F\u002F 30 — leftover seconds\n",[112,1116,1117],{"class":114,"line":132},[112,1118,1119],{},"\u002F\u002F 150 seconds = 2 minutes, 30 seconds\n",[69,1121,412],{"id":411},[19,1123,1124,1132],{},[22,1125,1126,1129,1130,79],{},[25,1127,1128],{},"Dividing two whole numbers and expecting a decimal."," It truncates instead — check whether at least one side is a ",[95,1131,580],{},[22,1133,1134,1137,1138,1141,1142,1145,1146,207,1149,1152],{},[25,1135,1136],{},"Dividing by zero."," Whole-number division by ",[95,1139,1140],{},"0"," crashes the program. Decimal division by ",[95,1143,1144],{},"0.0"," doesn't crash, but gives a nonsense result (",[95,1147,1148],{},"Infinity",[95,1150,1151],{},"NaN",") — a sign something's wrong upstream.",[69,1154,450],{"id":449},[19,1156,1157,1166,1169,1182],{},[22,1158,1159,1162,1163,1165],{},[95,1160,1161],{},"print"," stays on the line; ",[95,1164,345],{}," moves to a new one.",[22,1167,1168],{},"Dividing two whole numbers truncates the decimal part instead of rounding.",[22,1170,1171,1172,1051,1174,1176,1177,1051,1179,1181],{},"Use ",[95,1173,1048],{},[95,1175,1051],{}," before ",[95,1178,848],{},[95,1180,1057],{},", unless parentheses say otherwise.",[22,1183,1184,1186],{},[95,1185,1080],{}," gives the remainder after division — useful for splitting a total into two units (like seconds into minutes and seconds).",[15,1188,493,1189,497,1191,1194],{},[95,1190,496],{},[95,1192,1193],{},"unit-1-using-objects-and-methods\u002F1.03-expressions-and-output.md"," (CSA 1.3)",[503,1196,505],{},{"title":48,"searchDepth":49,"depth":49,"links":1198},[1199,1200,1201,1202,1204,1205],{"id":960,"depth":49,"text":961},{"id":1001,"depth":49,"text":1002},{"id":1041,"depth":49,"text":1042},{"id":1076,"depth":49,"text":1203},"The Remainder Operator (%)",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":1207,"status":519},"2.2 — Expressions and Output (CSA 1.3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2-expressions-and-output",{"title":952,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.2-expressions-and-output","6tnmF7LQb0O2jyK5L7EYxfcuG7niad6ONTC2PYdx0zQ",{"id":1213,"title":1214,"body":1215,"description":48,"extension":51,"meta":1422,"navigation":55,"path":1424,"seo":1425,"stem":1426,"__hash__":1427},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.3-assignment-and-input.md","Assignment & Input",{"type":8,"value":1216,"toc":1414},[1217,1220,1224,1229,1238,1241,1266,1270,1273,1293,1302,1306,1309,1324,1331,1335,1338,1353,1355,1379,1381,1404,1412],[11,1218,1214],{"id":1219},"assignment-input",[69,1221,1223],{"id":1222},"assignment-one-more-time","Assignment, One More Time",[15,1225,1226,1228],{},[95,1227,686],{}," always has one variable on the left, and a value (or a math expression) on the right. Read it as \"gets assigned,\" not \"equals.\"",[104,1230,1232],{"className":106,"code":1231,"language":108,"meta":48,"style":48},"int score = 10 * 2 + 5; \u002F\u002F score is assigned the value 25\n",[95,1233,1234],{"__ignoreMap":48},[112,1235,1236],{"class":114,"line":115},[112,1237,1231],{},[15,1239,1240],{},"Copying one variable into another only copies the value at that moment — it doesn't link them together.",[104,1242,1244],{"className":106,"code":1243,"language":108,"meta":48,"style":48},"int x = 3;\nint y = 2;\nx = y;   \u002F\u002F x is now assigned a copy of y's value: 2\ny = 5;   \u002F\u002F y changes — x is still 2, unaffected\n",[95,1245,1246,1251,1256,1261],{"__ignoreMap":48},[112,1247,1248],{"class":114,"line":115},[112,1249,1250],{},"int x = 3;\n",[112,1252,1253],{"class":114,"line":49},[112,1254,1255],{},"int y = 2;\n",[112,1257,1258],{"class":114,"line":126},[112,1259,1260],{},"x = y;   \u002F\u002F x is now assigned a copy of y's value: 2\n",[112,1262,1263],{"class":114,"line":132},[112,1264,1265],{},"y = 5;   \u002F\u002F y changes — x is still 2, unaffected\n",[69,1267,1269],{"id":1268},"every-variable-needs-a-value-first","Every Variable Needs a Value First",[15,1271,1272],{},"You can't use a variable in an expression before it's been assigned something, and the value has to match the type:",[104,1274,1276],{"className":106,"code":1275,"language":108,"meta":48,"style":48},"int x = 1;\ndouble y = 2.2;\nx = 2 * y;   \u002F\u002F won't compile — 2 * y is a double, and x is an int\n",[95,1277,1278,1283,1288],{"__ignoreMap":48},[112,1279,1280],{"class":114,"line":115},[112,1281,1282],{},"int x = 1;\n",[112,1284,1285],{"class":114,"line":49},[112,1286,1287],{},"double y = 2.2;\n",[112,1289,1290],{"class":114,"line":126},[112,1291,1292],{},"x = 2 * y;   \u002F\u002F won't compile — 2 * y is a double, and x is an int\n",[15,1294,1295,1296,1298,1299,1301],{},"The fix here isn't to force it — it's to make ",[95,1297,785],{}," a ",[95,1300,580],{}," in the first place, since that's what it's actually meant to hold.",[69,1303,1305],{"id":1304},"updating-a-value-using-itself","Updating a Value Using Itself",[15,1307,1308],{},"A common pattern: change a variable based on its own current value.",[104,1310,1312],{"className":106,"code":1311,"language":108,"meta":48,"style":48},"int step = 0;\nstep = step + 1; \u002F\u002F uses the OLD value of step, then stores the new result back into it\n",[95,1313,1314,1319],{"__ignoreMap":48},[112,1315,1316],{"class":114,"line":115},[112,1317,1318],{},"int step = 0;\n",[112,1320,1321],{"class":114,"line":49},[112,1322,1323],{},"step = step + 1; \u002F\u002F uses the OLD value of step, then stores the new result back into it\n",[15,1325,1326,1327,1330],{},"(Lesson 2.5 covers a shorthand for this: ",[95,1328,1329],{},"step++",".)",[69,1332,1334],{"id":1333},"where-input-comes-from","Where \"Input\" Comes From",[15,1336,1337],{},"Some value comes from outside your code, gets stored in a variable, and your code reacts to it. On a robot, that's a joystick or a sensor, not typed text — but it's the same idea: the variable holds whatever value showed up, and the rest of the code doesn't need to change no matter what that value is.",[104,1339,1341],{"className":106,"code":1340,"language":108,"meta":48,"style":48},"double throttle = 0.6; \u002F\u002F stands in for \"whatever value the controller sends\"\ndouble output = throttle * maxSpeed;\n",[95,1342,1343,1348],{"__ignoreMap":48},[112,1344,1345],{"class":114,"line":115},[112,1346,1347],{},"double throttle = 0.6; \u002F\u002F stands in for \"whatever value the controller sends\"\n",[112,1349,1350],{"class":114,"line":49},[112,1351,1352],{},"double output = throttle * maxSpeed;\n",[69,1354,412],{"id":411},[19,1356,1357,1363],{},[22,1358,1359,1362],{},[25,1360,1361],{},"Using a variable before it has a value."," Java won't let this compile — it's a safety net, not an inconvenience.",[22,1364,1365,1372,1373,1375,1376,79],{},[25,1366,1367,1368,1371],{},"Assuming ",[95,1369,1370],{},"y = x"," keeps them linked."," It copies the value once. Changing ",[95,1374,785],{}," later does nothing to ",[95,1377,1378],{},"y",[69,1380,450],{"id":449},[19,1382,1383,1389,1392,1395,1401],{},[22,1384,1385,1386,1388],{},"Read ",[95,1387,686],{}," as \"gets assigned,\" not \"equals.\"",[22,1390,1391],{},"Copying a variable's value into another does not link them — each is independent afterward.",[22,1393,1394],{},"A variable must have a value, of a matching type, before it's used in an expression.",[22,1396,1397,1400],{},[95,1398,1399],{},"step = step + 1"," uses the old value first, then overwrites the variable.",[22,1402,1403],{},"\"Input\" is any value that comes from outside your code — a joystick reading, a sensor, or typed text.",[15,1405,493,1406,497,1408,1411],{},[95,1407,496],{},[95,1409,1410],{},"unit-1-using-objects-and-methods\u002F1.04-assignment-and-input.md"," (CSA 1.4)",[503,1413,505],{},{"title":48,"searchDepth":49,"depth":49,"links":1415},[1416,1417,1418,1419,1420,1421],{"id":1222,"depth":49,"text":1223},{"id":1268,"depth":49,"text":1269},{"id":1304,"depth":49,"text":1305},{"id":1333,"depth":49,"text":1334},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":1423,"status":519},"2.3 — Assignment and Input (CSA 1.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F3-assignment-and-input",{"title":1214,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.3-assignment-and-input","x0wGASJjYmPSWq_rUMDJQuYFwRvQo4GSZuXws6MzAQY",{"id":1429,"title":1430,"body":1431,"description":48,"extension":51,"meta":1642,"navigation":55,"path":1644,"seo":1645,"stem":1646,"__hash__":1647},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.4-casting-and-ranges-of-values.md","Casting & Ranges of Values",{"type":8,"value":1432,"toc":1634},[1433,1436,1440,1450,1465,1479,1486,1495,1499,1506,1535,1539,1545,1554,1557,1561,1570,1572,1591,1593,1624,1632],[11,1434,1430],{"id":1435},"casting-ranges-of-values",[69,1437,1439],{"id":1438},"converting-between-types-casting","Converting Between Types (Casting)",[15,1441,1442,1443,207,1446,1449],{},"Put ",[95,1444,1445],{},"(int)",[95,1447,1448],{},"(double)"," right before a value to convert it to that type on the spot:",[104,1451,1453],{"className":106,"code":1452,"language":108,"meta":48,"style":48},"(double) 1 \u002F 3   \u002F\u002F 0.333... — the 1 becomes a double first, then divides\n(int) 3.6        \u002F\u002F 3 — cuts off everything after the decimal point\n",[95,1454,1455,1460],{"__ignoreMap":48},[112,1456,1457],{"class":114,"line":115},[112,1458,1459],{},"(double) 1 \u002F 3   \u002F\u002F 0.333... — the 1 becomes a double first, then divides\n",[112,1461,1462],{"class":114,"line":49},[112,1463,1464],{},"(int) 3.6        \u002F\u002F 3 — cuts off everything after the decimal point\n",[15,1466,1467,1469,1470,1090,1473,868,1476,79],{},[95,1468,1445],{}," always cuts off the decimal — it never rounds. ",[95,1471,1472],{},"(int) 3.9",[95,1474,1475],{},"3",[95,1477,1478],{},"4",[15,1480,1481,1482,1485],{},"If you actually want to round, add ",[95,1483,1484],{},"0.5"," first, then cast:",[104,1487,1489],{"className":106,"code":1488,"language":108,"meta":48,"style":48},"int rounded = (int)(5.7 + 0.5); \u002F\u002F 6 — this is rounding, not truncating\n",[95,1490,1491],{"__ignoreMap":48},[112,1492,1493],{"class":114,"line":115},[112,1494,1488],{},[69,1496,1498],{"id":1497},"the-fix-for-truncating-division","The Fix for Truncating Division",[15,1500,1501,1502,1505],{},"Lesson 2.2 showed that dividing two whole numbers cuts off the decimal. Casting one of them fixes it — but only if the cast happens ",[262,1503,1504],{},"before"," the division:",[104,1507,1509],{"className":106,"code":1508,"language":108,"meta":48,"style":48},"int total = 17;\nint games = 5;\n\ndouble average = (double) total \u002F games;   \u002F\u002F correct: 3.4\ndouble wrong    = (double) (total \u002F games); \u002F\u002F wrong: divides as whole numbers first (3), then casts: 3.0\n",[95,1510,1511,1516,1521,1525,1530],{"__ignoreMap":48},[112,1512,1513],{"class":114,"line":115},[112,1514,1515],{},"int total = 17;\n",[112,1517,1518],{"class":114,"line":49},[112,1519,1520],{},"int games = 5;\n",[112,1522,1523],{"class":114,"line":126},[112,1524,820],{"emptyLinePlaceholder":55},[112,1526,1527],{"class":114,"line":132},[112,1528,1529],{},"double average = (double) total \u002F games;   \u002F\u002F correct: 3.4\n",[112,1531,1532],{"class":114,"line":138},[112,1533,1534],{},"double wrong    = (double) (total \u002F games); \u002F\u002F wrong: divides as whole numbers first (3), then casts: 3.0\n",[69,1536,1538],{"id":1537},"whole-numbers-have-a-limit","Whole Numbers Have a Limit",[15,1540,1541,1542,1544],{},"An ",[95,1543,552],{}," can only hold values in a fixed range (roughly ±2.1 billion). Go past that limit, and the number silently wraps around to a wrong value — no error, no warning.",[104,1546,1548],{"className":106,"code":1547,"language":108,"meta":48,"style":48},"System.out.println(Integer.MAX_VALUE + 1); \u002F\u002F wraps to the smallest possible int\n",[95,1549,1550],{"__ignoreMap":48},[112,1551,1552],{"class":114,"line":115},[112,1553,1547],{},[15,1555,1556],{},"This is unlikely to come up in a match, but it's a real risk for a counter that keeps growing and is never reset.",[69,1558,1560],{"id":1559},"decimals-have-a-precision-limit-too","Decimals Have a Precision Limit Too",[15,1562,355,1563,1565,1566,1569],{},[95,1564,580],{}," can only store so many digits (about 14-15). Beyond that, the extra digits get quietly rounded off. This is why comparing two decimals with ",[95,1567,1568],{},"=="," is risky — two values that \"should\" be equal might differ by a tiny rounding amount.",[69,1571,412],{"id":411},[19,1573,1574,1580],{},[22,1575,1576,1579],{},[25,1577,1578],{},"Casting after dividing instead of before."," The division already happened as whole numbers by the time the cast runs — putting the cast in the wrong spot doesn't fix anything.",[22,1581,1582,426,1585,1587,1588,1590],{},[25,1583,1584],{},"Assuming a cast rounds.",[95,1586,1445],{}," cuts off the decimal. Rounding needs the add-",[95,1589,1484],{},"-then-cast trick.",[69,1592,450],{"id":449},[19,1594,1595,1605,1611,1616],{},[22,1596,1597,486,1599,1601,1602,1604],{},[95,1598,1445],{},[95,1600,1448],{}," convert a value's type on the spot; ",[95,1603,1445],{}," always cuts off decimals, never rounds.",[22,1606,1607,1608,1610],{},"To fix truncating division, cast one of the numbers ",[262,1609,1504],{}," dividing — position matters.",[22,1612,1613,1615],{},[95,1614,552],{}," values have a fixed range; going past it silently wraps to a wrong value.",[22,1617,1618,1620,1621,1623],{},[95,1619,580],{}," values have a precision limit — tiny rounding differences can make ",[95,1622,1568],{}," unreliable.",[15,1625,493,1626,497,1628,1631],{},[95,1627,496],{},[95,1629,1630],{},"unit-1-using-objects-and-methods\u002F1.05-casting-and-ranges-of-values.md"," (CSA 1.5)",[503,1633,505],{},{"title":48,"searchDepth":49,"depth":49,"links":1635},[1636,1637,1638,1639,1640,1641],{"id":1438,"depth":49,"text":1439},{"id":1497,"depth":49,"text":1498},{"id":1537,"depth":49,"text":1538},{"id":1559,"depth":49,"text":1560},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":1643,"status":519},"2.4 — Casting and Ranges of Values (CSA 1.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F4-casting-and-ranges-of-values",{"title":1430,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.4-casting-and-ranges-of-values","iYNTS0UjWzs_bD9h2nNKkthTqzVayFaLDb0dA1j50WI",{"id":1649,"title":1650,"body":1651,"description":48,"extension":51,"meta":1910,"navigation":55,"path":1912,"seo":1913,"stem":1914,"__hash__":1915},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.5-compound-assignment-operators.md","Compound Assignment Operators",{"type":8,"value":1652,"toc":1902},[1653,1656,1660,1673,1688,1692,1701,1716,1720,1723,1761,1772,1776,1779,1835,1847,1849,1866,1868,1892,1900],[11,1654,1650],{"id":1655},"compound-assignment-operators",[69,1657,1659],{"id":1658},"a-shortcut-for-update-using-the-old-value","A Shortcut for \"Update Using the Old Value\"",[15,1661,1662,1665,1666,1669,1670,79],{},[95,1663,1664],{},"x = x + 1;"," comes up so often that Java has a shortcut: ",[95,1667,1668],{},"x += 1;",". Same idea works for every operator: ",[95,1671,1672],{},"+= -= *= \u002F= %=",[104,1674,1676],{"className":106,"code":1675,"language":108,"meta":48,"style":48},"score += 10;   \u002F\u002F same as: score = score + 10;\npower *= 0.5;  \u002F\u002F same as: power = power * 0.5;\n",[95,1677,1678,1683],{"__ignoreMap":48},[112,1679,1680],{"class":114,"line":115},[112,1681,1682],{},"score += 10;   \u002F\u002F same as: score = score + 10;\n",[112,1684,1685],{"class":114,"line":49},[112,1686,1687],{},"power *= 0.5;  \u002F\u002F same as: power = power * 0.5;\n",[69,1689,1691],{"id":1690},"increment-and-decrement","Increment and Decrement",[15,1693,1694,1695,486,1698,79],{},"Adding or subtracting exactly 1 is common enough to get its own shortcut: ",[95,1696,1697],{},"++",[95,1699,1700],{},"--",[104,1702,1704],{"className":106,"code":1703,"language":108,"meta":48,"style":48},"step++;   \u002F\u002F same as step += 1, same as step = step + 1\ntimer--;\n",[95,1705,1706,1711],{"__ignoreMap":48},[112,1707,1708],{"class":114,"line":115},[112,1709,1710],{},"step++;   \u002F\u002F same as step += 1, same as step = step + 1\n",[112,1712,1713],{"class":114,"line":49},[112,1714,1715],{},"timer--;\n",[69,1717,1719],{"id":1718},"a-real-example-ramping-up-power","A Real Example: Ramping Up Power",[15,1721,1722],{},"Instead of jumping straight to full power, increase it gradually, a little bit each time:",[104,1724,1726],{"className":106,"code":1725,"language":108,"meta":48,"style":48},"double power = 0.0;\ndouble rampRate = 0.02; \u002F\u002F add 2% each time this runs\n\npower += rampRate;\nif (power > targetPower) {\n    power = targetPower; \u002F\u002F stop it from going past the target\n}\n",[95,1727,1728,1733,1738,1742,1747,1752,1757],{"__ignoreMap":48},[112,1729,1730],{"class":114,"line":115},[112,1731,1732],{},"double power = 0.0;\n",[112,1734,1735],{"class":114,"line":49},[112,1736,1737],{},"double rampRate = 0.02; \u002F\u002F add 2% each time this runs\n",[112,1739,1740],{"class":114,"line":126},[112,1741,820],{"emptyLinePlaceholder":55},[112,1743,1744],{"class":114,"line":132},[112,1745,1746],{},"power += rampRate;\n",[112,1748,1749],{"class":114,"line":138},[112,1750,1751],{},"if (power > targetPower) {\n",[112,1753,1754],{"class":114,"line":144},[112,1755,1756],{},"    power = targetPower; \u002F\u002F stop it from going past the target\n",[112,1758,1759],{"class":114,"line":150},[112,1760,153],{},[15,1762,1763,1764,1767,1768,1771],{},"That ",[95,1765,1766],{},"if"," check matters — without it, ",[95,1769,1770],{},"power"," would just keep climbing past where you wanted it to stop.",[69,1773,1775],{"id":1774},"tracing-code-by-hand","Tracing Code by Hand",[15,1777,1778],{},"Tracing means walking through code line by line, by hand, updating each variable as you go — a genuinely useful way to find bugs when just reading the code isn't enough.",[104,1780,1782],{"className":106,"code":1781,"language":108,"meta":48,"style":48},"int step = 0;\nint delta = 5;\nint total = 1;\n\nstep++;              \u002F\u002F step: 1\ndelta -= 3;          \u002F\u002F delta: 2\ntotal = step + delta; \u002F\u002F total: 1 + 2 = 3\nstep = total * 2;    \u002F\u002F step: 3 * 2 = 6\ndelta %= 2;          \u002F\u002F delta: 2 % 2 = 0\ntotal--;             \u002F\u002F total: 2\n",[95,1783,1784,1788,1793,1798,1802,1807,1812,1817,1823,1829],{"__ignoreMap":48},[112,1785,1786],{"class":114,"line":115},[112,1787,1318],{},[112,1789,1790],{"class":114,"line":49},[112,1791,1792],{},"int delta = 5;\n",[112,1794,1795],{"class":114,"line":126},[112,1796,1797],{},"int total = 1;\n",[112,1799,1800],{"class":114,"line":132},[112,1801,820],{"emptyLinePlaceholder":55},[112,1803,1804],{"class":114,"line":138},[112,1805,1806],{},"step++;              \u002F\u002F step: 1\n",[112,1808,1809],{"class":114,"line":144},[112,1810,1811],{},"delta -= 3;          \u002F\u002F delta: 2\n",[112,1813,1814],{"class":114,"line":150},[112,1815,1816],{},"total = step + delta; \u002F\u002F total: 1 + 2 = 3\n",[112,1818,1820],{"class":114,"line":1819},8,[112,1821,1822],{},"step = total * 2;    \u002F\u002F step: 3 * 2 = 6\n",[112,1824,1826],{"class":114,"line":1825},9,[112,1827,1828],{},"delta %= 2;          \u002F\u002F delta: 2 % 2 = 0\n",[112,1830,1832],{"class":114,"line":1831},10,[112,1833,1834],{},"total--;             \u002F\u002F total: 2\n",[15,1836,1837,1838,275,1841,275,1844,79],{},"Final values: ",[95,1839,1840],{},"step = 6",[95,1842,1843],{},"delta = 0",[95,1845,1846],{},"total = 2",[69,1848,412],{"id":411},[19,1850,1851,1860],{},[22,1852,1853,426,1856,1859],{},[25,1854,1855],{},"Forgetting the clamp when ramping.",[95,1857,1858],{},"power += rampRate"," with no limit check will just keep climbing past your target.",[22,1861,1862,1865],{},[25,1863,1864],{},"Skipping ahead while tracing."," Go one line at a time, in order — skipping ahead is how you miss the actual bug.",[69,1867,450],{"id":449},[19,1869,1870,1875,1882,1889],{},[22,1871,1872,1874],{},[95,1873,1672],{}," update a variable using its current value, then store the result back.",[22,1876,1877,486,1879,1881],{},[95,1878,1697],{},[95,1880,1700],{}," are shortcuts for adding or subtracting exactly 1.",[22,1883,1884,1885,1888],{},"Ramping a motor's power up gradually is a real use of ",[95,1886,1887],{},"+=",", checked against a limit each time.",[22,1890,1891],{},"Tracing code by hand — one line, one value at a time — is a real debugging skill.",[15,1893,493,1894,497,1896,1899],{},[95,1895,496],{},[95,1897,1898],{},"unit-1-using-objects-and-methods\u002F1.06-compound-assignment-operators.md"," (CSA 1.6)",[503,1901,505],{},{"title":48,"searchDepth":49,"depth":49,"links":1903},[1904,1905,1906,1907,1908,1909],{"id":1658,"depth":49,"text":1659},{"id":1690,"depth":49,"text":1691},{"id":1718,"depth":49,"text":1719},{"id":1774,"depth":49,"text":1775},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":1911,"status":519},"2.5 — Compound Assignment Operators (CSA 1.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F5-compound-assignment-operators",{"title":1650,"description":48},"shockwave-curriculum\u002Flessons\u002Fch02-variables-and-types\u002F2.5-compound-assignment-operators","X9MES8F27Rz85UVbSHV9ymKYaSsCYpp7MGhewOpriKg",{"id":1917,"title":1918,"body":1919,"description":48,"extension":51,"meta":2089,"navigation":55,"path":2091,"seo":2092,"stem":2093,"__hash__":2094},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.1-apis-and-libraries.md","APIs and Libraries",{"type":8,"value":1920,"toc":2082},[1921,1924,1928,1934,1941,1945,1959,1962,1976,1995,2012,2016,2025,2027,2053,2055,2072,2080],[11,1922,1918],{"id":1923},"apis-and-libraries",[69,1925,1927],{"id":1926},"libraries-and-apis","Libraries and APIs",[15,1929,355,1930,1933],{},[25,1931,1932],{},"library"," is a collection of code someone else already wrote, that you can reuse instead of writing it yourself. WPILib — the library every FRC robot depends on — is exactly this: motor control, sensors, the whole command-based framework, all written once and reused by thousands of teams.",[15,1935,1936,1937,1940],{},"The ",[25,1938,1939],{},"API"," (Application Programming Interface) is the instructions for how to actually use a library: what classes it gives you, what each one can do, and what you need to pass in. You don't need to know how a library's code works internally — you just need its API.",[69,1942,1944],{"id":1943},"classes-attributes-and-behaviors","Classes, Attributes, and Behaviors",[15,1946,355,1947,1949,1950,207,1952,1954,1955,1958],{},[25,1948,97],{}," is the building block a library gives you — it defines a new kind of value, the same way ",[95,1951,552],{},[95,1953,580],{}," do, except you (or a library author) define what it means. An ",[25,1956,1957],{},"object"," is one specific thing built from a class.",[15,1960,1961],{},"Every class bundles two things together:",[19,1963,1964,1970],{},[22,1965,1966,1969],{},[25,1967,1968],{},"Attributes"," — the data it holds. Stored in variables.",[22,1971,1972,1975],{},[25,1973,1974],{},"Behaviors"," — what it can do. Defined as methods.",[104,1977,1979],{"className":106,"code":1978,"language":108,"meta":48,"style":48},"TalonFX shooterMotor = new TalonFX(5); \u002F\u002F shooterMotor is an object, built from the TalonFX class\n\nshooterMotor.set(0.8); \u002F\u002F a behavior — call a method with the dot operator\n",[95,1980,1981,1986,1990],{"__ignoreMap":48},[112,1982,1983],{"class":114,"line":115},[112,1984,1985],{},"TalonFX shooterMotor = new TalonFX(5); \u002F\u002F shooterMotor is an object, built from the TalonFX class\n",[112,1987,1988],{"class":114,"line":49},[112,1989,820],{"emptyLinePlaceholder":55},[112,1991,1992],{"class":114,"line":126},[112,1993,1994],{},"shooterMotor.set(0.8); \u002F\u002F a behavior — call a method with the dot operator\n",[15,1996,1936,1997,1999,2000,2003,2004,2007,2008,2011],{},[95,1998,79],{}," (dot operator) is how you reach an object's behaviors and attributes. ",[95,2001,2002],{},"shooterMotor.set(0.8)"," means: find the ",[95,2005,2006],{},"set"," method defined in the ",[95,2009,2010],{},"TalonFX"," class, and run it on this specific motor object.",[69,2013,2015],{"id":2014},"why-this-matters","Why This Matters",[15,2017,2018,2019,2021,2022,2024],{},"You don't need to know how ",[95,2020,2010],{}," is implemented internally — motor controller firmware, CAN bus protocol, none of it — to use ",[95,2023,2002],{}," correctly. That's the entire point of a library: someone else solved the hard problem once, documented how to use their solution, and you build on top of it instead of starting from scratch.",[69,2026,412],{"id":411},[19,2028,2029,2044],{},[22,2030,2031,426,2034,2036,2037,2040,2041,2043],{},[25,2032,2033],{},"Confusing a class with an object.",[95,2035,2010],{}," is the class (the blueprint); ",[95,2038,2039],{},"shooterMotor"," is one specific object built from it. A robot might have several ",[95,2042,2010],{}," objects — one per motor.",[22,2045,2046,426,2049,2052],{},[25,2047,2048],{},"Forgetting the dot operator.",[95,2050,2051],{},"shooterMotor set(0.8)"," isn't valid — the dot is what connects an object to its behavior.",[69,2054,450],{"id":449},[19,2056,2057,2060,2063,2066],{},[22,2058,2059],{},"A library is reusable code written by someone else; its API documents how to use it.",[22,2061,2062],{},"A class defines a new kind of value, bundling attributes (data) and behaviors (methods) together.",[22,2064,2065],{},"An object is one specific instance built from a class.",[22,2067,2068,2069,2071],{},"The dot operator (",[95,2070,79],{},") accesses an object's attributes and behaviors.",[15,2073,493,2074,497,2076,2079],{},[95,2075,496],{},[95,2077,2078],{},"unit-1-using-objects-and-methods\u002F1.07-apis-and-libraries.md"," (CSA 1.7)",[503,2081,505],{},{"title":48,"searchDepth":49,"depth":49,"links":2083},[2084,2085,2086,2087,2088],{"id":1926,"depth":49,"text":1927},{"id":1943,"depth":49,"text":1944},{"id":2014,"depth":49,"text":2015},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":2090,"status":519},"3.1 — APIs and Libraries (CSA 1.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F1-apis-and-libraries",{"title":1918,"description":48},"shockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.1-apis-and-libraries","olaEgMQjroOFsbd7Zy6UrkqXIxnjo0BIcDsqf3Zs8fU",{"id":2096,"title":2097,"body":2098,"description":48,"extension":51,"meta":2265,"navigation":55,"path":2267,"seo":2268,"stem":2269,"__hash__":2270},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.2-documentation-with-comments-and-preconditions.md","Documentation with Comments and Preconditions",{"type":8,"value":2099,"toc":2258},[2100,2103,2107,2132,2135,2139,2149,2184,2202,2206,2209,2211,2228,2230,2248,2256],[11,2101,2097],{"id":2102},"documentation-with-comments-and-preconditions",[69,2104,2106],{"id":2105},"three-kinds-of-comments","Three Kinds of Comments",[104,2108,2110],{"className":106,"code":2109,"language":108,"meta":48,"style":48},"\u002F\u002F single-line comment\n\u002F* multi-line\n   comment *\u002F\n\u002F** a documentation comment — describes a class or method for other programmers *\u002F\n",[95,2111,2112,2117,2122,2127],{"__ignoreMap":48},[112,2113,2114],{"class":114,"line":115},[112,2115,2116],{},"\u002F\u002F single-line comment\n",[112,2118,2119],{"class":114,"line":49},[112,2120,2121],{},"\u002F* multi-line\n",[112,2123,2124],{"class":114,"line":126},[112,2125,2126],{},"   comment *\u002F\n",[112,2128,2129],{"class":114,"line":132},[112,2130,2131],{},"\u002F** a documentation comment — describes a class or method for other programmers *\u002F\n",[15,2133,2134],{},"The compiler ignores all three completely — they exist for whoever reads the code next, including future-you.",[69,2136,2138],{"id":2137},"preconditions-and-postconditions","Preconditions and Postconditions",[15,2140,355,2141,2144,2145,2148],{},[25,2142,2143],{},"precondition"," is what has to be true before a method is called for it to work correctly. A ",[25,2146,2147],{},"postcondition"," is what's guaranteed true after it runs.",[104,2150,2152],{"className":106,"code":2151,"language":108,"meta":48,"style":48},"\u002F**\n * @param targetRPM the speed to spin up to\n * Precondition: targetRPM is between 0 and the motor's max RPM.\n * Postcondition: the motor ramps toward targetRPM.\n *\u002F\npublic void spinUpTo(double targetRPM) { ... }\n",[95,2153,2154,2159,2164,2169,2174,2179],{"__ignoreMap":48},[112,2155,2156],{"class":114,"line":115},[112,2157,2158],{},"\u002F**\n",[112,2160,2161],{"class":114,"line":49},[112,2162,2163],{}," * @param targetRPM the speed to spin up to\n",[112,2165,2166],{"class":114,"line":126},[112,2167,2168],{}," * Precondition: targetRPM is between 0 and the motor's max RPM.\n",[112,2170,2171],{"class":114,"line":132},[112,2172,2173],{}," * Postcondition: the motor ramps toward targetRPM.\n",[112,2175,2176],{"class":114,"line":138},[112,2177,2178],{}," *\u002F\n",[112,2180,2181],{"class":114,"line":144},[112,2182,2183],{},"public void spinUpTo(double targetRPM) { ... }\n",[15,2185,2186,2187,2190,2191,2194,2195,2197,2198,2201],{},"Java doesn't enforce preconditions automatically — nothing stops you from calling ",[95,2188,2189],{},"spinUpTo(-500)",". A precondition is a documented expectation, not a guarantee the method checks it. ",[95,2192,2193],{},"Math.sqrt(-4)"," is a real example: nothing crashes, but the result is ",[95,2196,1151],{}," (\"not a number\") because negative input violates ",[95,2199,2200],{},"sqrt","'s precondition.",[69,2203,2205],{"id":2204},"why-bother-documenting-this","Why Bother Documenting This",[15,2207,2208],{},"Once you write a method, other people (including future-you, and your whole team) will call it without reading its implementation. Documenting preconditions and postconditions is how they know what's safe to pass in and what to expect back — without documentation, the only way to find out is to read the method's full source or guess.",[69,2210,412],{"id":411},[19,2212,2213,2222],{},[22,2214,2215,2218,2219,2221],{},[25,2216,2217],{},"Assuming a precondition is enforced."," Documenting a precondition doesn't make Java check it — passing a bad value can still silently produce a wrong result (like ",[95,2220,1151],{},") instead of an error.",[22,2223,2224,2227],{},[25,2225,2226],{},"Skipping documentation on methods other people will call."," The cost of a two-line comment is much smaller than the cost of a teammate guessing wrong about what a method expects.",[69,2229,450],{"id":449},[19,2231,2232,2242,2245],{},[22,2233,2234,275,2236,278,2238,2241],{},[95,2235,388],{},[95,2237,489],{},[95,2239,2240],{},"\u002F** *\u002F"," are the three comment styles; the compiler ignores all of them.",[22,2243,2244],{},"A precondition is what must be true before a method is called; a postcondition is what's guaranteed true after it returns.",[22,2246,2247],{},"Preconditions are documented expectations, not automatically enforced — violating one can produce a wrong result without an error.",[15,2249,493,2250,497,2252,2255],{},[95,2251,496],{},[95,2253,2254],{},"unit-1-using-objects-and-methods\u002F1.08-documentation-with-comments-and-preconditions.md"," (CSA 1.8)",[503,2257,505],{},{"title":48,"searchDepth":49,"depth":49,"links":2259},[2260,2261,2262,2263,2264],{"id":2105,"depth":49,"text":2106},{"id":2137,"depth":49,"text":2138},{"id":2204,"depth":49,"text":2205},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":2266,"status":519},"3.2 — Documentation with Comments and Preconditions (CSA 1.8)","\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F2-documentation-with-comments-and-preconditions",{"title":2097,"description":48},"shockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.2-documentation-with-comments-and-preconditions","Ndlw6iSvuMMfWqb8T5eQpESFc-h4G1cSh9FCptXgKM8",{"id":2272,"title":2273,"body":2274,"description":48,"extension":51,"meta":2434,"navigation":55,"path":2436,"seo":2437,"stem":2438,"__hash__":2439},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.3-packages-and-imports.md","Packages & Imports",{"type":8,"value":2275,"toc":2427},[2276,2279,2283,2293,2297,2304,2337,2353,2357,2377,2379,2396,2398,2418,2425],[11,2277,2273],{"id":2278},"packages-imports",[69,2280,2282],{"id":2281},"packages-are-folders-for-classes","Packages Are Folders for Classes",[15,2284,355,2285,2288,2289,2292],{},[25,2286,2287],{},"package"," groups related classes together — like a folder. ",[95,2290,2291],{},"edu.wpi.first.wpilibj2.command"," is a real WPILib package holding all the command-based framework's classes.",[69,2294,2296],{"id":2295},"importing-a-class","Importing a Class",[15,2298,2299,2300,2303],{},"To use a class from another package, ",[95,2301,2302],{},"import"," it at the top of your file:",[104,2305,2307],{"className":106,"code":2306,"language":108,"meta":48,"style":48},"package frc.robot.subsystems;\n\nimport edu.wpi.first.wpilibj2.command.SubsystemBase;\nimport com.revrobotics.CANSparkMax;\n\npublic class Drivetrain extends SubsystemBase { ... }\n",[95,2308,2309,2314,2318,2323,2328,2332],{"__ignoreMap":48},[112,2310,2311],{"class":114,"line":115},[112,2312,2313],{},"package frc.robot.subsystems;\n",[112,2315,2316],{"class":114,"line":49},[112,2317,820],{"emptyLinePlaceholder":55},[112,2319,2320],{"class":114,"line":126},[112,2321,2322],{},"import edu.wpi.first.wpilibj2.command.SubsystemBase;\n",[112,2324,2325],{"class":114,"line":132},[112,2326,2327],{},"import com.revrobotics.CANSparkMax;\n",[112,2329,2330],{"class":114,"line":138},[112,2331,820],{"emptyLinePlaceholder":55},[112,2333,2334],{"class":114,"line":144},[112,2335,2336],{},"public class Drivetrain extends SubsystemBase { ... }\n",[15,2338,1936,2339,2341,2342,2345,2346,2348,2349,2352],{},[95,2340,2287],{}," line at the top says where ",[262,2343,2344],{},"this"," file lives; each ",[95,2347,2302],{}," brings in one class from somewhere else so you can use it by its short name (",[95,2350,2351],{},"SubsystemBase",") instead of its full path.",[69,2354,2356],{"id":2355},"one-package-needs-no-import","One Package Needs No Import",[15,2358,2359,2362,2363,275,2365,2367,2368,2370,2371,486,2374,2376],{},[95,2360,2361],{},"java.lang"," is special — its classes (",[95,2364,315],{},[95,2366,312],{},", and a handful of others) are always available, in every Java file, with no ",[95,2369,2302],{}," needed. That's why you've been able to use ",[95,2372,2373],{},"System.out.println",[95,2375,315],{}," this whole time without importing anything.",[69,2378,412],{"id":411},[19,2380,2381,2390],{},[22,2382,2383,2386,2387,2389],{},[25,2384,2385],{},"Forgetting an import."," If a class isn't in ",[95,2388,2361],{}," and isn't in your own package, using it without importing it is a compile error.",[22,2391,2392,2395],{},[25,2393,2394],{},"Importing something you don't use."," Not a functional bug, but most IDEs will flag it — it's just clutter.",[69,2397,450],{"id":449},[19,2399,2400,2403,2408],{},[22,2401,2402],{},"A package groups related classes together, the way a folder groups related files.",[22,2404,2405,2407],{},[95,2406,2302],{}," brings a class from another package into your file so you can use its short name.",[22,2409,2410,2412,2413,486,2415,2417],{},[95,2411,2361],{}," (which includes ",[95,2414,315],{},[95,2416,312],{},") never needs an import — it's always available.",[15,2419,493,2420,497,2422,2424],{},[95,2421,496],{},[95,2423,2078],{}," (CSA 1.7 §1.7.2)",[503,2426,505],{},{"title":48,"searchDepth":49,"depth":49,"links":2428},[2429,2430,2431,2432,2433],{"id":2281,"depth":49,"text":2282},{"id":2295,"depth":49,"text":2296},{"id":2355,"depth":49,"text":2356},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":2435,"status":519},"3.3 — Packages & Imports (CSA 1.7 §1.7.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3-packages-and-imports",{"title":2273,"description":48},"shockwave-curriculum\u002Flessons\u002Fch03-apis-libraries-and-documentation\u002F3.3-packages-and-imports","ij_JRSQVjOaWEMjmtdjACluOXv0refm2jhQHQBKzed4",{"id":2441,"title":2442,"body":2443,"description":48,"extension":51,"meta":2626,"navigation":55,"path":2628,"seo":2629,"stem":2630,"__hash__":2631},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.1-methods-signatures-and-parameters.md","Methods, Signatures & Parameters",{"type":8,"value":2444,"toc":2618},[2445,2448,2452,2464,2468,2475,2484,2494,2503,2520,2524,2531,2535,2550,2570,2572,2592,2594,2608,2616],[11,2446,2442],{"id":2447},"methods-signatures-parameters",[69,2449,2451],{"id":2450},"what-a-method-is","What a Method Is",[15,2453,355,2454,2457,2458,2460,2461,2463],{},[25,2455,2456],{},"method"," is a named block of code that runs when you call it. ",[95,2459,338],{}," is a method call — you've been calling methods since Lesson 1.2 without needing to know how ",[95,2462,345],{}," is implemented internally. That's the whole benefit: you use a method by its name and what it does, not by reading its insides.",[69,2465,2467],{"id":2466},"signature-parameters-arguments","Signature, Parameters, Arguments",[15,2469,2470,2471,2474],{},"A method's ",[25,2472,2473],{},"signature"," is its name plus its parameter types — what you need to know to call it correctly.",[104,2476,2478],{"className":106,"code":2477,"language":108,"meta":48,"style":48},"public void rampTo(double targetSpeed) { ... }\n",[95,2479,2480],{"__ignoreMap":48},[112,2481,2482],{"class":114,"line":115},[112,2483,2477],{},[15,2485,2486,2489,2490,2493],{},[95,2487,2488],{},"targetSpeed"," here is a ",[25,2491,2492],{},"parameter"," — a variable declared in the method's header, usable inside the method's body. When you actually call the method:",[104,2495,2497],{"className":106,"code":2496,"language":108,"meta":48,"style":48},"drivetrain.rampTo(0.8);\n",[95,2498,2499],{"__ignoreMap":48},[112,2500,2501],{"class":114,"line":115},[112,2502,2496],{},[15,2504,2505,2508,2509,2512,2513,2516,2517,79],{},[95,2506,2507],{},"0.8"," is the ",[25,2510,2511],{},"argument"," — the real value being passed in. \"Parameter\" and \"argument\" describe the same slot from two different sides: the parameter is the variable ",[262,2514,2515],{},"in the method","; the argument is the value ",[262,2518,2519],{},"at the call site",[69,2521,2523],{"id":2522},"call-by-value","Call by Value",[15,2525,2526,2527,2530],{},"Java copies the argument's value into the parameter — ",[25,2528,2529],{},"call by value",". If the method changes its own parameter internally, the original value the caller passed in is unaffected; only a copy went in.",[69,2532,2534],{"id":2533},"overloading","Overloading",[15,2536,2537,2538,778,2540,2543,2544,2546,2547,2549],{},"Two methods can share the same name if their parameter lists differ in number or type — this is ",[25,2539,2533],{},[95,2541,2542],{},"System.out.println()"," is a real example: there's a version for no arguments, one for a ",[95,2545,315],{},", one for an ",[95,2548,552],{},", and more — Java picks the right one based on what you pass in.",[104,2551,2553],{"className":106,"code":2552,"language":108,"meta":48,"style":48},"void println()          \u002F\u002F no parameters\nvoid println(String x)  \u002F\u002F takes a String\nvoid println(int x)     \u002F\u002F takes an int\n",[95,2554,2555,2560,2565],{"__ignoreMap":48},[112,2556,2557],{"class":114,"line":115},[112,2558,2559],{},"void println()          \u002F\u002F no parameters\n",[112,2561,2562],{"class":114,"line":49},[112,2563,2564],{},"void println(String x)  \u002F\u002F takes a String\n",[112,2566,2567],{"class":114,"line":126},[112,2568,2569],{},"void println(int x)     \u002F\u002F takes an int\n",[69,2571,412],{"id":411},[19,2573,2574,2580,2586],{},[22,2575,2576,2579],{},[25,2577,2578],{},"Mixing up \"parameter\" and \"argument.\""," They're often used loosely as if interchangeable, but precisely: parameter = the variable in the method header, argument = the value at the call site.",[22,2581,2582,2585],{},[25,2583,2584],{},"Assuming a method can change the caller's original value."," Call by value means the method only ever gets a copy — reassigning a parameter inside the method never affects the variable the caller passed in.",[22,2587,2588,2591],{},[25,2589,2590],{},"Wrong argument count or type."," The compiler checks a call's arguments against the method's signature — mismatches (wrong count, wrong type, wrong order) won't compile.",[69,2593,450],{"id":449},[19,2595,2596,2599,2602,2605],{},[22,2597,2598],{},"A method's signature is its name plus its parameter types.",[22,2600,2601],{},"A parameter is a variable in the method's own header; an argument is the actual value passed in at the call site.",[22,2603,2604],{},"Java uses call by value — a method receives a copy of each argument, not the original.",[22,2606,2607],{},"Overloading means multiple methods share a name but differ in their parameter lists; Java picks the matching one based on the call.",[15,2609,493,2610,497,2612,2615],{},[95,2611,496],{},[95,2613,2614],{},"unit-1-using-objects-and-methods\u002F1.09-method-signatures.md"," (CSA 1.9)",[503,2617,505],{},{"title":48,"searchDepth":49,"depth":49,"links":2619},[2620,2621,2622,2623,2624,2625],{"id":2450,"depth":49,"text":2451},{"id":2466,"depth":49,"text":2467},{"id":2522,"depth":49,"text":2523},{"id":2533,"depth":49,"text":2534},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":2627,"status":519},"4.1 — Methods, Signatures and Parameters (CSA 1.9)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F1-methods-signatures-and-parameters",{"title":2442,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.1-methods-signatures-and-parameters","b19oBEt6uwnI_2lPtLm88WevR2lsAcnrUJ6g6BadwuY",{"id":2633,"title":2634,"body":2635,"description":48,"extension":51,"meta":2834,"navigation":55,"path":2836,"seo":2837,"stem":2838,"__hash__":2839},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.2-calling-class-methods.md","Calling Class Methods",{"type":8,"value":2636,"toc":2827},[2637,2640,2644,2660,2669,2672,2676,2685,2713,2722,2737,2741,2758,2773,2775,2795,2797,2817,2825],[11,2638,2634],{"id":2639},"calling-class-methods",[69,2641,2643],{"id":2642},"class-methods-static-methods","Class Methods (Static Methods)",[15,2645,2646,2647,2650,2651,207,2654,778,2657,2659],{},"A method marked ",[95,2648,2649],{},"static"," belongs to the class itself, not to any object — called a ",[25,2652,2653],{},"class method",[25,2655,2656],{},"static method",[95,2658,101],{}," is always static. Call one using the class name and the dot operator:",[104,2661,2663],{"className":106,"code":2662,"language":108,"meta":48,"style":48},"double distance = Math.abs(target - current);\n",[95,2664,2665],{"__ignoreMap":48},[112,2666,2667],{"class":114,"line":115},[112,2668,2662],{},[15,2670,2671],{},"Inside the same class that defines the method, you can drop the class name and just call it directly.",[69,2673,2675],{"id":2674},"void-vs-non-void-methods","Void vs. Non-Void Methods",[15,2677,355,2678,2680,2681,2684],{},[95,2679,281],{}," method doesn't return anything — you call it purely for its effect (like printing, or setting a motor's speed). A ",[25,2682,2683],{},"non-void"," method computes and returns a value, which the caller must actually use:",[104,2686,2688],{"className":106,"code":2687,"language":108,"meta":48,"style":48},"public static int square(int number)\n{\n    int result = number * number;\n    return result;\n}\n",[95,2689,2690,2695,2699,2704,2709],{"__ignoreMap":48},[112,2691,2692],{"class":114,"line":115},[112,2693,2694],{},"public static int square(int number)\n",[112,2696,2697],{"class":114,"line":49},[112,2698,123],{},[112,2700,2701],{"class":114,"line":126},[112,2702,2703],{},"    int result = number * number;\n",[112,2705,2706],{"class":114,"line":132},[112,2707,2708],{},"    return result;\n",[112,2710,2711],{"class":114,"line":138},[112,2712,153],{},[15,2714,2715,2718,2719,2721],{},[95,2716,2717],{},"return"," sends the value back to whoever called the method, and ends the method immediately — nothing after ",[95,2720,2717],{}," runs.",[104,2723,2725],{"className":106,"code":2724,"language":108,"meta":48,"style":48},"int y = square(5);        \u002F\u002F stored in a variable\nSystem.out.println(square(4)); \u002F\u002F used directly in an expression\n",[95,2726,2727,2732],{"__ignoreMap":48},[112,2728,2729],{"class":114,"line":115},[112,2730,2731],{},"int y = square(5);        \u002F\u002F stored in a variable\n",[112,2733,2734],{"class":114,"line":49},[112,2735,2736],{},"System.out.println(square(4)); \u002F\u002F used directly in an expression\n",[69,2738,2740],{"id":2739},"common-errors","Common Errors",[19,2742,2743,2746,2755],{},[22,2744,2745],{},"Forgetting to do something with a non-void method's return value — it has to be stored or used, not just called and ignored.",[22,2747,2748,2749,2751,2752,2754],{},"A type mismatch between what a method returns and what you try to store it in (assigning a ",[95,2750,580],{}," return into an ",[95,2753,552],{}," variable won't compile).",[22,2756,2757],{},"Wrong argument count, order, or type at the call site.",[104,2759,2761],{"className":106,"code":2760,"language":108,"meta":48,"style":48},"int total = calculateChecksum(data); \u002F\u002F fine — assuming calculateChecksum returns an int\ncalculateChecksum(data);             \u002F\u002F compiles, but the returned value is silently thrown away\n",[95,2762,2763,2768],{"__ignoreMap":48},[112,2764,2765],{"class":114,"line":115},[112,2766,2767],{},"int total = calculateChecksum(data); \u002F\u002F fine — assuming calculateChecksum returns an int\n",[112,2769,2770],{"class":114,"line":49},[112,2771,2772],{},"calculateChecksum(data);             \u002F\u002F compiles, but the returned value is silently thrown away\n",[69,2774,412],{"id":411},[19,2776,2777,2783],{},[22,2778,2779,2782],{},[25,2780,2781],{},"Calling a non-void method and doing nothing with the result."," It still compiles — Java doesn't force you to use a return value, which makes this an easy mistake to miss.",[22,2784,2785,2788,2789,2791,2792,2794],{},[25,2786,2787],{},"Assigning a return value to the wrong type."," A ",[95,2790,580],{},"-returning method's result can't go straight into an ",[95,2793,552],{}," variable without an explicit cast (Ch.2.4) — and casting one truncates the decimal, which may not be what you wanted.",[69,2796,450],{"id":449},[19,2798,2799,2804,2809,2814],{},[22,2800,355,2801,2803],{},[95,2802,2649],{}," method is a class method, called via the class name (or bare, from inside the same class).",[22,2805,355,2806,2808],{},[95,2807,281],{}," method returns nothing; a non-void method computes a value that must be stored or used.",[22,2810,2811,2813],{},[95,2812,2717],{}," sends a value back to the caller and ends the method immediately.",[22,2815,2816],{},"A non-void method's return value being ignored is a real, easy-to-miss bug — it still compiles.",[15,2818,493,2819,497,2821,2824],{},[95,2820,496],{},[95,2822,2823],{},"unit-1-using-objects-and-methods\u002F1.10-calling-class-methods.md"," (CSA 1.10)",[503,2826,505],{},{"title":48,"searchDepth":49,"depth":49,"links":2828},[2829,2830,2831,2832,2833],{"id":2642,"depth":49,"text":2643},{"id":2674,"depth":49,"text":2675},{"id":2739,"depth":49,"text":2740},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":2835,"status":519},"4.2 — Calling Class Methods (CSA 1.10)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F2-calling-class-methods",{"title":2634,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.2-calling-class-methods","Cnr6AlfLO4RFKqDWBi1PPY0juPb0R84tkAVEnzWP-g8",{"id":2841,"title":2842,"body":2843,"description":48,"extension":51,"meta":3080,"navigation":55,"path":3082,"seo":3083,"stem":3084,"__hash__":3085},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.3-using-the-math-class.md","Using the Math Class",{"type":8,"value":2844,"toc":3074},[2845,2848,2852,2862,2887,2890,2894,2907,2922,2928,2957,2980,2982,3021,3023,3064,3072],[11,2846,2842],{"id":2847},"using-the-math-class",[69,2849,2851],{"id":2850},"maths-static-methods","Math's Static Methods",[15,2853,2854,2857,2858,2861],{},[95,2855,2856],{},"Math"," is a built-in class of static methods — no object, no ",[95,2859,2860],{},"new",", just call it directly by its class name:",[104,2863,2865],{"className":106,"code":2864,"language":108,"meta":48,"style":48},"Math.abs(-4);     \u002F\u002F 4 — absolute value\nMath.pow(2, 3);   \u002F\u002F 8.0 — 2 to the power of 3\nMath.sqrt(9);     \u002F\u002F 3.0\nMath.random();    \u002F\u002F a double >= 0.0 and \u003C 1.0\n",[95,2866,2867,2872,2877,2882],{"__ignoreMap":48},[112,2868,2869],{"class":114,"line":115},[112,2870,2871],{},"Math.abs(-4);     \u002F\u002F 4 — absolute value\n",[112,2873,2874],{"class":114,"line":49},[112,2875,2876],{},"Math.pow(2, 3);   \u002F\u002F 8.0 — 2 to the power of 3\n",[112,2878,2879],{"class":114,"line":126},[112,2880,2881],{},"Math.sqrt(9);     \u002F\u002F 3.0\n",[112,2883,2884],{"class":114,"line":132},[112,2885,2886],{},"Math.random();    \u002F\u002F a double >= 0.0 and \u003C 1.0\n",[15,2888,2889],{},"These all return a value, so — same rule as the last lesson — you must actually use what they return.",[69,2891,2893],{"id":2892},"random-numbers-in-a-range","Random Numbers in a Range",[15,2895,2896,2899,2900,2902,2903,2906],{},[95,2897,2898],{},"Math.random()"," alone gives a ",[95,2901,580],{}," in ",[95,2904,2905],{},"[0.0, 1.0)"," — including 0.0, never reaching 1.0. That's rarely useful on its own; you stretch and shift it to get the range you actually want:",[104,2908,2910],{"className":106,"code":2909,"language":108,"meta":48,"style":48},"int rnd = (int)(Math.random() * 10);      \u002F\u002F an int from 0-9 (10 possible values)\nint rnd2 = (int)(Math.random() * 10) + 1; \u002F\u002F an int from 1-10 (shifted up by 1)\n",[95,2911,2912,2917],{"__ignoreMap":48},[112,2913,2914],{"class":114,"line":115},[112,2915,2916],{},"int rnd = (int)(Math.random() * 10);      \u002F\u002F an int from 0-9 (10 possible values)\n",[112,2918,2919],{"class":114,"line":49},[112,2920,2921],{},"int rnd2 = (int)(Math.random() * 10) + 1; \u002F\u002F an int from 1-10 (shifted up by 1)\n",[15,2923,2924,2925,2927],{},"The general recipe: multiply by how many values you want, cast to ",[95,2926,552],{}," to drop the decimal, then add the minimum to shift the whole range up.",[104,2929,2931],{"className":106,"code":2930,"language":108,"meta":48,"style":48},"\u002F\u002F A random autonomous delay between 1 and 4 seconds\ndouble delay = Math.random() * 3.0 + 1.0; \u002F\u002F [1.0, 4.0)\n\n\u002F\u002F A random starting position index, 0 through 2 (3 choices)\nint startPos = (int)(Math.random() * 3);\n",[95,2932,2933,2938,2943,2947,2952],{"__ignoreMap":48},[112,2934,2935],{"class":114,"line":115},[112,2936,2937],{},"\u002F\u002F A random autonomous delay between 1 and 4 seconds\n",[112,2939,2940],{"class":114,"line":49},[112,2941,2942],{},"double delay = Math.random() * 3.0 + 1.0; \u002F\u002F [1.0, 4.0)\n",[112,2944,2945],{"class":114,"line":126},[112,2946,820],{"emptyLinePlaceholder":55},[112,2948,2949],{"class":114,"line":132},[112,2950,2951],{},"\u002F\u002F A random starting position index, 0 through 2 (3 choices)\n",[112,2953,2954],{"class":114,"line":138},[112,2955,2956],{},"int startPos = (int)(Math.random() * 3);\n",[15,2958,2959,2960,2963,2964,2967,2968,2970,2971,2974,2975,2977,2978,79],{},"The parentheses matter: ",[95,2961,2962],{},"(int)(Math.random() * 10)"," casts the whole scaled expression; ",[95,2965,2966],{},"(int)Math.random() * 10"," casts ",[95,2969,2898],{}," alone ",[262,2972,2973],{},"first"," — which truncates it to ",[95,2976,1140],{}," every time, then multiplies by 10, always giving ",[95,2979,1140],{},[69,2981,412],{"id":411},[19,2983,2984,2999,3012],{},[22,2985,2986,426,2989,2991,2992,2994,2995,2998],{},[25,2987,2988],{},"Forgetting the parentheses around the scaled expression.",[95,2990,2966],{}," always evaluates to ",[95,2993,1140],{}," — the cast has to wrap the whole ",[95,2996,2997],{},"Math.random() * range"," expression.",[22,3000,3001,3004,3005,868,3008,3011],{},[25,3002,3003],{},"Off-by-one on the range size."," For an inclusive range like 1-10, the range size is ",[95,3006,3007],{},"10",[95,3009,3010],{},"9"," — count how many distinct values you actually want.",[22,3013,3014,426,3017,3020],{},[25,3015,3016],{},"Ignoring the return value.",[95,3018,3019],{},"Math.abs(x);"," on its own line compiles but does nothing useful — the result has to be stored or used.",[69,3022,450],{"id":449},[19,3024,3025,3034,3044,3055],{},[22,3026,3027,3029,3030,3033],{},[95,3028,2856],{}," methods are static — call them as ",[95,3031,3032],{},"Math.methodName(...)",", no object needed.",[22,3035,3036,3038,3039,2902,3041,3043],{},[95,3037,2898],{}," returns a ",[95,3040,580],{},[95,3042,2905],{}," — 0.0 possible, 1.0 never reached.",[22,3045,3046,3047,3050,3051,3054],{},"To get a random int in a range: ",[95,3048,3049],{},"(int)(Math.random() * range) + min",", where ",[95,3052,3053],{},"range"," is the count of possible values.",[22,3056,3057,3058,3060,3061,3063],{},"The parentheses around ",[95,3059,2997],{}," are required — casting only ",[95,3062,2898],{}," breaks the formula.",[15,3065,493,3066,497,3068,3071],{},[95,3067,496],{},[95,3069,3070],{},"unit-1-using-objects-and-methods\u002F1.11-using-the-math-class.md"," (CSA 1.11)",[503,3073,505],{},{"title":48,"searchDepth":49,"depth":49,"links":3075},[3076,3077,3078,3079],{"id":2850,"depth":49,"text":2851},{"id":2892,"depth":49,"text":2893},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":3081,"status":519},"4.3 — Using the Math Class (CSA 1.11)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F3-using-the-math-class",{"title":2842,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.3-using-the-math-class","RNaWZ7ElPdXRxJczEN3ER0ZVuxIAbuDDtpy3x96sE2E",{"id":3087,"title":3088,"body":3089,"description":48,"extension":51,"meta":3312,"navigation":55,"path":3314,"seo":3315,"stem":3316,"__hash__":3317},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.4-objects-instances-of-classes.md","Objects — Instances of Classes",{"type":8,"value":3090,"toc":3305},[3091,3094,3098,3116,3131,3154,3158,3161,3180,3199,3203,3218,3221,3241,3244,3246,3271,3273,3295,3303],[11,3092,3088],{"id":3093},"objects-instances-of-classes",[69,3095,3097],{"id":3096},"class-as-blueprint-object-as-instance","Class as Blueprint, Object as Instance",[15,3099,355,3100,3102,3103,3105,3106,3108,3109,486,3112,3115],{},[25,3101,97],{}," is a blueprint; an ",[25,3104,1957],{}," is one specific thing built from it — the way a cookie cutter (class) stamps out cookies (objects), all the same shape but each its own cookie. ",[95,3107,2010],{}," is a class; ",[95,3110,3111],{},"leftMotor",[95,3113,3114],{},"rightMotor"," are two separate objects built from it.",[104,3117,3119],{"className":106,"code":3118,"language":108,"meta":48,"style":48},"TalonFX leftMotor;\nTalonFX rightMotor;\n",[95,3120,3121,3126],{"__ignoreMap":48},[112,3122,3123],{"class":114,"line":115},[112,3124,3125],{},"TalonFX leftMotor;\n",[112,3127,3128],{"class":114,"line":49},[112,3129,3130],{},"TalonFX rightMotor;\n",[15,3132,3133,3134,3137,3138,207,3140,3142,3143,3146,3147,3150,3151,3153],{},"A class also defines a new ",[262,3135,3136],{},"type",", the same way ",[95,3139,552],{},[95,3141,580],{}," do — ",[95,3144,3145],{},"TalonFX leftMotor;"," declares a variable exactly like ",[95,3148,3149],{},"int score;"," does, just holding a ",[95,3152,2010],{}," instead of a whole number.",[69,3155,3157],{"id":3156},"attributes-and-behaviors-revisited","Attributes and Behaviors, Revisited",[15,3159,3160],{},"Every object has:",[19,3162,3163,3168],{},[22,3164,3165,3167],{},[25,3166,1968],{}," — the data it holds (its CAN ID, its current speed).",[22,3169,3170,3172,3173,275,3176,3179],{},[25,3171,1974],{}," — what it can do, defined as methods (",[95,3174,3175],{},"set()",[95,3177,3178],{},"getVelocity()",").",[15,3181,3182,3183,3186,3187,3190,3191,486,3193,3195,3196,3198],{},"The class defines ",[262,3184,3185],{},"what"," attributes and behaviors exist; each individual object has its ",[262,3188,3189],{},"own"," values for them. ",[95,3192,3111],{},[95,3194,3114],{}," are both ",[95,3197,2010],{}," objects, but each has its own CAN ID and its own current speed.",[69,3200,3202],{"id":3201},"reference-variables","Reference Variables",[15,3204,3205,3206,3208,3209,3212,3213,275,3215,3217],{},"A variable like ",[95,3207,3111],{}," doesn't hold the motor object directly — it holds a ",[25,3210,3211],{},"reference"," to it, like a tracking number pointing at where the real object lives in memory. This is different from a primitive variable (",[95,3214,552],{},[95,3216,580],{},"), which holds its value directly with nothing in between.",[15,3219,3220],{},"You can create as many objects from one class as you need:",[104,3222,3224],{"className":106,"code":3223,"language":108,"meta":48,"style":48},"TalonFX leftMotor = new TalonFX(1);\nTalonFX rightMotor = new TalonFX(2);\nTalonFX intakeMotor = new TalonFX(3);\n",[95,3225,3226,3231,3236],{"__ignoreMap":48},[112,3227,3228],{"class":114,"line":115},[112,3229,3230],{},"TalonFX leftMotor = new TalonFX(1);\n",[112,3232,3233],{"class":114,"line":49},[112,3234,3235],{},"TalonFX rightMotor = new TalonFX(2);\n",[112,3237,3238],{"class":114,"line":126},[112,3239,3240],{},"TalonFX intakeMotor = new TalonFX(3);\n",[15,3242,3243],{},"Three separate objects, one class.",[69,3245,412],{"id":411},[19,3247,3248,3259],{},[22,3249,3250,426,3253,3255,3256,3258],{},[25,3251,3252],{},"Confusing the class name with an object's name.",[95,3254,2010],{}," is always the class (capitalized, PascalCase); ",[95,3257,3111],{}," is a specific object (camelCase). Mixing these up is a common early error.",[22,3260,3261,426,3264,486,3266,3195,3268,3270],{},[25,3262,3263],{},"Assuming two objects of the same class share state.",[95,3265,3111],{},[95,3267,3114],{},[95,3269,2010],{}," objects, but changing one's speed has zero effect on the other — each object's attributes are entirely its own.",[69,3272,450],{"id":449},[19,3274,3275,3278,3286,3289,3292],{},[22,3276,3277],{},"A class is a blueprint; an object is one specific instance built from it.",[22,3279,3280,3281,207,3283,3285],{},"A class defines a new type, just like ",[95,3282,552],{},[95,3284,580],{}," — a class variable declares a variable of that type.",[22,3287,3288],{},"Attributes are an object's data; behaviors are what it can do, defined as methods.",[22,3290,3291],{},"A reference variable holds a pointer to an object, not the object's data directly.",[22,3293,3294],{},"Many objects can be created from the same class, each with its own independent attribute values.",[15,3296,493,3297,497,3299,3302],{},[95,3298,496],{},[95,3300,3301],{},"unit-1-using-objects-and-methods\u002F1.12-objects-instances-of-classes.md"," (CSA 1.12)",[503,3304,505],{},{"title":48,"searchDepth":49,"depth":49,"links":3306},[3307,3308,3309,3310,3311],{"id":3096,"depth":49,"text":3097},{"id":3156,"depth":49,"text":3157},{"id":3201,"depth":49,"text":3202},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":3313,"status":519},"4.4 — Objects – Instances of Classes (CSA 1.12)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4-objects-instances-of-classes",{"title":3088,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.4-objects-instances-of-classes","MI6pmHdFBgpAUCtiGKlzU24KRzwCcTAlNf0z7uwQSXw",{"id":3319,"title":3320,"body":3321,"description":48,"extension":51,"meta":3556,"navigation":55,"path":3558,"seo":3559,"stem":3560,"__hash__":3561},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.5-creating-and-initializing-objects-constructors.md","Creating & Initializing Objects: Constructors",{"type":8,"value":3322,"toc":3546},[3323,3326,3332,3341,3350,3354,3360,3375,3378,3385,3391,3406,3416,3420,3423,3447,3449,3505,3507,3536,3544],[11,3324,3320],{"id":3325},"creating-initializing-objects-constructors",[69,3327,3329,3330],{"id":3328},"building-an-object-with-new","Building an Object with ",[95,3331,2860],{},[15,3333,355,3334,3337,3338,3340],{},[25,3335,3336],{},"constructor"," initializes a new object's attributes when it's created. To build one, use ",[95,3339,2860],{}," followed by the class name — that's actually a call to the constructor:",[104,3342,3344],{"className":106,"code":3343,"language":108,"meta":48,"style":48},"TalonFX leftMotor = new TalonFX(5); \u002F\u002F 5 is the CAN ID — argument order matters\n",[95,3345,3346],{"__ignoreMap":48},[112,3347,3348],{"class":114,"line":115},[112,3349,3343],{},[69,3351,3353],{"id":3352},"constructors-can-be-overloaded","Constructors Can Be Overloaded",[15,3355,3356,3357,3359],{},"A class can offer more than one constructor — different ways to set up an object, distinguished by their parameter lists. This is the same ",[25,3358,2533],{}," concept from methods (Lesson 4.1), applied to constructors:",[104,3361,3363],{"className":106,"code":3362,"language":108,"meta":48,"style":48},"Pose2d start1 = new Pose2d();                       \u002F\u002F no-argument constructor: defaults to (0, 0, facing 0°)\nPose2d start2 = new Pose2d(1.0, 2.0, new Rotation2d()); \u002F\u002F x, y, and heading, explicitly\n",[95,3364,3365,3370],{"__ignoreMap":48},[112,3366,3367],{"class":114,"line":115},[112,3368,3369],{},"Pose2d start1 = new Pose2d();                       \u002F\u002F no-argument constructor: defaults to (0, 0, facing 0°)\n",[112,3371,3372],{"class":114,"line":49},[112,3373,3374],{},"Pose2d start2 = new Pose2d(1.0, 2.0, new Rotation2d()); \u002F\u002F x, y, and heading, explicitly\n",[15,3376,3377],{},"Argument order matters — mixing up which number means what (is it x-then-y, or y-then-x?) produces a real, silent bug: the code compiles fine, but the object ends up with the wrong values.",[69,3379,3381,3382],{"id":3380},"object-references-and-null","Object References and ",[95,3383,3384],{},"null",[15,3386,3387,3388,3390],{},"A reference variable can be declared without pointing at any object yet — that's ",[95,3389,3384],{},", meaning \"doesn't refer to anything.\"",[104,3392,3394],{"className":106,"code":3393,"language":108,"meta":48,"style":48},"TalonFX intakeMotor = null; \u002F\u002F no object yet\nintakeMotor = new TalonFX(7); \u002F\u002F now it does\n",[95,3395,3396,3401],{"__ignoreMap":48},[112,3397,3398],{"class":114,"line":115},[112,3399,3400],{},"TalonFX intakeMotor = null; \u002F\u002F no object yet\n",[112,3402,3403],{"class":114,"line":49},[112,3404,3405],{},"intakeMotor = new TalonFX(7); \u002F\u002F now it does\n",[15,3407,3408,3409,3411,3412,3415],{},"Calling a method on a ",[95,3410,3384],{}," reference — one that was declared but never actually constructed — throws a ",[95,3413,3414],{},"NullPointerException"," at runtime (more on this in the next lesson).",[69,3417,3419],{"id":3418},"constructor-signatures","Constructor Signatures",[15,3421,3422],{},"Just like methods, a constructor has a signature: its name (always the same as the class) plus its parameter types. Look up a library class's constructors in its documentation to see what arguments it expects and in what order.",[104,3424,3426],{"className":106,"code":3425,"language":108,"meta":48,"style":48},"public class Pose2d {\n    public Pose2d() { \u002F* implementation not shown *\u002F }\n    public Pose2d(double x, double y, Rotation2d rotation) { \u002F* implementation not shown *\u002F }\n}\n",[95,3427,3428,3433,3438,3443],{"__ignoreMap":48},[112,3429,3430],{"class":114,"line":115},[112,3431,3432],{},"public class Pose2d {\n",[112,3434,3435],{"class":114,"line":49},[112,3436,3437],{},"    public Pose2d() { \u002F* implementation not shown *\u002F }\n",[112,3439,3440],{"class":114,"line":126},[112,3441,3442],{},"    public Pose2d(double x, double y, Rotation2d rotation) { \u002F* implementation not shown *\u002F }\n",[112,3444,3445],{"class":114,"line":132},[112,3446,153],{},[69,3448,412],{"id":411},[19,3450,3451,3464,3478],{},[22,3452,3453,426,3458,3461,3462,79],{},[25,3454,3455,3456,79],{},"Forgetting ",[95,3457,2860],{},[95,3459,3460],{},"TalonFX leftMotor = TalonFX(5);"," doesn't compile — creating an object always requires ",[95,3463,2860],{},[22,3465,3466,3469,3470,3473,3474,3477],{},[25,3467,3468],{},"Mixing up argument order."," A constructor taking ",[95,3471,3472],{},"(x, y, rotation)"," called as ",[95,3475,3476],{},"(rotation, x, y)"," either won't compile (wrong types) or, worse, compiles with the wrong values silently swapped.",[22,3479,3480,3483,3484,3487,3488,3491,3492,3495,3496,3498,3499,3502,3503,79],{},[25,3481,3482],{},"Calling a method on an unconstructed reference."," Declaring ",[95,3485,3486],{},"TalonFX m;"," without ever assigning ",[95,3489,3490],{},"new TalonFX(...)"," to it leaves ",[95,3493,3494],{},"m"," as ",[95,3497,3384],{}," — calling ",[95,3500,3501],{},"m.set(0.5)"," crashes with a ",[95,3504,3414],{},[69,3506,450],{"id":449},[19,3508,3509,3515,3518,3526,3533],{},[22,3510,3511,3514],{},[95,3512,3513],{},"new ClassName(arguments)"," calls a constructor to build and initialize an object.",[22,3516,3517],{},"A class can have multiple overloaded constructors, differing in their parameter lists.",[22,3519,3520,3521,3523,3524,79],{},"A reference variable can be ",[95,3522,3384],{}," — pointing at no object at all — until it's assigned a real one with ",[95,3525,2860],{},[22,3527,3408,3528,3530,3531,79],{},[95,3529,3384],{}," reference throws a ",[95,3532,3414],{},[22,3534,3535],{},"Constructor argument order must match the constructor's signature exactly.",[15,3537,493,3538,497,3540,3543],{},[95,3539,496],{},[95,3541,3542],{},"unit-1-using-objects-and-methods\u002F1.13-creating-and-initializing-objects-constructors.md"," (CSA 1.13)",[503,3545,505],{},{"title":48,"searchDepth":49,"depth":49,"links":3547},[3548,3550,3551,3553,3554,3555],{"id":3328,"depth":49,"text":3549},"Building an Object with new",{"id":3352,"depth":49,"text":3353},{"id":3380,"depth":49,"text":3552},"Object References and null",{"id":3418,"depth":49,"text":3419},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":3557,"status":519},"4.5 — Creating and Initializing Objects: Constructors (CSA 1.13)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F5-creating-and-initializing-objects-constructors",{"title":3320,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.5-creating-and-initializing-objects-constructors","bfm8oGJbn_9qYKDLOEob28hFRseW3ZLVodu6HIFhFS0",{"id":3563,"title":3564,"body":3565,"description":48,"extension":51,"meta":3763,"navigation":55,"path":3765,"seo":3766,"stem":3767,"__hash__":3768},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.6-calling-instance-methods.md","Calling Instance Methods",{"type":8,"value":3566,"toc":3755},[3567,3570,3574,3585,3594,3604,3607,3619,3634,3638,3641,3656,3660,3671,3686,3688,3728,3730,3745,3753],[11,3568,3564],{"id":3569},"calling-instance-methods",[69,3571,3573],{"id":3572},"instance-methods-vs-static-methods","Instance Methods vs. Static Methods",[15,3575,3576,3577,3580,3581,3584],{},"Lesson 4.2 covered static (class) methods, called via the class name. An ",[25,3578,3579],{},"instance method"," is the opposite: it's always called on a specific object, and it reads or changes ",[262,3582,3583],{},"that object's"," attributes.",[104,3586,3588],{"className":106,"code":3587,"language":108,"meta":48,"style":48},"leftMotor.set(0.5); \u002F\u002F instance method — acts on leftMotor specifically, not TalonFX in general\n",[95,3589,3590],{"__ignoreMap":48},[112,3591,3592],{"class":114,"line":115},[112,3593,3587],{},[15,3595,3596,3599,3600,3603],{},[95,3597,3598],{},"Math.sqrt(9)"," doesn't care which object called it (there is no object) — it's pure computation. ",[95,3601,3602],{},"leftMotor.set(0.5)"," only makes sense applied to one specific motor.",[69,3605,3414],{"id":3606},"nullpointerexception",[15,3608,3609,3610,3612,3613,3615,3616,3618],{},"Calling a method on a reference that's ",[95,3611,3384],{}," — declared but never actually built with ",[95,3614,2860],{}," — throws a ",[95,3617,3414],{}," at runtime. This is one of the most common real bugs in object-oriented code:",[104,3620,3622],{"className":106,"code":3621,"language":108,"meta":48,"style":48},"TalonFX intakeMotor = null;\nintakeMotor.set(0.5); \u002F\u002F crashes: intakeMotor doesn't refer to a real object yet\n",[95,3623,3624,3629],{"__ignoreMap":48},[112,3625,3626],{"class":114,"line":115},[112,3627,3628],{},"TalonFX intakeMotor = null;\n",[112,3630,3631],{"class":114,"line":49},[112,3632,3633],{},"intakeMotor.set(0.5); \u002F\u002F crashes: intakeMotor doesn't refer to a real object yet\n",[69,3635,3637],{"id":3636},"methods-with-arguments","Methods With Arguments",[15,3639,3640],{},"Just like the constructors from the last lesson, instance methods can take arguments:",[104,3642,3644],{"className":106,"code":3643,"language":108,"meta":48,"style":48},"leftMotor.set(0.5);          \u002F\u002F no extra behavior beyond the speed itself\nelevator.moveToPosition(24.0); \u002F\u002F 24.0 is the argument, saved into the method's parameter\n",[95,3645,3646,3651],{"__ignoreMap":48},[112,3647,3648],{"class":114,"line":115},[112,3649,3650],{},"leftMotor.set(0.5);          \u002F\u002F no extra behavior beyond the speed itself\n",[112,3652,3653],{"class":114,"line":49},[112,3654,3655],{},"elevator.moveToPosition(24.0); \u002F\u002F 24.0 is the argument, saved into the method's parameter\n",[69,3657,3659],{"id":3658},"getters-accessors","Getters (Accessors)",[15,3661,3662,3663,3666,3667,3670],{},"A method that just reports one of an object's attributes — no side effects, just returns a value — is a ",[25,3664,3665],{},"getter"," (formally, an accessor). By convention its name starts with ",[95,3668,3669],{},"get",", and its return value must actually be used:",[104,3672,3674],{"className":106,"code":3673,"language":108,"meta":48,"style":48},"double speed = leftMotor.getVelocity(); \u002F\u002F a getter — must use the returned value\nSystem.out.println(\"Current speed: \" + leftMotor.getVelocity());\n",[95,3675,3676,3681],{"__ignoreMap":48},[112,3677,3678],{"class":114,"line":115},[112,3679,3680],{},"double speed = leftMotor.getVelocity(); \u002F\u002F a getter — must use the returned value\n",[112,3682,3683],{"class":114,"line":49},[112,3684,3685],{},"System.out.println(\"Current speed: \" + leftMotor.getVelocity());\n",[69,3687,412],{"id":411},[19,3689,3690,3705,3719],{},[22,3691,3692,426,3695,3698,3699,3701,3702,3704],{},[25,3693,3694],{},"Calling an instance method without an object.",[95,3696,3697],{},"TalonFX.set(0.5)"," doesn't make sense — ",[95,3700,2006],{}," needs a specific motor to act on; only ",[95,3703,3602],{}," does.",[22,3706,3707,3712,3713,3715,3716,3718],{},[25,3708,3408,3709,3711],{},[95,3710,3384],{}," reference."," The single most common source of ",[95,3714,3414],{}," — make sure every object is actually constructed with ",[95,3717,2860],{}," before calling anything on it.",[22,3720,3721,426,3724,3727],{},[25,3722,3723],{},"Ignoring a getter's return value.",[95,3725,3726],{},"leftMotor.getVelocity();"," alone does nothing useful — a getter exists specifically to report a value you then use.",[69,3729,450],{"id":449},[19,3731,3732,3735,3742],{},[22,3733,3734],{},"An instance method is called on a specific object and can read\u002Fchange that object's own attributes; a static method belongs to the class itself.",[22,3736,3408,3737,3530,3739,3741],{},[95,3738,3384],{},[95,3740,3414],{}," — one of the most common real bugs.",[22,3743,3744],{},"A getter (accessor) reports one of an object's attributes; its return value must be used, not ignored.",[15,3746,493,3747,497,3749,3752],{},[95,3748,496],{},[95,3750,3751],{},"unit-1-using-objects-and-methods\u002F1.14-calling-instance-methods.md"," (CSA 1.14)",[503,3754,505],{},{"title":48,"searchDepth":49,"depth":49,"links":3756},[3757,3758,3759,3760,3761,3762],{"id":3572,"depth":49,"text":3573},{"id":3606,"depth":49,"text":3414},{"id":3636,"depth":49,"text":3637},{"id":3658,"depth":49,"text":3659},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":3764,"status":519},"4.6 — Calling Instance Methods (CSA 1.14)","\u002Fshockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F6-calling-instance-methods",{"title":3564,"description":48},"shockwave-curriculum\u002Flessons\u002Fch04-using-objects-and-calling-methods\u002F4.6-calling-instance-methods","yYyzuQ8-wpJFp-ssUVby9Z24PvFzXsOMix0seK8AC70",{"id":3770,"title":3771,"body":3772,"description":48,"extension":51,"meta":4037,"navigation":55,"path":4040,"seo":4041,"stem":4042,"__hash__":4043},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.1-5.2-if-statements-and-for-loops.md","Control Structures: if Statements & For Loops",{"type":8,"value":3773,"toc":4029},[3774,3777,3781,3786,3809,3816,3855,3858,3868,3891,3895,3901,3937,3953,3955,3990,3992,4018,4027],[11,3775,3771],{"id":3776},"control-structures-if-statements-for-loops",[69,3778,3780],{"id":3779},"if-statements-one-way-and-two-way-selection","if Statements: One-Way and Two-Way Selection",[15,3782,1541,3783,3785],{},[95,3784,1766],{}," statement runs its body only when a boolean condition is true:",[104,3787,3789],{"className":106,"code":3788,"language":108,"meta":48,"style":48},"if (joystick.getRawButton(1))\n{\n    intake.spin(0.5);\n}\n",[95,3790,3791,3796,3800,3805],{"__ignoreMap":48},[112,3792,3793],{"class":114,"line":115},[112,3794,3795],{},"if (joystick.getRawButton(1))\n",[112,3797,3798],{"class":114,"line":49},[112,3799,123],{},[112,3801,3802],{"class":114,"line":126},[112,3803,3804],{},"    intake.spin(0.5);\n",[112,3806,3807],{"class":114,"line":132},[112,3808,153],{},[15,3810,3811,3812,3815],{},"Add an ",[95,3813,3814],{},"else"," for a second branch that runs when the condition is false:",[104,3817,3819],{"className":106,"code":3818,"language":108,"meta":48,"style":48},"if (joystick.getRawButton(1))\n{\n    intake.spin(0.5);\n}\nelse\n{\n    intake.stop();\n}\n",[95,3820,3821,3825,3829,3833,3837,3842,3846,3851],{"__ignoreMap":48},[112,3822,3823],{"class":114,"line":115},[112,3824,3795],{},[112,3826,3827],{"class":114,"line":49},[112,3828,123],{},[112,3830,3831],{"class":114,"line":126},[112,3832,3804],{},[112,3834,3835],{"class":114,"line":132},[112,3836,153],{},[112,3838,3839],{"class":114,"line":138},[112,3840,3841],{},"else\n",[112,3843,3844],{"class":114,"line":144},[112,3845,123],{},[112,3847,3848],{"class":114,"line":150},[112,3849,3850],{},"    intake.stop();\n",[112,3852,3853],{"class":114,"line":1819},[112,3854,153],{},[15,3856,3857],{},"Always use curly braces, even for a single statement — Java doesn't require them, but skipping them is exactly how the classic \"which statement is actually inside the if\" bug happens.",[69,3859,3861,3862,3864,3865,3867],{"id":3860},"the-classic-vs-mistake","The Classic ",[95,3863,686],{}," vs. ",[95,3866,1568],{}," Mistake",[15,3869,3870,3871,3873,3874,3876,3877,3880,3881,3883,3884,3887,3888,3890],{},"One ",[95,3872,686],{}," assigns a value; two ",[95,3875,1568],{}," test whether a value equals something. Writing ",[95,3878,3879],{},"if (isCold = true)"," inside a condition compiles (it's a legal assignment expression) but silently does the wrong thing — it assigns ",[95,3882,610],{}," to ",[95,3885,3886],{},"isCold"," and the condition is always true, regardless of what ",[95,3889,3886],{}," was before.",[69,3892,3894],{"id":3893},"for-loops-three-parts-one-line","For Loops: Three Parts, One Line",[15,3896,355,3897,3900],{},[95,3898,3899],{},"for"," loop bundles the three steps of a loop — initialize, test, update — into one header:",[104,3902,3904],{"className":106,"code":3903,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C sensors.length; i++)\n{\n    if (sensors[i].isFaulty())\n    {\n        report(sensors[i]);\n    }\n}\n",[95,3905,3906,3911,3915,3920,3924,3929,3933],{"__ignoreMap":48},[112,3907,3908],{"class":114,"line":115},[112,3909,3910],{},"for (int i = 0; i \u003C sensors.length; i++)\n",[112,3912,3913],{"class":114,"line":49},[112,3914,123],{},[112,3916,3917],{"class":114,"line":126},[112,3918,3919],{},"    if (sensors[i].isFaulty())\n",[112,3921,3922],{"class":114,"line":132},[112,3923,135],{},[112,3925,3926],{"class":114,"line":138},[112,3927,3928],{},"        report(sensors[i]);\n",[112,3930,3931],{"class":114,"line":144},[112,3932,147],{},[112,3934,3935],{"class":114,"line":150},[112,3936,153],{},[15,3938,3939,3940,3942,3943,3946,3947,3942,3949,3952],{},"The three parts are always separated by semicolons, in this order: initialize the loop variable, test it, update it. Starting at ",[95,3941,1140],{}," pairs naturally with ",[95,3944,3945],{},"\u003C","; starting at ",[95,3948,1093],{},[95,3950,3951],{},"\u003C="," — pick whichever matches how many times you actually want to run.",[69,3954,412],{"id":411},[19,3956,3957,3966,3977],{},[22,3958,3959,3962,3963,3965],{},[25,3960,3961],{},"Missing curly braces."," Without them, only the very next line is actually part of the ",[95,3964,1766],{},"\u002Floop body — everything after it runs unconditionally, every time.",[22,3967,3968,3976],{},[25,3969,3970,3972,3973,3975],{},[95,3971,686],{}," instead of ",[95,3974,1568],{}," in a condition."," A real, silent bug — the code compiles and the condition is always true.",[22,3978,3979,426,3982,3985,3986,3989],{},[25,3980,3981],{},"Off-by-one in a for loop's bound.",[95,3983,3984],{},"i \u003C sensors.length"," visits every valid index; ",[95,3987,3988],{},"i \u003C= sensors.length"," runs one iteration too many and reads past the end.",[69,3991,450],{"id":449},[19,3993,3994,4002,4005,4013],{},[22,3995,1541,3996,3998,3999,4001],{},[95,3997,1766],{}," runs its body only when its condition is true; an ",[95,4000,3814],{}," gives it a second branch for when it's false.",[22,4003,4004],{},"Always use curly braces around a conditional or loop body.",[22,4006,4007,4009,4010,4012],{},[95,4008,1568],{}," tests equality; ",[95,4011,686],{}," assigns. Confusing them compiles but silently breaks the logic.",[22,4014,355,4015,4017],{},[95,4016,3899],{}," loop's header has three parts — initialize, test, update — always in that order, separated by semicolons.",[15,4019,4020,426,4023,4026],{},[25,4021,4022],{},"Deck context:",[95,4024,4025],{},"mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js",", slide 5 (\"CONTROL STRUCTURES\")",[503,4028,505],{},{"title":48,"searchDepth":49,"depth":49,"links":4030},[4031,4032,4034,4035,4036],{"id":3779,"depth":49,"text":3780},{"id":3860,"depth":49,"text":4033},"The Classic = vs. == Mistake",{"id":3893,"depth":49,"text":3894},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":4038,"status":4039},"5.1 (if Statements, CSA 2.3) + 5.2 (For Loops, CSA 2.8) — combined","new — authored lesson (fuller depth than the teaser slide). This single lesson covers both items together, matching the existing deck slide's combined granularity.","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F1-5.2-if-statements-and-for-loops",{"title":3771,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.1-5.2-if-statements-and-for-loops","A9YIWpKibkAeZBK6L-ls471oRtG6CWYByfqn956D5hk",{"id":4045,"title":4046,"body":4047,"description":48,"extension":51,"meta":4190,"navigation":55,"path":4192,"seo":4193,"stem":4194,"__hash__":4195},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.10-nested-iteration.md","Nested Iteration",{"type":8,"value":4048,"toc":4184},[4049,4052,4056,4063,4099,4113,4115,4118,4120,4153,4155,4174,4182],[11,4050,4046],{"id":4051},"nested-iteration",[69,4053,4055],{"id":4054},"a-loop-inside-a-loop","A Loop Inside a Loop",[15,4057,4058,4059,4062],{},"Nesting one loop inside another means the inner loop runs to completion for ",[262,4060,4061],{},"every single pass"," of the outer one:",[104,4064,4066],{"className":106,"code":4065,"language":108,"meta":48,"style":48},"for (int row = 0; row \u003C 8; row++)\n{\n    for (int col = 0; col \u003C 8; col++)\n    {\n        visionGrid[row][col] = sampleCell(row, col);\n    }\n}\n",[95,4067,4068,4073,4077,4082,4086,4091,4095],{"__ignoreMap":48},[112,4069,4070],{"class":114,"line":115},[112,4071,4072],{},"for (int row = 0; row \u003C 8; row++)\n",[112,4074,4075],{"class":114,"line":49},[112,4076,123],{},[112,4078,4079],{"class":114,"line":126},[112,4080,4081],{},"    for (int col = 0; col \u003C 8; col++)\n",[112,4083,4084],{"class":114,"line":132},[112,4085,135],{},[112,4087,4088],{"class":114,"line":138},[112,4089,4090],{},"        visionGrid[row][col] = sampleCell(row, col);\n",[112,4092,4093],{"class":114,"line":144},[112,4094,147],{},[112,4096,4097],{"class":114,"line":150},[112,4098,153],{},[15,4100,4101,4102,4105,4106,4109,4110,4112],{},"For each value of ",[95,4103,4104],{},"row",", the inner loop runs all the way through every ",[95,4107,4108],{},"col"," value before the outer loop advances to the next ",[95,4111,4104],{},". The inner loop restarts from scratch each time.",[69,4114,2015],{"id":2014},[15,4116,4117],{},"Nested loops are the natural shape for anything grid-like: scanning a 2D vision frame, checking every pair of sensors against each other, or generating a table of test cases. (2D arrays, which pair naturally with nested loops, get their own full chapter — Ch.10.)",[69,4119,412],{"id":411},[19,4121,4122,4144],{},[22,4123,4124,426,4127,4130,4131,4133,4134,1051,4136,275,4138,1051,4141,3179],{},[25,4125,4126],{},"Reusing the same loop variable name for both loops.",[95,4128,4129],{},"for (int i ...)"," nested inside another ",[95,4132,4129],{}," won't compile — the inner declaration shadows\u002Fconflicts with the outer one in the same scope. Use distinct names (",[95,4135,4104],{},[95,4137,4108],{},[95,4139,4140],{},"i",[95,4142,4143],{},"j",[22,4145,4146,4149,4150,4152],{},[25,4147,4148],{},"Assuming the inner loop's variable persists across outer iterations."," It doesn't — a loop variable declared in the ",[95,4151,3899],{}," header is freshly initialized every time that loop starts, including every restart of an inner loop.",[69,4154,450],{"id":449},[19,4156,4157,4160,4163],{},[22,4158,4159],{},"A loop nested inside another runs completely, every single time the outer loop takes one step.",[22,4161,4162],{},"Nested loops are the standard shape for anything grid-shaped — rows and columns, pairs of items, tables of test cases.",[22,4164,4165,4166,1051,4168,868,4170,1051,4172,3179],{},"Use distinct loop variable names for nested loops (",[95,4167,4104],{},[95,4169,4108],{},[95,4171,4140],{},[95,4173,4140],{},[15,4175,493,4176,497,4178,4181],{},[95,4177,496],{},[95,4179,4180],{},"unit-2-selection-and-iteration\u002F2.11-nested-iteration.md"," (CSA 2.11)",[503,4183,505],{},{"title":48,"searchDepth":49,"depth":49,"links":4185},[4186,4187,4188,4189],{"id":4054,"depth":49,"text":4055},{"id":2014,"depth":49,"text":2015},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":4191,"status":519},"5.10 — Nested Iteration (CSA 2.11)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F10-nested-iteration",{"title":4046,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.10-nested-iteration","Y5NdCotalo1bwBpXQp-7Q-fhJ7sAg0dnLVbXr1RXF4w",{"id":4197,"title":4198,"body":4199,"description":48,"extension":51,"meta":4327,"navigation":55,"path":4329,"seo":4330,"stem":4331,"__hash__":4332},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.11-informal-runtime-analysis-of-loops.md","Informal Runtime Analysis of Loops",{"type":8,"value":4200,"toc":4320},[4201,4204,4208,4211,4220,4233,4237,4240,4260,4262,4265,4267,4294,4296,4310,4318],[11,4202,4198],{"id":4203},"informal-runtime-analysis-of-loops",[69,4205,4207],{"id":4206},"counting-iterations-without-running-the-code","Counting Iterations Without Running the Code",[15,4209,4210],{},"You can predict exactly how many times a loop runs just by reading its header:",[104,4212,4214],{"className":106,"code":4213,"language":108,"meta":48,"style":48},"for (int i = 3; i \u003C 7; i++) { ... } \u002F\u002F runs 6 - 3 + 1 = 4 times\n",[95,4215,4216],{"__ignoreMap":48},[112,4217,4218],{"class":114,"line":115},[112,4219,4213],{},[15,4221,4222,4223,4226,4227,4229,4230,4232],{},"The formula: ",[95,4224,4225],{},"largest value the loop variable reaches − smallest value + 1",". For a ",[95,4228,3945],{}," bound, the largest value is one less than the limit; for ",[95,4231,3951],{},", it's the limit itself.",[69,4234,4236],{"id":4235},"nested-loops-multiply","Nested Loops Multiply",[15,4238,4239],{},"A nested loop's total iteration count is outer iterations × inner iterations:",[104,4241,4243],{"className":106,"code":4242,"language":108,"meta":48,"style":48},"\u002F\u002F 5 outer passes × 10 inner passes = 50 total iterations\nfor (int row = 0; row \u003C 5; row++)\n    for (int col = 0; col \u003C 10; col++) { ... }\n",[95,4244,4245,4250,4255],{"__ignoreMap":48},[112,4246,4247],{"class":114,"line":115},[112,4248,4249],{},"\u002F\u002F 5 outer passes × 10 inner passes = 50 total iterations\n",[112,4251,4252],{"class":114,"line":49},[112,4253,4254],{},"for (int row = 0; row \u003C 5; row++)\n",[112,4256,4257],{"class":114,"line":126},[112,4258,4259],{},"    for (int col = 0; col \u003C 10; col++) { ... }\n",[69,4261,2015],{"id":2014},[15,4263,4264],{},"Being able to predict a loop's iteration count without running it is a real debugging tool — if a loop is running way more (or fewer) times than expected, tracing through this formula by hand usually finds the off-by-one or the wrong bound immediately, faster than adding print statements and re-running.",[69,4266,412],{"id":411},[19,4268,4269,4288],{},[22,4270,4271,426,4277,4280,4281,4283,4284,4287],{},[25,4272,4273,4274,4276],{},"Forgetting to subtract 1 for a ",[95,4275,3945],{}," bound.",[95,4278,4279],{},"i \u003C 7"," starting at ",[95,4282,1475],{}," reaches ",[95,4285,4286],{},"3, 4, 5, 6"," — four values, not seven minus three.",[22,4289,4290,4293],{},[25,4291,4292],{},"Multiplying the wrong two numbers for a nested loop."," It's outer-count × inner-count-per-outer-pass, not outer-count + inner-count.",[69,4295,450],{"id":449},[19,4297,4298,4304,4307],{},[22,4299,4300,4301,79],{},"A loop's iteration count is ",[95,4302,4303],{},"largest reachable value − smallest value + 1",[22,4305,4306],{},"Nested loops multiply: total iterations = outer count × inner count.",[22,4308,4309],{},"Counting iterations by hand is a fast way to catch an off-by-one bug before it turns into a mysterious runtime problem.",[15,4311,493,4312,497,4314,4317],{},[95,4313,496],{},[95,4315,4316],{},"unit-2-selection-and-iteration\u002F2.12-informal-runtime-analysis-of-loops.md"," (CSA 2.12)",[503,4319,505],{},{"title":48,"searchDepth":49,"depth":49,"links":4321},[4322,4323,4324,4325,4326],{"id":4206,"depth":49,"text":4207},{"id":4235,"depth":49,"text":4236},{"id":2014,"depth":49,"text":2015},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":4328,"status":519},"5.11 — Informal Runtime Analysis of Loops (CSA 2.12)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F11-informal-runtime-analysis-of-loops",{"title":4198,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.11-informal-runtime-analysis-of-loops","ZvOAySDpMaU12NdXsnZwxu1baHoQ0S0DUtTn2uRgVNY",{"id":4334,"title":4335,"body":4336,"description":48,"extension":51,"meta":4441,"navigation":55,"path":4443,"seo":4444,"stem":4445,"__hash__":4446},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.3-algorithms-with-selection-and-repetition.md","Algorithms with Selection and Repetition",{"type":8,"value":4337,"toc":4435},[4338,4341,4345,4348,4372,4375,4379,4385,4388,4396,4399,4401,4417,4419,4427],[11,4339,4335],{"id":4340},"algorithms-with-selection-and-repetition",[69,4342,4344],{"id":4343},"the-three-building-blocks","The Three Building Blocks",[15,4346,4347],{},"Every algorithm, no matter how complex, is built from just three ingredients:",[19,4349,4350,4356,4366],{},[22,4351,4352,4355],{},[25,4353,4354],{},"Sequence"," — steps run in order, one after another.",[22,4357,4358,4361,4362,1051,4364,3179],{},[25,4359,4360],{},"Selection"," — branch based on a true\u002Ffalse decision (",[95,4363,1766],{},[95,4365,3814],{},[22,4367,4368,4371],{},[25,4369,4370],{},"Repetition"," — repeat a block until some condition is met (loops).",[15,4373,4374],{},"That's genuinely it. Every autonomous routine, every teleop control loop, every piece of robot code you'll ever write is some combination of these three.",[69,4376,4378],{"id":4377},"planning-before-coding","Planning Before Coding",[15,4380,4381,4382,4384],{},"For anything beyond a couple of lines, it helps to plan the steps before writing real Java — in plain English, a diagram, or ",[25,4383,85],{}," (informal step-by-step notes that aren't real code, but capture the sequence\u002Fselection\u002Frepetition structure). This is the same idea from Lesson 1.2, applied to a bigger problem.",[15,4386,4387],{},"Pseudocode for a simple autonomous routine:",[104,4389,4394],{"className":4390,"code":4392,"language":4393},[4391],"language-text","Drive forward until the distance sensor reads \u003C 12 inches\nIf a game piece is detected, run the intake\nOtherwise, back up and try a different path\n","text",[95,4395,4392],{"__ignoreMap":48},[15,4397,4398],{},"Only after the steps are clear does it make sense to translate each line into real Java.",[69,4400,412],{"id":411},[19,4402,4403,4409],{},[22,4404,4405,4408],{},[25,4406,4407],{},"Skipping the planning step for a multi-branch routine."," Jumping straight to code for anything with several conditions or a loop is exactly how logic errors sneak in — a wrong branch order, a missed case.",[22,4410,4411,4416],{},[25,4412,4413,4414,79],{},"Assuming \"selection\" only means ",[95,4415,1766],{}," Any true\u002Ffalse branching decision counts, including the conditions inside loops.",[69,4418,450],{"id":449},[19,4420,4421,4424],{},[22,4422,4423],{},"Every algorithm is built from sequence, selection, and repetition — nothing else is needed.",[22,4425,4426],{},"Pseudocode (informal step-by-step notes) is a real planning tool, not busywork — use it before writing real code for anything with multiple branches or a loop.",[15,4428,493,4429,497,4431,4434],{},[95,4430,496],{},[95,4432,4433],{},"unit-2-selection-and-iteration\u002F2.01-algorithms-with-selection-and-repetition.md"," (CSA 2.1)",{"title":48,"searchDepth":49,"depth":49,"links":4436},[4437,4438,4439,4440],{"id":4343,"depth":49,"text":4344},{"id":4377,"depth":49,"text":4378},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":4442,"status":519},"5.3 — Algorithms with Selection and Repetition (CSA 2.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F3-algorithms-with-selection-and-repetition",{"title":4335,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.3-algorithms-with-selection-and-repetition","ZRKhIKmx9n0OiUhkcqPJEmxdXPZziYVg3zrXjFo_bzs",{"id":4448,"title":4449,"body":4450,"description":48,"extension":51,"meta":4666,"navigation":55,"path":4668,"seo":4669,"stem":4670,"__hash__":4671},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.4-boolean-expressions.md","Boolean Expressions",{"type":8,"value":4451,"toc":4659},[4452,4455,4459,4466,4501,4521,4525,4553,4557,4562,4582,4584,4614,4616,4649,4657],[11,4453,4449],{"id":4454},"boolean-expressions",[69,4456,4458],{"id":4457},"relational-operators","Relational Operators",[15,4460,4461,4462,207,4464,687],{},"Six operators compare values and always produce ",[95,4463,610],{},[95,4465,613],{},[104,4467,4469],{"className":106,"code":4468,"language":108,"meta":48,"style":48},"==   \u002F\u002F equals\n!=   \u002F\u002F does not equal\n\u003C    \u002F\u002F less than\n>    \u002F\u002F greater than\n\u003C=   \u002F\u002F less than or equal to\n>=   \u002F\u002F greater than or equal to\n",[95,4470,4471,4476,4481,4486,4491,4496],{"__ignoreMap":48},[112,4472,4473],{"class":114,"line":115},[112,4474,4475],{},"==   \u002F\u002F equals\n",[112,4477,4478],{"class":114,"line":49},[112,4479,4480],{},"!=   \u002F\u002F does not equal\n",[112,4482,4483],{"class":114,"line":126},[112,4484,4485],{},"\u003C    \u002F\u002F less than\n",[112,4487,4488],{"class":114,"line":132},[112,4489,4490],{},">    \u002F\u002F greater than\n",[112,4492,4493],{"class":114,"line":138},[112,4494,4495],{},"\u003C=   \u002F\u002F less than or equal to\n",[112,4497,4498],{"class":114,"line":144},[112,4499,4500],{},">=   \u002F\u002F greater than or equal to\n",[104,4502,4504],{"className":106,"code":4503,"language":108,"meta":48,"style":48},"double battery = 11.8;\nSystem.out.println(battery \u003C 12.0);  \u002F\u002F true — low battery\nSystem.out.println(battery >= 12.0); \u002F\u002F false\n",[95,4505,4506,4511,4516],{"__ignoreMap":48},[112,4507,4508],{"class":114,"line":115},[112,4509,4510],{},"double battery = 11.8;\n",[112,4512,4513],{"class":114,"line":49},[112,4514,4515],{},"System.out.println(battery \u003C 12.0);  \u002F\u002F true — low battery\n",[112,4517,4518],{"class":114,"line":126},[112,4519,4520],{},"System.out.println(battery >= 12.0); \u002F\u002F false\n",[69,4522,4524],{"id":4523},"equality-primitives-vs-objects","Equality: Primitives vs. Objects",[15,4526,4527,4529,4530,275,4532,275,4534,4536,4537,4539,4540,4543,4544,4546,4547,4549,4550,4552],{},[95,4528,1568],{}," on primitives (",[95,4531,552],{},[95,4533,580],{},[95,4535,606],{},") compares the actual values — exactly what you'd expect. ",[95,4538,1568],{}," on objects compares whether two variables refer to the ",[262,4541,4542],{},"same object in memory",", not whether their contents look the same. Two separately-built ",[95,4545,2010],{}," objects with identical settings are still two different objects — ",[95,4548,1568],{}," between them is ",[95,4551,613],{},". (Object equality gets its own full treatment in Ch.6, once Strings are introduced.)",[69,4554,4556],{"id":4555},"divisibility-with-the-remainder-operator","Divisibility with the Remainder Operator",[15,4558,4559,4561],{},[95,4560,1080],{}," (from Ch.2) is how you test whether a number divides evenly into another:",[104,4563,4565],{"className":106,"code":4564,"language":108,"meta":48,"style":48},"(number % 2 == 0)  \u002F\u002F true if number is even\n(number % 2 != 0)  \u002F\u002F true if number is odd\n(number % x == 0)  \u002F\u002F true if number is evenly divisible by x\n",[95,4566,4567,4572,4577],{"__ignoreMap":48},[112,4568,4569],{"class":114,"line":115},[112,4570,4571],{},"(number % 2 == 0)  \u002F\u002F true if number is even\n",[112,4573,4574],{"class":114,"line":49},[112,4575,4576],{},"(number % 2 != 0)  \u002F\u002F true if number is odd\n",[112,4578,4579],{"class":114,"line":126},[112,4580,4581],{},"(number % x == 0)  \u002F\u002F true if number is evenly divisible by x\n",[69,4583,412],{"id":411},[19,4585,4586,4595],{},[22,4587,4588,4594],{},[25,4589,4590,4591,4593],{},"Using ",[95,4592,1568],{}," on objects expecting a content comparison."," It checks \"same object,\" not \"same values\" — two different but identical-looking objects compare unequal.",[22,4596,4597,4603,4604,868,4607,4609,4610,4613],{},[25,4598,4599,4600,79],{},"Testing oddness with ",[95,4601,4602],{},"num % 2 == 1"," This looks right but fails for negative odd numbers (their remainder is ",[95,4605,4606],{},"-1",[95,4608,1093],{},"). Use ",[95,4611,4612],{},"num % 2 != 0"," instead — it works for both signs.",[69,4615,450],{"id":449},[19,4617,4618,4625,4633],{},[22,4619,4620,4621,4624],{},"Relational operators (",[95,4622,4623],{},"== != \u003C > \u003C= >=",") always produce a boolean result.",[22,4626,4627,4629,4630,4632],{},[95,4628,1568],{}," on primitives compares values; ",[95,4631,1568],{}," on objects compares identity (same object), not content.",[22,4634,4635,4637,4638,4641,4642,4644,4645,4648],{},[95,4636,1080],{}," tests divisibility — ",[95,4639,4640],{},"num % 2 == 0"," for even, ",[95,4643,4612],{}," for odd (not ",[95,4646,4647],{},"== 1",", which breaks on negatives).",[15,4650,493,4651,497,4653,4656],{},[95,4652,496],{},[95,4654,4655],{},"unit-2-selection-and-iteration\u002F2.02-boolean-expressions.md"," (CSA 2.2)",[503,4658,505],{},{"title":48,"searchDepth":49,"depth":49,"links":4660},[4661,4662,4663,4664,4665],{"id":4457,"depth":49,"text":4458},{"id":4523,"depth":49,"text":4524},{"id":4555,"depth":49,"text":4556},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":4667,"status":519},"5.4 — Boolean Expressions (CSA 2.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F4-boolean-expressions",{"title":4449,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.4-boolean-expressions","BZcSUCl6jPPLGlMy07HtfC78Ia6BBngefIwXNoTt-QM",{"id":4673,"title":4674,"body":4675,"description":48,"extension":51,"meta":5024,"navigation":55,"path":5026,"seo":5027,"stem":5028,"__hash__":5029},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.5-nested-if-statements.md","Nested if Statements",{"type":8,"value":4676,"toc":5017},[4677,4680,4684,4691,4751,4757,4761,4773,4816,4820,4833,4887,4889,4931,4977,4984,4986,5007,5015],[11,4678,4674],{"id":4679},"nested-if-statements",[69,4681,4683],{"id":4682},"multiway-selection-with-else-if","Multiway Selection with else if",[15,4685,4686,4687,4690],{},"Chain ",[95,4688,4689],{},"else if"," to pick between three or more paths — only the first true branch runs:",[104,4692,4694],{"className":106,"code":4693,"language":108,"meta":48,"style":48},"if (distance \u003C 1.0)\n{\n    state = IntakeState.CLOSE;\n}\nelse if (distance \u003C 3.0)\n{\n    state = IntakeState.MID;\n}\nelse\n{\n    state = IntakeState.FAR;\n}\n",[95,4695,4696,4701,4705,4710,4714,4719,4723,4728,4732,4736,4740,4746],{"__ignoreMap":48},[112,4697,4698],{"class":114,"line":115},[112,4699,4700],{},"if (distance \u003C 1.0)\n",[112,4702,4703],{"class":114,"line":49},[112,4704,123],{},[112,4706,4707],{"class":114,"line":126},[112,4708,4709],{},"    state = IntakeState.CLOSE;\n",[112,4711,4712],{"class":114,"line":132},[112,4713,153],{},[112,4715,4716],{"class":114,"line":138},[112,4717,4718],{},"else if (distance \u003C 3.0)\n",[112,4720,4721],{"class":114,"line":144},[112,4722,123],{},[112,4724,4725],{"class":114,"line":150},[112,4726,4727],{},"    state = IntakeState.MID;\n",[112,4729,4730],{"class":114,"line":1819},[112,4731,153],{},[112,4733,4734],{"class":114,"line":1825},[112,4735,3841],{},[112,4737,4738],{"class":114,"line":1831},[112,4739,123],{},[112,4741,4743],{"class":114,"line":4742},11,[112,4744,4745],{},"    state = IntakeState.FAR;\n",[112,4747,4749],{"class":114,"line":4748},12,[112,4750,153],{},[15,4752,4753,4754,4756],{},"A trailing plain ",[95,4755,3814],{}," (no condition) catches everything not already matched — it's optional, but leaving it off means \"do nothing\" is a real possible outcome.",[69,4758,4760],{"id":4759},"chained-vs-separate-ifs","Chained vs. Separate ifs",[15,4762,4763,4765,4766,4768,4769,4772],{},[95,4764,4689],{}," connects the branches together — only one of them ever runs. Writing separate, unconnected ",[95,4767,1766],{}," statements instead is a different (and often wrong) thing entirely, because ",[262,4770,4771],{},"all"," of them get checked independently:",[104,4774,4776],{"className":106,"code":4775,"language":108,"meta":48,"style":48},"\u002F\u002F Connected — only one branch runs\nif (score >= 90) { grade = \"A\"; }\nelse if (score >= 80) { grade = \"B\"; }\nelse { grade = \"C\"; }\n\n\u002F\u002F NOT connected — multiple could run, overwriting each other\nif (score >= 90) { grade = \"A\"; }\nif (score >= 80) { grade = \"B\"; } \u002F\u002F a 95 would hit this too, overwriting \"A\" with \"B\"!\n",[95,4777,4778,4783,4788,4793,4798,4802,4807,4811],{"__ignoreMap":48},[112,4779,4780],{"class":114,"line":115},[112,4781,4782],{},"\u002F\u002F Connected — only one branch runs\n",[112,4784,4785],{"class":114,"line":49},[112,4786,4787],{},"if (score >= 90) { grade = \"A\"; }\n",[112,4789,4790],{"class":114,"line":126},[112,4791,4792],{},"else if (score >= 80) { grade = \"B\"; }\n",[112,4794,4795],{"class":114,"line":132},[112,4796,4797],{},"else { grade = \"C\"; }\n",[112,4799,4800],{"class":114,"line":138},[112,4801,820],{"emptyLinePlaceholder":55},[112,4803,4804],{"class":114,"line":144},[112,4805,4806],{},"\u002F\u002F NOT connected — multiple could run, overwriting each other\n",[112,4808,4809],{"class":114,"line":150},[112,4810,4787],{},[112,4812,4813],{"class":114,"line":1819},[112,4814,4815],{},"if (score >= 80) { grade = \"B\"; } \u002F\u002F a 95 would hit this too, overwriting \"A\" with \"B\"!\n",[69,4817,4819],{"id":4818},"the-dangling-else","The Dangling Else",[15,4821,4822,4823,4825,4826,4829,4830,4832],{},"When ifs are nested without braces, an ",[95,4824,3814],{}," always attaches to the ",[262,4827,4828],{},"closest"," unmatched ",[95,4831,1766],{}," — regardless of indentation. If that's not what you meant, braces fix it:",[104,4834,4836],{"className":106,"code":4835,"language":108,"meta":48,"style":48},"if (sunny)\n{\n    if (hot)\n    {\n        goToBeach();\n    }\n}\nelse \u002F\u002F now belongs to the OUTER if, thanks to the braces\n{\n    bringUmbrella();\n}\n",[95,4837,4838,4843,4847,4852,4856,4861,4865,4869,4874,4878,4883],{"__ignoreMap":48},[112,4839,4840],{"class":114,"line":115},[112,4841,4842],{},"if (sunny)\n",[112,4844,4845],{"class":114,"line":49},[112,4846,123],{},[112,4848,4849],{"class":114,"line":126},[112,4850,4851],{},"    if (hot)\n",[112,4853,4854],{"class":114,"line":132},[112,4855,135],{},[112,4857,4858],{"class":114,"line":138},[112,4859,4860],{},"        goToBeach();\n",[112,4862,4863],{"class":114,"line":144},[112,4864,147],{},[112,4866,4867],{"class":114,"line":150},[112,4868,153],{},[112,4870,4871],{"class":114,"line":1819},[112,4872,4873],{},"else \u002F\u002F now belongs to the OUTER if, thanks to the braces\n",[112,4875,4876],{"class":114,"line":1825},[112,4877,123],{},[112,4879,4880],{"class":114,"line":1831},[112,4881,4882],{},"    bringUmbrella();\n",[112,4884,4885],{"class":114,"line":4742},[112,4886,153],{},[69,4888,412],{"id":411},[19,4890,4891,4902,4918],{},[22,4892,4893,4901],{},[25,4894,4895,4896,4898,4899,79],{},"Using separate ",[95,4897,1766],{},"s instead of ",[95,4900,4689],{}," Separate ifs are each checked independently — a later one can silently overwrite what an earlier one just set.",[22,4903,4904,4907,4908,4911,4912,4914,4915,4917],{},[25,4905,4906],{},"Relying on indentation instead of braces."," Java ignores indentation entirely; only ",[95,4909,4910],{},"{ }"," actually determines which ",[95,4913,1766],{}," an ",[95,4916,3814],{}," belongs to.",[22,4919,4920,4926,4927,4930],{},[25,4921,4922,4923,4925],{},"Skipping the trailing ",[95,4924,3814],{}," when a local variable is only assigned inside branches."," Java requires a local variable to be ",[262,4928,4929],{},"definitely assigned"," before it's read — if no branch is guaranteed to run, the compiler won't let you read it afterward:",[104,4932,4934],{"className":106,"code":4933,"language":108,"meta":48,"style":48},"String tier; \u002F\u002F local variable, no initial value\n\nif (score >= 8)\n{\n    tier = \"ELITE\";\n}\n\u002F\u002F no else — if score \u003C 8, tier is never assigned\n\nSystem.out.println(tier); \u002F\u002F won't compile: tier might not be assigned\n",[95,4935,4936,4941,4945,4950,4954,4959,4963,4968,4972],{"__ignoreMap":48},[112,4937,4938],{"class":114,"line":115},[112,4939,4940],{},"String tier; \u002F\u002F local variable, no initial value\n",[112,4942,4943],{"class":114,"line":49},[112,4944,820],{"emptyLinePlaceholder":55},[112,4946,4947],{"class":114,"line":126},[112,4948,4949],{},"if (score >= 8)\n",[112,4951,4952],{"class":114,"line":132},[112,4953,123],{},[112,4955,4956],{"class":114,"line":138},[112,4957,4958],{},"    tier = \"ELITE\";\n",[112,4960,4961],{"class":114,"line":144},[112,4962,153],{},[112,4964,4965],{"class":114,"line":150},[112,4966,4967],{},"\u002F\u002F no else — if score \u003C 8, tier is never assigned\n",[112,4969,4970],{"class":114,"line":1819},[112,4971,820],{"emptyLinePlaceholder":55},[112,4973,4974],{"class":114,"line":1825},[112,4975,4976],{},"System.out.println(tier); \u002F\u002F won't compile: tier might not be assigned\n",[15,4978,4979,4980,4983],{},"This only applies to local variables — an instance variable like ",[95,4981,4982],{},"state"," above already has a default value, so it doesn't need every branch to cover it.",[69,4985,450],{"id":449},[19,4987,4988,4993,4999],{},[22,4989,4990,4992],{},[95,4991,4689],{}," chains pick exactly one branch — the first condition that's true, and nothing after it.",[22,4994,4995,4996,4998],{},"Unconnected, separate ",[95,4997,1766],{}," statements are checked independently and can overwrite each other's results.",[22,5000,1541,5001,5003,5004,5006],{},[95,5002,3814],{}," always attaches to the nearest unmatched ",[95,5005,1766],{}," — braces are the only reliable way to control this.",[15,5008,493,5009,497,5011,5014],{},[95,5010,496],{},[95,5012,5013],{},"unit-2-selection-and-iteration\u002F2.04-nested-if-statements.md"," (CSA 2.4)",[503,5016,505],{},{"title":48,"searchDepth":49,"depth":49,"links":5018},[5019,5020,5021,5022,5023],{"id":4682,"depth":49,"text":4683},{"id":4759,"depth":49,"text":4760},{"id":4818,"depth":49,"text":4819},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":5025,"status":519},"5.5 — Nested if Statements (CSA 2.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5-nested-if-statements",{"title":4674,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.5-nested-if-statements","7STtpxPvNqxDs5AlTLv9IoTQolmQirhiIsFZS2XDnco",{"id":5031,"title":5032,"body":5033,"description":48,"extension":51,"meta":5281,"navigation":55,"path":5283,"seo":5284,"stem":5285,"__hash__":5286},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.6-compound-boolean-expressions.md","Compound Boolean Expressions",{"type":8,"value":5034,"toc":5274},[5035,5038,5042,5057,5080,5091,5095,5098,5125,5128,5151,5172,5176,5187,5202,5204,5235,5237,5264,5272],[11,5036,5032],{"id":5037},"compound-boolean-expressions",[69,5039,5041],{"id":5040},"and-or-not","And, Or, Not",[15,5043,5044,5045,5048,5049,5052,5053,5056],{},"Combine conditions with ",[95,5046,5047],{},"&&"," (and), ",[95,5050,5051],{},"||"," (or), and ",[95,5054,5055],{},"!"," (not):",[104,5058,5060],{"className":106,"code":5059,"language":108,"meta":48,"style":48},"if (armReady && intakeReady)\n{\n    scoreCommand.schedule();\n}\n",[95,5061,5062,5067,5071,5076],{"__ignoreMap":48},[112,5063,5064],{"class":114,"line":115},[112,5065,5066],{},"if (armReady && intakeReady)\n",[112,5068,5069],{"class":114,"line":49},[112,5070,123],{},[112,5072,5073],{"class":114,"line":126},[112,5074,5075],{},"    scoreCommand.schedule();\n",[112,5077,5078],{"class":114,"line":132},[112,5079,153],{},[15,5081,5082,5084,5085,5087,5088,5090],{},[95,5083,5047],{}," needs both sides true; ",[95,5086,5051],{}," needs just one (or both). ",[95,5089,5055],{}," flips a boolean's value.",[69,5092,5094],{"id":5093},"short-circuit-evaluation","Short-Circuit Evaluation",[15,5096,5097],{},"Java stops checking as soon as the answer is already known — it never evaluates more than it needs to:",[19,5099,5100,5114],{},[22,5101,5102,5103,5106,5107,5109,5110,5113],{},"In ",[95,5104,5105],{},"a && b",": if ",[95,5108,239],{}," is false, ",[95,5111,5112],{},"b"," is never even checked — the whole thing is already false.",[22,5115,5102,5116,5106,5119,5121,5122,5124],{},[95,5117,5118],{},"a || b",[95,5120,239],{}," is true, ",[95,5123,5112],{}," is never checked — the whole thing is already true.",[15,5126,5127],{},"This isn't just an optimization — it's a real safety pattern:",[104,5129,5131],{"className":106,"code":5130,"language":108,"meta":48,"style":48},"if (sensor != null && sensor.isFaulty())\n{\n    report(sensor);\n}\n",[95,5132,5133,5138,5142,5147],{"__ignoreMap":48},[112,5134,5135],{"class":114,"line":115},[112,5136,5137],{},"if (sensor != null && sensor.isFaulty())\n",[112,5139,5140],{"class":114,"line":49},[112,5141,123],{},[112,5143,5144],{"class":114,"line":126},[112,5145,5146],{},"    report(sensor);\n",[112,5148,5149],{"class":114,"line":132},[112,5150,153],{},[15,5152,5153,5154,1090,5157,5159,5160,5162,5163,5166,5167,5169,5170,79],{},"If ",[95,5155,5156],{},"sensor",[95,5158,3384],{},", the left side is false, so ",[95,5161,5047],{}," never evaluates ",[95,5164,5165],{},"sensor.isFaulty()"," — which would otherwise throw a ",[95,5168,3414],{},". The order here matters: the null check has to come ",[262,5171,2973],{},[69,5173,5175],{"id":5174},"operator-precedence","Operator Precedence",[15,5177,5178,5180,5181,5183,5184,5186],{},[95,5179,5055],{}," binds tightest, then ",[95,5182,5047],{},", then ",[95,5185,5051],{}," — parentheses override all of it and make intent explicit:",[104,5188,5190],{"className":106,"code":5189,"language":108,"meta":48,"style":48},"if (!ready || !armed) { ... }        \u002F\u002F ! applies to each individually\nif (!(ready && armed)) { ... }       \u002F\u002F different! ! applies to the whole expression\n",[95,5191,5192,5197],{"__ignoreMap":48},[112,5193,5194],{"class":114,"line":115},[112,5195,5196],{},"if (!ready || !armed) { ... }        \u002F\u002F ! applies to each individually\n",[112,5198,5199],{"class":114,"line":49},[112,5200,5201],{},"if (!(ready && armed)) { ... }       \u002F\u002F different! ! applies to the whole expression\n",[69,5203,412],{"id":411},[19,5205,5206,5223],{},[22,5207,5208,426,5211,5214,5215,5217,5218,1090,5220,5222],{},[25,5209,5210],{},"Putting the null check on the wrong side.",[95,5212,5213],{},"sensor.isFaulty() && sensor != null"," checks the faulty status ",[262,5216,2973],{}," — if ",[95,5219,5156],{},[95,5221,3384],{},", it crashes before the null check ever runs. The null check must come first for short-circuiting to protect you.",[22,5224,5225,5234],{},[25,5226,1367,5227,5230,5231,79],{},[95,5228,5229],{},"!(a && b)"," is the same as ",[95,5232,5233],{},"!a && !b"," It's not — that's a real logic error (the correct equivalent, De Morgan's Law, comes in the next lesson).",[69,5236,450],{"id":449},[19,5238,5239,5250,5253],{},[22,5240,5241,5243,5244,5246,5247,5249],{},[95,5242,5047],{}," requires both sides true; ",[95,5245,5051],{}," requires at least one; ",[95,5248,5055],{}," flips a boolean.",[22,5251,5252],{},"Short-circuit evaluation skips the right side once the left side already determines the result — order a null-check first specifically to exploit this.",[22,5254,5255,5257,5258,5260,5261,5263],{},[95,5256,5055],{}," has higher precedence than ",[95,5259,5047],{},", which has higher precedence than ",[95,5262,5051],{},"; use parentheses when the default grouping isn't what you mean.",[15,5265,493,5266,497,5268,5271],{},[95,5267,496],{},[95,5269,5270],{},"unit-2-selection-and-iteration\u002F2.05-compound-boolean-expressions.md"," (CSA 2.5)",[503,5273,505],{},{"title":48,"searchDepth":49,"depth":49,"links":5275},[5276,5277,5278,5279,5280],{"id":5040,"depth":49,"text":5041},{"id":5093,"depth":49,"text":5094},{"id":5174,"depth":49,"text":5175},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":5282,"status":519},"5.6 — Compound Boolean Expressions (CSA 2.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F6-compound-boolean-expressions",{"title":5032,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.6-compound-boolean-expressions","dxadTj2blMWcbXylXwa7gucFiNlNngKYcG8dakOGHvE",{"id":5288,"title":5289,"body":5290,"description":48,"extension":51,"meta":5543,"navigation":55,"path":5545,"seo":5546,"stem":5547,"__hash__":5548},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.7-comparing-boolean-expressions-de-morgans-laws.md","Comparing Boolean Expressions (De Morgan's Laws)",{"type":8,"value":5291,"toc":5535},[5292,5295,5299,5302,5317,5333,5337,5340,5360,5374,5378,5387,5406,5410,5434,5443,5445,5479,5481,5525,5533],[11,5293,5289],{"id":5294},"comparing-boolean-expressions-de-morgans-laws",[69,5296,5298],{"id":5297},"de-morgans-laws","De Morgan's Laws",[15,5300,5301],{},"Negating a compound condition flips both the operator and each individual comparison:",[104,5303,5305],{"className":106,"code":5304,"language":108,"meta":48,"style":48},"!(a && b)  is equivalent to  !a || !b\n!(a || b)  is equivalent to  !a && !b\n",[95,5306,5307,5312],{"__ignoreMap":48},[112,5308,5309],{"class":114,"line":115},[112,5310,5311],{},"!(a && b)  is equivalent to  !a || !b\n",[112,5313,5314],{"class":114,"line":49},[112,5315,5316],{},"!(a || b)  is equivalent to  !a && !b\n",[15,5318,5319,5320,5322,5323,3883,5325,5327,5328,3883,5330,5332],{},"A simple way to remember it: push the ",[95,5321,5055],{}," inward, and flip ",[95,5324,5047],{},[95,5326,5051],{}," (or ",[95,5329,5051],{},[95,5331,5047],{},") as it moves in.",[69,5334,5336],{"id":5335},"flipping-relational-operators-under-negation","Flipping Relational Operators Under Negation",[15,5338,5339],{},"The same idea applies to relational operators — negating a comparison flips its sign:",[104,5341,5343],{"className":106,"code":5342,"language":108,"meta":48,"style":48},"!(c == d)  is  c != d\n!(c \u003C d)   is  c >= d\n!(c > d)   is  c \u003C= d\n",[95,5344,5345,5350,5355],{"__ignoreMap":48},[112,5346,5347],{"class":114,"line":115},[112,5348,5349],{},"!(c == d)  is  c != d\n",[112,5351,5352],{"class":114,"line":49},[112,5353,5354],{},"!(c \u003C d)   is  c >= d\n",[112,5356,5357],{"class":114,"line":126},[112,5358,5359],{},"!(c > d)   is  c \u003C= d\n",[15,5361,5362,5363,5366,5367,5370,5371,79],{},"Putting both rules together: ",[95,5364,5365],{},"!(x \u003C 3 && y > 2)"," becomes ",[95,5368,5369],{},"!(x \u003C 3) || !(y > 2)",", which simplifies further to ",[95,5372,5373],{},"(x >= 3 || y \u003C= 2)",[69,5375,5377],{"id":5376},"why-bother-simplifying","Why Bother Simplifying",[15,5379,5380,486,5383,5386],{},[95,5381,5382],{},"!(ready && armed)",[95,5384,5385],{},"!ready || !armed"," always evaluate to the same result — but the second one reads more directly as \"either one isn't ready\" instead of \"it's not true that both are ready.\" Simplifying a negated condition often makes the code's actual intent clearer.",[104,5388,5390],{"className":106,"code":5389,"language":108,"meta":48,"style":48},"if (!ready || !armed) {\n    abort();\n}\n",[95,5391,5392,5397,5402],{"__ignoreMap":48},[112,5393,5394],{"class":114,"line":115},[112,5395,5396],{},"if (!ready || !armed) {\n",[112,5398,5399],{"class":114,"line":49},[112,5400,5401],{},"    abort();\n",[112,5403,5404],{"class":114,"line":126},[112,5405,153],{},[69,5407,5409],{"id":5408},"a-preview-comparing-objects","A Preview: Comparing Objects",[15,5411,5412,5414,5415,5418,5419,5421,5422,5425,5426,1051,5428,5431,5432,79],{},[95,5413,1568],{}," on objects (a preview from Lesson 5.4) compares whether two variables point at the ",[262,5416,5417],{},"same"," object, not whether their contents match. This matters for ",[95,5420,315],{},"s specifically, which get their own full treatment in Ch.6 — for now, the short version: use ",[95,5423,5424],{},".equals()"," to compare what two objects actually contain, and reserve ",[95,5427,1568],{},[95,5429,5430],{},"!="," for checking against ",[95,5433,3384],{},[104,5435,5437],{"className":106,"code":5436,"language":108,"meta":48,"style":48},"if (sensor != null && sensor.isFaulty()) { ... } \u002F\u002F == used correctly, against null\n",[95,5438,5439],{"__ignoreMap":48},[112,5440,5441],{"class":114,"line":115},[112,5442,5436],{},[69,5444,412],{"id":411},[19,5446,5447,5468],{},[22,5448,5449,426,5454,1090,5457,868,5460,5463,5464,5467],{},[25,5450,5451,5452,79],{},"Forgetting to flip the operator, not just add a ",[95,5453,5055],{},[95,5455,5456],{},"!(x \u003C 3)",[95,5458,5459],{},"x >= 3",[95,5461,5462],{},"x !\u003C 3"," (which isn't valid Java) and not ",[95,5465,5466],{},"x > 3"," (which misses the equal case).",[22,5469,5470,5473,5474,1051,5476,5478],{},[25,5471,5472],{},"Applying De Morgan's Law only to one side."," Both the operator (",[95,5475,5047],{},[95,5477,5051],{},") and both individual comparisons flip — doing only one produces a wrong, non-equivalent expression.",[69,5480,450],{"id":449},[19,5482,5483,5497,5514,5517],{},[22,5484,5485,5487,5488,5491,5492,5487,5495,79],{},[95,5486,5229],{}," is equivalent to ",[95,5489,5490],{},"!a || !b","; ",[95,5493,5494],{},"!(a || b)",[95,5496,5233],{},[22,5498,5499,5500,5366,5502,275,5505,5366,5508,275,5510,5366,5512,79],{},"Negating a relational operator flips its sign: ",[95,5501,3945],{},[95,5503,5504],{},">=",[95,5506,5507],{},">",[95,5509,3951],{},[95,5511,1568],{},[95,5513,5430],{},[22,5515,5516],{},"Simplifying a negated condition often makes its intent easier to read, even though it's logically equivalent either way.",[22,5518,5519,5521,5522,5524],{},[95,5520,1568],{}," on objects checks identity, not content — ",[95,5523,5424],{}," (covered fully in Ch.6) is for comparing what's actually inside.",[15,5526,493,5527,497,5529,5532],{},[95,5528,496],{},[95,5530,5531],{},"unit-2-selection-and-iteration\u002F2.06-comparing-boolean-expressions-de-morgan-s-laws.md"," (CSA 2.6)",[503,5534,505],{},{"title":48,"searchDepth":49,"depth":49,"links":5536},[5537,5538,5539,5540,5541,5542],{"id":5297,"depth":49,"text":5298},{"id":5335,"depth":49,"text":5336},{"id":5376,"depth":49,"text":5377},{"id":5408,"depth":49,"text":5409},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":5544,"status":519},"5.7 — Comparing Boolean Expressions (De Morgan's Laws) (CSA 2.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F7-comparing-boolean-expressions-de-morgans-laws",{"title":5289,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.7-comparing-boolean-expressions-de-morgans-laws","fBNcnhY7d7t2NbhxpMZQxwI2P25wAFnOQMVdZdbcESk",{"id":5550,"title":5551,"body":5552,"description":48,"extension":51,"meta":5752,"navigation":55,"path":5754,"seo":5755,"stem":5756,"__hash__":5757},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.8-while-loops.md","While Loops",{"type":8,"value":5553,"toc":5744},[5554,5557,5561,5570,5599,5608,5612,5615,5643,5646,5655,5667,5690,5692,5709,5711,5734,5742],[11,5555,5551],{"id":5556},"while-loops",[69,5558,5560],{"id":5559},"the-three-steps-of-a-loop","The Three Steps of a Loop",[15,5562,355,5563,5566,5567,5569],{},[95,5564,5565],{},"while"," loop repeats its body as long as a condition holds, checked ",[262,5568,1504],{}," every pass, including the first:",[104,5571,5573],{"className":106,"code":5572,"language":108,"meta":48,"style":48},"int attempts = 0;             \u002F\u002F 1. initialize\nwhile (attempts \u003C 3 && !connected) { \u002F\u002F 2. test\n    connected = tryConnect();\n    attempts++;                \u002F\u002F 3. update\n}\n",[95,5574,5575,5580,5585,5590,5595],{"__ignoreMap":48},[112,5576,5577],{"class":114,"line":115},[112,5578,5579],{},"int attempts = 0;             \u002F\u002F 1. initialize\n",[112,5581,5582],{"class":114,"line":49},[112,5583,5584],{},"while (attempts \u003C 3 && !connected) { \u002F\u002F 2. test\n",[112,5586,5587],{"class":114,"line":126},[112,5588,5589],{},"    connected = tryConnect();\n",[112,5591,5592],{"class":114,"line":132},[112,5593,5594],{},"    attempts++;                \u002F\u002F 3. update\n",[112,5596,5597],{"class":114,"line":138},[112,5598,153],{},[15,5600,5601,5602,5604,5605,5607],{},"Every loop needs these same three steps — initialize the loop variable, test it, update it inside the loop. A ",[95,5603,3899],{}," loop (Lesson 5.1-5.2) just packs all three into one header line; a ",[95,5606,5565],{}," loop spreads them out, which is more natural when the \"update\" isn't a simple counter.",[69,5609,5611],{"id":5610},"infinite-loops","Infinite Loops",[15,5613,5614],{},"Forget step 3 and the condition never changes — the loop runs forever:",[104,5616,5618],{"className":106,"code":5617,"language":108,"meta":48,"style":48},"int i = 0;\nwhile (i \u003C 10)\n{\n    System.out.println(i); \u002F\u002F i never changes — this never stops\n}\n",[95,5619,5620,5625,5630,5634,5639],{"__ignoreMap":48},[112,5621,5622],{"class":114,"line":115},[112,5623,5624],{},"int i = 0;\n",[112,5626,5627],{"class":114,"line":49},[112,5628,5629],{},"while (i \u003C 10)\n",[112,5631,5632],{"class":114,"line":126},[112,5633,123],{},[112,5635,5636],{"class":114,"line":132},[112,5637,5638],{},"    System.out.println(i); \u002F\u002F i never changes — this never stops\n",[112,5640,5641],{"class":114,"line":138},[112,5642,153],{},[15,5644,5645],{},"An infinite loop on a robot doesn't just print forever — it can freeze the whole robot's control loop, since nothing after it ever gets a chance to run.",[69,5647,5649,5650,5652,5653],{"id":5648},"when-to-reach-for-while-instead-of-for","When to Reach for ",[95,5651,5565],{}," Instead of ",[95,5654,3899],{},[15,5656,5657,5659,5660,5662,5663,5666],{},[95,5658,3899],{}," fits naturally when you already know the number of iterations. ",[95,5661,5565],{}," fits better when you're waiting for a ",[262,5664,5665],{},"condition",", not counting to a number — like waiting for a sensor to settle, or retrying a connection a limited number of times:",[104,5668,5670],{"className":106,"code":5669,"language":108,"meta":48,"style":48},"while (!gyro.isConnected() && attempts \u003C 5)\n{\n    attempts++;\n}\n",[95,5671,5672,5677,5681,5686],{"__ignoreMap":48},[112,5673,5674],{"class":114,"line":115},[112,5675,5676],{},"while (!gyro.isConnected() && attempts \u003C 5)\n",[112,5678,5679],{"class":114,"line":49},[112,5680,123],{},[112,5682,5683],{"class":114,"line":126},[112,5684,5685],{},"    attempts++;\n",[112,5687,5688],{"class":114,"line":132},[112,5689,153],{},[69,5691,412],{"id":411},[19,5693,5694,5703],{},[22,5695,5696,5699,5700,5702],{},[25,5697,5698],{},"Forgetting to update the loop variable."," The single most common cause of an infinite loop — every ",[95,5701,5565],{}," loop needs something inside it that eventually makes the condition false.",[22,5704,5705,5708],{},[25,5706,5707],{},"A condition that's false from the very first check."," If the condition never holds, the loop body never runs at all — not even once. Double-check the loop variable's starting value against the condition.",[69,5710,450],{"id":449},[19,5712,5713,5721,5726,5729],{},[22,5714,5715,5716,5718,5719,3704],{},"Every loop needs three steps: initialize, test, update — ",[95,5717,5565],{}," just doesn't bundle them into one line like ",[95,5720,3899],{},[22,5722,355,5723,5725],{},[95,5724,5565],{}," loop's condition is checked before every pass, including the first — if it starts false, the body never runs.",[22,5727,5728],{},"Forgetting to update the loop variable is the classic cause of an infinite loop, which can freeze a robot's control code.",[22,5730,5731,5733],{},[95,5732,5565],{}," fits naturally when you're waiting for a condition rather than counting a known number of iterations.",[15,5735,493,5736,497,5738,5741],{},[95,5737,496],{},[95,5739,5740],{},"unit-2-selection-and-iteration\u002F2.07-while-loops.md"," (CSA 2.7)",[503,5743,505],{},{"title":48,"searchDepth":49,"depth":49,"links":5745},[5746,5747,5748,5750,5751],{"id":5559,"depth":49,"text":5560},{"id":5610,"depth":49,"text":5611},{"id":5648,"depth":49,"text":5749},"When to Reach for while Instead of for",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":5753,"status":519},"5.8 — While Loops (CSA 2.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F8-while-loops",{"title":5551,"description":48},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.8-while-loops","UcVs8NhTt6CXVb3P7janbTM8gt06S_9b4WjVeZFsxFM",{"id":5759,"title":5760,"body":5761,"description":5768,"extension":51,"meta":6026,"navigation":55,"path":6028,"seo":6029,"stem":6030,"__hash__":6031},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.9-implementing-selection-and-iteration-algorithms.md","Implementing Selection and Iteration Algorithms",{"type":8,"value":5762,"toc":6018},[5763,5766,5769,5784,5788,5791,5824,5828,5834,5874,5878,5881,5922,5926,5935,5958,5960,5985,5987,6008,6016],[11,5764,5760],{"id":5765},"implementing-selection-and-iteration-algorithms",[15,5767,5768],{},"A handful of loop-and-selection patterns come up constantly. Once you recognize them, you'll see the same shape everywhere.",[15,5770,5771],{},[262,5772,5773,5774,275,5777,5780,5781,5783],{},"The examples below loop over an existing collection (",[95,5775,5776],{},"visionLatencies",[95,5778,5779],{},"sensors",") with an enhanced ",[95,5782,3899],{}," — building your own comes in Ch.9. For now, focus on the accumulator\u002Fselection shape itself; it applies the same way once you get there.",[69,5785,5787],{"id":5786},"the-accumulator-pattern","The Accumulator Pattern",[15,5789,5790],{},"Build up a running total across a loop: initialize before the loop, update inside it, use the result after.",[104,5792,5794],{"className":106,"code":5793,"language":108,"meta":48,"style":48},"double sum = 0;\nfor (double sample : visionLatencies)\n{\n    sum += sample; \u002F\u002F accumulate\n}\ndouble average = sum \u002F visionLatencies.size();\n",[95,5795,5796,5801,5806,5810,5815,5819],{"__ignoreMap":48},[112,5797,5798],{"class":114,"line":115},[112,5799,5800],{},"double sum = 0;\n",[112,5802,5803],{"class":114,"line":49},[112,5804,5805],{},"for (double sample : visionLatencies)\n",[112,5807,5808],{"class":114,"line":126},[112,5809,123],{},[112,5811,5812],{"class":114,"line":132},[112,5813,5814],{},"    sum += sample; \u002F\u002F accumulate\n",[112,5816,5817],{"class":114,"line":138},[112,5818,153],{},[112,5820,5821],{"class":114,"line":144},[112,5822,5823],{},"double average = sum \u002F visionLatencies.size();\n",[69,5825,5827],{"id":5826},"minmax-with-an-if-inside-a-loop","Min\u002FMax with an if Inside a Loop",[15,5829,5830,5831,5833],{},"Track the smallest or largest value seen so far by pairing an accumulator with an ",[95,5832,1766],{}," inside the loop:",[104,5835,5837],{"className":106,"code":5836,"language":108,"meta":48,"style":48},"double max = Double.MIN_VALUE;\nfor (double sample : visionLatencies)\n{\n    if (sample > max)\n    {\n        max = sample; \u002F\u002F running max\n    }\n}\n",[95,5838,5839,5844,5848,5852,5857,5861,5866,5870],{"__ignoreMap":48},[112,5840,5841],{"class":114,"line":115},[112,5842,5843],{},"double max = Double.MIN_VALUE;\n",[112,5845,5846],{"class":114,"line":49},[112,5847,5805],{},[112,5849,5850],{"class":114,"line":126},[112,5851,123],{},[112,5853,5854],{"class":114,"line":132},[112,5855,5856],{},"    if (sample > max)\n",[112,5858,5859],{"class":114,"line":138},[112,5860,135],{},[112,5862,5863],{"class":114,"line":144},[112,5864,5865],{},"        max = sample; \u002F\u002F running max\n",[112,5867,5868],{"class":114,"line":150},[112,5869,147],{},[112,5871,5872],{"class":114,"line":1819},[112,5873,153],{},[69,5875,5877],{"id":5876},"frequency-counting","Frequency Counting",[15,5879,5880],{},"Count how many values in a sequence meet some criterion, using a counter incremented inside a conditional:",[104,5882,5884],{"className":106,"code":5883,"language":108,"meta":48,"style":48},"int faultyCount = 0;\nfor (Sensor sensor : sensors)\n{\n    if (sensor.isFaulty())\n    {\n        faultyCount++;\n    }\n}\n",[95,5885,5886,5891,5896,5900,5905,5909,5914,5918],{"__ignoreMap":48},[112,5887,5888],{"class":114,"line":115},[112,5889,5890],{},"int faultyCount = 0;\n",[112,5892,5893],{"class":114,"line":49},[112,5894,5895],{},"for (Sensor sensor : sensors)\n",[112,5897,5898],{"class":114,"line":126},[112,5899,123],{},[112,5901,5902],{"class":114,"line":132},[112,5903,5904],{},"    if (sensor.isFaulty())\n",[112,5906,5907],{"class":114,"line":138},[112,5908,135],{},[112,5910,5911],{"class":114,"line":144},[112,5912,5913],{},"        faultyCount++;\n",[112,5915,5916],{"class":114,"line":150},[112,5917,147],{},[112,5919,5920],{"class":114,"line":1819},[112,5921,153],{},[69,5923,5925],{"id":5924},"simulating-probability-with-mathrandom","Simulating Probability with Math.random()",[15,5927,5928,5931,5932,5934],{},[95,5929,5930],{},"Math.random() \u003C p"," is true with probability ",[95,5933,15],{}," — a real way to simulate an event that happens some percentage of the time (useful for testing code against randomized simulated sensor noise, for instance):",[104,5936,5938],{"className":106,"code":5937,"language":108,"meta":48,"style":48},"if (Math.random() \u003C 0.1) \u002F\u002F roughly 10% of the time\n{\n    simulateSensorGlitch();\n}\n",[95,5939,5940,5945,5949,5954],{"__ignoreMap":48},[112,5941,5942],{"class":114,"line":115},[112,5943,5944],{},"if (Math.random() \u003C 0.1) \u002F\u002F roughly 10% of the time\n",[112,5946,5947],{"class":114,"line":49},[112,5948,123],{},[112,5950,5951],{"class":114,"line":126},[112,5952,5953],{},"    simulateSensorGlitch();\n",[112,5955,5956],{"class":114,"line":132},[112,5957,153],{},[69,5959,412],{"id":411},[19,5961,5962,5975],{},[22,5963,5964,5967,5968,5970,5971,5974],{},[25,5965,5966],{},"Initializing an accumulator with the wrong starting value."," A sum starts at ",[95,5969,1140],{},"; a max should start at the smallest possible value (",[95,5972,5973],{},"Double.MIN_VALUE"," or similar) so the very first real value always replaces it.",[22,5976,5977,5980,5981,5984],{},[25,5978,5979],{},"Putting the accumulator update outside the loop."," It has to be ",[262,5982,5983],{},"inside"," the loop body to actually accumulate across every iteration.",[69,5986,450],{"id":449},[19,5988,5989,5992,5998,6001],{},[22,5990,5991],{},"The accumulator pattern: initialize before the loop, update inside it, use the result after.",[22,5993,5994,5995,5997],{},"Min\u002Fmax tracking pairs an accumulator with an ",[95,5996,1766],{}," inside the loop, comparing each new value against the best one seen so far.",[22,5999,6000],{},"Frequency counting increments a counter inside a conditional, once per matching iteration.",[22,6002,6003,6005,6006,79],{},[95,6004,5930],{}," simulates an event with probability ",[95,6007,15],{},[15,6009,493,6010,497,6012,6015],{},[95,6011,496],{},[95,6013,6014],{},"unit-2-selection-and-iteration\u002F2.09-implementing-selection-and-iteration-algorithms.md"," (CSA 2.9)",[503,6017,505],{},{"title":48,"searchDepth":49,"depth":49,"links":6019},[6020,6021,6022,6023,6024,6025],{"id":5786,"depth":49,"text":5787},{"id":5826,"depth":49,"text":5827},{"id":5876,"depth":49,"text":5877},{"id":5924,"depth":49,"text":5925},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":6027,"status":519},"5.9 — Implementing Selection and Iteration Algorithms (CSA 2.9)","\u002Fshockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F9-implementing-selection-and-iteration-algorithms",{"title":5760,"description":5768},"shockwave-curriculum\u002Flessons\u002Fch05-control-structures\u002F5.9-implementing-selection-and-iteration-algorithms","0_lv1ZwbdhXyyRZpiKT7qhp3F_PkkAah4M-d0IwVqDc",{"id":6033,"title":6034,"body":6035,"description":48,"extension":51,"meta":6396,"navigation":55,"path":6398,"seo":6399,"stem":6400,"__hash__":6401},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.1-strings.md","Strings",{"type":8,"value":6036,"toc":6385},[6037,6040,6044,6059,6074,6080,6084,6090,6110,6114,6121,6130,6152,6156,6179,6190,6194,6229,6237,6245,6260,6285,6287,6333,6335,6375,6383],[11,6038,6034],{"id":6039},"strings",[69,6041,6043],{"id":6042},"strings-are-objects","Strings Are Objects",[15,6045,6046,6048,6049,6051,6052,6054,6055,6058],{},[95,6047,315],{}," is a class, part of ",[95,6050,2361],{}," (no import needed). Like any class, you can create one with ",[95,6053,2860],{},", or with the shorter ",[25,6056,6057],{},"string literal"," syntax:",[104,6060,6062],{"className":106,"code":6061,"language":108,"meta":48,"style":48},"String autoName = new String(\"BlueAlliance-Left\"); \u002F\u002F rarely used\nString autoName = \"BlueAlliance-Left\";              \u002F\u002F the normal way\n",[95,6063,6064,6069],{"__ignoreMap":48},[112,6065,6066],{"class":114,"line":115},[112,6067,6068],{},"String autoName = new String(\"BlueAlliance-Left\"); \u002F\u002F rarely used\n",[112,6070,6071],{"class":114,"line":49},[112,6072,6073],{},"String autoName = \"BlueAlliance-Left\";              \u002F\u002F the normal way\n",[15,6075,6076,6077,6079],{},"Both create a ",[95,6078,315],{}," object; the literal form is what you'll use almost always.",[69,6081,6083],{"id":6082},"strings-are-immutable","Strings Are Immutable",[15,6085,6086,6087,6089],{},"Once a ",[95,6088,315],{}," is created, its characters can never change. Every method that looks like it \"modifies\" a string actually returns a brand-new one, leaving the original untouched:",[104,6091,6093],{"className":106,"code":6092,"language":108,"meta":48,"style":48},"String name = \"Titan\";\nname.toUpperCase(); \u002F\u002F does nothing useful — the result is thrown away!\nname = name.toUpperCase(); \u002F\u002F this is how you actually keep the change\n",[95,6094,6095,6100,6105],{"__ignoreMap":48},[112,6096,6097],{"class":114,"line":115},[112,6098,6099],{},"String name = \"Titan\";\n",[112,6101,6102],{"class":114,"line":49},[112,6103,6104],{},"name.toUpperCase(); \u002F\u002F does nothing useful — the result is thrown away!\n",[112,6106,6107],{"class":114,"line":126},[112,6108,6109],{},"name = name.toUpperCase(); \u002F\u002F this is how you actually keep the change\n",[69,6111,6113],{"id":6112},"concatenation","Concatenation",[15,6115,6116,486,6118,6120],{},[95,6117,848],{},[95,6119,1887],{}," join strings together, and automatically convert non-string values into strings:",[104,6122,6124],{"className":106,"code":6123,"language":108,"meta":48,"style":48},"String status = \"Auto: \" + autoName + \", step \" + 3; \u002F\u002F the int 3 converts automatically\n",[95,6125,6126],{"__ignoreMap":48},[112,6127,6128],{"class":114,"line":115},[112,6129,6123],{},[15,6131,6132,6133,6135,6136,6139,6140,6143,6144,6147,6148,6151],{},"Watch the order when mixing ",[95,6134,848],{}," with numbers — it's evaluated left to right, so ",[95,6137,6138],{},"\"Score: \" + 1 + 2"," gives ",[95,6141,6142],{},"\"Score: 12\""," (each number appends as text in turn), not ",[95,6145,6146],{},"\"Score: 3\"",". Use parentheses — ",[95,6149,6150],{},"\"Score: \" + (1 + 2)"," — to force the addition first.",[69,6153,6155],{"id":6154},"index-and-length","Index and Length",[15,6157,6158,6159,6162,6163,6166,6167,6170,6171,6174,6175,6178],{},"Each character has a position, or ",[25,6160,6161],{},"index",", starting at 0. ",[95,6164,6165],{},"length()"," returns the total character count — the last valid index is always ",[95,6168,6169],{},"length() - 1",". There's no bracket notation like an array's (",[95,6172,6173],{},"autoName[0]"," isn't valid Java) — getting a single character means using ",[95,6176,6177],{},"substring",", covered next.",[15,6180,6181,6182,3883,6184,6186,6187,79],{},"Accessing an index outside ",[95,6183,1140],{},[95,6185,6169],{}," throws an ",[95,6188,6189],{},"IndexOutOfBoundsException",[69,6191,6193],{"id":6192},"the-core-string-methods","The Core String Methods",[104,6195,6197],{"className":106,"code":6196,"language":108,"meta":48,"style":48},"String autoName = \"BlueAlliance-Left\";\nautoName.length();          \u002F\u002F 17\nautoName.substring(0, 4);   \u002F\u002F \"Blue\" — from index 0 up to (not including) 4\nautoName.substring(13);     \u002F\u002F \"Left\" — from index 13 to the end\nautoName.indexOf(\"Left\");   \u002F\u002F 13 — or -1 if not found\nautoName.equals(\"BlueAlliance-Left\"); \u002F\u002F true — compares actual characters\n",[95,6198,6199,6204,6209,6214,6219,6224],{"__ignoreMap":48},[112,6200,6201],{"class":114,"line":115},[112,6202,6203],{},"String autoName = \"BlueAlliance-Left\";\n",[112,6205,6206],{"class":114,"line":49},[112,6207,6208],{},"autoName.length();          \u002F\u002F 17\n",[112,6210,6211],{"class":114,"line":126},[112,6212,6213],{},"autoName.substring(0, 4);   \u002F\u002F \"Blue\" — from index 0 up to (not including) 4\n",[112,6215,6216],{"class":114,"line":132},[112,6217,6218],{},"autoName.substring(13);     \u002F\u002F \"Left\" — from index 13 to the end\n",[112,6220,6221],{"class":114,"line":138},[112,6222,6223],{},"autoName.indexOf(\"Left\");   \u002F\u002F 13 — or -1 if not found\n",[112,6225,6226],{"class":114,"line":144},[112,6227,6228],{},"autoName.equals(\"BlueAlliance-Left\"); \u002F\u002F true — compares actual characters\n",[15,6230,6231,6234,6235,79],{},[95,6232,6233],{},"substring(i, i + 1)"," is the standard way to get just the single character at index ",[95,6236,4140],{},[69,6238,6240,6242,6243],{"id":6239},"equals-not",[95,6241,5424],{},", Not ",[95,6244,1568],{},[15,6246,6247,6249,6250,6252,6253,6256,6257,6259],{},[95,6248,1568],{}," on a ",[95,6251,315],{}," checks whether two variables point at the ",[262,6254,6255],{},"same object"," — not whether their text matches. Use ",[95,6258,5424],{}," to compare actual content:",[104,6261,6263],{"className":106,"code":6262,"language":108,"meta":48,"style":48},"String a = new String(\"Left\");\nString b = new String(\"Left\");\nSystem.out.println(a == b);       \u002F\u002F false — two different objects\nSystem.out.println(a.equals(b));  \u002F\u002F true — same characters\n",[95,6264,6265,6270,6275,6280],{"__ignoreMap":48},[112,6266,6267],{"class":114,"line":115},[112,6268,6269],{},"String a = new String(\"Left\");\n",[112,6271,6272],{"class":114,"line":49},[112,6273,6274],{},"String b = new String(\"Left\");\n",[112,6276,6277],{"class":114,"line":126},[112,6278,6279],{},"System.out.println(a == b);       \u002F\u002F false — two different objects\n",[112,6281,6282],{"class":114,"line":132},[112,6283,6284],{},"System.out.println(a.equals(b));  \u002F\u002F true — same characters\n",[69,6286,412],{"id":411},[19,6288,6289,6300,6313],{},[22,6290,6291,6296,6297,6299],{},[25,6292,4590,6293,6295],{},[95,6294,1568],{}," to compare string content."," It compiles, runs, and gives the wrong answer far more often than it errors — always use ",[95,6298,5424],{}," for strings.",[22,6301,6302,426,6305,6308,6309,6312],{},[25,6303,6304],{},"Forgetting a string method's result has to be used.",[95,6306,6307],{},"autoName.toUpperCase();"," alone does nothing — strings are immutable, so the result must be captured (",[95,6310,6311],{},"autoName = autoName.toUpperCase();",") or it's lost.",[22,6314,6315,6320,6321,6324,6325,6328,6329,6332],{},[25,6316,6317,6318,79],{},"Off-by-one in ",[95,6319,6177],{}," The ",[95,6322,6323],{},"to"," index in ",[95,6326,6327],{},"substring(from, to)"," is exclusive — ",[95,6330,6331],{},"substring(0, 4)"," gives 4 characters (indices 0-3), not 5.",[69,6334,450],{"id":449},[19,6336,6337,6346,6349,6356,6367],{},[22,6338,6339,6341,6342,6345],{},[95,6340,315],{}," is a class; string literals (",[95,6343,6344],{},"\"text\"",") are the normal way to create one.",[22,6347,6348],{},"Strings are immutable — every \"modifying\" method returns a new string instead of changing the original.",[22,6350,6351,1051,6353,6355],{},[95,6352,848],{},[95,6354,1887],{}," concatenate, auto-converting non-string values to text.",[22,6357,6358,275,6360,275,6363,6366],{},[95,6359,6165],{},[95,6361,6362],{},"substring()",[95,6364,6365],{},"indexOf()"," are the core methods, all indexed from 0.",[22,6368,1171,6369,6371,6372,6374],{},[95,6370,5424],{}," to compare string content — ",[95,6373,1568],{}," only checks whether two variables reference the same object.",[15,6376,493,6377,497,6379,6382],{},[95,6378,496],{},[95,6380,6381],{},"unit-1-using-objects-and-methods\u002F1.15-strings.md"," (CSA 1.15)",[503,6384,505],{},{"title":48,"searchDepth":49,"depth":49,"links":6386},[6387,6388,6389,6390,6391,6392,6394,6395],{"id":6042,"depth":49,"text":6043},{"id":6082,"depth":49,"text":6083},{"id":6112,"depth":49,"text":6113},{"id":6154,"depth":49,"text":6155},{"id":6192,"depth":49,"text":6193},{"id":6239,"depth":49,"text":6393},".equals(), Not ==",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":6397,"status":519},"6.1 — Strings (CSA 1.15)","\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F1-strings",{"title":6034,"description":48},"shockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.1-strings","CzlVUB-B15xl0HZeg0TIl43IYyfgPVENJg4K8AXJiYI",{"id":6403,"title":6404,"body":6405,"description":48,"extension":51,"meta":6667,"navigation":55,"path":6669,"seo":6670,"stem":6671,"__hash__":6672},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.2-string-algorithms.md","String Algorithms",{"type":8,"value":6406,"toc":6659},[6407,6410,6414,6421,6466,6475,6485,6493,6540,6550,6554,6557,6589,6591,6625,6627,6649,6657],[11,6408,6404],{"id":6409},"string-algorithms",[69,6411,6413],{"id":6412},"scanning-a-string-character-by-character","Scanning a String Character by Character",[15,6415,355,6416,6418,6419,687],{},[95,6417,3899],{}," loop is the standard way to visit every character of a string — start at 0, stop before ",[95,6420,6165],{},[104,6422,6424],{"className":106,"code":6423,"language":108,"meta":48,"style":48},"String autoName = \"BlueAlliance-Left\";\nint dashCount = 0;\nfor (int i = 0; i \u003C autoName.length(); i++)\n{\n    if (autoName.substring(i, i + 1).equals(\"-\"))\n    {\n        dashCount++;\n    }\n}\n",[95,6425,6426,6430,6435,6440,6444,6449,6453,6458,6462],{"__ignoreMap":48},[112,6427,6428],{"class":114,"line":115},[112,6429,6203],{},[112,6431,6432],{"class":114,"line":49},[112,6433,6434],{},"int dashCount = 0;\n",[112,6436,6437],{"class":114,"line":126},[112,6438,6439],{},"for (int i = 0; i \u003C autoName.length(); i++)\n",[112,6441,6442],{"class":114,"line":132},[112,6443,123],{},[112,6445,6446],{"class":114,"line":138},[112,6447,6448],{},"    if (autoName.substring(i, i + 1).equals(\"-\"))\n",[112,6450,6451],{"class":114,"line":144},[112,6452,135],{},[112,6454,6455],{"class":114,"line":150},[112,6456,6457],{},"        dashCount++;\n",[112,6459,6460],{"class":114,"line":1819},[112,6461,147],{},[112,6463,6464],{"class":114,"line":1825},[112,6465,153],{},[15,6467,6468,6469,6471,6472,6474],{},"Use a ",[95,6470,3899],{}," loop when you know you want to check every character. Use a ",[95,6473,5565],{}," loop instead when you're searching for something and don't know in advance how many characters you'll need to check — see the find-and-replace pattern below.",[69,6476,6478,6479,6482,6483],{"id":6477},"find-and-replace-with-indexof-substring","Find and Replace with ",[95,6480,6481],{},"indexOf"," + ",[95,6484,6177],{},[15,6486,355,6487,6489,6490,6492],{},[95,6488,5565],{}," loop paired with ",[95,6491,6481],{}," repeatedly finds and processes one match at a time, until none remain:",[104,6494,6496],{"className":106,"code":6495,"language":108,"meta":48,"style":48},"String name = \"Alli1ance\";\nint i = 0;\nwhile (name.indexOf(\"1\") >= 0)\n{\n    i = name.indexOf(\"1\");\n    String firstPart = name.substring(0, i);\n    String lastPart = name.substring(i + 1);\n    name = firstPart + \"l\" + lastPart; \u002F\u002F replace the \"1\" with \"l\"\n}\n",[95,6497,6498,6503,6507,6512,6516,6521,6526,6531,6536],{"__ignoreMap":48},[112,6499,6500],{"class":114,"line":115},[112,6501,6502],{},"String name = \"Alli1ance\";\n",[112,6504,6505],{"class":114,"line":49},[112,6506,5624],{},[112,6508,6509],{"class":114,"line":126},[112,6510,6511],{},"while (name.indexOf(\"1\") >= 0)\n",[112,6513,6514],{"class":114,"line":132},[112,6515,123],{},[112,6517,6518],{"class":114,"line":138},[112,6519,6520],{},"    i = name.indexOf(\"1\");\n",[112,6522,6523],{"class":114,"line":144},[112,6524,6525],{},"    String firstPart = name.substring(0, i);\n",[112,6527,6528],{"class":114,"line":150},[112,6529,6530],{},"    String lastPart = name.substring(i + 1);\n",[112,6532,6533],{"class":114,"line":1819},[112,6534,6535],{},"    name = firstPart + \"l\" + lastPart; \u002F\u002F replace the \"1\" with \"l\"\n",[112,6537,6538],{"class":114,"line":1825},[112,6539,153],{},[15,6541,6542,6543,6546,6547,79],{},"Each pass finds the ",[262,6544,6545],{},"next"," occurrence, because the string was already reassigned — the search always runs against the current (updated) value of ",[95,6548,6549],{},"name",[69,6551,6553],{"id":6552},"building-a-new-string","Building a New String",[15,6555,6556],{},"Since strings are immutable, \"building\" one really means starting with an empty string and concatenating onto it inside a loop:",[104,6558,6560],{"className":106,"code":6559,"language":108,"meta":48,"style":48},"String reversed = \"\";\nfor (int i = 0; i \u003C autoName.length(); i++)\n{\n    String letter = autoName.substring(i, i + 1);\n    reversed = letter + reversed; \u002F\u002F prepend — builds the string backwards\n}\n",[95,6561,6562,6567,6571,6575,6580,6585],{"__ignoreMap":48},[112,6563,6564],{"class":114,"line":115},[112,6565,6566],{},"String reversed = \"\";\n",[112,6568,6569],{"class":114,"line":49},[112,6570,6439],{},[112,6572,6573],{"class":114,"line":126},[112,6574,123],{},[112,6576,6577],{"class":114,"line":132},[112,6578,6579],{},"    String letter = autoName.substring(i, i + 1);\n",[112,6581,6582],{"class":114,"line":138},[112,6583,6584],{},"    reversed = letter + reversed; \u002F\u002F prepend — builds the string backwards\n",[112,6586,6587],{"class":114,"line":144},[112,6588,153],{},[69,6590,412],{"id":411},[19,6592,6593,6599,6616],{},[22,6594,6595,6598],{},[25,6596,6597],{},"Starting a string-scanning loop at 1 instead of 0."," The first character is always at index 0 — starting at 1 skips it.",[22,6600,6601,426,6610,6613,6614,79],{},[25,6602,4590,6603,3972,6605,6607,6608,79],{},[95,6604,3951],{},[95,6606,3945],{}," against ",[95,6609,6165],{},[95,6611,6612],{},"i \u003C= autoName.length()"," reads one index past the end and throws ",[95,6615,6189],{},[22,6617,6618,6621,6622,6624],{},[25,6619,6620],{},"An infinite loop in a find-and-replace pattern."," If the replacement text itself still contains the thing you're searching for, ",[95,6623,6481],{}," finds it again forever — make sure each pass genuinely reduces what's left to find.",[69,6626,450],{"id":449},[19,6628,6629,6637,6646],{},[22,6630,6631,6633,6634,6636],{},[95,6632,3899],{}," loops fit scanning every character; ",[95,6635,5565],{}," loops fit searching for an unknown number of matches.",[22,6638,6639,6640,6642,6643,6645],{},"A find-and-replace loop combines ",[95,6641,6481],{}," (to locate) with ",[95,6644,6177],{}," (to rebuild around the match), reassigning the string each pass.",[22,6647,6648],{},"Building a new string from scratch means starting empty and concatenating inside a loop — strings can't be modified in place.",[15,6650,493,6651,497,6653,6656],{},[95,6652,496],{},[95,6654,6655],{},"unit-2-selection-and-iteration\u002F2.10-implementing-string-algorithms.md"," (CSA 2.10)",[503,6658,505],{},{"title":48,"searchDepth":49,"depth":49,"links":6660},[6661,6662,6664,6665,6666],{"id":6412,"depth":49,"text":6413},{"id":6477,"depth":49,"text":6663},"Find and Replace with indexOf + substring",{"id":6552,"depth":49,"text":6553},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":6668,"status":519},"6.2 — String Algorithms (CSA 2.10)","\u002Fshockwave-curriculum\u002Flessons\u002Fch06-strings\u002F2-string-algorithms",{"title":6404,"description":48},"shockwave-curriculum\u002Flessons\u002Fch06-strings\u002F6.2-string-algorithms","ASNjq99mN4YY939D5ySBHjQ-gE2cQrIen1G6ux69Zdw",{"id":6674,"title":6675,"body":6676,"description":48,"extension":51,"meta":7037,"navigation":55,"path":7039,"seo":7040,"stem":7041,"__hash__":7042},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.1-anatomy-of-a-java-class.md","The Class Blueprint",{"type":8,"value":6677,"toc":7028},[6678,6681,6685,6688,6729,6758,6762,6768,6800,6807,6820,6849,6871,6875,6971,6977,6979,6996,6998,7018,7026],[11,6679,6675],{"id":6680},"the-class-blueprint",[69,6682,6684],{"id":6683},"the-three-anatomical-parts","The Three Anatomical Parts",[15,6686,6687],{},"Every class you write has the same three main parts, in this order:",[104,6689,6691],{"className":106,"code":6690,"language":108,"meta":48,"style":48},"public class Intake\n{\n    \u002F\u002F 1. instance variables — the data each object owns\n\n    \u002F\u002F 2. constructors — initialize the instance variables\n\n    \u002F\u002F 3. methods — the behaviors\n}\n",[95,6692,6693,6698,6702,6707,6711,6716,6720,6725],{"__ignoreMap":48},[112,6694,6695],{"class":114,"line":115},[112,6696,6697],{},"public class Intake\n",[112,6699,6700],{"class":114,"line":49},[112,6701,123],{},[112,6703,6704],{"class":114,"line":126},[112,6705,6706],{},"    \u002F\u002F 1. instance variables — the data each object owns\n",[112,6708,6709],{"class":114,"line":132},[112,6710,820],{"emptyLinePlaceholder":55},[112,6712,6713],{"class":114,"line":138},[112,6714,6715],{},"    \u002F\u002F 2. constructors — initialize the instance variables\n",[112,6717,6718],{"class":114,"line":144},[112,6719,820],{"emptyLinePlaceholder":55},[112,6721,6722],{"class":114,"line":150},[112,6723,6724],{},"    \u002F\u002F 3. methods — the behaviors\n",[112,6726,6727],{"class":114,"line":1819},[112,6728,153],{},[19,6730,6731,6744,6752],{},[22,6732,6733,6736,6737,6740,6741,79],{},[25,6734,6735],{},"Instance variables"," hold the data — each object gets its own separate copy. Two ",[95,6738,6739],{},"Intake"," objects can each have their own ",[95,6742,6743],{},"currentSpeed",[22,6745,6746,6749,6750,79],{},[25,6747,6748],{},"Constructors"," initialize those instance variables when an object is built with ",[95,6751,2860],{},[22,6753,6754,6757],{},[25,6755,6756],{},"Methods"," define what the object can do, and can read\u002Fchange its instance variables.",[69,6759,6761],{"id":6760},"designing-a-class-what-data-does-it-represent","Designing a Class: What Data Does It Represent?",[15,6763,6764,6765,6767],{},"Before writing any code, ask: what does this thing need to know about itself? For an ",[95,6766,6739],{}," subsystem: is it currently deployed? What's its current motor speed? Does it have a sensor reading a game piece?",[104,6769,6771],{"className":106,"code":6770,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private boolean isDeployed;\n    private double currentSpeed;\n    private boolean hasGamePiece;\n}\n",[95,6772,6773,6777,6781,6786,6791,6796],{"__ignoreMap":48},[112,6774,6775],{"class":114,"line":115},[112,6776,6697],{},[112,6778,6779],{"class":114,"line":49},[112,6780,123],{},[112,6782,6783],{"class":114,"line":126},[112,6784,6785],{},"    private boolean isDeployed;\n",[112,6787,6788],{"class":114,"line":132},[112,6789,6790],{},"    private double currentSpeed;\n",[112,6792,6793],{"class":114,"line":138},[112,6794,6795],{},"    private boolean hasGamePiece;\n",[112,6797,6798],{"class":114,"line":144},[112,6799,153],{},[69,6801,6803,6804],{"id":6802},"encapsulation-why-instance-variables-are-private","Encapsulation: Why Instance Variables Are ",[95,6805,6806],{},"private",[15,6808,6809,486,6811,6813,6814,6816,6817,6819],{},[95,6810,274],{},[95,6812,6806],{}," control who can access something. ",[95,6815,274],{}," means any other class can reach it; ",[95,6818,6806],{}," restricts access to code inside that same class only.",[15,6821,6822,6823,6825,6826,6829,6830,6832,6833,6835,6836,6838,6839,6841,6842,6845,6846,6848],{},"Instance variables should almost always be ",[95,6824,6806],{}," — this is ",[25,6827,6828],{},"encapsulation",": the class's internal data is hidden, and other code can only interact with it through the methods the class chooses to expose. This matters in practice: if ",[95,6831,6743],{}," were ",[95,6834,274],{},", any other subsystem could set it directly, bypassing whatever safety logic the ",[95,6837,6739],{}," class's own methods enforce (a ramp limit, a max-speed clamp). Keeping it ",[95,6840,6806],{}," means the ",[262,6843,6844],{},"only"," way to change it is through ",[95,6847,6739],{},"'s own methods, which can enforce those rules every time.",[104,6850,6852],{"className":106,"code":6851,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private double currentSpeed; \u002F\u002F only Intake's own code can touch this directly\n}\n",[95,6853,6854,6858,6862,6867],{"__ignoreMap":48},[112,6855,6856],{"class":114,"line":115},[112,6857,6697],{},[112,6859,6860],{"class":114,"line":49},[112,6861,123],{},[112,6863,6864],{"class":114,"line":126},[112,6865,6866],{},"    private double currentSpeed; \u002F\u002F only Intake's own code can touch this directly\n",[112,6868,6869],{"class":114,"line":132},[112,6870,153],{},[69,6872,6874],{"id":6873},"putting-it-together","Putting It Together",[104,6876,6878],{"className":106,"code":6877,"language":108,"meta":48,"style":48},"public class Intake\n{\n    \u002F\u002F 1. instance variables\n    private boolean isDeployed;\n    private double currentSpeed;\n\n    \u002F\u002F 2. constructor\n    public Intake()\n    {\n        isDeployed = false;\n        currentSpeed = 0.0;\n    }\n\n    \u002F\u002F 3. methods\n    public void deploy()\n    {\n        isDeployed = true;\n    }\n}\n",[95,6879,6880,6884,6888,6893,6897,6901,6905,6910,6915,6919,6924,6929,6933,6938,6944,6950,6955,6961,6966],{"__ignoreMap":48},[112,6881,6882],{"class":114,"line":115},[112,6883,6697],{},[112,6885,6886],{"class":114,"line":49},[112,6887,123],{},[112,6889,6890],{"class":114,"line":126},[112,6891,6892],{},"    \u002F\u002F 1. instance variables\n",[112,6894,6895],{"class":114,"line":132},[112,6896,6785],{},[112,6898,6899],{"class":114,"line":138},[112,6900,6790],{},[112,6902,6903],{"class":114,"line":144},[112,6904,820],{"emptyLinePlaceholder":55},[112,6906,6907],{"class":114,"line":150},[112,6908,6909],{},"    \u002F\u002F 2. constructor\n",[112,6911,6912],{"class":114,"line":1819},[112,6913,6914],{},"    public Intake()\n",[112,6916,6917],{"class":114,"line":1825},[112,6918,135],{},[112,6920,6921],{"class":114,"line":1831},[112,6922,6923],{},"        isDeployed = false;\n",[112,6925,6926],{"class":114,"line":4742},[112,6927,6928],{},"        currentSpeed = 0.0;\n",[112,6930,6931],{"class":114,"line":4748},[112,6932,147],{},[112,6934,6936],{"class":114,"line":6935},13,[112,6937,820],{"emptyLinePlaceholder":55},[112,6939,6941],{"class":114,"line":6940},14,[112,6942,6943],{},"    \u002F\u002F 3. methods\n",[112,6945,6947],{"class":114,"line":6946},15,[112,6948,6949],{},"    public void deploy()\n",[112,6951,6953],{"class":114,"line":6952},16,[112,6954,135],{},[112,6956,6958],{"class":114,"line":6957},17,[112,6959,6960],{},"        isDeployed = true;\n",[112,6962,6964],{"class":114,"line":6963},18,[112,6965,147],{},[112,6967,6969],{"class":114,"line":6968},19,[112,6970,153],{},[15,6972,6973,6974,6976],{},"Any class can also have a ",[95,6975,101],{}," method — usually not for the class's normal job, but as a quick way to test that one class in isolation.",[69,6978,412],{"id":411},[19,6980,6981,6990],{},[22,6982,6983,6989],{},[25,6984,6985,6986,6988],{},"Making instance variables ",[95,6987,274],{}," \"to keep things simple.\""," This defeats encapsulation — any other class can then set them to anything, with none of the class's own safety logic enforced.",[22,6991,6992,6995],{},[25,6993,6994],{},"Skipping the design step."," Jumping straight to code without first asking \"what does this class need to know about itself\" tends to produce classes with the wrong data, discovered only after writing several methods around it.",[69,6997,450],{"id":449},[19,6999,7000,7003,7006,7015],{},[22,7001,7002],{},"Every class has the same three parts, in order: instance variables, constructors, methods.",[22,7004,7005],{},"Instance variables are per-object — each object gets its own independent copies.",[22,7007,7008,7009,7011,7012,7014],{},"Instance variables should be ",[95,7010,6806],{},"; methods that are meant to be used by other classes are ",[95,7013,274],{},". This is encapsulation.",[22,7016,7017],{},"Design a class by first asking what data it needs to represent, before writing any code.",[15,7019,493,7020,497,7022,7025],{},[95,7021,496],{},[95,7023,7024],{},"unit-3-class-creation\u002F3.03-anatomy-of-a-java-class.md"," (CSA 3.3)",[503,7027,505],{},{"title":48,"searchDepth":49,"depth":49,"links":7029},[7030,7031,7032,7034,7035,7036],{"id":6683,"depth":49,"text":6684},{"id":6760,"depth":49,"text":6761},{"id":6802,"depth":49,"text":7033},"Encapsulation: Why Instance Variables Are private",{"id":6873,"depth":49,"text":6874},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":7038,"status":519},"7.1 — Anatomy of a Java Class (CSA 3.3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F1-anatomy-of-a-java-class",{"title":6675,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.1-anatomy-of-a-java-class","5iJGKU_N4CNmaGw6KtRtS78fv7Bn25jCo9Lej63SPu4",{"id":7044,"title":7045,"body":7046,"description":48,"extension":51,"meta":7316,"navigation":55,"path":7318,"seo":7319,"stem":7320,"__hash__":7321},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.2-methods-how-to-write-them.md","Methods: How to Write Them",{"type":8,"value":7047,"toc":7307},[7048,7051,7055,7061,7104,7106,7120,7143,7146,7150,7162,7185,7192,7196,7207,7230,7244,7248,7255,7257,7276,7278,7297,7305],[11,7049,7045],{"id":7050},"methods-how-to-write-them",[69,7052,7054],{"id":7053},"void-vs-non-void-revisited-for-your-own-classes","Void vs. Non-Void, Revisited for Your Own Classes",[15,7056,7057,7058,7060],{},"Same rule as Ch.4, now applied to methods you write inside your own class: ",[95,7059,281],{}," methods act (no return value); non-void methods compute and return one.",[104,7062,7064],{"className":106,"code":7063,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private double currentSpeed;\n\n    public void spin(double speed) \u002F\u002F void — acts, doesn't return anything\n    {\n        currentSpeed = speed;\n    }\n}\n",[95,7065,7066,7070,7074,7078,7082,7087,7091,7096,7100],{"__ignoreMap":48},[112,7067,7068],{"class":114,"line":115},[112,7069,6697],{},[112,7071,7072],{"class":114,"line":49},[112,7073,123],{},[112,7075,7076],{"class":114,"line":126},[112,7077,6790],{},[112,7079,7080],{"class":114,"line":132},[112,7081,820],{"emptyLinePlaceholder":55},[112,7083,7084],{"class":114,"line":138},[112,7085,7086],{},"    public void spin(double speed) \u002F\u002F void — acts, doesn't return anything\n",[112,7088,7089],{"class":114,"line":144},[112,7090,135],{},[112,7092,7093],{"class":114,"line":150},[112,7094,7095],{},"        currentSpeed = speed;\n",[112,7097,7098],{"class":114,"line":1819},[112,7099,147],{},[112,7101,7102],{"class":114,"line":1825},[112,7103,153],{},[69,7105,3659],{"id":3658},[15,7107,7108,7109,7111,7112,7114,7115,7117,7118,79],{},"Since instance variables are ",[95,7110,6806],{}," (Lesson 7.1), other classes need a way to read them — a ",[25,7113,3665],{},": a ",[95,7116,274],{}," method, no arguments, that returns one instance variable's value. By convention its name starts with ",[95,7119,3669],{},[104,7121,7123],{"className":106,"code":7122,"language":108,"meta":48,"style":48},"public double getCurrentSpeed()\n{\n    return currentSpeed;\n}\n",[95,7124,7125,7130,7134,7139],{"__ignoreMap":48},[112,7126,7127],{"class":114,"line":115},[112,7128,7129],{},"public double getCurrentSpeed()\n",[112,7131,7132],{"class":114,"line":49},[112,7133,123],{},[112,7135,7136],{"class":114,"line":126},[112,7137,7138],{},"    return currentSpeed;\n",[112,7140,7141],{"class":114,"line":132},[112,7142,153],{},[15,7144,7145],{},"You don't need a getter for every instance variable — only the ones other code genuinely needs to read.",[69,7147,7149],{"id":7148},"setters-mutators","Setters (Mutators)",[15,7151,355,7152,7155,7156,7158,7159,7161],{},[25,7153,7154],{},"setter"," is the write-side equivalent: a ",[95,7157,281],{}," method, named starting with ",[95,7160,2006],{},", taking one parameter — the new value — and assigning it to the instance variable.",[104,7163,7165],{"className":106,"code":7164,"language":108,"meta":48,"style":48},"public void setCurrentSpeed(double newSpeed)\n{\n    currentSpeed = newSpeed;\n}\n",[95,7166,7167,7172,7176,7181],{"__ignoreMap":48},[112,7168,7169],{"class":114,"line":115},[112,7170,7171],{},"public void setCurrentSpeed(double newSpeed)\n",[112,7173,7174],{"class":114,"line":49},[112,7175,123],{},[112,7177,7178],{"class":114,"line":126},[112,7179,7180],{},"    currentSpeed = newSpeed;\n",[112,7182,7183],{"class":114,"line":132},[112,7184,153],{},[15,7186,7187,7188,7191],{},"Think just as hard before writing a setter as before writing a getter. Not every instance variable should be freely settable from outside — sometimes the class should only change its own data through a specific method (like ",[95,7189,7190],{},"spin(speed)"," above) that also enforces some rule, rather than through a bare setter that lets anyone assign anything.",[69,7193,7195],{"id":7194},"tostring","toString",[15,7197,7198,7200,7201,7204,7205,79],{},[95,7199,7195],{}," is a special method Java calls automatically whenever it needs to turn an object into text — including every time you ",[95,7202,7203],{},"System.out.println(someObject)"," or concatenate an object with ",[95,7206,848],{},[104,7208,7210],{"className":106,"code":7209,"language":108,"meta":48,"style":48},"public String toString()\n{\n    return \"Intake[speed=\" + currentSpeed + \", deployed=\" + isDeployed + \"]\";\n}\n",[95,7211,7212,7217,7221,7226],{"__ignoreMap":48},[112,7213,7214],{"class":114,"line":115},[112,7215,7216],{},"public String toString()\n",[112,7218,7219],{"class":114,"line":49},[112,7220,123],{},[112,7222,7223],{"class":114,"line":126},[112,7224,7225],{},"    return \"Intake[speed=\" + currentSpeed + \", deployed=\" + isDeployed + \"]\";\n",[112,7227,7228],{"class":114,"line":132},[112,7229,153],{},[15,7231,7232,7233,7235,7236,7239,7240,7243],{},"Without a ",[95,7234,7195],{},", printing an object directly gives an unhelpful default (something like ",[95,7237,7238],{},"Intake@1a2b3c",") — writing your own gives every ",[95,7241,7242],{},"System.out.println(myIntake)"," a genuinely useful message instead.",[69,7245,7247],{"id":7246},"method-parameters-revisited","Method Parameters, Revisited",[15,7249,7250,7251,7254],{},"Same call-by-value rule from Ch.4.1: a primitive parameter (",[95,7252,7253],{},"double speed",") gets a copy. Changing it inside the method never affects the caller's original variable.",[69,7256,412],{"id":411},[19,7258,7259,7265],{},[22,7260,7261,7264],{},[25,7262,7263],{},"Writing a getter or setter for every instance variable reflexively."," Only write one when something outside the class genuinely needs to read or change that specific value — a setter in particular can undermine whatever rules the class's own methods were meant to enforce.",[22,7266,7267,7272,7273,7275],{},[25,7268,3455,7269,7271],{},[95,7270,7195],{}," and being surprised by ugly default output."," If you're going to print an object for debugging or status, ",[95,7274,7195],{}," is worth the two minutes it takes to write.",[69,7277,450],{"id":449},[19,7279,7280,7286,7289,7294],{},[22,7281,7282,7283,7285],{},"Getters return an instance variable's value (no parameters); setters assign a new value (one parameter, ",[95,7284,281],{}," return).",[22,7287,7288],{},"Not every instance variable needs a getter or setter — only add one when something outside the class actually needs it.",[22,7290,7291,7293],{},[95,7292,7195],{}," is called automatically whenever Java needs to convert an object to text — write your own for useful debug output.",[22,7295,7296],{},"Method parameters follow the same call-by-value rule as before: primitives are copied.",[15,7298,493,7299,497,7301,7304],{},[95,7300,496],{},[95,7302,7303],{},"unit-3-class-creation\u002F3.05-methods-how-to-write-them.md"," (CSA 3.5)",[503,7306,505],{},{"title":48,"searchDepth":49,"depth":49,"links":7308},[7309,7310,7311,7312,7313,7314,7315],{"id":7053,"depth":49,"text":7054},{"id":3658,"depth":49,"text":3659},{"id":7148,"depth":49,"text":7149},{"id":7194,"depth":49,"text":7195},{"id":7246,"depth":49,"text":7247},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":7317,"status":519},"7.2 — Methods: How to Write Them (CSA 3.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F2-methods-how-to-write-them",{"title":7045,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.2-methods-how-to-write-them","rziI5DSzogbADMldwXYCi9YbR_KPIlmXl57CJZgMWEA",{"id":7323,"title":7324,"body":7325,"description":48,"extension":51,"meta":7655,"navigation":55,"path":7657,"seo":7658,"stem":7659,"__hash__":7660},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.3-methods-passing-and-returning-references-of-an-object.md","Methods: Passing & Returning References of an Object",{"type":8,"value":7326,"toc":7646},[7327,7330,7334,7349,7409,7413,7426,7454,7465,7469,7472,7508,7518,7522,7529,7552,7567,7570,7574,7581,7583,7614,7616,7636,7644],[11,7328,7324],{"id":7329},"methods-passing-returning-references-of-an-object",[69,7331,7333],{"id":7332},"objects-as-instance-variables-has-a","Objects as Instance Variables (Has-A)",[15,7335,7336,7337,7340,7341,7344,7345,7348],{},"A class's instance variable can itself be an object of another class — a ",[25,7338,7339],{},"has-a"," relationship. A ",[95,7342,7343],{},"Subsystem"," might have a ",[95,7346,7347],{},"MotorConfig"," (its tuning settings) as an instance variable:",[104,7350,7352],{"className":106,"code":7351,"language":108,"meta":48,"style":48},"class MotorConfig\n{\n    private double rampRate;\n    private int currentLimit;\n    \u002F\u002F constructor, getters, setters not shown\n}\n\nclass Subsystem\n{\n    private String name;\n    private MotorConfig config; \u002F\u002F instance variable of type MotorConfig\n}\n",[95,7353,7354,7359,7363,7368,7373,7378,7382,7386,7391,7395,7400,7405],{"__ignoreMap":48},[112,7355,7356],{"class":114,"line":115},[112,7357,7358],{},"class MotorConfig\n",[112,7360,7361],{"class":114,"line":49},[112,7362,123],{},[112,7364,7365],{"class":114,"line":126},[112,7366,7367],{},"    private double rampRate;\n",[112,7369,7370],{"class":114,"line":132},[112,7371,7372],{},"    private int currentLimit;\n",[112,7374,7375],{"class":114,"line":138},[112,7376,7377],{},"    \u002F\u002F constructor, getters, setters not shown\n",[112,7379,7380],{"class":114,"line":144},[112,7381,153],{},[112,7383,7384],{"class":114,"line":150},[112,7385,820],{"emptyLinePlaceholder":55},[112,7387,7388],{"class":114,"line":1819},[112,7389,7390],{},"class Subsystem\n",[112,7392,7393],{"class":114,"line":1825},[112,7394,123],{},[112,7396,7397],{"class":114,"line":1831},[112,7398,7399],{},"    private String name;\n",[112,7401,7402],{"class":114,"line":4742},[112,7403,7404],{},"    private MotorConfig config; \u002F\u002F instance variable of type MotorConfig\n",[112,7406,7407],{"class":114,"line":4748},[112,7408,153],{},[69,7410,7412],{"id":7411},"call-by-value-for-object-references","Call by Value, for Object References",[15,7414,7415,7416,7419,7420,7422,7423,7425],{},"Java always uses call by value — but for an object, the ",[262,7417,7418],{},"value"," being copied is the reference (the pointer to the object), not the object itself. Passing a ",[95,7421,7347],{}," into a method copies the reference — the parameter and the argument then both point at the ",[262,7424,5417],{}," object.",[104,7427,7429],{"className":106,"code":7428,"language":108,"meta":48,"style":48},"public Subsystem(String initName, MotorConfig initConfig)\n{\n    name = initName;\n    config = initConfig; \u002F\u002F stores the SAME reference the caller passed in\n}\n",[95,7430,7431,7436,7440,7445,7450],{"__ignoreMap":48},[112,7432,7433],{"class":114,"line":115},[112,7434,7435],{},"public Subsystem(String initName, MotorConfig initConfig)\n",[112,7437,7438],{"class":114,"line":49},[112,7439,123],{},[112,7441,7442],{"class":114,"line":126},[112,7443,7444],{},"    name = initName;\n",[112,7446,7447],{"class":114,"line":132},[112,7448,7449],{},"    config = initConfig; \u002F\u002F stores the SAME reference the caller passed in\n",[112,7451,7452],{"class":114,"line":138},[112,7453,153],{},[15,7455,5153,7456,7458,7459,7461,7462,7464],{},[95,7457,7347],{}," is mutable (has setters), this matters a lot: whoever else holds a reference to that same ",[95,7460,7347],{}," object can change it, and the ",[95,7463,7343],{}," sees the change too — because it's not a separate copy, it's the same object viewed from two places.",[69,7466,7468],{"id":7467},"defensive-copying","Defensive Copying",[15,7470,7471],{},"If you don't want outside code to be able to reach in and change your object's data after the fact, make a copy instead of storing the reference you were handed:",[104,7473,7475],{"className":106,"code":7474,"language":108,"meta":48,"style":48},"public Subsystem(String initName, MotorConfig initConfig)\n{\n    name = initName;\n    \u002F\u002F Defensive copy — a brand new MotorConfig with the same values,\n    \u002F\u002F not the same object\n    config = new MotorConfig(initConfig.getRampRate(), initConfig.getCurrentLimit());\n}\n",[95,7476,7477,7481,7485,7489,7494,7499,7504],{"__ignoreMap":48},[112,7478,7479],{"class":114,"line":115},[112,7480,7435],{},[112,7482,7483],{"class":114,"line":49},[112,7484,123],{},[112,7486,7487],{"class":114,"line":126},[112,7488,7444],{},[112,7490,7491],{"class":114,"line":132},[112,7492,7493],{},"    \u002F\u002F Defensive copy — a brand new MotorConfig with the same values,\n",[112,7495,7496],{"class":114,"line":138},[112,7497,7498],{},"    \u002F\u002F not the same object\n",[112,7500,7501],{"class":114,"line":144},[112,7502,7503],{},"    config = new MotorConfig(initConfig.getRampRate(), initConfig.getCurrentLimit());\n",[112,7505,7506],{"class":114,"line":150},[112,7507,153],{},[15,7509,7510,7511,7514,7515,7517],{},"Now changing the original ",[95,7512,7513],{},"initConfig"," object afterward has zero effect on ",[95,7516,7343],{},"'s own copy.",[69,7519,7521],{"id":7520},"returning-an-object-reference","Returning an Object Reference",[15,7523,7524,7525,7528],{},"The same rule applies in reverse: a method that returns an object returns a reference to the ",[262,7526,7527],{},"real"," object, not a copy. If that object is mutable, whoever calls the getter can reach in and change it:",[104,7530,7532],{"className":106,"code":7531,"language":108,"meta":48,"style":48},"public MotorConfig getConfig()\n{\n    return config; \u002F\u002F returns the SAME object — caller can mutate it!\n}\n",[95,7533,7534,7539,7543,7548],{"__ignoreMap":48},[112,7535,7536],{"class":114,"line":115},[112,7537,7538],{},"public MotorConfig getConfig()\n",[112,7540,7541],{"class":114,"line":49},[112,7542,123],{},[112,7544,7545],{"class":114,"line":126},[112,7546,7547],{},"    return config; \u002F\u002F returns the SAME object — caller can mutate it!\n",[112,7549,7550],{"class":114,"line":132},[112,7551,153],{},[104,7553,7555],{"className":106,"code":7554,"language":108,"meta":48,"style":48},"MotorConfig c = subsystem.getConfig();\nc.setRampRate(0.5); \u002F\u002F this actually changes subsystem's real config!\n",[95,7556,7557,7562],{"__ignoreMap":48},[112,7558,7559],{"class":114,"line":115},[112,7560,7561],{},"MotorConfig c = subsystem.getConfig();\n",[112,7563,7564],{"class":114,"line":49},[112,7565,7566],{},"c.setRampRate(0.5); \u002F\u002F this actually changes subsystem's real config!\n",[15,7568,7569],{},"If that's not what you want, return a defensive copy from the getter too.",[69,7571,7573],{"id":7572},"chaining-method-calls","Chaining Method Calls",[15,7575,7576,7577,7580],{},"Calling a method directly on another method's return value — ",[95,7578,7579],{},"subsystem.getConfig().getRampRate()"," — is called chaining. It only works if you know exactly what type each method in the chain returns, since the next method has to actually exist on that type.",[69,7582,412],{"id":411},[19,7584,7585,7591,7597],{},[22,7586,7587,7590],{},[25,7588,7589],{},"Assuming storing a passed-in object automatically makes an independent copy."," It doesn't — only the reference is copied, so the stored object is the exact same one the caller still has.",[22,7592,7593,7596],{},[25,7594,7595],{},"Returning a mutable instance variable directly from a getter."," This hands the caller a live reference to your object's actual internal state — they can change it without going through any of your class's own methods.",[22,7598,7599,426,7602,7605,7606,7609,7610,7613],{},[25,7600,7601],{},"Chaining calls without checking each return type.",[95,7603,7604],{},"a.getX().getY()"," only compiles if ",[95,7607,7608],{},"getX()","'s return type actually has a ",[95,7611,7612],{},"getY()"," method.",[69,7615,450],{"id":449},[19,7617,7618,7621,7627,7630],{},[22,7619,7620],{},"An object can be another object's instance variable — a \"has-a\" relationship.",[22,7622,7623,7624,7626],{},"Passing or returning an object copies its ",[262,7625,3211],{},", not the object itself — both sides then point at the same object.",[22,7628,7629],{},"If the object is mutable and you don't want outside code able to change it later, make a defensive copy — on the way in (constructor\u002Fsetter) and\u002For on the way out (getter).",[22,7631,7632,7633,7635],{},"Chaining method calls (",[95,7634,7604],{},") requires knowing exactly what type each call in the chain returns.",[15,7637,493,7638,497,7640,7643],{},[95,7639,496],{},[95,7641,7642],{},"unit-3-class-creation\u002F3.06-methods-passing-and-returning-references-of-an-object.md"," (CSA 3.6)",[503,7645,505],{},{"title":48,"searchDepth":49,"depth":49,"links":7647},[7648,7649,7650,7651,7652,7653,7654],{"id":7332,"depth":49,"text":7333},{"id":7411,"depth":49,"text":7412},{"id":7467,"depth":49,"text":7468},{"id":7520,"depth":49,"text":7521},{"id":7572,"depth":49,"text":7573},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":7656,"status":519},"7.3 — Methods: Passing\u002FReturning References of an Object (CSA 3.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F3-methods-passing-and-returning-references-of-an-object",{"title":7324,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.3-methods-passing-and-returning-references-of-an-object","iyrlFMuBM1U5Bwl3IYj1MywCUBQs6nlklLTwmgX1CzU",{"id":7662,"title":7663,"body":7664,"description":48,"extension":51,"meta":7964,"navigation":55,"path":7966,"seo":7967,"stem":7968,"__hash__":7969},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.4-class-static-variables-and-methods.md","Class (static) Variables & Methods",{"type":8,"value":7665,"toc":7955},[7666,7669,7673,7685,7730,7734,7741,7785,7788,7811,7815,7820,7879,7882,7889,7894,7903,7909,7911,7925,7927,7945,7953],[11,7667,7663],{"id":7668},"class-static-variables-methods",[69,7670,7672],{"id":7671},"class-methods-belong-to-the-class-not-an-object","Class Methods Belong to the Class, Not an Object",[15,7674,355,7675,7677,7678,7680,7681,7684],{},[95,7676,2649],{}," method or variable belongs to the class itself — there's exactly one shared copy, no matter how many objects (or zero objects) exist. ",[95,7679,2898],{}," is the example you already know: you never make a ",[95,7682,7683],{},"new Math()"," first.",[104,7686,7688],{"className":106,"code":7687,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    public static int instanceCount = 0; \u002F\u002F one shared copy for ALL Subsystem objects\n\n    public Subsystem()\n    {\n        instanceCount++; \u002F\u002F every constructor call increments the ONE shared counter\n    }\n}\n",[95,7689,7690,7695,7699,7704,7708,7713,7717,7722,7726],{"__ignoreMap":48},[112,7691,7692],{"class":114,"line":115},[112,7693,7694],{},"public class Subsystem\n",[112,7696,7697],{"class":114,"line":49},[112,7698,123],{},[112,7700,7701],{"class":114,"line":126},[112,7702,7703],{},"    public static int instanceCount = 0; \u002F\u002F one shared copy for ALL Subsystem objects\n",[112,7705,7706],{"class":114,"line":132},[112,7707,820],{"emptyLinePlaceholder":55},[112,7709,7710],{"class":114,"line":138},[112,7711,7712],{},"    public Subsystem()\n",[112,7714,7715],{"class":114,"line":144},[112,7716,135],{},[112,7718,7719],{"class":114,"line":150},[112,7720,7721],{},"        instanceCount++; \u002F\u002F every constructor call increments the ONE shared counter\n",[112,7723,7724],{"class":114,"line":1819},[112,7725,147],{},[112,7727,7728],{"class":114,"line":1825},[112,7729,153],{},[69,7731,7733],{"id":7732},"static-code-cant-touch-instance-data-directly","Static Code Can't Touch Instance Data Directly",[15,7735,7736,7737,7740],{},"A static method can access other static members freely, but it ",[262,7738,7739],{},"cannot"," reach an instance variable or call an instance method — because static code runs without any particular object in hand, and instance data only exists per-object.",[104,7742,7744],{"className":106,"code":7743,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    private double currentSpeed; \u002F\u002F instance variable — belongs to ONE object\n\n    public static void printStatic()\n    {\n        System.out.println(currentSpeed); \u002F\u002F compile error! no object to read this from\n    }\n}\n",[95,7745,7746,7750,7754,7759,7763,7768,7772,7777,7781],{"__ignoreMap":48},[112,7747,7748],{"class":114,"line":115},[112,7749,7694],{},[112,7751,7752],{"class":114,"line":49},[112,7753,123],{},[112,7755,7756],{"class":114,"line":126},[112,7757,7758],{},"    private double currentSpeed; \u002F\u002F instance variable — belongs to ONE object\n",[112,7760,7761],{"class":114,"line":132},[112,7762,820],{"emptyLinePlaceholder":55},[112,7764,7765],{"class":114,"line":138},[112,7766,7767],{},"    public static void printStatic()\n",[112,7769,7770],{"class":114,"line":144},[112,7771,135],{},[112,7773,7774],{"class":114,"line":150},[112,7775,7776],{},"        System.out.println(currentSpeed); \u002F\u002F compile error! no object to read this from\n",[112,7778,7779],{"class":114,"line":1819},[112,7780,147],{},[112,7782,7783],{"class":114,"line":1825},[112,7784,153],{},[15,7786,7787],{},"The fix, if a static method genuinely needs instance data, is to pass in an actual object as a parameter:",[104,7789,7791],{"className":106,"code":7790,"language":108,"meta":48,"style":48},"public static void printSpeed(Subsystem s)\n{\n    System.out.println(s.currentSpeed); \u002F\u002F fine — reading a specific object's data\n}\n",[95,7792,7793,7798,7802,7807],{"__ignoreMap":48},[112,7794,7795],{"class":114,"line":115},[112,7796,7797],{},"public static void printSpeed(Subsystem s)\n",[112,7799,7800],{"class":114,"line":49},[112,7801,123],{},[112,7803,7804],{"class":114,"line":126},[112,7805,7806],{},"    System.out.println(s.currentSpeed); \u002F\u002F fine — reading a specific object's data\n",[112,7808,7809],{"class":114,"line":132},[112,7810,153],{},[69,7812,7814],{"id":7813},"class-variables-one-shared-copy","Class Variables: One Shared Copy",[15,7816,355,7817,7819],{},[95,7818,2649],{}," variable is shared by every object of the class — changing it from one object's constructor or method affects what every other object sees, since there's only ever one copy.",[104,7821,7823],{"className":106,"code":7822,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    public static double maxObservedCurrent = 0;\n\n    public Subsystem(double current)\n    {\n        if (current > maxObservedCurrent)\n        {\n            maxObservedCurrent = current; \u002F\u002F updates the ONE shared value\n        }\n    }\n}\n",[95,7824,7825,7829,7833,7838,7842,7847,7851,7856,7861,7866,7871,7875],{"__ignoreMap":48},[112,7826,7827],{"class":114,"line":115},[112,7828,7694],{},[112,7830,7831],{"class":114,"line":49},[112,7832,123],{},[112,7834,7835],{"class":114,"line":126},[112,7836,7837],{},"    public static double maxObservedCurrent = 0;\n",[112,7839,7840],{"class":114,"line":132},[112,7841,820],{"emptyLinePlaceholder":55},[112,7843,7844],{"class":114,"line":138},[112,7845,7846],{},"    public Subsystem(double current)\n",[112,7848,7849],{"class":114,"line":144},[112,7850,135],{},[112,7852,7853],{"class":114,"line":150},[112,7854,7855],{},"        if (current > maxObservedCurrent)\n",[112,7857,7858],{"class":114,"line":1819},[112,7859,7860],{},"        {\n",[112,7862,7863],{"class":114,"line":1825},[112,7864,7865],{},"            maxObservedCurrent = current; \u002F\u002F updates the ONE shared value\n",[112,7867,7868],{"class":114,"line":1831},[112,7869,7870],{},"        }\n",[112,7872,7873],{"class":114,"line":4742},[112,7874,147],{},[112,7876,7877],{"class":114,"line":4748},[112,7878,153],{},[15,7880,7881],{},"This is a genuinely common real use: tracking a running maximum, minimum, or count across every object ever created from a class.",[69,7883,7885,7888],{"id":7884},"final-for-constants",[95,7886,7887],{},"final"," for Constants",[15,7890,7891,7893],{},[95,7892,7887],{}," makes a variable's value unchangeable after it's set — used for true constants, conventionally named in all caps:",[104,7895,7897],{"className":106,"code":7896,"language":108,"meta":48,"style":48},"public static final double MAX_SPEED = 1.0;\n",[95,7898,7899],{"__ignoreMap":48},[112,7900,7901],{"class":114,"line":115},[112,7902,7896],{},[15,7904,7905,7906,7908],{},"Trying to reassign a ",[95,7907,7887],{}," variable later is a compile error.",[69,7910,412],{"id":411},[19,7912,7913,7919],{},[22,7914,7915,7918],{},[25,7916,7917],{},"Trying to read an instance variable from a static method."," It doesn't compile — static code has no specific object to read from, unless one is explicitly passed in as a parameter.",[22,7920,7921,7924],{},[25,7922,7923],{},"Expecting a static variable to have a separate copy per object."," It doesn't — there's exactly one, shared by everything, which is precisely what makes it useful for things like a running count or max.",[69,7926,450],{"id":449},[19,7928,7929,7934,7937,7940],{},[22,7930,7931,7933],{},[95,7932,2649],{}," members belong to the class itself — one shared copy, independent of how many objects exist.",[22,7935,7936],{},"Static code cannot access instance variables or instance methods directly — it needs an actual object passed in to do that.",[22,7938,7939],{},"A static variable's value is shared across every object of the class — useful for running totals, counts, or maximums.",[22,7941,7942,7944],{},[95,7943,7887],{}," marks a variable as an unchangeable constant, conventionally named in ALL_CAPS.",[15,7946,493,7947,497,7949,7952],{},[95,7948,496],{},[95,7950,7951],{},"unit-3-class-creation\u002F3.07-class-static-variables-and-methods.md"," (CSA 3.7)",[503,7954,505],{},{"title":48,"searchDepth":49,"depth":49,"links":7956},[7957,7958,7959,7960,7962,7963],{"id":7671,"depth":49,"text":7672},{"id":7732,"depth":49,"text":7733},{"id":7813,"depth":49,"text":7814},{"id":7884,"depth":49,"text":7961},"final for Constants",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":7965,"status":519},"7.4 — Class (static) Variables and Methods (CSA 3.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F4-class-static-variables-and-methods",{"title":7663,"description":48},"shockwave-curriculum\u002Flessons\u002Fch07-the-class-blueprint\u002F7.4-class-static-variables-and-methods","aVnCXw46Sahk-Rsw70A3f4WHiRbxt4ehKo8qufleBnY",{"id":7971,"title":7972,"body":7973,"description":48,"extension":51,"meta":8362,"navigation":55,"path":8364,"seo":8365,"stem":8366,"__hash__":8367},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch08-constructors-and-this\u002F8.1-8.2-constructors-and-this.md","Constructors & \"this\"",{"type":8,"value":7974,"toc":8351},[7975,7978,7982,7992,8037,8041,8059,8081,8085,8091,8169,8175,8192,8215,8224,8235,8241,8246,8290,8292,8317,8319,8342,8349],[11,7976,7972],{"id":7977},"constructors-this",[69,7979,7981],{"id":7980},"a-constructors-job","A Constructor's Job",[15,7983,7984,7985,7988,7989,7991],{},"A constructor's only job is to put a new object into a ",[25,7986,7987],{},"valid state"," — every instance variable set to something usable. Its signature looks like a method's, but with two differences: no return type (not even ",[95,7990,281],{},"), and its name is always exactly the class's name.",[104,7993,7995],{"className":106,"code":7994,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort;\n\n    public Climber(int motorPort) \u002F\u002F same name as the class, no return type\n    {\n        this.motorPort = motorPort;\n    }\n}\n",[95,7996,7997,8002,8006,8011,8015,8020,8024,8029,8033],{"__ignoreMap":48},[112,7998,7999],{"class":114,"line":115},[112,8000,8001],{},"public class Climber\n",[112,8003,8004],{"class":114,"line":49},[112,8005,123],{},[112,8007,8008],{"class":114,"line":126},[112,8009,8010],{},"    private int motorPort;\n",[112,8012,8013],{"class":114,"line":132},[112,8014,820],{"emptyLinePlaceholder":55},[112,8016,8017],{"class":114,"line":138},[112,8018,8019],{},"    public Climber(int motorPort) \u002F\u002F same name as the class, no return type\n",[112,8021,8022],{"class":114,"line":144},[112,8023,135],{},[112,8025,8026],{"class":114,"line":150},[112,8027,8028],{},"        this.motorPort = motorPort;\n",[112,8030,8031],{"class":114,"line":1819},[112,8032,147],{},[112,8034,8035],{"class":114,"line":1825},[112,8036,153],{},[69,8038,8040],{"id":8039},"the-default-constructor","The Default Constructor",[15,8042,8043,8044,168,8046,275,8048,168,8050,275,8052,168,8054,275,8056,8058],{},"If you don't write any constructor at all, Java gives your class a free no-argument one that sets every instance variable to its type's default (",[95,8045,1140],{},[95,8047,552],{},[95,8049,1144],{},[95,8051,580],{},[95,8053,613],{},[95,8055,606],{},[95,8057,3384],{}," for any reference type). The moment you write even one constructor yourself, that free one disappears — you have to cover every way you want objects of your class to be built.",[104,8060,8062],{"className":106,"code":8061,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort; \u002F\u002F if no constructor is written, this defaults to 0\n}\n",[95,8063,8064,8068,8072,8077],{"__ignoreMap":48},[112,8065,8066],{"class":114,"line":115},[112,8067,8001],{},[112,8069,8070],{"class":114,"line":49},[112,8071,123],{},[112,8073,8074],{"class":114,"line":126},[112,8075,8076],{},"    private int motorPort; \u002F\u002F if no constructor is written, this defaults to 0\n",[112,8078,8079],{"class":114,"line":132},[112,8080,153],{},[69,8082,8084],{"id":8083},"overloaded-constructors","Overloaded Constructors",[15,8086,8087,8088,8090],{},"Just like methods (Ch.4.1), a class can have several constructors, distinguished by their parameter lists — this is the same ",[25,8089,2533],{}," concept:",[104,8092,8094],{"className":106,"code":8093,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private int motorPort;\n    private double climbSpeed;\n\n    public Climber(int motorPort)\n    {\n        this.motorPort = motorPort;\n        this.climbSpeed = 0.5; \u002F\u002F a sensible default\n    }\n\n    public Climber(int motorPort, double climbSpeed)\n    {\n        this.motorPort = motorPort;\n        this.climbSpeed = climbSpeed;\n    }\n}\n",[95,8095,8096,8100,8104,8108,8113,8117,8122,8126,8130,8135,8139,8143,8148,8152,8156,8161,8165],{"__ignoreMap":48},[112,8097,8098],{"class":114,"line":115},[112,8099,8001],{},[112,8101,8102],{"class":114,"line":49},[112,8103,123],{},[112,8105,8106],{"class":114,"line":126},[112,8107,8010],{},[112,8109,8110],{"class":114,"line":132},[112,8111,8112],{},"    private double climbSpeed;\n",[112,8114,8115],{"class":114,"line":138},[112,8116,820],{"emptyLinePlaceholder":55},[112,8118,8119],{"class":114,"line":144},[112,8120,8121],{},"    public Climber(int motorPort)\n",[112,8123,8124],{"class":114,"line":150},[112,8125,135],{},[112,8127,8128],{"class":114,"line":1819},[112,8129,8028],{},[112,8131,8132],{"class":114,"line":1825},[112,8133,8134],{},"        this.climbSpeed = 0.5; \u002F\u002F a sensible default\n",[112,8136,8137],{"class":114,"line":1831},[112,8138,147],{},[112,8140,8141],{"class":114,"line":4742},[112,8142,820],{"emptyLinePlaceholder":55},[112,8144,8145],{"class":114,"line":4748},[112,8146,8147],{},"    public Climber(int motorPort, double climbSpeed)\n",[112,8149,8150],{"class":114,"line":6935},[112,8151,135],{},[112,8153,8154],{"class":114,"line":6940},[112,8155,8028],{},[112,8157,8158],{"class":114,"line":6946},[112,8159,8160],{},"        this.climbSpeed = climbSpeed;\n",[112,8162,8163],{"class":114,"line":6952},[112,8164,147],{},[112,8166,8167],{"class":114,"line":6957},[112,8168,153],{},[69,8170,8172,8174],{"id":8171},"this-referring-to-the-current-object",[95,8173,2344],{},": Referring to the Current Object",[15,8176,8177,8178,8180,8181,8184,8185,8188,8189,8191],{},"Inside an instance method or constructor, ",[95,8179,2344],{}," refers to the specific object the method\u002Fconstructor is currently running for. It's most useful when a parameter shares a name with an instance variable — ",[95,8182,8183],{},"this.motorPort"," unambiguously means \"this object's ",[95,8186,8187],{},"motorPort",",\" while bare ",[95,8190,8187],{}," means the parameter:",[104,8193,8195],{"className":106,"code":8194,"language":108,"meta":48,"style":48},"public Climber(int motorPort)\n{\n    this.motorPort = motorPort; \u002F\u002F left side: instance variable. right side: parameter.\n}\n",[95,8196,8197,8202,8206,8211],{"__ignoreMap":48},[112,8198,8199],{"class":114,"line":115},[112,8200,8201],{},"public Climber(int motorPort)\n",[112,8203,8204],{"class":114,"line":49},[112,8205,123],{},[112,8207,8208],{"class":114,"line":126},[112,8209,8210],{},"    this.motorPort = motorPort; \u002F\u002F left side: instance variable. right side: parameter.\n",[112,8212,8213],{"class":114,"line":132},[112,8214,153],{},[15,8216,8217,8218,275,8220,8223],{},"Without ",[95,8219,2344],{},[95,8221,8222],{},"motorPort = motorPort;"," would just assign the parameter to itself — the instance variable would never actually get set.",[15,8225,8226,8228,8229,8231,8232,8234],{},[95,8227,2344],{}," only exists inside instance methods and constructors — a ",[95,8230,2649],{}," method has no current object to refer to, so it has no ",[95,8233,2344],{}," (Ch.7.4).",[69,8236,8238,8240],{"id":8237},"this-as-an-argument",[95,8239,2344],{}," as an Argument",[15,8242,8243,8245],{},[95,8244,2344],{}," is a real reference, usable anywhere an object reference is expected — including passing the current object into another method or constructor:",[104,8247,8249],{"className":106,"code":8248,"language":108,"meta":48,"style":48},"public class Climber\n{\n    private double currentHeight;\n\n    public void reportTo(ClimbLogger logger)\n    {\n        logger.record(this); \u002F\u002F pass the current Climber object itself\n    }\n}\n",[95,8250,8251,8255,8259,8264,8268,8273,8277,8282,8286],{"__ignoreMap":48},[112,8252,8253],{"class":114,"line":115},[112,8254,8001],{},[112,8256,8257],{"class":114,"line":49},[112,8258,123],{},[112,8260,8261],{"class":114,"line":126},[112,8262,8263],{},"    private double currentHeight;\n",[112,8265,8266],{"class":114,"line":132},[112,8267,820],{"emptyLinePlaceholder":55},[112,8269,8270],{"class":114,"line":138},[112,8271,8272],{},"    public void reportTo(ClimbLogger logger)\n",[112,8274,8275],{"class":114,"line":144},[112,8276,135],{},[112,8278,8279],{"class":114,"line":150},[112,8280,8281],{},"        logger.record(this); \u002F\u002F pass the current Climber object itself\n",[112,8283,8284],{"class":114,"line":1819},[112,8285,147],{},[112,8287,8288],{"class":114,"line":1825},[112,8289,153],{},[69,8291,412],{"id":411},[19,8293,8294,8307],{},[22,8295,8296,426,8301,8303,8304,8306],{},[25,8297,3455,8298,8300],{},[95,8299,2344],{}," when a parameter shadows an instance variable.",[95,8302,8222],{}," (no ",[95,8305,2344],{},") does nothing useful — it assigns the parameter to itself, leaving the actual instance variable untouched.",[22,8308,8309,8312,8313,8316],{},[25,8310,8311],{},"Assuming a class always gets a free default constructor."," Only true if you write ",[262,8314,8315],{},"zero"," constructors yourself. Write even one, and you're responsible for every constructor your class needs.",[69,8318,450],{"id":449},[19,8320,8321,8324,8327,8330,8335],{},[22,8322,8323],{},"A constructor's signature has no return type and always matches the class's name; its job is to leave the object in a valid state.",[22,8325,8326],{},"With no constructor written, Java provides a default one that zeroes\u002Fnulls every instance variable — writing any constructor yourself removes that default.",[22,8328,8329],{},"Constructors can be overloaded, just like methods, distinguished by parameter lists.",[22,8331,8332,8334],{},[95,8333,2344],{}," refers to the current object inside an instance method or constructor — essential for disambiguating a parameter from an instance variable of the same name.",[22,8336,8337,8339,8340,79],{},[95,8338,2344],{}," can be passed as an argument, like any other object reference. Static methods have no ",[95,8341,2344],{},[15,8343,8344,426,8346,8348],{},[25,8345,4022],{},[95,8347,4025],{},", slide 8 (\"CONSTRUCTORS\")",[503,8350,505],{},{"title":48,"searchDepth":49,"depth":49,"links":8352},[8353,8354,8355,8356,8358,8360,8361],{"id":7980,"depth":49,"text":7981},{"id":8039,"depth":49,"text":8040},{"id":8083,"depth":49,"text":8084},{"id":8171,"depth":49,"text":8357},"this: Referring to the Current Object",{"id":8237,"depth":49,"text":8359},"this as an Argument",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":8363,"status":4039},"8.1 (Writing Constructors, CSA 3.4) + 8.2 (this Keyword, CSA 3.9) — combined","\u002Fshockwave-curriculum\u002Flessons\u002Fch08-constructors-and-this\u002F1-8.2-constructors-and-this",{"title":7972,"description":48},"shockwave-curriculum\u002Flessons\u002Fch08-constructors-and-this\u002F8.1-8.2-constructors-and-this","-3qv80WFPOtmH728hukb9Itvv2JdIpc3usPyTrZSRDM",{"id":8369,"title":8370,"body":8371,"description":48,"extension":51,"meta":8656,"navigation":55,"path":8659,"seo":8660,"stem":8661,"__hash__":8662},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.1-array-creation-and-access.md","Array Creation and Access",{"type":8,"value":8372,"toc":8647},[8373,8376,8380,8396,8405,8409,8433,8439,8462,8466,8480,8500,8511,8515,8524,8539,8543,8546,8566,8568,8611,8613,8637,8645],[11,8374,8370],{"id":8375},"array-creation-and-access",[69,8377,8379],{"id":8378},"what-an-array-is","What an Array Is",[15,8381,8382,8383,8385,8386,275,8389,275,8392,8395],{},"An array is a fixed-size block of memory holding several values of the same type, accessed by position (",[25,8384,6161],{},") instead of by separate variable names — the fix for needing ",[95,8387,8388],{},"motor1",[95,8390,8391],{},"motor2",[95,8393,8394],{},"motor3","... variables.",[104,8397,8399],{"className":106,"code":8398,"language":108,"meta":48,"style":48},"int[] canBusIds = {1, 2, 3, 4}; \u002F\u002F an initializer list — size inferred, values set immediately\n",[95,8400,8401],{"__ignoreMap":48},[112,8402,8403],{"class":114,"line":115},[112,8404,8398],{},[69,8406,8408],{"id":8407},"two-ways-to-create-one","Two Ways to Create One",[104,8410,8412],{"className":106,"code":8411,"language":108,"meta":48,"style":48},"int[] canBusIds;              \u002F\u002F declares the variable — no array exists yet (it's null)\ncanBusIds = new int[4];       \u002F\u002F creates a 4-element array — all elements start at 0\n\nint[] canBusIds2 = {1, 2, 3, 4}; \u002F\u002F initializer list: create + fill in one step\n",[95,8413,8414,8419,8424,8428],{"__ignoreMap":48},[112,8415,8416],{"class":114,"line":115},[112,8417,8418],{},"int[] canBusIds;              \u002F\u002F declares the variable — no array exists yet (it's null)\n",[112,8420,8421],{"class":114,"line":49},[112,8422,8423],{},"canBusIds = new int[4];       \u002F\u002F creates a 4-element array — all elements start at 0\n",[112,8425,8426],{"class":114,"line":126},[112,8427,820],{"emptyLinePlaceholder":55},[112,8429,8430],{"class":114,"line":132},[112,8431,8432],{},"int[] canBusIds2 = {1, 2, 3, 4}; \u002F\u002F initializer list: create + fill in one step\n",[15,8434,8435,8436,8438],{},"An array is itself an object — a declared-but-not-yet-created array variable holds ",[95,8437,3384],{},", exactly like any other reference type.",[15,8440,8441,8442,8444,8445,168,8447,275,8449,168,8451,275,8453,168,8455,275,8457,168,8459,8461],{},"When you create an array with ",[95,8443,2860],{}," and a size, every element starts at that type's default: ",[95,8446,1140],{},[95,8448,552],{},[95,8450,1144],{},[95,8452,580],{},[95,8454,613],{},[95,8456,606],{},[95,8458,3384],{},[95,8460,315],{}," or any reference type.",[69,8463,8465],{"id":8464},"indexing","Indexing",[15,8467,8468,8469,8472,8473,8476,8477,3179],{},"Indices start at 0; the last valid index is always ",[95,8470,8471],{},"length - 1"," (a ",[95,8474,8475],{},"public final int"," field, not a method — no parentheses, unlike ",[95,8478,8479],{},"String.length()",[104,8481,8483],{"className":106,"code":8482,"language":108,"meta":48,"style":48},"System.out.println(canBusIds.length); \u002F\u002F 4\ncanBusIds[0] = 5;                     \u002F\u002F assign\nSystem.out.println(canBusIds[0]);     \u002F\u002F read — prints 5\n",[95,8484,8485,8490,8495],{"__ignoreMap":48},[112,8486,8487],{"class":114,"line":115},[112,8488,8489],{},"System.out.println(canBusIds.length); \u002F\u002F 4\n",[112,8491,8492],{"class":114,"line":49},[112,8493,8494],{},"canBusIds[0] = 5;                     \u002F\u002F assign\n",[112,8496,8497],{"class":114,"line":126},[112,8498,8499],{},"System.out.println(canBusIds[0]);     \u002F\u002F read — prints 5\n",[15,8501,6181,8502,3883,8504,8506,8507,8510],{},[95,8503,1140],{},[95,8505,8471],{}," throws ",[95,8508,8509],{},"ArrayIndexOutOfBoundsException"," — one of the most common real runtime errors.",[69,8512,8514],{"id":8513},"parallel-arrays","Parallel Arrays",[15,8516,8517,8518,8520,8521,8523],{},"Two (or more) arrays, kept in the same order, where index ",[95,8519,4140],{}," in one corresponds to index ",[95,8522,4140],{}," in the other:",[104,8525,8527],{"className":106,"code":8526,"language":108,"meta":48,"style":48},"String[] autoNames = {\"3-Piece-Left\", \"1-Piece-Safe\", \"Mobility-Only\"};\ndouble[] autoTimes = {14.2, 8.5, 3.1}; \u002F\u002F autoTimes[i] is the recorded time for autoNames[i]\n",[95,8528,8529,8534],{"__ignoreMap":48},[112,8530,8531],{"class":114,"line":115},[112,8532,8533],{},"String[] autoNames = {\"3-Piece-Left\", \"1-Piece-Safe\", \"Mobility-Only\"};\n",[112,8535,8536],{"class":114,"line":49},[112,8537,8538],{},"double[] autoTimes = {14.2, 8.5, 3.1}; \u002F\u002F autoTimes[i] is the recorded time for autoNames[i]\n",[69,8540,8542],{"id":8541},"arrays-of-objects","Arrays of Objects",[15,8544,8545],{},"An array can hold any type, including your own classes — but each element still has to be constructed individually:",[104,8547,8549],{"className":106,"code":8548,"language":108,"meta":48,"style":48},"TalonFX[] driveMotors = new TalonFX[4]; \u002F\u002F 4 slots, all currently null\ndriveMotors[0] = new TalonFX(1);        \u002F\u002F must construct each element separately\ndriveMotors[0].set(0.5);                \u002F\u002F then call methods through the index\n",[95,8550,8551,8556,8561],{"__ignoreMap":48},[112,8552,8553],{"class":114,"line":115},[112,8554,8555],{},"TalonFX[] driveMotors = new TalonFX[4]; \u002F\u002F 4 slots, all currently null\n",[112,8557,8558],{"class":114,"line":49},[112,8559,8560],{},"driveMotors[0] = new TalonFX(1);        \u002F\u002F must construct each element separately\n",[112,8562,8563],{"class":114,"line":126},[112,8564,8565],{},"driveMotors[0].set(0.5);                \u002F\u002F then call methods through the index\n",[69,8567,412],{"id":411},[19,8569,8570,8586,8597],{},[22,8571,8572,426,8575,8578,8579,8581,8582,8585],{},[25,8573,8574],{},"Forgetting an array must be constructed, not just declared.",[95,8576,8577],{},"int[] canBusIds;"," alone is ",[95,8580,3384],{}," — you need ",[95,8583,8584],{},"new int[size]"," or an initializer list before using it.",[22,8587,8588,8591,8592,868,8594,79],{},[25,8589,8590],{},"Off-by-one on the last index."," The last valid index is ",[95,8593,8471],{},[95,8595,8596],{},"length",[22,8598,8599,426,8602,8605,8606,8608,8609,79],{},[25,8600,8601],{},"Forgetting to construct each element of an object array.",[95,8603,8604],{},"new TalonFX[4]"," gives you 4 ",[95,8607,3384],{}," slots, not 4 ready-to-use motor objects — each one still needs its own ",[95,8610,3490],{},[69,8612,450],{"id":449},[19,8614,8615,8618,8624,8631,8634],{},[22,8616,8617],{},"An array is a fixed-size, same-type collection, accessed by a 0-based index.",[22,8619,8620,8623],{},[95,8621,8622],{},"new type[size]"," creates an array with every element at its type's default; an initializer list creates and fills it in one step.",[22,8625,8626,8628,8629,79],{},[95,8627,8596],{}," is a field (no parentheses); the last valid index is ",[95,8630,8471],{},[22,8632,8633],{},"Parallel arrays keep related data in sync by index.",[22,8635,8636],{},"An array of objects still requires constructing each element individually — the array itself doesn't build the objects for you.",[15,8638,493,8639,497,8641,8644],{},[95,8640,496],{},[95,8642,8643],{},"unit-4-data-collections\u002F4.03-array-creation-and-access.md"," (CSA 4.3)",[503,8646,505],{},{"title":48,"searchDepth":49,"depth":49,"links":8648},[8649,8650,8651,8652,8653,8654,8655],{"id":8378,"depth":49,"text":8379},{"id":8407,"depth":49,"text":8408},{"id":8464,"depth":49,"text":8465},{"id":8513,"depth":49,"text":8514},{"id":8541,"depth":49,"text":8542},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":8657,"status":8658},"9.1 — Array Creation and Access (CSA 4.3)","new — authored lesson (fuller depth than the teaser slide). The existing deck slide combines items 9.1-9.3 into one teaser; this Lesson covers 9.1 (Arrays) on its own, since each of the three data structures (array, ArrayList, HashMap) warrants its own full-depth treatment.","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F1-array-creation-and-access",{"title":8370,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.1-array-creation-and-access","KbuktCEu4_ThVJYExQZg5Ox1YztR55I_sYhr9lHZxtM",{"id":8664,"title":8665,"body":8666,"description":48,"extension":51,"meta":9018,"navigation":55,"path":9021,"seo":9022,"stem":9023,"__hash__":9024},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.2-arraylist-and-its-methods.md","ArrayList and its Methods",{"type":8,"value":8667,"toc":9010},[8668,8671,8675,8684,8708,8712,8728,8743,8747,8786,8800,8804,8887,8889,8944,8946,9000,9008],[11,8669,8665],{"id":8670},"arraylist-and-its-methods",[69,8672,8674],{"id":8673},"why-arraylist-exists","Why ArrayList Exists",[15,8676,8677,8678,8683],{},"An array's size is fixed forever once created. ",[25,8679,8680],{},[95,8681,8682],{},"ArrayList"," is Java's resizable alternative — use it whenever you don't know the final size up front, or items will be added\u002Fremoved while the program runs (a growing log of events, for instance).",[104,8685,8687],{"className":106,"code":8686,"language":108,"meta":48,"style":48},"import java.util.ArrayList;\n\nArrayList\u003CString> logs = new ArrayList\u003CString>();\nlogs.add(\"Robot Initialized\");\n",[95,8688,8689,8694,8698,8703],{"__ignoreMap":48},[112,8690,8691],{"class":114,"line":115},[112,8692,8693],{},"import java.util.ArrayList;\n",[112,8695,8696],{"class":114,"line":49},[112,8697,820],{"emptyLinePlaceholder":55},[112,8699,8700],{"class":114,"line":126},[112,8701,8702],{},"ArrayList\u003CString> logs = new ArrayList\u003CString>();\n",[112,8704,8705],{"class":114,"line":132},[112,8706,8707],{},"logs.add(\"Robot Initialized\");\n",[69,8709,8711],{"id":8710},"the-type-parameter","The Type Parameter",[15,8713,8714,8717,8718,8720,8721,1051,8724,8727],{},[95,8715,8716],{},"ArrayList\u003CType>"," — the type in angle brackets is what kind of object the list holds. ",[95,8719,8682],{}," can only hold objects, never primitives directly — a list of numbers uses the wrapper types ",[95,8722,8723],{},"Integer",[95,8725,8726],{},"Double"," (Java auto-converts back and forth, called autoboxing\u002Funboxing):",[104,8729,8731],{"className":106,"code":8730,"language":108,"meta":48,"style":48},"ArrayList\u003CDouble> sensorReadings = new ArrayList\u003CDouble>();\nsensorReadings.add(2.4); \u002F\u002F autoboxed into a Double automatically\n",[95,8732,8733,8738],{"__ignoreMap":48},[112,8734,8735],{"class":114,"line":115},[112,8736,8737],{},"ArrayList\u003CDouble> sensorReadings = new ArrayList\u003CDouble>();\n",[112,8739,8740],{"class":114,"line":49},[112,8741,8742],{},"sensorReadings.add(2.4); \u002F\u002F autoboxed into a Double automatically\n",[69,8744,8746],{"id":8745},"core-methods","Core Methods",[104,8748,8750],{"className":106,"code":8749,"language":108,"meta":48,"style":48},"ArrayList\u003CString> logs = new ArrayList\u003CString>();\nlogs.size();          \u002F\u002F number of elements (like length, but a method — () required)\nlogs.add(\"started\");  \u002F\u002F appends to the end\nlogs.add(0, \"boot\");  \u002F\u002F inserts at index 0, shifting everything else right\nlogs.get(0);           \u002F\u002F reads the element at index 0\nlogs.set(0, \"ready\");  \u002F\u002F replaces the element at index 0\nlogs.remove(0);        \u002F\u002F removes the element at index 0, shifting later ones left\n",[95,8751,8752,8756,8761,8766,8771,8776,8781],{"__ignoreMap":48},[112,8753,8754],{"class":114,"line":115},[112,8755,8702],{},[112,8757,8758],{"class":114,"line":49},[112,8759,8760],{},"logs.size();          \u002F\u002F number of elements (like length, but a method — () required)\n",[112,8762,8763],{"class":114,"line":126},[112,8764,8765],{},"logs.add(\"started\");  \u002F\u002F appends to the end\n",[112,8767,8768],{"class":114,"line":132},[112,8769,8770],{},"logs.add(0, \"boot\");  \u002F\u002F inserts at index 0, shifting everything else right\n",[112,8772,8773],{"class":114,"line":138},[112,8774,8775],{},"logs.get(0);           \u002F\u002F reads the element at index 0\n",[112,8777,8778],{"class":114,"line":144},[112,8779,8780],{},"logs.set(0, \"ready\");  \u002F\u002F replaces the element at index 0\n",[112,8782,8783],{"class":114,"line":150},[112,8784,8785],{},"logs.remove(0);        \u002F\u002F removes the element at index 0, shifting later ones left\n",[15,8787,8788,8790,8791,1051,8793,8795,8796,8799],{},[95,8789,8682],{}," uses methods (",[95,8792,3669],{},[95,8794,2006],{},") instead of ",[95,8797,8798],{},"[]"," — it's a real class, not a built-in language feature the way arrays are.",[69,8801,8803],{"id":8802},"array-vs-arraylist-side-by-side","Array vs. ArrayList, Side by Side",[8805,8806,8807,8822],"table",{},[8808,8809,8810],"thead",{},[8811,8812,8813,8817,8820],"tr",{},[8814,8815,8816],"th",{},"Operation",[8814,8818,8819],{},"array",[8814,8821,8682],{},[8823,8824,8825,8841,8856,8871],"tbody",{},[8811,8826,8827,8831,8836],{},[8828,8829,8830],"td",{},"count",[8828,8832,8833],{},[95,8834,8835],{},"arr.length",[8828,8837,8838],{},[95,8839,8840],{},"list.size()",[8811,8842,8843,8846,8851],{},[8828,8844,8845],{},"read",[8828,8847,8848],{},[95,8849,8850],{},"arr[i]",[8828,8852,8853],{},[95,8854,8855],{},"list.get(i)",[8811,8857,8858,8861,8866],{},[8828,8859,8860],{},"write",[8828,8862,8863],{},[95,8864,8865],{},"arr[i] = v;",[8828,8867,8868],{},[95,8869,8870],{},"list.set(i, v);",[8811,8872,8873,8876,8879],{},[8828,8874,8875],{},"grow\u002Fshrink",[8828,8877,8878],{},"not possible",[8828,8880,8881,1051,8884],{},[95,8882,8883],{},"add",[95,8885,8886],{},"remove",[69,8888,412],{"id":411},[19,8890,8891,8905,8924],{},[22,8892,8893,8898,8899,1051,8902,601],{},[25,8894,4590,8895,8897],{},[95,8896,8798],{}," on an ArrayList."," It doesn't compile — always ",[95,8900,8901],{},"get(i)",[95,8903,8904],{},"set(i, v)",[22,8906,8907,8916,8917,5491,8919,8921,8922,79],{},[25,8908,8909,8910,486,8913,79],{},"Mixing up ",[95,8911,8912],{},".length",[95,8914,8915],{},".size()"," Arrays use the field ",[95,8918,8912],{},[95,8920,8682],{}," uses the method ",[95,8923,8915],{},[22,8925,8926,3483,8931,8934,8935,8938,8939,8941,8942,79],{},[25,8927,8928,8929,79],{},"Using an uninitialized ",[95,8930,8682],{},[95,8932,8933],{},"ArrayList\u003CString> list;"," without ",[95,8936,8937],{},"new ArrayList\u003CString>()"," leaves it ",[95,8940,3384],{}," — calling any method on it throws ",[95,8943,3414],{},[69,8945,450],{"id":449},[19,8947,8948,8953,8963,8984],{},[22,8949,8950,8952],{},[95,8951,8682],{}," is a resizable list — use it when the size isn't known up front or will change at runtime.",[22,8954,8955,8956,8958,8959,275,8961,3179],{},"The type parameter (",[95,8957,8716],{},") says what it holds; primitives need their wrapper type (",[95,8960,8723],{},[95,8962,8726],{},[22,8964,8965,8966,275,8969,275,8972,275,8975,275,8978,275,8981,79],{},"Core methods: ",[95,8967,8968],{},"size()",[95,8970,8971],{},"add()",[95,8973,8974],{},"add(index, obj)",[95,8976,8977],{},"get(index)",[95,8979,8980],{},"set(index, obj)",[95,8982,8983],{},"remove(index)",[22,8985,8986,8987,486,8989,5491,8991,8993,8994,486,8996,1051,8998,79],{},"Arrays use ",[95,8988,8912],{},[95,8990,8798],{},[95,8992,8682],{}," uses ",[95,8995,8915],{},[95,8997,3669],{},[95,8999,2006],{},[15,9001,493,9002,497,9004,9007],{},[95,9003,496],{},[95,9005,9006],{},"unit-4-data-collections\u002F4.08-arraylist-and-its-methods.md"," (CSA 4.8)",[503,9009,505],{},{"title":48,"searchDepth":49,"depth":49,"links":9011},[9012,9013,9014,9015,9016,9017],{"id":8673,"depth":49,"text":8674},{"id":8710,"depth":49,"text":8711},{"id":8745,"depth":49,"text":8746},{"id":8802,"depth":49,"text":8803},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":9019,"status":9020},"9.2 — ArrayList and its Methods (CSA 4.8)","new — authored lesson (fuller depth than the teaser slide). See 9.1's note on why this combined-slide topic gets its own separate Lesson.","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F2-arraylist-and-its-methods",{"title":8665,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.2-arraylist-and-its-methods","Yyt7oOfvltYqIzFmb4ZQAEfoRDG1CRGIYkA8ebKN8mc",{"id":9026,"title":9027,"body":9028,"description":48,"extension":51,"meta":9255,"navigation":55,"path":9258,"seo":9259,"stem":9260,"__hash__":9261},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.3-optional-hashmap-dictionary-data-structure.md","Optional: HashMap (Dictionary) Data Structure",{"type":8,"value":9029,"toc":9248},[9030,9033,9037,9052,9090,9100,9104,9113,9133,9137,9147,9175,9177,9208,9210,9238,9246],[11,9031,9027],{"id":9032},"optional-hashmap-dictionary-data-structure",[69,9034,9036],{"id":9035},"key-value-pairs","Key-Value Pairs",[15,9038,355,9039,9044,9045,9048,9049,9051],{},[25,9040,9041],{},[95,9042,9043],{},"HashMap"," stores pairs — each unique ",[25,9046,9047],{},"key"," maps to a ",[25,9050,7418],{},", like a real dictionary mapping a word to its definition:",[104,9053,9055],{"className":106,"code":9054,"language":108,"meta":48,"style":48},"import java.util.HashMap;\n\nHashMap\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\nmotorOffsets.put(5, 0.02);   \u002F\u002F CAN ID 5's calibration offset is 0.02\nmotorOffsets.put(6, -0.01);\n\ndouble offset = motorOffsets.get(5); \u002F\u002F 0.02\n",[95,9056,9057,9062,9066,9071,9076,9081,9085],{"__ignoreMap":48},[112,9058,9059],{"class":114,"line":115},[112,9060,9061],{},"import java.util.HashMap;\n",[112,9063,9064],{"class":114,"line":49},[112,9065,820],{"emptyLinePlaceholder":55},[112,9067,9068],{"class":114,"line":126},[112,9069,9070],{},"HashMap\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\n",[112,9072,9073],{"class":114,"line":132},[112,9074,9075],{},"motorOffsets.put(5, 0.02);   \u002F\u002F CAN ID 5's calibration offset is 0.02\n",[112,9077,9078],{"class":114,"line":138},[112,9079,9080],{},"motorOffsets.put(6, -0.01);\n",[112,9082,9083],{"class":114,"line":144},[112,9084,820],{"emptyLinePlaceholder":55},[112,9086,9087],{"class":114,"line":150},[112,9088,9089],{},"double offset = motorOffsets.get(5); \u002F\u002F 0.02\n",[15,9091,9092,9095,9096,9099],{},[95,9093,9094],{},"put(key, value)"," adds or replaces a pair; ",[95,9097,9098],{},"get(key)"," retrieves the value for a key.",[69,9101,9103],{"id":9102},"when-to-reach-for-a-hashmap","When to Reach for a HashMap",[15,9105,9106,9107,9109,9110,9112],{},"Arrays and ",[95,9108,8682],{}," are naturally indexed by position (0, 1, 2...). A ",[95,9111,9043],{}," is for when the natural \"index\" is something else entirely — a name, an ID number, a label — and you want to look values up by that instead of a position:",[104,9114,9116],{"className":106,"code":9115,"language":108,"meta":48,"style":48},"HashMap\u003CString, String> subsystemStatus = new HashMap\u003CString, String>();\nsubsystemStatus.put(\"Intake\", \"Ready\");\nsubsystemStatus.put(\"Shooter\", \"Spinning Up\");\n",[95,9117,9118,9123,9128],{"__ignoreMap":48},[112,9119,9120],{"class":114,"line":115},[112,9121,9122],{},"HashMap\u003CString, String> subsystemStatus = new HashMap\u003CString, String>();\n",[112,9124,9125],{"class":114,"line":49},[112,9126,9127],{},"subsystemStatus.put(\"Intake\", \"Ready\");\n",[112,9129,9130],{"class":114,"line":126},[112,9131,9132],{},"subsystemStatus.put(\"Shooter\", \"Spinning Up\");\n",[69,9134,9136],{"id":9135},"looping-through-every-pair","Looping Through Every Pair",[15,9138,9139,9142,9143,9146],{},[95,9140,9141],{},"keySet()"," gives you every key, which you can then use with ",[95,9144,9145],{},"get()"," to reach each value:",[104,9148,9150],{"className":106,"code":9149,"language":108,"meta":48,"style":48},"for (String name : subsystemStatus.keySet())\n{\n    String status = subsystemStatus.get(name);\n    System.out.println(name + \": \" + status);\n}\n",[95,9151,9152,9157,9161,9166,9171],{"__ignoreMap":48},[112,9153,9154],{"class":114,"line":115},[112,9155,9156],{},"for (String name : subsystemStatus.keySet())\n",[112,9158,9159],{"class":114,"line":49},[112,9160,123],{},[112,9162,9163],{"class":114,"line":126},[112,9164,9165],{},"    String status = subsystemStatus.get(name);\n",[112,9167,9168],{"class":114,"line":132},[112,9169,9170],{},"    System.out.println(name + \": \" + status);\n",[112,9172,9173],{"class":114,"line":138},[112,9174,153],{},[69,9176,412],{"id":411},[19,9178,9179,9193],{},[22,9180,9181,9187,9188,9190,9191,79],{},[25,9182,9183,9184,9186],{},"Assuming a ",[95,9185,9043],{}," remembers insertion order."," Unlike ",[95,9189,8682],{},", it doesn't guarantee any particular order when you loop through ",[95,9192,9141],{},[22,9194,9195,9204,9205,9207],{},[25,9196,9197,9198,9200,9201,79],{},"Calling ",[95,9199,9145],{}," with a key that was never ",[95,9202,9203],{},"put()"," Returns ",[95,9206,3384],{}," rather than throwing an error — check for that if a lookup might legitimately miss.",[69,9209,450],{"id":449},[19,9211,9212,9218,9225,9231],{},[22,9213,355,9214,9217],{},[95,9215,9216],{},"HashMap\u003CKeyType, ValueType>"," stores unique keys mapped to values.",[22,9219,9220,9095,9222,9224],{},[95,9221,9094],{},[95,9223,9098],{}," retrieves the value.",[22,9226,9227,9228,9230],{},"Reach for a ",[95,9229,9043],{}," when you naturally look things up by name\u002FID rather than by position.",[22,9232,9233,9235,9236,79],{},[95,9234,9141],{}," gives every key, for looping through all pairs with ",[95,9237,9145],{},[15,9239,493,9240,497,9242,9245],{},[95,9241,496],{},[95,9243,9244],{},"unit-4-data-collections\u002F4.60-optional-hashmap-dictionary-data-structure.md"," (CSA 4.60)",[503,9247,505],{},{"title":48,"searchDepth":49,"depth":49,"links":9249},[9250,9251,9252,9253,9254],{"id":9035,"depth":49,"text":9036},{"id":9102,"depth":49,"text":9103},{"id":9135,"depth":49,"text":9136},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":9256,"status":9257},"9.3 — Optional: HashMap (Dictionary) Data Structure (CSA 4.60)","new — authored lesson (fuller depth than the teaser slide). See 9.1's note on why this combined-slide topic gets its own separate Lesson. Not on the AP CSA exam, but genuinely useful and common in real code.","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F3-optional-hashmap-dictionary-data-structure",{"title":9027,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.3-optional-hashmap-dictionary-data-structure","9P2hlYnVmAE7pevLC-Hr4nzHvzS-DhTX9bPIdyMu3WY",{"id":9263,"title":9264,"body":9265,"description":48,"extension":51,"meta":9506,"navigation":55,"path":9508,"seo":9509,"stem":9510,"__hash__":9511},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.4-array-traversals.md","Array Traversals",{"type":8,"value":9266,"toc":9498},[9267,9270,9274,9280,9308,9314,9318,9321,9357,9361,9364,9387,9390,9394,9425,9427,9466,9468,9488,9496],[11,9268,9264],{"id":9269},"array-traversals",[69,9271,9273],{"id":9272},"looping-through-an-array","Looping Through an Array",[15,9275,9276,9279],{},[25,9277,9278],{},"Traversing"," an array means visiting its elements, usually with a loop. The loop variable doubles as the index:",[104,9281,9283],{"className":106,"code":9282,"language":108,"meta":48,"style":48},"double[] sensorReadings = {2.1, 2.4, 1.9, 2.2};\nfor (int i = 0; i \u003C sensorReadings.length; i++)\n{\n    System.out.println(sensorReadings[i]);\n}\n",[95,9284,9285,9290,9295,9299,9304],{"__ignoreMap":48},[112,9286,9287],{"class":114,"line":115},[112,9288,9289],{},"double[] sensorReadings = {2.1, 2.4, 1.9, 2.2};\n",[112,9291,9292],{"class":114,"line":49},[112,9293,9294],{},"for (int i = 0; i \u003C sensorReadings.length; i++)\n",[112,9296,9297],{"class":114,"line":126},[112,9298,123],{},[112,9300,9301],{"class":114,"line":132},[112,9302,9303],{},"    System.out.println(sensorReadings[i]);\n",[112,9305,9306],{"class":114,"line":138},[112,9307,153],{},[15,9309,9310,9311,9313],{},"Writing the loop against ",[95,9312,8912],{}," (not a hardcoded number) means the same code keeps working no matter how many elements the array actually has.",[69,9315,9317],{"id":9316},"arrays-are-objects-passed-by-reference","Arrays Are Objects — Passed by Reference",[15,9319,9320],{},"An array is an object, so passing one into a method passes the reference — changes a method makes to the array's contents are visible back in the caller, same as any mutable object (Ch.7.3):",[104,9322,9324],{"className":106,"code":9323,"language":108,"meta":48,"style":48},"public static void zeroOut(double[] values)\n{\n    for (int i = 0; i \u003C values.length; i++)\n    {\n        values[i] = 0.0; \u002F\u002F this really does change the caller's array\n    }\n}\n",[95,9325,9326,9331,9335,9340,9344,9349,9353],{"__ignoreMap":48},[112,9327,9328],{"class":114,"line":115},[112,9329,9330],{},"public static void zeroOut(double[] values)\n",[112,9332,9333],{"class":114,"line":49},[112,9334,123],{},[112,9336,9337],{"class":114,"line":126},[112,9338,9339],{},"    for (int i = 0; i \u003C values.length; i++)\n",[112,9341,9342],{"class":114,"line":132},[112,9343,135],{},[112,9345,9346],{"class":114,"line":138},[112,9347,9348],{},"        values[i] = 0.0; \u002F\u002F this really does change the caller's array\n",[112,9350,9351],{"class":114,"line":144},[112,9352,147],{},[112,9354,9355],{"class":114,"line":150},[112,9356,153],{},[69,9358,9360],{"id":9359},"the-enhanced-for-each-loop","The Enhanced For-Each Loop",[15,9362,9363],{},"When you just need every value, with no index and no plan to modify elements, the for-each form is simpler:",[104,9365,9367],{"className":106,"code":9366,"language":108,"meta":48,"style":48},"for (double reading : sensorReadings)\n{\n    System.out.println(reading);\n}\n",[95,9368,9369,9374,9378,9383],{"__ignoreMap":48},[112,9370,9371],{"class":114,"line":115},[112,9372,9373],{},"for (double reading : sensorReadings)\n",[112,9375,9376],{"class":114,"line":49},[112,9377,123],{},[112,9379,9380],{"class":114,"line":126},[112,9381,9382],{},"    System.out.println(reading);\n",[112,9384,9385],{"class":114,"line":132},[112,9386,153],{},[15,9388,9389],{},"It always starts at index 0 and runs through every element in order. It's genuinely equivalent to an indexed loop — just more concise when you don't need the index.",[69,9391,9393],{"id":9392},"what-for-each-cant-do","What For-Each Can't Do",[19,9395,9396,9409,9419],{},[22,9397,9398,426,9401,9404,9405,9408],{},[25,9399,9400],{},"Can't modify a primitive array's elements.",[95,9402,9403],{},"reading = 0.0;"," inside the loop only changes the local copy, not the real array — you need an indexed loop (",[95,9406,9407],{},"values[i] = 0.0;",") to actually change values.",[22,9410,9411,9414,9415,9418],{},[25,9412,9413],{},"Can't get the index."," If you need to know ",[262,9416,9417],{},"where"," something is, use an indexed loop.",[22,9420,9421,9424],{},[25,9422,9423],{},"Can't skip around or go partway."," For-each always visits every element in order, front to back.",[69,9426,412],{"id":411},[19,9428,9429,9444,9453],{},[22,9430,9431,426,9434,9437,9438,9440,9441,79],{},[25,9432,9433],{},"Off-by-one on the loop bound.",[95,9435,9436],{},"i \u003C= values.length"," runs one iteration too many and throws ",[95,9439,8509],{},"; the correct bound is always ",[95,9442,9443],{},"i \u003C values.length",[22,9445,9446,426,9449,9452],{},[25,9447,9448],{},"Expecting a for-each loop to change array values.",[95,9450,9451],{},"for (double v : values) { v = 0.0; }"," compiles, runs, and does absolutely nothing to the real array.",[22,9454,9455,9458,9459,9462,9463,9465],{},[25,9456,9457],{},"Returning \"not found\" too early in a search."," A search loop must check ",[262,9460,9461],{},"every"," element before concluding something isn't present — returning ",[95,9464,613],{}," from inside the loop on the first non-match only ever checks the first element.",[69,9467,450],{"id":449},[19,9469,9470,9475,9478,9485],{},[22,9471,9472,9473,79],{},"Traversing an array means looping through it, index by index, with the loop bound written against ",[95,9474,8912],{},[22,9476,9477],{},"Arrays are objects — a method that changes array elements changes the caller's real array too.",[22,9479,9480,9481,9484],{},"The for-each loop (",[95,9482,9483],{},"for (type v : array)",") is simpler when you don't need the index and won't modify elements.",[22,9486,9487],{},"For-each cannot modify primitive array elements or provide the index — use an indexed loop for those.",[15,9489,493,9490,497,9492,9495],{},[95,9491,496],{},[95,9493,9494],{},"unit-4-data-collections\u002F4.04-array-traversals.md"," (CSA 4.4)",[503,9497,505],{},{"title":48,"searchDepth":49,"depth":49,"links":9499},[9500,9501,9502,9503,9504,9505],{"id":9272,"depth":49,"text":9273},{"id":9316,"depth":49,"text":9317},{"id":9359,"depth":49,"text":9360},{"id":9392,"depth":49,"text":9393},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":9507,"status":519},"9.4 — Array Traversals (CSA 4.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F4-array-traversals",{"title":9264,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.4-array-traversals","zup0Lwb8cDuvwLOmpiyaQzx_jbkeDfkAmJma9mIaumU",{"id":9513,"title":9514,"body":9515,"description":9522,"extension":51,"meta":9956,"navigation":55,"path":9958,"seo":9959,"stem":9960,"__hash__":9961},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.5-implementing-array-algorithms.md","Implementing Array Algorithms",{"type":8,"value":9516,"toc":9945},[9517,9520,9523,9527,9558,9562,9602,9606,9660,9664,9667,9690,9694,9752,9756,9759,9782,9785,9821,9825,9873,9875,9919,9921,9935,9943],[11,9518,9514],{"id":9519},"implementing-array-algorithms",[15,9521,9522],{},"A handful of patterns, all built from a loop plus a little bookkeeping, cover almost everything you'll want to do with an array.",[69,9524,9526],{"id":9525},"sum-average-accumulator","Sum \u002F Average (Accumulator)",[104,9528,9530],{"className":106,"code":9529,"language":108,"meta":48,"style":48},"double sum = 0;\nfor (double reading : sensorReadings)\n{\n    sum += reading;\n}\ndouble average = sum \u002F sensorReadings.length;\n",[95,9531,9532,9536,9540,9544,9549,9553],{"__ignoreMap":48},[112,9533,9534],{"class":114,"line":115},[112,9535,5800],{},[112,9537,9538],{"class":114,"line":49},[112,9539,9373],{},[112,9541,9542],{"class":114,"line":126},[112,9543,123],{},[112,9545,9546],{"class":114,"line":132},[112,9547,9548],{},"    sum += reading;\n",[112,9550,9551],{"class":114,"line":138},[112,9552,153],{},[112,9554,9555],{"class":114,"line":144},[112,9556,9557],{},"double average = sum \u002F sensorReadings.length;\n",[69,9559,9561],{"id":9560},"min-max","Min \u002F Max",[104,9563,9565],{"className":106,"code":9564,"language":108,"meta":48,"style":48},"double max = sensorReadings[0]; \u002F\u002F seed with the first element, not 0 — a reading could be negative\nfor (double reading : sensorReadings)\n{\n    if (reading > max)\n    {\n        max = reading;\n    }\n}\n",[95,9566,9567,9572,9576,9580,9585,9589,9594,9598],{"__ignoreMap":48},[112,9568,9569],{"class":114,"line":115},[112,9570,9571],{},"double max = sensorReadings[0]; \u002F\u002F seed with the first element, not 0 — a reading could be negative\n",[112,9573,9574],{"class":114,"line":49},[112,9575,9373],{},[112,9577,9578],{"class":114,"line":126},[112,9579,123],{},[112,9581,9582],{"class":114,"line":132},[112,9583,9584],{},"    if (reading > max)\n",[112,9586,9587],{"class":114,"line":138},[112,9588,135],{},[112,9590,9591],{"class":114,"line":144},[112,9592,9593],{},"        max = reading;\n",[112,9595,9596],{"class":114,"line":150},[112,9597,147],{},[112,9599,9600],{"class":114,"line":1819},[112,9601,153],{},[69,9603,9605],{"id":9604},"search-check-everything-before-giving-up","Search — Check Everything Before Giving Up",[104,9607,9609],{"className":106,"code":9608,"language":108,"meta":48,"style":48},"public static boolean contains(double[] values, double target)\n{\n    for (double v : values)\n    {\n        if (v == target)\n        {\n            return true; \u002F\u002F fine to return early on a MATCH\n        }\n    }\n    return false; \u002F\u002F only after checking every element\n}\n",[95,9610,9611,9616,9620,9625,9629,9634,9638,9643,9647,9651,9656],{"__ignoreMap":48},[112,9612,9613],{"class":114,"line":115},[112,9614,9615],{},"public static boolean contains(double[] values, double target)\n",[112,9617,9618],{"class":114,"line":49},[112,9619,123],{},[112,9621,9622],{"class":114,"line":126},[112,9623,9624],{},"    for (double v : values)\n",[112,9626,9627],{"class":114,"line":132},[112,9628,135],{},[112,9630,9631],{"class":114,"line":138},[112,9632,9633],{},"        if (v == target)\n",[112,9635,9636],{"class":114,"line":144},[112,9637,7860],{},[112,9639,9640],{"class":114,"line":150},[112,9641,9642],{},"            return true; \u002F\u002F fine to return early on a MATCH\n",[112,9644,9645],{"class":114,"line":1819},[112,9646,7870],{},[112,9648,9649],{"class":114,"line":1825},[112,9650,147],{},[112,9652,9653],{"class":114,"line":1831},[112,9654,9655],{},"    return false; \u002F\u002F only after checking every element\n",[112,9657,9658],{"class":114,"line":4742},[112,9659,153],{},[69,9661,9663],{"id":9662},"looping-back-to-front","Looping Back to Front",[15,9665,9666],{},"Same shape, just counting down:",[104,9668,9670],{"className":106,"code":9669,"language":108,"meta":48,"style":48},"for (int i = values.length - 1; i >= 0; i--)\n{\n    \u002F\u002F process values[i], starting from the end\n}\n",[95,9671,9672,9677,9681,9686],{"__ignoreMap":48},[112,9673,9674],{"class":114,"line":115},[112,9675,9676],{},"for (int i = values.length - 1; i >= 0; i--)\n",[112,9678,9679],{"class":114,"line":49},[112,9680,123],{},[112,9682,9683],{"class":114,"line":126},[112,9684,9685],{},"    \u002F\u002F process values[i], starting from the end\n",[112,9687,9688],{"class":114,"line":132},[112,9689,153],{},[69,9691,9693],{"id":9692},"at-least-one-all-count","\"At Least One\" \u002F \"All\" \u002F \"Count\"",[104,9695,9697],{"className":106,"code":9696,"language":108,"meta":48,"style":48},"\u002F\u002F at least one has the property\nfor (double v : values) { if (isFaulty(v)) return true; }\nreturn false;\n\n\u002F\u002F all have the property (check the NEGATION, bail early on a counter-example)\nfor (double v : values) { if (!isFaulty(v)) return false; }\nreturn true;\n\n\u002F\u002F count how many have the property\nint count = 0;\nfor (double v : values) { if (isFaulty(v)) count++; }\n",[95,9698,9699,9704,9709,9714,9718,9723,9728,9733,9737,9742,9747],{"__ignoreMap":48},[112,9700,9701],{"class":114,"line":115},[112,9702,9703],{},"\u002F\u002F at least one has the property\n",[112,9705,9706],{"class":114,"line":49},[112,9707,9708],{},"for (double v : values) { if (isFaulty(v)) return true; }\n",[112,9710,9711],{"class":114,"line":126},[112,9712,9713],{},"return false;\n",[112,9715,9716],{"class":114,"line":132},[112,9717,820],{"emptyLinePlaceholder":55},[112,9719,9720],{"class":114,"line":138},[112,9721,9722],{},"\u002F\u002F all have the property (check the NEGATION, bail early on a counter-example)\n",[112,9724,9725],{"class":114,"line":144},[112,9726,9727],{},"for (double v : values) { if (!isFaulty(v)) return false; }\n",[112,9729,9730],{"class":114,"line":150},[112,9731,9732],{},"return true;\n",[112,9734,9735],{"class":114,"line":1819},[112,9736,820],{"emptyLinePlaceholder":55},[112,9738,9739],{"class":114,"line":1825},[112,9740,9741],{},"\u002F\u002F count how many have the property\n",[112,9743,9744],{"class":114,"line":1831},[112,9745,9746],{},"int count = 0;\n",[112,9748,9749],{"class":114,"line":4742},[112,9750,9751],{},"for (double v : values) { if (isFaulty(v)) count++; }\n",[69,9753,9755],{"id":9754},"duplicates","Duplicates",[15,9757,9758],{},"Adjacent only — a single loop comparing neighbors:",[104,9760,9762],{"className":106,"code":9761,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C values.length - 1; i++)\n{\n    if (values[i] == values[i + 1]) return true;\n}\n",[95,9763,9764,9769,9773,9778],{"__ignoreMap":48},[112,9765,9766],{"class":114,"line":115},[112,9767,9768],{},"for (int i = 0; i \u003C values.length - 1; i++)\n",[112,9770,9771],{"class":114,"line":49},[112,9772,123],{},[112,9774,9775],{"class":114,"line":126},[112,9776,9777],{},"    if (values[i] == values[i + 1]) return true;\n",[112,9779,9780],{"class":114,"line":132},[112,9781,153],{},[15,9783,9784],{},"Anywhere in the array — a nested loop comparing every pair:",[104,9786,9788],{"className":106,"code":9787,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C values.length; i++)\n{\n    for (int j = i + 1; j \u003C values.length; j++)\n    {\n        if (values[i] == values[j]) return true;\n    }\n}\n",[95,9789,9790,9795,9799,9804,9808,9813,9817],{"__ignoreMap":48},[112,9791,9792],{"class":114,"line":115},[112,9793,9794],{},"for (int i = 0; i \u003C values.length; i++)\n",[112,9796,9797],{"class":114,"line":49},[112,9798,123],{},[112,9800,9801],{"class":114,"line":126},[112,9802,9803],{},"    for (int j = i + 1; j \u003C values.length; j++)\n",[112,9805,9806],{"class":114,"line":132},[112,9807,135],{},[112,9809,9810],{"class":114,"line":138},[112,9811,9812],{},"        if (values[i] == values[j]) return true;\n",[112,9814,9815],{"class":114,"line":144},[112,9816,147],{},[112,9818,9819],{"class":114,"line":150},[112,9820,153],{},[69,9822,9824],{"id":9823},"reversing-swap-from-both-ends","Reversing (Swap From Both Ends)",[104,9826,9828],{"className":106,"code":9827,"language":108,"meta":48,"style":48},"int start = 0, end = values.length - 1;\nwhile (start \u003C end)\n{\n    double temp = values[start];\n    values[start] = values[end];\n    values[end] = temp;\n    start++;\n    end--;\n}\n",[95,9829,9830,9835,9840,9844,9849,9854,9859,9864,9869],{"__ignoreMap":48},[112,9831,9832],{"class":114,"line":115},[112,9833,9834],{},"int start = 0, end = values.length - 1;\n",[112,9836,9837],{"class":114,"line":49},[112,9838,9839],{},"while (start \u003C end)\n",[112,9841,9842],{"class":114,"line":126},[112,9843,123],{},[112,9845,9846],{"class":114,"line":132},[112,9847,9848],{},"    double temp = values[start];\n",[112,9850,9851],{"class":114,"line":138},[112,9852,9853],{},"    values[start] = values[end];\n",[112,9855,9856],{"class":114,"line":144},[112,9857,9858],{},"    values[end] = temp;\n",[112,9860,9861],{"class":114,"line":150},[112,9862,9863],{},"    start++;\n",[112,9865,9866],{"class":114,"line":1819},[112,9867,9868],{},"    end--;\n",[112,9870,9871],{"class":114,"line":1825},[112,9872,153],{},[69,9874,412],{"id":411},[19,9876,9877,9889,9899],{},[22,9878,9879,9885,9886,9888],{},[25,9880,9881,9882,9884],{},"Seeding min\u002Fmax with ",[95,9883,1140],{}," instead of the first element."," If every real value is negative (or all above some baseline), ",[95,9887,1140],{}," is a wrong starting point that never gets replaced correctly.",[22,9890,9891,9894,9895,9898],{},[25,9892,9893],{},"Returning \"not found\" from inside the loop."," Only a ",[262,9896,9897],{},"match"," should return early; \"not found\" has to wait until the loop has checked every element.",[22,9900,9901,9911,9912,9915,9916,3179],{},[25,9902,9903,9904,3883,9907,9910],{},"Comparing ",[95,9905,9906],{},"values[i]",[95,9908,9909],{},"values[i+1]"," all the way to the last index."," This reads one past the end — the adjacent-duplicate loop must stop at ",[95,9913,9914],{},"length - 2"," (i.e., bound the loop by ",[95,9917,9918],{},"i \u003C values.length - 1",[69,9920,450],{"id":449},[19,9922,9923,9926,9929,9932],{},[22,9924,9925],{},"Sum\u002Faverage, min\u002Fmax, search, and property-counting are all the same basic shape: a loop plus a little state (an accumulator, a running best, a counter, or an early return).",[22,9927,9928],{},"A search for \"not found\" must check every element before concluding absence; a search for a match can return the instant it's found.",[22,9930,9931],{},"Adjacent-duplicate checks are a single loop; any-pair duplicate checks need a nested loop.",[22,9933,9934],{},"Reversing in place swaps from both ends toward the middle using a temporary variable.",[15,9936,493,9937,497,9939,9942],{},[95,9938,496],{},[95,9940,9941],{},"unit-4-data-collections\u002F4.05-implementing-array-algorithms.md"," (CSA 4.5)",[503,9944,505],{},{"title":48,"searchDepth":49,"depth":49,"links":9946},[9947,9948,9949,9950,9951,9952,9953,9954,9955],{"id":9525,"depth":49,"text":9526},{"id":9560,"depth":49,"text":9561},{"id":9604,"depth":49,"text":9605},{"id":9662,"depth":49,"text":9663},{"id":9692,"depth":49,"text":9693},{"id":9754,"depth":49,"text":9755},{"id":9823,"depth":49,"text":9824},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":9957,"status":519},"9.5 — Implementing Array Algorithms (CSA 4.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F5-implementing-array-algorithms",{"title":9514,"description":9522},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.5-implementing-array-algorithms","Mx3A3iaAUCneBTjSB0a3F1nGnX_ubuOpPCTdKG1jwbc",{"id":9963,"title":9964,"body":9965,"description":48,"extension":51,"meta":10202,"navigation":55,"path":10204,"seo":10205,"stem":10206,"__hash__":10207},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.6-arraylist-traversals.md","ArrayList Traversals",{"type":8,"value":9966,"toc":10194},[9967,9970,9974,9994,10009,10013,10028,10032,10039,10097,10101,10116,10118,10158,10160,10184,10192],[11,9968,9964],{"id":9969},"arraylist-traversals",[69,9971,9973],{"id":9972},"same-loop-shapes-as-arrays","Same Loop Shapes as Arrays",[15,9975,9976,9977,278,9979,9981,9982,9984,9985,3972,9987,278,9990,3972,9992,687],{},"For-each, indexed ",[95,9978,3899],{},[95,9980,5565],{}," all work on an ",[95,9983,8682],{}," — just with ",[95,9986,8901],{},[95,9988,9989],{},"[i]",[95,9991,8915],{},[95,9993,8912],{},[104,9995,9997],{"className":106,"code":9996,"language":108,"meta":48,"style":48},"for (String log : logs) { System.out.println(log); }             \u002F\u002F for-each — read-only pass\nfor (int i = 0; i \u003C logs.size(); i++) { System.out.println(logs.get(i)); } \u002F\u002F indexed\n",[95,9998,9999,10004],{"__ignoreMap":48},[112,10000,10001],{"class":114,"line":115},[112,10002,10003],{},"for (String log : logs) { System.out.println(log); }             \u002F\u002F for-each — read-only pass\n",[112,10005,10006],{"class":114,"line":49},[112,10007,10008],{},"for (int i = 0; i \u003C logs.size(); i++) { System.out.println(logs.get(i)); } \u002F\u002F indexed\n",[69,10010,10012],{"id":10011},"the-big-restriction-dont-resize-during-a-for-each","The Big Restriction: Don't Resize During a For-Each",[15,10014,10015,10016,10018,10019,10022,10023,207,10025,10027],{},"Adding or removing elements from an ",[95,10017,8682],{}," while a for-each loop is traversing it throws ",[95,10020,10021],{},"ConcurrentModificationException",". If you need to add or remove while looping, use an indexed ",[95,10024,3899],{},[95,10026,5565],{}," loop instead.",[69,10029,10031],{"id":10030},"removing-while-looping-the-careful-way","Removing While Looping — The Careful Way",[15,10033,10034,10035,10038],{},"Removing an element shifts every later element down by one index. If you increment the loop index ",[262,10036,10037],{},"unconditionally"," after a removal, you skip checking the element that just got shifted into the spot you were on:",[104,10040,10042],{"className":106,"code":10041,"language":108,"meta":48,"style":48},"int i = 0;\nwhile (i \u003C logs.size())\n{\n    if (shouldRemove(logs.get(i)))\n    {\n        logs.remove(i); \u002F\u002F don't increment i here — the next element just shifted into index i\n    }\n    else\n    {\n        i++; \u002F\u002F only advance when nothing was removed this iteration\n    }\n}\n",[95,10043,10044,10048,10053,10057,10062,10066,10071,10075,10080,10084,10089,10093],{"__ignoreMap":48},[112,10045,10046],{"class":114,"line":115},[112,10047,5624],{},[112,10049,10050],{"class":114,"line":49},[112,10051,10052],{},"while (i \u003C logs.size())\n",[112,10054,10055],{"class":114,"line":126},[112,10056,123],{},[112,10058,10059],{"class":114,"line":132},[112,10060,10061],{},"    if (shouldRemove(logs.get(i)))\n",[112,10063,10064],{"class":114,"line":138},[112,10065,135],{},[112,10067,10068],{"class":114,"line":144},[112,10069,10070],{},"        logs.remove(i); \u002F\u002F don't increment i here — the next element just shifted into index i\n",[112,10072,10073],{"class":114,"line":150},[112,10074,147],{},[112,10076,10077],{"class":114,"line":1819},[112,10078,10079],{},"    else\n",[112,10081,10082],{"class":114,"line":1825},[112,10083,135],{},[112,10085,10086],{"class":114,"line":1831},[112,10087,10088],{},"        i++; \u002F\u002F only advance when nothing was removed this iteration\n",[112,10090,10091],{"class":114,"line":4742},[112,10092,147],{},[112,10094,10095],{"class":114,"line":4748},[112,10096,153],{},[69,10098,10100],{"id":10099},"chaining-through-a-list-of-objects","Chaining Through a List of Objects",[104,10102,10104],{"className":106,"code":10103,"language":108,"meta":48,"style":48},"ArrayList\u003CSubsystem> subsystems = new ArrayList\u003CSubsystem>();\nString firstName = subsystems.get(0).getName(); \u002F\u002F chain: get the object, then call a method on it\n",[95,10105,10106,10111],{"__ignoreMap":48},[112,10107,10108],{"class":114,"line":115},[112,10109,10110],{},"ArrayList\u003CSubsystem> subsystems = new ArrayList\u003CSubsystem>();\n",[112,10112,10113],{"class":114,"line":49},[112,10114,10115],{},"String firstName = subsystems.get(0).getName(); \u002F\u002F chain: get the object, then call a method on it\n",[69,10117,412],{"id":411},[19,10119,10120,10134,10146],{},[22,10121,10122,10125,10126,10128,10129,207,10131,10133],{},[25,10123,10124],{},"Adding\u002Fremoving inside a for-each loop."," Throws ",[95,10127,10021],{}," — switch to an indexed ",[95,10130,3899],{},[95,10132,5565],{}," loop if the list's size needs to change mid-traversal.",[22,10135,10136,10141,10142,10145],{},[25,10137,10138,10139,79],{},"Incrementing the index unconditionally after a ",[95,10140,8886],{}," This skips the element that shifted into the just-vacated slot — only advance the index when you ",[262,10143,10144],{},"didn't"," remove anything that pass.",[22,10147,10148,10154,10155,79],{},[25,10149,4590,10150,6607,10152,79],{},[95,10151,3951],{},[95,10153,8915],{}," Same off-by-one risk as arrays — the last valid index is ",[95,10156,10157],{},"size() - 1",[69,10159,450],{"id":449},[19,10161,10162,10175,10181],{},[22,10163,10164,10166,10167,1051,10169,3972,10171,1051,10173,79],{},[95,10165,8682],{}," supports the same loop shapes as arrays, using ",[95,10168,8901],{},[95,10170,8915],{},[95,10172,9989],{},[95,10174,8912],{},[22,10176,10177,10178,10180],{},"Never add or remove elements from an ",[95,10179,8682],{}," while traversing it with a for-each loop.",[22,10182,10183],{},"When removing elements in an indexed\u002Fwhile loop, only advance the index on iterations where nothing was removed.",[15,10185,493,10186,497,10188,10191],{},[95,10187,496],{},[95,10189,10190],{},"unit-4-data-collections\u002F4.09-arraylist-traversals.md"," (CSA 4.9)",[503,10193,505],{},{"title":48,"searchDepth":49,"depth":49,"links":10195},[10196,10197,10198,10199,10200,10201],{"id":9972,"depth":49,"text":9973},{"id":10011,"depth":49,"text":10012},{"id":10030,"depth":49,"text":10031},{"id":10099,"depth":49,"text":10100},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":10203,"status":519},"9.6 — ArrayList Traversals (CSA 4.9)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F6-arraylist-traversals",{"title":9964,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.6-arraylist-traversals","lRajvPJ1ck5WId9R2fs_AG-CKED98lMLTDVvhZo28k8",{"id":10209,"title":10210,"body":10211,"description":10535,"extension":51,"meta":10536,"navigation":55,"path":10538,"seo":10539,"stem":10540,"__hash__":10541},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.7-implementing-arraylist-algorithms.md","Implementing ArrayList Algorithms",{"type":8,"value":10212,"toc":10525},[10213,10216,10230,10234,10280,10288,10301,10350,10358,10404,10408,10411,10431,10433,10478,10480,10515,10523],[11,10214,10210],{"id":10215},"implementing-arraylist-algorithms",[15,10217,10218,10219,10221,10222,1051,10224,168,10226,1051,10228,79],{},"Every pattern from Lesson 9.5 (sum\u002Faverage, min\u002Fmax, search, property checks, duplicates, reversing) applies to ",[95,10220,8682],{}," too — just swap ",[95,10223,9989],{},[95,10225,8912],{},[95,10227,8901],{},[95,10229,8915],{},[69,10231,10233],{"id":10232},"min-max-average","Min \u002F Max \u002F Average",[104,10235,10237],{"className":106,"code":10236,"language":108,"meta":48,"style":48},"public static double average(ArrayList\u003CDouble> nums)\n{\n    double sum = 0;\n    for (int i = 0; i \u003C nums.size(); i++)\n    {\n        sum += nums.get(i);\n    }\n    return sum \u002F nums.size();\n}\n",[95,10238,10239,10244,10248,10253,10258,10262,10267,10271,10276],{"__ignoreMap":48},[112,10240,10241],{"class":114,"line":115},[112,10242,10243],{},"public static double average(ArrayList\u003CDouble> nums)\n",[112,10245,10246],{"class":114,"line":49},[112,10247,123],{},[112,10249,10250],{"class":114,"line":126},[112,10251,10252],{},"    double sum = 0;\n",[112,10254,10255],{"class":114,"line":132},[112,10256,10257],{},"    for (int i = 0; i \u003C nums.size(); i++)\n",[112,10259,10260],{"class":114,"line":138},[112,10261,135],{},[112,10263,10264],{"class":114,"line":144},[112,10265,10266],{},"        sum += nums.get(i);\n",[112,10268,10269],{"class":114,"line":150},[112,10270,147],{},[112,10272,10273],{"class":114,"line":1819},[112,10274,10275],{},"    return sum \u002F nums.size();\n",[112,10277,10278],{"class":114,"line":1825},[112,10279,153],{},[69,10281,10283,10284,6242,10286],{"id":10282},"duplicates-use-equals-not","Duplicates — Use ",[95,10285,5424],{},[95,10287,1568],{},[15,10289,10290,10291,10294,10295,10297,10298,10300],{},"For ",[95,10292,10293],{},"ArrayList\u003CInteger>"," (or any object type), comparing with ",[95,10296,1568],{}," checks identity, not value — use ",[95,10299,5424],{}," instead:",[104,10302,10304],{"className":106,"code":10303,"language":108,"meta":48,"style":48},"for (int i = 0; i \u003C nums.size(); i++)\n{\n    for (int j = i + 1; j \u003C nums.size(); j++)\n    {\n        if (nums.get(i).equals(nums.get(j))) \u002F\u002F .equals(), not ==\n        {\n            return true;\n        }\n    }\n}\n",[95,10305,10306,10311,10315,10320,10324,10329,10333,10338,10342,10346],{"__ignoreMap":48},[112,10307,10308],{"class":114,"line":115},[112,10309,10310],{},"for (int i = 0; i \u003C nums.size(); i++)\n",[112,10312,10313],{"class":114,"line":49},[112,10314,123],{},[112,10316,10317],{"class":114,"line":126},[112,10318,10319],{},"    for (int j = i + 1; j \u003C nums.size(); j++)\n",[112,10321,10322],{"class":114,"line":132},[112,10323,135],{},[112,10325,10326],{"class":114,"line":138},[112,10327,10328],{},"        if (nums.get(i).equals(nums.get(j))) \u002F\u002F .equals(), not ==\n",[112,10330,10331],{"class":114,"line":144},[112,10332,7860],{},[112,10334,10335],{"class":114,"line":150},[112,10336,10337],{},"            return true;\n",[112,10339,10340],{"class":114,"line":1819},[112,10341,7870],{},[112,10343,10344],{"class":114,"line":1825},[112,10345,147],{},[112,10347,10348],{"class":114,"line":1831},[112,10349,153],{},[69,10351,10353,10354,1051,10356,1081],{"id":10352},"rotating-in-place-with-getset","Rotating (In Place, with ",[95,10355,3669],{},[95,10357,2006],{},[104,10359,10361],{"className":106,"code":10360,"language":108,"meta":48,"style":48},"public static void rotateRight(ArrayList\u003CDouble> nums)\n{\n    double last = nums.get(nums.size() - 1);\n    for (int i = nums.size() - 1; i > 0; i--)\n    {\n        nums.set(i, nums.get(i - 1));\n    }\n    nums.set(0, last);\n}\n",[95,10362,10363,10368,10372,10377,10382,10386,10391,10395,10400],{"__ignoreMap":48},[112,10364,10365],{"class":114,"line":115},[112,10366,10367],{},"public static void rotateRight(ArrayList\u003CDouble> nums)\n",[112,10369,10370],{"class":114,"line":49},[112,10371,123],{},[112,10373,10374],{"class":114,"line":126},[112,10375,10376],{},"    double last = nums.get(nums.size() - 1);\n",[112,10378,10379],{"class":114,"line":132},[112,10380,10381],{},"    for (int i = nums.size() - 1; i > 0; i--)\n",[112,10383,10384],{"class":114,"line":138},[112,10385,135],{},[112,10387,10388],{"class":114,"line":144},[112,10389,10390],{},"        nums.set(i, nums.get(i - 1));\n",[112,10392,10393],{"class":114,"line":150},[112,10394,147],{},[112,10396,10397],{"class":114,"line":1819},[112,10398,10399],{},"    nums.set(0, last);\n",[112,10401,10402],{"class":114,"line":1825},[112,10403,153],{},[69,10405,10407],{"id":10406},"parallel-arraylists","Parallel ArrayLists",[15,10409,10410],{},"Same idea as parallel arrays (Ch.9.1) — two lists kept in sync by index:",[104,10412,10414],{"className":106,"code":10413,"language":108,"meta":48,"style":48},"ArrayList\u003CString> autoNames = new ArrayList\u003CString>();\nArrayList\u003CDouble> autoTimes = new ArrayList\u003CDouble>();\n\u002F\u002F autoTimes.get(i) is the recorded time for autoNames.get(i)\n",[95,10415,10416,10421,10426],{"__ignoreMap":48},[112,10417,10418],{"class":114,"line":115},[112,10419,10420],{},"ArrayList\u003CString> autoNames = new ArrayList\u003CString>();\n",[112,10422,10423],{"class":114,"line":49},[112,10424,10425],{},"ArrayList\u003CDouble> autoTimes = new ArrayList\u003CDouble>();\n",[112,10427,10428],{"class":114,"line":126},[112,10429,10430],{},"\u002F\u002F autoTimes.get(i) is the recorded time for autoNames.get(i)\n",[69,10432,412],{"id":411},[19,10434,10435,10451,10470],{},[22,10436,10437,10444,10445,10448,10449,908],{},[25,10438,10439,10440,3972,10442,79],{},"Comparing objects with ",[95,10441,1568],{},[95,10443,5424],{}," This is the single most common ArrayList-specific mistake — ",[95,10446,10447],{},"nums.get(i) == nums.get(j)"," checks whether they're the same object, which is unreliable even for boxed ",[95,10450,8723],{},[22,10452,10453,426,10459,10462,10463,10465,10466,1051,10468,79],{},[25,10454,10455,10456,10458],{},"Using array syntax (",[95,10457,8798],{},") out of habit.",[95,10460,10461],{},"nums[i]"," doesn't compile on an ",[95,10464,8682],{}," — it's always ",[95,10467,3669],{},[95,10469,2006],{},[22,10471,10472,10477],{},[25,10473,3455,10474,10476],{},[95,10475,8915],{}," changes as you add\u002Fremove."," A loop bound computed once before a series of removals can end up stale.",[69,10479,450],{"id":449},[19,10481,10482,10496,10509],{},[22,10483,10484,10485,10487,10488,1051,10490,168,10492,1051,10494,79],{},"Every array algorithm pattern (accumulator, min\u002Fmax, search, property checks, duplicates, rotate, reverse) transfers directly to ",[95,10486,8682],{}," — just swap ",[95,10489,9989],{},[95,10491,8912],{},[95,10493,8901],{},[95,10495,8915],{},[22,10497,10498,10499,10501,10502,868,10504,10506,10507,3179],{},"Compare ",[95,10500,8682],{}," elements with ",[95,10503,5424],{},[95,10505,1568],{},", when the element type is an object (including boxed numbers like ",[95,10508,8723],{},[22,10510,10511,10512,10514],{},"Parallel ",[95,10513,8682],{},"s keep related data in sync by index, same as parallel arrays.",[15,10516,493,10517,497,10519,10522],{},[95,10518,496],{},[95,10520,10521],{},"unit-4-data-collections\u002F4.10-implementing-arraylist-algorithms.md"," (CSA 4.10)",[503,10524,505],{},{"title":48,"searchDepth":49,"depth":49,"links":10526},[10527,10528,10530,10532,10533,10534],{"id":10232,"depth":49,"text":10233},{"id":10282,"depth":49,"text":10529},"Duplicates — Use .equals(), Not ==",{"id":10352,"depth":49,"text":10531},"Rotating (In Place, with get\u002Fset)",{"id":10406,"depth":49,"text":10407},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"Every pattern from Lesson 9.5 (sum\u002Faverage, min\u002Fmax, search, property checks, duplicates, reversing) applies to ArrayList too — just swap [i]\u002F.length for get(i)\u002F.size().",{"outlineRef":10537,"status":519},"9.7 — Implementing ArrayList Algorithms (CSA 4.10)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F7-implementing-arraylist-algorithms",{"title":10210,"description":10535},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.7-implementing-arraylist-algorithms","Iv9LEMY1J3VAZdGRDdu2fo3q6h-tARzFQrDoV1npOp0",{"id":10543,"title":10544,"body":10545,"description":48,"extension":51,"meta":10913,"navigation":55,"path":10915,"seo":10916,"stem":10917,"__hash__":10918},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.8-using-text-files.md","Using Text Files",{"type":8,"value":10546,"toc":10903},[10547,10550,10554,10557,10561,10578,10607,10614,10652,10656,10689,10697,10701,10715,10750,10754,10760,10787,10791,10797,10829,10831,10861,10863,10893,10901],[11,10548,10544],{"id":10549},"using-text-files",[69,10551,10553],{"id":10552},"why-read-from-a-file","Why Read From a File",[15,10555,10556],{},"A file's data persists even when the program isn't running — useful for loading configuration or data that's too large (or too changeable) to hard-code into your source. A robot might load a table of autonomous starting positions from a file instead of hardcoding them.",[69,10558,10560],{"id":10559},"opening-a-file","Opening a File",[15,10562,10563,10566,10567,10570,10571,10566,10574,10577],{},[95,10564,10565],{},"File"," (from ",[95,10568,10569],{},"java.io",") represents the file itself; ",[95,10572,10573],{},"Scanner",[95,10575,10576],{},"java.util"," — the same class used for keyboard input) reads from it:",[104,10579,10581],{"className":106,"code":10580,"language":108,"meta":48,"style":48},"import java.io.*;\nimport java.util.*;\n\nFile configFile = new File(\"auto_config.csv\");\nScanner scan = new Scanner(configFile); \u002F\u002F can throw FileNotFoundException\n",[95,10582,10583,10588,10593,10597,10602],{"__ignoreMap":48},[112,10584,10585],{"class":114,"line":115},[112,10586,10587],{},"import java.io.*;\n",[112,10589,10590],{"class":114,"line":49},[112,10591,10592],{},"import java.util.*;\n",[112,10594,10595],{"class":114,"line":126},[112,10596,820],{"emptyLinePlaceholder":55},[112,10598,10599],{"class":114,"line":132},[112,10600,10601],{},"File configFile = new File(\"auto_config.csv\");\n",[112,10603,10604],{"class":114,"line":138},[112,10605,10606],{},"Scanner scan = new Scanner(configFile); \u002F\u002F can throw FileNotFoundException\n",[15,10608,10609,10610,10613],{},"Since opening a file can fail (wrong name, missing file), Java requires you to acknowledge that. The simplest way: add ",[95,10611,10612],{},"throws IOException"," to the method's header — if the file genuinely can't be found, the program terminates with an error instead of continuing silently:",[104,10615,10617],{"className":106,"code":10616,"language":108,"meta":48,"style":48},"public static void main(String[] args) throws IOException\n{\n    File configFile = new File(\"auto_config.csv\");\n    Scanner scan = new Scanner(configFile);\n    \u002F\u002F ...\n    scan.close();\n}\n",[95,10618,10619,10624,10628,10633,10638,10643,10648],{"__ignoreMap":48},[112,10620,10621],{"class":114,"line":115},[112,10622,10623],{},"public static void main(String[] args) throws IOException\n",[112,10625,10626],{"class":114,"line":49},[112,10627,123],{},[112,10629,10630],{"class":114,"line":126},[112,10631,10632],{},"    File configFile = new File(\"auto_config.csv\");\n",[112,10634,10635],{"class":114,"line":132},[112,10636,10637],{},"    Scanner scan = new Scanner(configFile);\n",[112,10639,10640],{"class":114,"line":138},[112,10641,10642],{},"    \u002F\u002F ...\n",[112,10644,10645],{"class":114,"line":144},[112,10646,10647],{},"    scan.close();\n",[112,10649,10650],{"class":114,"line":150},[112,10651,153],{},[69,10653,10655],{"id":10654},"reading-line-by-line","Reading Line by Line",[104,10657,10659],{"className":106,"code":10658,"language":108,"meta":48,"style":48},"while (scan.hasNext())\n{\n    String line = scan.nextLine();\n    \u002F\u002F process this line\n}\nscan.close(); \u002F\u002F always close when done\n",[95,10660,10661,10666,10670,10675,10680,10684],{"__ignoreMap":48},[112,10662,10663],{"class":114,"line":115},[112,10664,10665],{},"while (scan.hasNext())\n",[112,10667,10668],{"class":114,"line":49},[112,10669,123],{},[112,10671,10672],{"class":114,"line":126},[112,10673,10674],{},"    String line = scan.nextLine();\n",[112,10676,10677],{"class":114,"line":132},[112,10678,10679],{},"    \u002F\u002F process this line\n",[112,10681,10682],{"class":114,"line":138},[112,10683,153],{},[112,10685,10686],{"class":114,"line":144},[112,10687,10688],{},"scan.close(); \u002F\u002F always close when done\n",[15,10690,10691,1090,10694,10696],{},[95,10692,10693],{},"hasNext()",[95,10695,610],{}," as long as there's more to read — the standard loop condition for \"read until the file ends.\"",[69,10698,10700],{"id":10699},"splitting-a-csv-line","Splitting a CSV Line",[15,10702,10703,10704,10706,10707,10710,10711,10714],{},"A CSV (comma-separated values) file packs several fields into one line. ",[95,10705,315],{},"'s ",[95,10708,10709],{},"split(\",\")"," breaks a line into a ",[95,10712,10713],{},"String[]"," around the commas:",[104,10716,10718],{"className":106,"code":10717,"language":108,"meta":48,"style":48},"\u002F\u002F One line of auto_config.csv: \"3-Piece-Left,14.2,BlueAlliance\"\nString line = scan.nextLine();\nString[] fields = line.split(\",\");\nString routeName = fields[0];       \u002F\u002F \"3-Piece-Left\"\ndouble routeTime = Double.parseDouble(fields[1]); \u002F\u002F \"14.2\" -> 14.2\nString alliance = fields[2];        \u002F\u002F \"BlueAlliance\"\n",[95,10719,10720,10725,10730,10735,10740,10745],{"__ignoreMap":48},[112,10721,10722],{"class":114,"line":115},[112,10723,10724],{},"\u002F\u002F One line of auto_config.csv: \"3-Piece-Left,14.2,BlueAlliance\"\n",[112,10726,10727],{"class":114,"line":49},[112,10728,10729],{},"String line = scan.nextLine();\n",[112,10731,10732],{"class":114,"line":126},[112,10733,10734],{},"String[] fields = line.split(\",\");\n",[112,10736,10737],{"class":114,"line":132},[112,10738,10739],{},"String routeName = fields[0];       \u002F\u002F \"3-Piece-Left\"\n",[112,10741,10742],{"class":114,"line":138},[112,10743,10744],{},"double routeTime = Double.parseDouble(fields[1]); \u002F\u002F \"14.2\" -> 14.2\n",[112,10746,10747],{"class":114,"line":144},[112,10748,10749],{},"String alliance = fields[2];        \u002F\u002F \"BlueAlliance\"\n",[69,10751,10753],{"id":10752},"reading-into-an-array-or-arraylist","Reading Into an Array or ArrayList",[15,10755,10756,10757,10759],{},"If you know the line count in advance, an array works; otherwise, ",[95,10758,8682],{}," (Ch.9.2) avoids needing to know the size up front:",[104,10761,10763],{"className":106,"code":10762,"language":108,"meta":48,"style":48},"ArrayList\u003CString> configLines = new ArrayList\u003CString>();\nwhile (scan.hasNext())\n{\n    configLines.add(scan.nextLine());\n}\n",[95,10764,10765,10770,10774,10778,10783],{"__ignoreMap":48},[112,10766,10767],{"class":114,"line":115},[112,10768,10769],{},"ArrayList\u003CString> configLines = new ArrayList\u003CString>();\n",[112,10771,10772],{"class":114,"line":49},[112,10773,10665],{},[112,10775,10776],{"class":114,"line":126},[112,10777,123],{},[112,10779,10780],{"class":114,"line":132},[112,10781,10782],{},"    configLines.add(scan.nextLine());\n",[112,10784,10785],{"class":114,"line":138},[112,10786,153],{},[69,10788,10790],{"id":10789},"reading-into-objects","Reading Into Objects",[15,10792,10793,10794,10796],{},"Rather than working with raw ",[95,10795,10713],{}," rows, define a class matching the file's columns and build one object per row — the same has-a\u002Fobject-per-record idea from Ch.7:",[104,10798,10800],{"className":106,"code":10799,"language":108,"meta":48,"style":48},"ArrayList\u003CAutoRoute> routes = new ArrayList\u003CAutoRoute>();\nwhile (scan.hasNext())\n{\n    String[] fields = scan.nextLine().split(\",\");\n    routes.add(new AutoRoute(fields[0], Double.parseDouble(fields[1]), fields[2]));\n}\n",[95,10801,10802,10807,10811,10815,10820,10825],{"__ignoreMap":48},[112,10803,10804],{"class":114,"line":115},[112,10805,10806],{},"ArrayList\u003CAutoRoute> routes = new ArrayList\u003CAutoRoute>();\n",[112,10808,10809],{"class":114,"line":49},[112,10810,10665],{},[112,10812,10813],{"class":114,"line":126},[112,10814,123],{},[112,10816,10817],{"class":114,"line":132},[112,10818,10819],{},"    String[] fields = scan.nextLine().split(\",\");\n",[112,10821,10822],{"class":114,"line":138},[112,10823,10824],{},"    routes.add(new AutoRoute(fields[0], Double.parseDouble(fields[1]), fields[2]));\n",[112,10826,10827],{"class":114,"line":144},[112,10828,153],{},[69,10830,412],{"id":411},[19,10832,10833,10841,10851],{},[22,10834,10835,10840],{},[25,10836,3455,10837,10839],{},[95,10838,10612],{}," (or a try\u002Fcatch)."," Java won't compile file-reading code unless you've acknowledged that opening the file might fail.",[22,10842,10843,10850],{},[25,10844,10845,10846,10849],{},"Forgetting to ",[95,10847,10848],{},"close()"," the scanner."," A small leak that adds up in a program that opens many files.",[22,10852,10853,10856,10857,10860],{},[25,10854,10855],{},"Trying to parse a header row as data."," The first line of a CSV is often column names, not values — skip it (e.g. ",[95,10858,10859],{},"if (i == 0) scan.nextLine();",") before parsing rows as real data.",[69,10862,450],{"id":449},[19,10864,10865,10876,10884,10890],{},[22,10866,10867,10869,10870,10872,10873,10875],{},[95,10868,10565],{}," represents the file; ",[95,10871,10573],{}," reads from it — both can throw exceptions if the file can't be opened, which Java requires you to acknowledge (",[95,10874,10612],{},", or try\u002Fcatch).",[22,10877,10878,10880,10881,10883],{},[95,10879,10693],{}," combined with a ",[95,10882,5565],{}," loop is the standard pattern for reading an entire file, line by line.",[22,10885,10886,10889],{},[95,10887,10888],{},"String.split(\",\")"," breaks a CSV line into fields.",[22,10891,10892],{},"Reading rows into custom objects (one object per line) is cleaner than working with raw split arrays once the data has real structure.",[15,10894,493,10895,497,10897,10900],{},[95,10896,496],{},[95,10898,10899],{},"unit-4-data-collections\u002F4.06-using-text-files.md"," (CSA 4.6)",[503,10902,505],{},{"title":48,"searchDepth":49,"depth":49,"links":10904},[10905,10906,10907,10908,10909,10910,10911,10912],{"id":10552,"depth":49,"text":10553},{"id":10559,"depth":49,"text":10560},{"id":10654,"depth":49,"text":10655},{"id":10699,"depth":49,"text":10700},{"id":10752,"depth":49,"text":10753},{"id":10789,"depth":49,"text":10790},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":10914,"status":519},"9.8 — Using Text Files (CSA 4.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F8-using-text-files",{"title":10544,"description":48},"shockwave-curriculum\u002Flessons\u002Fch09-storing-data\u002F9.8-using-text-files","HPWzbr4-mV-Un8lfsU69ogqnTD49ERtOPnU9rhuFYwM",{"id":10920,"title":10921,"body":10922,"description":48,"extension":51,"meta":11218,"navigation":55,"path":11221,"seo":11222,"stem":11223,"__hash__":11224},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.1-2d-array-creation-and-access.md","2D Array Creation and Access",{"type":8,"value":10923,"toc":11208},[10924,10927,10931,10934,10949,10972,10976,10979,11018,11025,11028,11043,11050,11054,11060,11075,11092,11096,11118,11127,11129,11167,11169,11198,11206],[11,10925,10921],{"id":10926},"_2d-array-creation-and-access",[69,10928,10930],{"id":10929},"why-2d","Why 2D",[15,10932,10933],{},"Some data is naturally rows-and-columns, not just a flat list. Swerve drive telemetry is a good example: 4 modules (front-left, front-right, back-left, back-right), each logging several current-draw samples over time. That's a 2D array — one row per module, one column per sample.",[104,10935,10937],{"className":106,"code":10936,"language":108,"meta":48,"style":48},"\u002F\u002F datatype[][] variableName = new datatype[numberRows][numberCols];\ndouble[][] moduleCurrents = new double[4][5]; \u002F\u002F 4 modules, 5 samples each\n",[95,10938,10939,10944],{"__ignoreMap":48},[112,10940,10941],{"class":114,"line":115},[112,10942,10943],{},"\u002F\u002F datatype[][] variableName = new datatype[numberRows][numberCols];\n",[112,10945,10946],{"class":114,"line":49},[112,10947,10948],{},"double[][] moduleCurrents = new double[4][5]; \u002F\u002F 4 modules, 5 samples each\n",[15,10950,10951,10952,10955,10956,10959,10960,10962,10963,10965,10966,10968,10969,10971],{},"Java stores this as an ",[262,10953,10954],{},"array of arrays"," — the outer array holds 4 references, each pointing to its own 5-element inner array. Declared but not yet created (",[95,10957,10958],{},"double[][] moduleCurrents;"," with no ",[95,10961,2860],{},"), the variable is ",[95,10964,3384],{},", same as any other reference type. Once created with ",[95,10967,2860],{},", every element starts at that type's default (",[95,10970,1144],{}," here).",[69,10973,10975],{"id":10974},"initializer-lists","Initializer Lists",[15,10977,10978],{},"An initializer list for a 2D array is a list of 1D initializer lists, one per row — size is inferred:",[104,10980,10982],{"className":106,"code":10981,"language":108,"meta":48,"style":48},"double[][] moduleCurrents =\n{\n    {12.1, 11.8, 40.2, 12.4, 11.9}, \u002F\u002F front-left\n    {12.0, 11.9, 12.1, 11.7, 12.2}, \u002F\u002F front-right\n    {11.9, 12.3, 12.0, 11.8, 12.1}, \u002F\u002F back-left\n    {12.2, 12.0, 11.9, 12.4, 11.9}, \u002F\u002F back-right\n};\n",[95,10983,10984,10989,10993,10998,11003,11008,11013],{"__ignoreMap":48},[112,10985,10986],{"class":114,"line":115},[112,10987,10988],{},"double[][] moduleCurrents =\n",[112,10990,10991],{"class":114,"line":49},[112,10992,123],{},[112,10994,10995],{"class":114,"line":126},[112,10996,10997],{},"    {12.1, 11.8, 40.2, 12.4, 11.9}, \u002F\u002F front-left\n",[112,10999,11000],{"class":114,"line":132},[112,11001,11002],{},"    {12.0, 11.9, 12.1, 11.7, 12.2}, \u002F\u002F front-right\n",[112,11004,11005],{"class":114,"line":138},[112,11006,11007],{},"    {11.9, 12.3, 12.0, 11.8, 12.1}, \u002F\u002F back-left\n",[112,11009,11010],{"class":114,"line":144},[112,11011,11012],{},"    {12.2, 12.0, 11.9, 12.4, 11.9}, \u002F\u002F back-right\n",[112,11014,11015],{"class":114,"line":150},[112,11016,11017],{},"};\n",[69,11019,11021,11022],{"id":11020},"accessing-elements-arrrowcol","Accessing Elements: ",[95,11023,11024],{},"arr[row][col]",[15,11026,11027],{},"The first index is the row, the second is the column:",[104,11029,11031],{"className":106,"code":11030,"language":108,"meta":48,"style":48},"double spike = moduleCurrents[0][2]; \u002F\u002F front-left module, 3rd sample -> 40.2\nmoduleCurrents[0][2] = 0.0;          \u002F\u002F overwrite a bad reading\n",[95,11032,11033,11038],{"__ignoreMap":48},[112,11034,11035],{"class":114,"line":115},[112,11036,11037],{},"double spike = moduleCurrents[0][2]; \u002F\u002F front-left module, 3rd sample -> 40.2\n",[112,11039,11040],{"class":114,"line":49},[112,11041,11042],{},"moduleCurrents[0][2] = 0.0;          \u002F\u002F overwrite a bad reading\n",[15,11044,11045,11046,11049],{},"Printing a 2D array directly (",[95,11047,11048],{},"System.out.println(moduleCurrents)",") just prints its object reference, not its contents — printing every value takes nested loops (Lesson 10.2).",[69,11051,11053],{"id":11052},"row-and-column-counts","Row and Column Counts",[15,11055,11056,11057,11059],{},"The number of rows is ",[95,11058,8912],{},"; the number of columns is the length of any one row (AP CSA — and this curriculum — assumes every row has the same length, i.e. the array is rectangular, not \"ragged\"):",[104,11061,11063],{"className":106,"code":11062,"language":108,"meta":48,"style":48},"moduleCurrents.length     \u002F\u002F 4  (number of modules \u002F rows)\nmoduleCurrents[0].length  \u002F\u002F 5  (samples per module \u002F columns)\n",[95,11064,11065,11070],{"__ignoreMap":48},[112,11066,11067],{"class":114,"line":115},[112,11068,11069],{},"moduleCurrents.length     \u002F\u002F 4  (number of modules \u002F rows)\n",[112,11071,11072],{"class":114,"line":49},[112,11073,11074],{},"moduleCurrents[0].length  \u002F\u002F 5  (samples per module \u002F columns)\n",[15,11076,11077,11078,3883,11080,11082,11083,3883,11085,11088,11089,11091],{},"Valid row indices: ",[95,11079,1140],{},[95,11081,8471],{},". Valid column indices: ",[95,11084,1140],{},[95,11086,11087],{},"arr[0].length - 1",". An out-of-range index in either dimension throws ",[95,11090,8509],{},", same as a 1D array.",[69,11093,11095],{"id":11094},"java-stores-it-as-an-array-of-arrays","Java Stores It as an Array of Arrays",[15,11097,11098,11099,11102,11103,11105,11106,11109,11110,11113,11114,11117],{},"Internally, ",[95,11100,11101],{},"moduleCurrents"," is one 4-element outer array, where each element is a ",[262,11104,3211],{}," to its own separate 5-element inner array — not one giant contiguous block. That's why ",[95,11107,11108],{},"moduleCurrents[0]"," alone is a valid expression: it's a real, complete ",[95,11111,11112],{},"double[]"," (front-left's row), which is what makes ",[95,11115,11116],{},"moduleCurrents[0].length"," work.",[104,11119,11121],{"className":106,"code":11120,"language":108,"meta":48,"style":48},"double[] frontLeftRow = moduleCurrents[0]; \u002F\u002F a single row IS a real 1D array on its own\n",[95,11122,11123],{"__ignoreMap":48},[112,11124,11125],{"class":114,"line":115},[112,11126,11120],{},[69,11128,412],{"id":411},[19,11130,11131,11143,11152],{},[22,11132,11133,426,11136,11139,11140,11142],{},[25,11134,11135],{},"Swapping row and column.",[95,11137,11138],{},"moduleCurrents[2][0]"," is back-left's ",[262,11141,2973],{}," sample, not front-left's third — the first index is always the row.",[22,11144,11145,11151],{},[25,11146,1367,11147,11150],{},[95,11148,11149],{},"new double[4][5]"," gives usable data."," It gives 20 zeros, not real readings — same default-value rule as 1D arrays.",[22,11153,11154,11159,11160,11163,11164,79],{},[25,11155,11156,11157,79],{},"Off-by-one against ",[95,11158,8912],{}," The last valid row index is ",[95,11161,11162],{},"moduleCurrents.length - 1","; the last valid column index is ",[95,11165,11166],{},"moduleCurrents[0].length - 1",[69,11168,450],{"id":449},[19,11170,11171,11178,11183,11195],{},[22,11172,11173,11174,11177],{},"A 2D array is declared\u002Fcreated as ",[95,11175,11176],{},"datatype[][] name = new datatype[rows][cols];",", or filled in one step with a nested initializer list (one inner list per row).",[22,11179,11180,11182],{},[95,11181,11024],{}," reads or writes one element; the first index is always the row, the second the column.",[22,11184,11185,11187,11188,11190,11191,11194],{},[95,11186,8912],{}," gives the row count; ",[95,11189,8912],{}," on any one row (e.g. ",[95,11192,11193],{},"arr[0].length",") gives the column count.",[22,11196,11197],{},"Java implements a 2D array as an array of arrays — each row is itself a real, independent 1D array.",[15,11199,493,11200,497,11202,11205],{},[95,11201,496],{},[95,11203,11204],{},"unit-4-data-collections\u002F4.11-2d-array-creation-and-access.md"," (CSA 4.11)",[503,11207,505],{},{"title":48,"searchDepth":49,"depth":49,"links":11209},[11210,11211,11212,11214,11215,11216,11217],{"id":10929,"depth":49,"text":10930},{"id":10974,"depth":49,"text":10975},{"id":11020,"depth":49,"text":11213},"Accessing Elements: arr[row][col]",{"id":11052,"depth":49,"text":11053},{"id":11094,"depth":49,"text":11095},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":11219,"status":11220},"10.1 — 2D Array Creation and Access (CSA 4.11)","new — authored lesson","\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F1-2d-array-creation-and-access",{"title":10921,"description":48},"shockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.1-2d-array-creation-and-access","g_zQc9vhKB2Zz2ScFpCcyQD6MT_r9y7qlaLdZU7AYjM",{"id":11226,"title":11227,"body":11228,"description":48,"extension":51,"meta":11536,"navigation":55,"path":11538,"seo":11539,"stem":11540,"__hash__":11541},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.2-2d-array-traversals-nested-loops.md","2D Array Traversals: Nested Loops",{"type":8,"value":11229,"toc":11528},[11230,11233,11237,11240,11281,11295,11299,11306,11352,11355,11359,11362,11398,11412,11416,11430,11466,11468,11502,11504,11518,11526],[11,11231,11227],{"id":11232},"_2d-array-traversals-nested-loops",[69,11234,11236],{"id":11235},"nested-loops","Nested Loops",[15,11238,11239],{},"Since a 2D array is really an array of arrays, traversing every element takes a loop inside a loop — the outer loop walks the rows, the inner loop walks the columns of whichever row the outer loop is currently on:",[104,11241,11243],{"className":106,"code":11242,"language":108,"meta":48,"style":48},"double[][] moduleCurrents = { {12.1, 11.8, 40.2}, {12.0, 11.9, 12.1} };\nfor (int row = 0; row \u003C moduleCurrents.length; row++)\n{\n    for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n    {\n        System.out.println(moduleCurrents[row][col]);\n    }\n}\n",[95,11244,11245,11250,11255,11259,11264,11268,11273,11277],{"__ignoreMap":48},[112,11246,11247],{"class":114,"line":115},[112,11248,11249],{},"double[][] moduleCurrents = { {12.1, 11.8, 40.2}, {12.0, 11.9, 12.1} };\n",[112,11251,11252],{"class":114,"line":49},[112,11253,11254],{},"for (int row = 0; row \u003C moduleCurrents.length; row++)\n",[112,11256,11257],{"class":114,"line":126},[112,11258,123],{},[112,11260,11261],{"class":114,"line":132},[112,11262,11263],{},"    for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n",[112,11265,11266],{"class":114,"line":138},[112,11267,135],{},[112,11269,11270],{"class":114,"line":144},[112,11271,11272],{},"        System.out.println(moduleCurrents[row][col]);\n",[112,11274,11275],{"class":114,"line":150},[112,11276,147],{},[112,11278,11279],{"class":114,"line":1819},[112,11280,153],{},[15,11282,11283,11284,11287,11288,11291,11292,11294],{},"The loop body runs ",[95,11285,11286],{},"rows × columns"," times total. ",[95,11289,11290],{},"moduleCurrents.length"," is the row bound; ",[95,11293,11116],{}," is the column bound (safe here because the array is rectangular — every row has the same length).",[69,11296,11298],{"id":11297},"row-major-vs-column-major","Row-Major vs. Column-Major",[15,11300,11301,11302,11305],{},"Which index changes in the ",[262,11303,11304],{},"outer"," loop decides the traversal order:",[104,11307,11309],{"className":106,"code":11308,"language":108,"meta":48,"style":48},"\u002F\u002F Row-major: finish one module's samples before moving to the next module\nfor (int row = 0; row \u003C moduleCurrents.length; row++)\n    for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n        process(moduleCurrents[row][col]);\n\n\u002F\u002F Column-major: look at sample #0 across ALL modules, then sample #1 across all modules...\nfor (int col = 0; col \u003C moduleCurrents[0].length; col++)\n    for (int row = 0; row \u003C moduleCurrents.length; row++)\n        process(moduleCurrents[row][col]);\n",[95,11310,11311,11316,11320,11324,11329,11333,11338,11343,11348],{"__ignoreMap":48},[112,11312,11313],{"class":114,"line":115},[112,11314,11315],{},"\u002F\u002F Row-major: finish one module's samples before moving to the next module\n",[112,11317,11318],{"class":114,"line":49},[112,11319,11254],{},[112,11321,11322],{"class":114,"line":126},[112,11323,11263],{},[112,11325,11326],{"class":114,"line":132},[112,11327,11328],{},"        process(moduleCurrents[row][col]);\n",[112,11330,11331],{"class":114,"line":138},[112,11332,820],{"emptyLinePlaceholder":55},[112,11334,11335],{"class":114,"line":144},[112,11336,11337],{},"\u002F\u002F Column-major: look at sample #0 across ALL modules, then sample #1 across all modules...\n",[112,11339,11340],{"class":114,"line":150},[112,11341,11342],{},"for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n",[112,11344,11345],{"class":114,"line":1819},[112,11346,11347],{},"    for (int row = 0; row \u003C moduleCurrents.length; row++)\n",[112,11349,11350],{"class":114,"line":1825},[112,11351,11328],{},[15,11353,11354],{},"Row-major is the natural choice for \"how did this one module behave over time.\" Column-major is the natural choice for \"what was total robot current draw at this one instant\" — e.g. checking whether all 4 modules spiked simultaneously (a brownout risk), which row-major order would never surface directly.",[69,11356,11358],{"id":11357},"enhanced-for-each-nested","Enhanced For-Each, Nested",[15,11360,11361],{},"A nested for-each also traverses a 2D array, with no indices — but only when you don't need row\u002Fcolumn numbers or in-place modification of primitive values:",[104,11363,11365],{"className":106,"code":11364,"language":108,"meta":48,"style":48},"for (double[] moduleRow : moduleCurrents)  \u002F\u002F outer variable is a 1D array — one row\n{\n    for (double sample : moduleRow)        \u002F\u002F inner variable matches the element type\n    {\n        System.out.println(sample);\n    }\n}\n",[95,11366,11367,11372,11376,11381,11385,11390,11394],{"__ignoreMap":48},[112,11368,11369],{"class":114,"line":115},[112,11370,11371],{},"for (double[] moduleRow : moduleCurrents)  \u002F\u002F outer variable is a 1D array — one row\n",[112,11373,11374],{"class":114,"line":49},[112,11375,123],{},[112,11377,11378],{"class":114,"line":126},[112,11379,11380],{},"    for (double sample : moduleRow)        \u002F\u002F inner variable matches the element type\n",[112,11382,11383],{"class":114,"line":132},[112,11384,135],{},[112,11386,11387],{"class":114,"line":138},[112,11388,11389],{},"        System.out.println(sample);\n",[112,11391,11392],{"class":114,"line":144},[112,11393,147],{},[112,11395,11396],{"class":114,"line":150},[112,11397,153],{},[15,11399,11400,11401,11403,11404,11407,11408,11411],{},"Pattern to remember: the ",[25,11402,11304],{}," loop variable is typed as a 1D array (a whole row); the ",[25,11405,11406],{},"inner"," loop variable is typed as one element. As with 1D for-each (Lesson 9.4), reassigning ",[95,11409,11410],{},"sample"," inside the loop does not change what's stored in the array.",[69,11413,11415],{"id":11414},"_2d-arrays-of-objects-are-different","2D Arrays of Objects Are Different",[15,11417,11418,11419,11422,11423,11425,11426,11429],{},"The for-each modification limit above is about ",[262,11420,11421],{},"primitives",". A 2D array of objects — like a grid of ",[95,11424,2010],{}," motor wrappers, or a vision system's ",[95,11427,11428],{},"Pixel[][]"," — can still have its objects mutated through a for-each loop, because you're calling a method on the object the loop variable refers to, not reassigning the array slot itself:",[104,11431,11433],{"className":106,"code":11432,"language":108,"meta":48,"style":48},"for (TalonFX[] moduleRow : driveMotors)\n{\n    for (TalonFX motor : moduleRow)\n    {\n        motor.setNeutralMode(NeutralModeValue.Brake); \u002F\u002F mutates the real object — this works\n    }\n}\n",[95,11434,11435,11440,11444,11449,11453,11458,11462],{"__ignoreMap":48},[112,11436,11437],{"class":114,"line":115},[112,11438,11439],{},"for (TalonFX[] moduleRow : driveMotors)\n",[112,11441,11442],{"class":114,"line":49},[112,11443,123],{},[112,11445,11446],{"class":114,"line":126},[112,11447,11448],{},"    for (TalonFX motor : moduleRow)\n",[112,11450,11451],{"class":114,"line":132},[112,11452,135],{},[112,11454,11455],{"class":114,"line":138},[112,11456,11457],{},"        motor.setNeutralMode(NeutralModeValue.Brake); \u002F\u002F mutates the real object — this works\n",[112,11459,11460],{"class":114,"line":144},[112,11461,147],{},[112,11463,11464],{"class":114,"line":150},[112,11465,153],{},[69,11467,412],{"id":411},[19,11469,11470,11487,11496],{},[22,11471,11472,11477,11478,11481,11482,868,11484,11486],{},[25,11473,4590,11474,11476],{},[95,11475,11290],{}," as the inner loop's bound."," The inner loop walks ",[262,11479,11480],{},"columns",", so its bound is ",[95,11483,11116],{},[95,11485,11290],{}," (the row count).",[22,11488,11489,426,11492,11495],{},[25,11490,11491],{},"Expecting for-each to let you assign into a primitive 2D array.",[95,11493,11494],{},"for (double sample : moduleRow) { sample = 0.0; }"," changes nothing — same rule as 1D arrays.",[22,11497,11498,11501],{},[25,11499,11500],{},"Confusing row-major and column-major with \"correct\" and \"incorrect.\""," Neither is wrong — pick whichever matches what the question actually asks (per-module trends vs. per-instant totals).",[69,11503,450],{"id":449},[19,11505,11506,11509,11512,11515],{},[22,11507,11508],{},"Traversing a full 2D array needs nested loops: outer for rows, inner for columns.",[22,11510,11511],{},"Row-major order finishes one row before moving to the next; column-major order finishes one column (across all rows) before moving to the next — which one to use depends on what you're computing.",[22,11513,11514],{},"A nested for-each loop traverses a 2D array with no indices; its outer variable is a 1D array (one row), its inner variable matches the element type.",[22,11516,11517],{},"For-each can't modify a primitive 2D array's stored values, but it can call mutator methods on objects the array holds (like motor controllers).",[15,11519,493,11520,497,11522,11525],{},[95,11521,496],{},[95,11523,11524],{},"unit-4-data-collections\u002F4.12-2d-array-traversals-nested-loops.md"," (CSA 4.12)",[503,11527,505],{},{"title":48,"searchDepth":49,"depth":49,"links":11529},[11530,11531,11532,11533,11534,11535],{"id":11235,"depth":49,"text":11236},{"id":11297,"depth":49,"text":11298},{"id":11357,"depth":49,"text":11358},{"id":11414,"depth":49,"text":11415},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":11537,"status":11220},"10.2 — 2D Array Traversals: Nested Loops (CSA 4.12)","\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F2-2d-array-traversals-nested-loops",{"title":11227,"description":48},"shockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.2-2d-array-traversals-nested-loops","263lgoH1TTjJAFtW3moXWNE1uZVU8gUFulFfGQR--CY",{"id":11543,"title":11544,"body":11545,"description":11552,"extension":51,"meta":12088,"navigation":55,"path":12090,"seo":12091,"stem":12092,"__hash__":12093},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.3-implementing-2d-array-algorithms.md","Implementing 2D Array Algorithms",{"type":8,"value":11546,"toc":12079},[11547,11550,11553,11557,11645,11655,11659,11732,11738,11742,11745,11822,11826,11836,11938,11948,11952,11955,12001,12003,12053,12055,12069,12077],[11,11548,11544],{"id":11549},"implementing-2d-array-algorithms",[15,11551,11552],{},"Every algorithm shape from Lesson 9.5 (sum\u002Faverage, min\u002Fmax, property checks, duplicates) extends to 2D arrays — applied to the whole grid, or to just one row, one column, or a subsection.",[69,11554,11556],{"id":11555},"sum-a-row-sum-a-column","Sum a Row, Sum a Column",[104,11558,11560],{"className":106,"code":11559,"language":108,"meta":48,"style":48},"public static double getTotalForModule(int row, double[][] a)\n{\n    double total = 0;\n    for (int col = 0; col \u003C a[0].length; col++)\n    {\n        total = total + a[row][col];\n    }\n    return total;\n}\n\npublic static double getTotalForSample(int col, double[][] a)\n{\n    double total = 0;\n    for (int row = 0; row \u003C a.length; row++)\n    {\n        total = total + a[row][col];\n    }\n    return total;\n}\n",[95,11561,11562,11567,11571,11576,11581,11585,11590,11594,11599,11603,11607,11612,11616,11620,11625,11629,11633,11637,11641],{"__ignoreMap":48},[112,11563,11564],{"class":114,"line":115},[112,11565,11566],{},"public static double getTotalForModule(int row, double[][] a)\n",[112,11568,11569],{"class":114,"line":49},[112,11570,123],{},[112,11572,11573],{"class":114,"line":126},[112,11574,11575],{},"    double total = 0;\n",[112,11577,11578],{"class":114,"line":132},[112,11579,11580],{},"    for (int col = 0; col \u003C a[0].length; col++)\n",[112,11582,11583],{"class":114,"line":138},[112,11584,135],{},[112,11586,11587],{"class":114,"line":144},[112,11588,11589],{},"        total = total + a[row][col];\n",[112,11591,11592],{"class":114,"line":150},[112,11593,147],{},[112,11595,11596],{"class":114,"line":1819},[112,11597,11598],{},"    return total;\n",[112,11600,11601],{"class":114,"line":1825},[112,11602,153],{},[112,11604,11605],{"class":114,"line":1831},[112,11606,820],{"emptyLinePlaceholder":55},[112,11608,11609],{"class":114,"line":4742},[112,11610,11611],{},"public static double getTotalForSample(int col, double[][] a)\n",[112,11613,11614],{"class":114,"line":4748},[112,11615,123],{},[112,11617,11618],{"class":114,"line":6935},[112,11619,11575],{},[112,11621,11622],{"class":114,"line":6940},[112,11623,11624],{},"    for (int row = 0; row \u003C a.length; row++)\n",[112,11626,11627],{"class":114,"line":6946},[112,11628,135],{},[112,11630,11631],{"class":114,"line":6952},[112,11632,11589],{},[112,11634,11635],{"class":114,"line":6957},[112,11636,147],{},[112,11638,11639],{"class":114,"line":6963},[112,11640,11598],{},[112,11642,11643],{"class":114,"line":6968},[112,11644,153],{},[15,11646,11647,11650,11651,11654],{},[95,11648,11649],{},"getTotalForModule"," sums one module's row across all samples; ",[95,11652,11653],{},"getTotalForSample"," sums one instant's column across all 4 modules (useful for spotting a simultaneous-spike brownout).",[69,11656,11658],{"id":11657},"max-across-the-whole-array","Max Across the Whole Array",[104,11660,11662],{"className":106,"code":11661,"language":108,"meta":48,"style":48},"public static double getPeakCurrent(double[][] a)\n{\n    double peak = a[0][0];\n    for (int row = 0; row \u003C a.length; row++)\n    {\n        for (int col = 0; col \u003C a[0].length; col++)\n        {\n            if (a[row][col] > peak)\n            {\n                peak = a[row][col];\n            }\n        }\n    }\n    return peak;\n}\n",[95,11663,11664,11669,11673,11678,11682,11686,11691,11695,11700,11705,11710,11715,11719,11723,11728],{"__ignoreMap":48},[112,11665,11666],{"class":114,"line":115},[112,11667,11668],{},"public static double getPeakCurrent(double[][] a)\n",[112,11670,11671],{"class":114,"line":49},[112,11672,123],{},[112,11674,11675],{"class":114,"line":126},[112,11676,11677],{},"    double peak = a[0][0];\n",[112,11679,11680],{"class":114,"line":132},[112,11681,11624],{},[112,11683,11684],{"class":114,"line":138},[112,11685,135],{},[112,11687,11688],{"class":114,"line":144},[112,11689,11690],{},"        for (int col = 0; col \u003C a[0].length; col++)\n",[112,11692,11693],{"class":114,"line":150},[112,11694,7860],{},[112,11696,11697],{"class":114,"line":1819},[112,11698,11699],{},"            if (a[row][col] > peak)\n",[112,11701,11702],{"class":114,"line":1825},[112,11703,11704],{},"            {\n",[112,11706,11707],{"class":114,"line":1831},[112,11708,11709],{},"                peak = a[row][col];\n",[112,11711,11712],{"class":114,"line":4742},[112,11713,11714],{},"            }\n",[112,11716,11717],{"class":114,"line":4748},[112,11718,7870],{},[112,11720,11721],{"class":114,"line":6935},[112,11722,147],{},[112,11724,11725],{"class":114,"line":6940},[112,11726,11727],{},"    return peak;\n",[112,11729,11730],{"class":114,"line":6946},[112,11731,153],{},[15,11733,11734,11735,11737],{},"Same seed-with-the-first-real-value rule from Lesson 9.5 — seeding with ",[95,11736,1140],{}," would be wrong if every reading happened to be negative.",[69,11739,11741],{"id":11740},"a-subsection-only","A Subsection Only",[15,11743,11744],{},"Loop bounds don't have to cover the whole array — narrowing them checks just a range of rows\u002Fcolumns, e.g. counting how many samples in a given module range exceeded a spike threshold:",[104,11746,11748],{"className":106,"code":11747,"language":108,"meta":48,"style":48},"public static int countSpikes(double threshold, double[][] a,\n                               int rowStart, int rowEnd, int colStart, int colEnd)\n{\n    int count = 0;\n    for (int row = rowStart; row \u003C= rowEnd; row++)\n    {\n        for (int col = colStart; col \u003C= colEnd; col++)\n        {\n            if (a[row][col] > threshold)\n            {\n                count++;\n            }\n        }\n    }\n    return count;\n}\n",[95,11749,11750,11755,11760,11764,11769,11774,11778,11783,11787,11792,11796,11801,11805,11809,11813,11818],{"__ignoreMap":48},[112,11751,11752],{"class":114,"line":115},[112,11753,11754],{},"public static int countSpikes(double threshold, double[][] a,\n",[112,11756,11757],{"class":114,"line":49},[112,11758,11759],{},"                               int rowStart, int rowEnd, int colStart, int colEnd)\n",[112,11761,11762],{"class":114,"line":126},[112,11763,123],{},[112,11765,11766],{"class":114,"line":132},[112,11767,11768],{},"    int count = 0;\n",[112,11770,11771],{"class":114,"line":138},[112,11772,11773],{},"    for (int row = rowStart; row \u003C= rowEnd; row++)\n",[112,11775,11776],{"class":114,"line":144},[112,11777,135],{},[112,11779,11780],{"class":114,"line":150},[112,11781,11782],{},"        for (int col = colStart; col \u003C= colEnd; col++)\n",[112,11784,11785],{"class":114,"line":1819},[112,11786,7860],{},[112,11788,11789],{"class":114,"line":1825},[112,11790,11791],{},"            if (a[row][col] > threshold)\n",[112,11793,11794],{"class":114,"line":1831},[112,11795,11704],{},[112,11797,11798],{"class":114,"line":4742},[112,11799,11800],{},"                count++;\n",[112,11802,11803],{"class":114,"line":4748},[112,11804,11714],{},[112,11806,11807],{"class":114,"line":6935},[112,11808,7870],{},[112,11810,11811],{"class":114,"line":6940},[112,11812,147],{},[112,11814,11815],{"class":114,"line":6946},[112,11816,11817],{},"    return count;\n",[112,11819,11820],{"class":114,"line":6952},[112,11821,153],{},[69,11823,11825],{"id":11824},"duplicates-need-4-nested-loops","Duplicates Need 4 Nested Loops",[15,11827,11828,11829,11831,11832,11835],{},"A 1D duplicate check needs 2 nested loops (Lesson 9.5). A full 2D duplicate check needs ",[25,11830,1478],{},": two to pick a starting cell (row, col), and two more to compare it against every cell that comes ",[262,11833,11834],{},"after"," it — later columns in the same row, plus every cell in every later row:",[104,11837,11839],{"className":106,"code":11838,"language":108,"meta":48,"style":48},"public static boolean hasDuplicateReading(double[][] a)\n{\n    for (int row = 0; row \u003C a.length; row++)\n    {\n        for (int col = 0; col \u003C a[0].length; col++)\n        {\n            for (int row2 = row; row2 \u003C a.length; row2++)\n            {\n                int startCol = (row2 == row) ? col + 1 : 0;\n                for (int col2 = startCol; col2 \u003C a[0].length; col2++)\n                {\n                    if (a[row][col] == a[row2][col2])\n                    {\n                        return true;\n                    }\n                }\n            }\n        }\n    }\n    return false;\n}\n",[95,11840,11841,11846,11850,11854,11858,11862,11866,11871,11875,11880,11885,11890,11895,11900,11905,11910,11915,11919,11923,11927,11933],{"__ignoreMap":48},[112,11842,11843],{"class":114,"line":115},[112,11844,11845],{},"public static boolean hasDuplicateReading(double[][] a)\n",[112,11847,11848],{"class":114,"line":49},[112,11849,123],{},[112,11851,11852],{"class":114,"line":126},[112,11853,11624],{},[112,11855,11856],{"class":114,"line":132},[112,11857,135],{},[112,11859,11860],{"class":114,"line":138},[112,11861,11690],{},[112,11863,11864],{"class":114,"line":144},[112,11865,7860],{},[112,11867,11868],{"class":114,"line":150},[112,11869,11870],{},"            for (int row2 = row; row2 \u003C a.length; row2++)\n",[112,11872,11873],{"class":114,"line":1819},[112,11874,11704],{},[112,11876,11877],{"class":114,"line":1825},[112,11878,11879],{},"                int startCol = (row2 == row) ? col + 1 : 0;\n",[112,11881,11882],{"class":114,"line":1831},[112,11883,11884],{},"                for (int col2 = startCol; col2 \u003C a[0].length; col2++)\n",[112,11886,11887],{"class":114,"line":4742},[112,11888,11889],{},"                {\n",[112,11891,11892],{"class":114,"line":4748},[112,11893,11894],{},"                    if (a[row][col] == a[row2][col2])\n",[112,11896,11897],{"class":114,"line":6935},[112,11898,11899],{},"                    {\n",[112,11901,11902],{"class":114,"line":6940},[112,11903,11904],{},"                        return true;\n",[112,11906,11907],{"class":114,"line":6946},[112,11908,11909],{},"                    }\n",[112,11911,11912],{"class":114,"line":6952},[112,11913,11914],{},"                }\n",[112,11916,11917],{"class":114,"line":6957},[112,11918,11714],{},[112,11920,11921],{"class":114,"line":6963},[112,11922,7870],{},[112,11924,11925],{"class":114,"line":6968},[112,11926,147],{},[112,11928,11930],{"class":114,"line":11929},20,[112,11931,11932],{},"    return false;\n",[112,11934,11936],{"class":114,"line":11935},21,[112,11937,153],{},[15,11939,1936,11940,11943,11944,11947],{},[95,11941,11942],{},"startCol"," trick avoids comparing a pair twice: within the same row (",[95,11945,11946],{},"row2 == row","), only look at columns after the candidate's own column; in a later row, every column is fair game.",[69,11949,11951],{"id":11950},"rotatereverse-a-single-row-or-column","Rotate\u002FReverse a Single Row or Column",[15,11953,11954],{},"Rotating or reversing just one row (or one \"virtual column\" — a fixed column index across every row) works exactly like the 1D version from Lesson 9.5, because you're really only touching one 1D array at a time:",[104,11956,11958],{"className":106,"code":11957,"language":108,"meta":48,"style":48},"public static void rotateRowRight(double[][] a, int row)\n{\n    double last = a[row][a[0].length - 1];\n    for (int col = a[0].length - 1; col > 0; col--)\n    {\n        a[row][col] = a[row][col - 1];\n    }\n    a[row][0] = last;\n}\n",[95,11959,11960,11965,11969,11974,11979,11983,11988,11992,11997],{"__ignoreMap":48},[112,11961,11962],{"class":114,"line":115},[112,11963,11964],{},"public static void rotateRowRight(double[][] a, int row)\n",[112,11966,11967],{"class":114,"line":49},[112,11968,123],{},[112,11970,11971],{"class":114,"line":126},[112,11972,11973],{},"    double last = a[row][a[0].length - 1];\n",[112,11975,11976],{"class":114,"line":132},[112,11977,11978],{},"    for (int col = a[0].length - 1; col > 0; col--)\n",[112,11980,11981],{"class":114,"line":138},[112,11982,135],{},[112,11984,11985],{"class":114,"line":144},[112,11986,11987],{},"        a[row][col] = a[row][col - 1];\n",[112,11989,11990],{"class":114,"line":150},[112,11991,147],{},[112,11993,11994],{"class":114,"line":1819},[112,11995,11996],{},"    a[row][0] = last;\n",[112,11998,11999],{"class":114,"line":1825},[112,12000,153],{},[69,12002,412],{"id":411},[19,12004,12005,12022,12031],{},[22,12006,12007,12010,12011,12013,12014,12016,12017,12013,12019,12021],{},[25,12008,12009],{},"Confusing \"sum a row\" with \"sum a column.\""," Fixing ",[95,12012,4104],{}," and looping ",[95,12015,4108],{}," sums a row; fixing ",[95,12018,4108],{},[95,12020,4104],{}," sums a column — it's easy to write the wrong one by habit.",[22,12023,12024,12030],{},[25,12025,12026,12027,12029],{},"Forgetting the duplicate check's ",[95,12028,11942],{}," trick."," Without it, a 2D duplicate search either misses valid pairs or double-compares the same pair twice.",[22,12032,12033,426,12040,10706,12043,1051,12046,12049,12050,12052],{},[25,12034,4590,12035,3972,12037,12039],{},[95,12036,3945],{},[95,12038,3951],{}," on subsection bounds that are meant to be inclusive.",[95,12041,12042],{},"countSpikes",[95,12044,12045],{},"rowEnd",[95,12047,12048],{},"colEnd"," are inclusive bounds by design — a ",[95,12051,3945],{}," would silently skip the last row\u002Fcolumn.",[69,12054,450],{"id":449},[19,12056,12057,12060,12063,12066],{},[22,12058,12059],{},"Every 1D array algorithm pattern (accumulator, min\u002Fmax, property count, duplicates, rotate) extends to 2D — applied to the whole array, one row, one column, or a bounded subsection.",[22,12061,12062],{},"Summing a row fixes the row index and loops columns; summing a column fixes the column index and loops rows.",[22,12064,12065],{},"A full 2D duplicate check needs 4 nested loops, not 2 — two to pick the candidate cell, two more to scan every cell that comes after it without re-checking any pair.",[22,12067,12068],{},"Rotating or reversing a single row (or a fixed-column \"column slice\") reuses the exact 1D in-place pattern from Lesson 9.5.",[15,12070,493,12071,497,12073,12076],{},[95,12072,496],{},[95,12074,12075],{},"unit-4-data-collections\u002F4.13-implementing-2d-array-algorithms.md"," (CSA 4.13)",[503,12078,505],{},{"title":48,"searchDepth":49,"depth":49,"links":12080},[12081,12082,12083,12084,12085,12086,12087],{"id":11555,"depth":49,"text":11556},{"id":11657,"depth":49,"text":11658},{"id":11740,"depth":49,"text":11741},{"id":11824,"depth":49,"text":11825},{"id":11950,"depth":49,"text":11951},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":12089,"status":11220},"10.3 — Implementing 2D Array Algorithms (CSA 4.13)","\u002Fshockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F3-implementing-2d-array-algorithms",{"title":11544,"description":11552},"shockwave-curriculum\u002Flessons\u002Fch10-2d-arrays\u002F10.3-implementing-2d-array-algorithms","6J1XIMNS6Zq4XeTVajuRWbbogZmuPV8ZbcFVYqEvPeQ",{"id":12095,"title":12096,"body":12097,"description":48,"extension":51,"meta":12514,"navigation":55,"path":12516,"seo":12517,"stem":12518,"__hash__":12519},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch11-enums-named-choices\u002F11-enums-named-choices.md","Enums: Named Choices",{"type":8,"value":12098,"toc":12503},[12099,12102,12106,12116,12153,12159,12163,12176,12209,12219,12223,12226,12301,12328,12331,12340,12347,12353,12376,12380,12395,12399,12409,12411,12456,12458,12489,12501],[11,12100,12096],{"id":12101},"enums-named-choices",[69,12103,12105],{"id":12104},"why-enums-exist","Why Enums Exist",[15,12107,1541,12108,12111,12112,12115],{},[25,12109,12110],{},"enum"," (\"enumerated type\") is a type with a fixed, predefined set of named values — a variable of that type can only ever be one of those values, nothing else. Before enums, code often used plain integers or strings to represent a fixed set of states (",[95,12113,12114],{},"int armState = 2;","), which lets any number in — including ones that mean nothing. An enum makes invalid states impossible to even compile:",[104,12117,12119],{"className":106,"code":12118,"language":108,"meta":48,"style":48},"public enum ArmPosition\n{\n    STOWED, INTAKE, SCORE\n}\n\nArmPosition target = ArmPosition.INTAKE; \u002F\u002F legal\nArmPosition target = ArmPosition.CLIMB;  \u002F\u002F compile error — CLIMB was never defined\n",[95,12120,12121,12126,12130,12135,12139,12143,12148],{"__ignoreMap":48},[112,12122,12123],{"class":114,"line":115},[112,12124,12125],{},"public enum ArmPosition\n",[112,12127,12128],{"class":114,"line":49},[112,12129,123],{},[112,12131,12132],{"class":114,"line":126},[112,12133,12134],{},"    STOWED, INTAKE, SCORE\n",[112,12136,12137],{"class":114,"line":132},[112,12138,153],{},[112,12140,12141],{"class":114,"line":138},[112,12142,820],{"emptyLinePlaceholder":55},[112,12144,12145],{"class":114,"line":144},[112,12146,12147],{},"ArmPosition target = ArmPosition.INTAKE; \u002F\u002F legal\n",[112,12149,12150],{"class":114,"line":150},[112,12151,12152],{},"ArmPosition target = ArmPosition.CLIMB;  \u002F\u002F compile error — CLIMB was never defined\n",[15,12154,12155,12156,12158],{},"By convention, enum constants are written in ",[95,12157,324],{},", the same naming style used for other constants (Lesson 1.2).",[69,12160,12162],{"id":12161},"switching-over-an-enum","Switching Over an Enum",[15,12164,355,12165,12168,12169,12172,12173,687],{},[95,12166,12167],{},"switch"," over an enum reads close to plain English, and (with modern arrow-style ",[95,12170,12171],{},"case",") needs no ",[95,12174,12175],{},"break",[104,12177,12179],{"className":106,"code":12178,"language":108,"meta":48,"style":48},"switch (target)\n{\n    case STOWED -> arm.setAngle(0);\n    case INTAKE -> arm.setAngle(35);\n    case SCORE  -> arm.setAngle(110);\n}\n",[95,12180,12181,12186,12190,12195,12200,12205],{"__ignoreMap":48},[112,12182,12183],{"class":114,"line":115},[112,12184,12185],{},"switch (target)\n",[112,12187,12188],{"class":114,"line":49},[112,12189,123],{},[112,12191,12192],{"class":114,"line":126},[112,12193,12194],{},"    case STOWED -> arm.setAngle(0);\n",[112,12196,12197],{"class":114,"line":132},[112,12198,12199],{},"    case INTAKE -> arm.setAngle(35);\n",[112,12201,12202],{"class":114,"line":138},[112,12203,12204],{},"    case SCORE  -> arm.setAngle(110);\n",[112,12206,12207],{"class":114,"line":144},[112,12208,153],{},[15,12210,12211,12212,868,12215,12218],{},"Notice the case labels are just ",[95,12213,12214],{},"STOWED",[95,12216,12217],{},"ArmPosition.STOWED"," — inside a switch over an enum, Java already knows the type, so the prefix would be redundant (and doesn't compile).",[69,12220,12222],{"id":12221},"an-enum-is-really-a-class","An Enum Is Really a Class",[15,12224,12225],{},"An enum isn't just a fancier set of named integers — it's a full class. Its body can declare fields, a constructor, and methods, letting each constant carry its own data:",[104,12227,12229],{"className":106,"code":12228,"language":108,"meta":48,"style":48},"public enum ArmPosition\n{\n    STOWED(0), INTAKE(35), SCORE(110); \u002F\u002F constants, WITH constructor arguments\n\n    private final double angleDegrees;\n\n    ArmPosition(double angleDegrees)\n    {\n        this.angleDegrees = angleDegrees;\n    }\n\n    public double getAngleDegrees()\n    {\n        return angleDegrees;\n    }\n}\n",[95,12230,12231,12235,12239,12244,12248,12253,12257,12262,12266,12271,12275,12279,12284,12288,12293,12297],{"__ignoreMap":48},[112,12232,12233],{"class":114,"line":115},[112,12234,12125],{},[112,12236,12237],{"class":114,"line":49},[112,12238,123],{},[112,12240,12241],{"class":114,"line":126},[112,12242,12243],{},"    STOWED(0), INTAKE(35), SCORE(110); \u002F\u002F constants, WITH constructor arguments\n",[112,12245,12246],{"class":114,"line":132},[112,12247,820],{"emptyLinePlaceholder":55},[112,12249,12250],{"class":114,"line":138},[112,12251,12252],{},"    private final double angleDegrees;\n",[112,12254,12255],{"class":114,"line":144},[112,12256,820],{"emptyLinePlaceholder":55},[112,12258,12259],{"class":114,"line":150},[112,12260,12261],{},"    ArmPosition(double angleDegrees)\n",[112,12263,12264],{"class":114,"line":1819},[112,12265,135],{},[112,12267,12268],{"class":114,"line":1825},[112,12269,12270],{},"        this.angleDegrees = angleDegrees;\n",[112,12272,12273],{"class":114,"line":1831},[112,12274,147],{},[112,12276,12277],{"class":114,"line":4742},[112,12278,820],{"emptyLinePlaceholder":55},[112,12280,12281],{"class":114,"line":4748},[112,12282,12283],{},"    public double getAngleDegrees()\n",[112,12285,12286],{"class":114,"line":6935},[112,12287,135],{},[112,12289,12290],{"class":114,"line":6940},[112,12291,12292],{},"        return angleDegrees;\n",[112,12294,12295],{"class":114,"line":6946},[112,12296,147],{},[112,12298,12299],{"class":114,"line":6952},[112,12300,153],{},[15,12302,12303,12304,12306,12307,275,12310,275,12313,12316,12317,12319,12320,12323,12324,12327],{},"Two rules this pattern depends on: the list of constants must come ",[25,12305,2973],{}," in the enum body, and once there are fields or methods after it, that constant list must end with a semicolon. Each constant listed (",[95,12308,12309],{},"STOWED(0)",[95,12311,12312],{},"INTAKE(35)",[95,12314,12315],{},"SCORE(110)",") calls the constructor with its own arguments — an enum's constructor is implicitly ",[95,12318,6806],{},", since you're never allowed to write ",[95,12321,12322],{},"new ArmPosition(...)"," yourself; the only ",[95,12325,12326],{},"ArmPosition"," objects that will ever exist are the ones listed in the enum body.",[15,12329,12330],{},"With this version, the earlier switch could be simplified — every position now carries its own target angle:",[104,12332,12334],{"className":106,"code":12333,"language":108,"meta":48,"style":48},"arm.setAngle(target.getAngleDegrees());\n",[95,12335,12336],{"__ignoreMap":48},[112,12337,12338],{"class":114,"line":115},[112,12339,12333],{},[69,12341,12343,12344],{"id":12342},"iterating-every-value-values","Iterating Every Value: ",[95,12345,12346],{},"values()",[15,12348,12349,12350,12352],{},"Every enum automatically gets a static ",[95,12351,12346],{}," method, returning an array of all its constants in declared order — handy for looping over every possibility:",[104,12354,12356],{"className":106,"code":12355,"language":108,"meta":48,"style":48},"for (ArmPosition position : ArmPosition.values())\n{\n    System.out.println(position + \" -> \" + position.getAngleDegrees() + \" degrees\");\n}\n",[95,12357,12358,12363,12367,12372],{"__ignoreMap":48},[112,12359,12360],{"class":114,"line":115},[112,12361,12362],{},"for (ArmPosition position : ArmPosition.values())\n",[112,12364,12365],{"class":114,"line":49},[112,12366,123],{},[112,12368,12369],{"class":114,"line":126},[112,12370,12371],{},"    System.out.println(position + \" -> \" + position.getAngleDegrees() + \" degrees\");\n",[112,12373,12374],{"class":114,"line":132},[112,12375,153],{},[69,12377,12379],{"id":12378},"what-enums-cant-do","What Enums Can't Do",[15,12381,12382,12383,12386,12387,12390,12391,12394],{},"Every enum implicitly extends ",[95,12384,12385],{},"java.lang.Enum"," behind the scenes. Since Java only allows extending one parent class, an enum can never ",[95,12388,12389],{},"extends"," anything else of its own — though it can still ",[95,12392,12393],{},"implement"," interfaces.",[69,12396,12398],{"id":12397},"looking-ahead","Looking Ahead",[15,12400,12401,12402,12404,12405,12408],{},"This chapter's ideas — a fixed set of named states, plus a ",[95,12403,12167],{}," that reacts to whichever one is currently active — are exactly the foundation the ",[25,12406,12407],{},"State Machine"," pattern (Java II) builds on, where a subsystem tracks \"which named state am I in right now\" and transitions between them over time.",[69,12410,412],{"id":411},[19,12412,12413,12430,12445],{},[22,12414,12415,426,12420,12423,12424,12426,12427,79],{},[25,12416,12417,12418,79],{},"Writing the enum type prefix inside a ",[95,12419,12167],{},[95,12421,12422],{},"case ArmPosition.INTAKE ->"," doesn't compile inside a switch over an ",[95,12425,12326],{}," — just ",[95,12428,12429],{},"case INTAKE ->",[22,12431,12432,426,12435,12438,12439,1176,12441,12444],{},[25,12433,12434],{},"Forgetting the semicolon after the constant list once fields\u002Fmethods follow.",[95,12436,12437],{},"STOWED(0), INTAKE(35), SCORE(110)"," with no trailing ",[95,12440,185],{},[95,12442,12443],{},"private final double angleDegrees;"," fails to compile.",[22,12446,12447,426,12453,12455],{},[25,12448,12449,12450,12452],{},"Trying to ",[95,12451,2860],{}," an enum constant.",[95,12454,12322],{}," is illegal — the only instances that will ever exist are the constants declared in the enum body itself.",[69,12457,450],{"id":449},[19,12459,12460,12463,12474,12477,12483],{},[22,12461,12462],{},"An enum defines a fixed, named set of legal values for a type — the compiler rejects anything not in that list.",[22,12464,12465,12466,12468,12469,12471,12472,79],{},"Enum constant names use ",[95,12467,324],{},"; a ",[95,12470,12167],{}," over an enum omits the type prefix on each ",[95,12473,12171],{},[22,12475,12476],{},"An enum is a real class — it can have its own fields, a constructor, and methods, letting each constant carry its own data.",[22,12478,12479,12482],{},[95,12480,12481],{},"EnumType.values()"," returns every constant, in order, for looping.",[22,12484,12485,12486,12488],{},"An enum implicitly extends ",[95,12487,12385],{},", so it can't extend any other class (interfaces are still fine).",[15,12490,493,12491,497,12494,12497,12498,12500],{},[95,12492,12493],{},"other-reference-repo",[95,12495,12496],{},"oracle-java-tutorials\u002Fenums\u002Fenum-types.md"," (ORACLE 10.1)\n",[25,12499,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js, slide 9 (\"Enums: Named Choices\")",[503,12502,505],{},{"title":48,"searchDepth":49,"depth":49,"links":12504},[12505,12506,12507,12508,12510,12511,12512,12513],{"id":12104,"depth":49,"text":12105},{"id":12161,"depth":49,"text":12162},{"id":12221,"depth":49,"text":12222},{"id":12342,"depth":49,"text":12509},"Iterating Every Value: values()",{"id":12378,"depth":49,"text":12379},{"id":12397,"depth":49,"text":12398},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":12515,"status":519},"11 — Enums: Named Choices (ORACLE 10.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch11-enums-named-choices\u002F11-enums-named-choices",{"title":12096,"description":48},"shockwave-curriculum\u002Flessons\u002Fch11-enums-named-choices\u002F11-enums-named-choices","OACHgpDBFfHnWGhWa3Uv5fINoC6h_-0Ks3IQInruIvc",{"id":12521,"title":12522,"body":12523,"description":48,"extension":51,"meta":13118,"navigation":55,"path":13120,"seo":13121,"stem":13122,"__hash__":13123},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch12-exceptions-and-try-catch\u002F12-exceptions-and-try-catch.md","Exceptions & try\u002Fcatch",{"type":8,"value":12524,"toc":13106},[12525,12528,12532,12546,12565,12569,12578,12629,12647,12655,12713,12716,12728,12809,12813,12816,12852,12864,12870,12873,12905,12913,12920,12930,12971,12991,12993,13040,13042,13081,13104],[11,12526,12522],{"id":12527},"exceptions-trycatch",[69,12529,12531],{"id":12530},"what-an-exception-is","What an Exception Is",[15,12533,1541,12534,12537,12538,12541,12542,12545],{},[25,12535,12536],{},"exception"," is an \"exceptional event\" — something that disrupts a program's normal flow while it runs (a file that doesn't exist, an array index that's out of range, dividing by zero). When an error occurs, the method creates an ",[25,12539,12540],{},"exception object"," describing what went wrong and hands it to the Java runtime — this is called ",[25,12543,12544],{},"throwing"," the exception.",[15,12547,12548,12549,12552,12553,12556,12557,12560,12561,12564],{},"The runtime then searches back up the ",[25,12550,12551],{},"call stack"," (the chain of methods that led to this point) looking for an ",[25,12554,12555],{},"exception handler"," — a block of code able to deal with that type of exception. The first matching handler it finds is said to ",[25,12558,12559],{},"catch"," the exception. If nothing on the whole call stack can handle it, the runtime terminates the program: on a robot, an uncaught exception in ",[95,12562,12563],{},"periodic()"," is exactly what turns the Driver Station's \"Robot Code\" indicator red.",[69,12566,12568],{"id":12567},"try-catch","try \u002F catch",[15,12570,355,12571,12574,12575,12577],{},[95,12572,12573],{},"try"," block wraps code that might throw; a ",[95,12576,12559],{}," block that follows it handles a specific exception type if one occurs:",[104,12579,12581],{"className":106,"code":12580,"language":108,"meta":48,"style":48},"try\n{\n    config = loadFromFile(\"tuning.json\");\n}\ncatch (IOException e)\n{\n    \u002F\u002F Recover: fall back to defaults\n    config = Config.defaults();\n    reportWarning(\"Using default tuning\");\n}\n",[95,12582,12583,12588,12592,12597,12601,12606,12610,12615,12620,12625],{"__ignoreMap":48},[112,12584,12585],{"class":114,"line":115},[112,12586,12587],{},"try\n",[112,12589,12590],{"class":114,"line":49},[112,12591,123],{},[112,12593,12594],{"class":114,"line":126},[112,12595,12596],{},"    config = loadFromFile(\"tuning.json\");\n",[112,12598,12599],{"class":114,"line":132},[112,12600,153],{},[112,12602,12603],{"class":114,"line":138},[112,12604,12605],{},"catch (IOException e)\n",[112,12607,12608],{"class":114,"line":144},[112,12609,123],{},[112,12611,12612],{"class":114,"line":150},[112,12613,12614],{},"    \u002F\u002F Recover: fall back to defaults\n",[112,12616,12617],{"class":114,"line":1819},[112,12618,12619],{},"    config = Config.defaults();\n",[112,12621,12622],{"class":114,"line":1825},[112,12623,12624],{},"    reportWarning(\"Using default tuning\");\n",[112,12626,12627],{"class":114,"line":1831},[112,12628,153],{},[15,12630,5153,12631,6186,12634,12637,12638,12640,12641,12643,12644,12646],{},[95,12632,12633],{},"loadFromFile",[95,12635,12636],{},"IOException",", execution jumps straight into the matching ",[95,12639,12559],{}," block — the rest of the ",[95,12642,12573],{}," block is skipped. If no exception occurs, the ",[95,12645,12559],{}," block never runs at all.",[15,12648,355,12649,12651,12652,12654],{},[95,12650,12573],{}," can have multiple ",[95,12653,12559],{}," blocks, checked in order, for handling different exception types differently:",[104,12656,12658],{"className":106,"code":12657,"language":108,"meta":48,"style":48},"try\n{\n    camera = new UsbCamera(\"Camera 1\", 0);\n}\ncatch (VideoException e)\n{\n    reportWarning(\"Camera unavailable — skipping vision this match\");\n}\ncatch (IllegalArgumentException e)\n{\n    reportWarning(\"Bad camera config — check the port number\");\n}\n",[95,12659,12660,12664,12668,12673,12677,12682,12686,12691,12695,12700,12704,12709],{"__ignoreMap":48},[112,12661,12662],{"class":114,"line":115},[112,12663,12587],{},[112,12665,12666],{"class":114,"line":49},[112,12667,123],{},[112,12669,12670],{"class":114,"line":126},[112,12671,12672],{},"    camera = new UsbCamera(\"Camera 1\", 0);\n",[112,12674,12675],{"class":114,"line":132},[112,12676,153],{},[112,12678,12679],{"class":114,"line":138},[112,12680,12681],{},"catch (VideoException e)\n",[112,12683,12684],{"class":114,"line":144},[112,12685,123],{},[112,12687,12688],{"class":114,"line":150},[112,12689,12690],{},"    reportWarning(\"Camera unavailable — skipping vision this match\");\n",[112,12692,12693],{"class":114,"line":1819},[112,12694,153],{},[112,12696,12697],{"class":114,"line":1825},[112,12698,12699],{},"catch (IllegalArgumentException e)\n",[112,12701,12702],{"class":114,"line":1831},[112,12703,123],{},[112,12705,12706],{"class":114,"line":4742},[112,12707,12708],{},"    reportWarning(\"Bad camera config — check the port number\");\n",[112,12710,12711],{"class":114,"line":4748},[112,12712,153],{},[69,12714,12715],{"id":12715},"finally",[15,12717,12718,12719,12721,12722,12724,12725,12727],{},"An optional ",[95,12720,12715],{}," block, after all the ",[95,12723,12559],{}," blocks, always runs — whether an exception was thrown or not, and even if the ",[95,12726,12559],{}," block itself returns early. It's the right place for cleanup that must happen no matter what (closing a file, releasing a resource):",[104,12729,12731],{"className":106,"code":12730,"language":108,"meta":48,"style":48},"Scanner scan = null;\ntry\n{\n    scan = new Scanner(new File(\"auto_config.csv\"));\n    \u002F\u002F ... read the file ...\n}\ncatch (FileNotFoundException e)\n{\n    reportWarning(\"Missing auto_config.csv — using default route\");\n}\nfinally\n{\n    if (scan != null)\n    {\n        scan.close(); \u002F\u002F runs whether the try succeeded, failed, or even returned early\n    }\n}\n",[95,12732,12733,12738,12742,12746,12751,12756,12760,12765,12769,12774,12778,12783,12787,12792,12796,12801,12805],{"__ignoreMap":48},[112,12734,12735],{"class":114,"line":115},[112,12736,12737],{},"Scanner scan = null;\n",[112,12739,12740],{"class":114,"line":49},[112,12741,12587],{},[112,12743,12744],{"class":114,"line":126},[112,12745,123],{},[112,12747,12748],{"class":114,"line":132},[112,12749,12750],{},"    scan = new Scanner(new File(\"auto_config.csv\"));\n",[112,12752,12753],{"class":114,"line":138},[112,12754,12755],{},"    \u002F\u002F ... read the file ...\n",[112,12757,12758],{"class":114,"line":144},[112,12759,153],{},[112,12761,12762],{"class":114,"line":150},[112,12763,12764],{},"catch (FileNotFoundException e)\n",[112,12766,12767],{"class":114,"line":1819},[112,12768,123],{},[112,12770,12771],{"class":114,"line":1825},[112,12772,12773],{},"    reportWarning(\"Missing auto_config.csv — using default route\");\n",[112,12775,12776],{"class":114,"line":1831},[112,12777,153],{},[112,12779,12780],{"class":114,"line":4742},[112,12781,12782],{},"finally\n",[112,12784,12785],{"class":114,"line":4748},[112,12786,123],{},[112,12788,12789],{"class":114,"line":6935},[112,12790,12791],{},"    if (scan != null)\n",[112,12793,12794],{"class":114,"line":6940},[112,12795,135],{},[112,12797,12798],{"class":114,"line":6946},[112,12799,12800],{},"        scan.close(); \u002F\u002F runs whether the try succeeded, failed, or even returned early\n",[112,12802,12803],{"class":114,"line":6952},[112,12804,147],{},[112,12806,12807],{"class":114,"line":6957},[112,12808,153],{},[69,12810,12812],{"id":12811},"checked-vs-unchecked-exceptions","Checked vs. Unchecked Exceptions",[15,12814,12815],{},"Java splits exceptions into two kinds, and the difference matters for what the compiler demands of you:",[19,12817,12818,12834],{},[22,12819,12820,12823,12824,12826,12827,12829,12830,12833],{},[25,12821,12822],{},"Checked exceptions"," (like ",[95,12825,12636],{},") — the compiler forces you to either ",[95,12828,12559],{}," them or declare them with a ",[95,12831,12832],{},"throws"," clause. They represent problems a caller could reasonably be expected to recover from.",[22,12835,12836,12839,12840,12843,12844,275,12846,275,12848,12851],{},[25,12837,12838],{},"Unchecked exceptions"," (",[95,12841,12842],{},"RuntimeException"," and its subclasses — ",[95,12845,3414],{},[95,12847,8509],{},[95,12849,12850],{},"ArithmeticException",") — the compiler does not require handling them at all, though you're always allowed to. They almost always represent a genuine programming bug (a null you forgot to check, an index you miscalculated) rather than something the caller can meaningfully recover from at runtime.",[15,12853,12854,12855,12858,12859,1051,12861,12863],{},"Guideline from the language's own designers: ",[262,12856,12857],{},"if a client can reasonably be expected to recover from a problem, make it checked; if a client can't do anything useful about it, make it unchecked."," This is also why CSA covers unchecked-exception concepts (NullPointerException, ArrayIndexOutOfBoundsException) as topics in their own right, without ever teaching the ",[95,12860,12573],{},[95,12862,12559],{}," mechanism itself — the AP exam doesn't test it.",[69,12865,1936,12867,12869],{"id":12866},"the-throws-clause",[95,12868,12832],{}," Clause",[15,12871,12872],{},"If a method doesn't want to handle a checked exception itself, it can instead declare that it might throw one, pushing the decision up to whoever calls it:",[104,12874,12876],{"className":106,"code":12875,"language":108,"meta":48,"style":48},"public void writeList() throws IOException\n{\n    PrintWriter out = new PrintWriter(new FileWriter(\"OutFile.txt\"));\n    \u002F\u002F ...\n    out.close();\n}\n",[95,12877,12878,12883,12887,12892,12896,12901],{"__ignoreMap":48},[112,12879,12880],{"class":114,"line":115},[112,12881,12882],{},"public void writeList() throws IOException\n",[112,12884,12885],{"class":114,"line":49},[112,12886,123],{},[112,12888,12889],{"class":114,"line":126},[112,12890,12891],{},"    PrintWriter out = new PrintWriter(new FileWriter(\"OutFile.txt\"));\n",[112,12893,12894],{"class":114,"line":132},[112,12895,10642],{},[112,12897,12898],{"class":114,"line":138},[112,12899,12900],{},"    out.close();\n",[112,12902,12903],{"class":114,"line":144},[112,12904,153],{},[15,12906,12907,12909,12910,12912],{},[95,12908,12832],{}," goes after the parameter list, before the method body's opening brace. Unchecked exceptions never need to appear in a ",[95,12911,12832],{}," clause (though nothing stops you from listing one).",[69,12914,1936,12916,12919],{"id":12915},"the-throw-statement",[95,12917,12918],{},"throw"," Statement",[15,12921,12922,12923,12925,12926,12929],{},"Any code — yours, a library's, or the Java runtime itself — can trigger an exception with the ",[95,12924,12918],{}," statement, given any object that's a ",[95,12927,12928],{},"Throwable"," (or a subclass):",[104,12931,12933],{"className":106,"code":12932,"language":108,"meta":48,"style":48},"public void setTargetAngle(double degrees)\n{\n    if (degrees \u003C 0 || degrees > 180)\n    {\n        throw new IllegalArgumentException(\"Angle out of range: \" + degrees);\n    }\n    this.targetAngle = degrees;\n}\n",[95,12934,12935,12940,12944,12949,12953,12958,12962,12967],{"__ignoreMap":48},[112,12936,12937],{"class":114,"line":115},[112,12938,12939],{},"public void setTargetAngle(double degrees)\n",[112,12941,12942],{"class":114,"line":49},[112,12943,123],{},[112,12945,12946],{"class":114,"line":126},[112,12947,12948],{},"    if (degrees \u003C 0 || degrees > 180)\n",[112,12950,12951],{"class":114,"line":132},[112,12952,135],{},[112,12954,12955],{"class":114,"line":138},[112,12956,12957],{},"        throw new IllegalArgumentException(\"Angle out of range: \" + degrees);\n",[112,12959,12960],{"class":114,"line":144},[112,12961,147],{},[112,12963,12964],{"class":114,"line":150},[112,12965,12966],{},"    this.targetAngle = degrees;\n",[112,12968,12969],{"class":114,"line":1819},[112,12970,153],{},[15,12972,12973,12974,12976,12977,12980,12981,12984,12985,12987,12988,12990],{},"Every exception type in Java descends from ",[95,12975,12928],{},". Its two direct children are ",[95,12978,12979],{},"Error"," (serious JVM-level failures — not something ordinary code catches or throws) and ",[95,12982,12983],{},"Exception"," (everything an ordinary program throws and catches), and ",[95,12986,12842],{}," is the branch of ",[95,12989,12983],{}," reserved for unchecked exceptions.",[69,12992,412],{"id":411},[19,12994,12995,13008,13022],{},[22,12996,12997,13000,13001,13003,13004,13007],{},[25,12998,12999],{},"Catch-and-ignore."," An empty ",[95,13002,12559],{}," block silently swallows a real problem — at minimum, log or report it (",[95,13005,13006],{},"reportWarning(...)"," above), even if there's nothing more to do.",[22,13009,13010,13013,13014,1051,13016,13018,13019,13021],{},[25,13011,13012],{},"Catching to \"fix\" a bug instead of fixing it."," Wrapping buggy code in ",[95,13015,12573],{},[95,13017,12559],{}," to suppress a ",[95,13020,3414],{}," hides the actual mistake instead of correcting it — reserve catching for genuinely recoverable situations (a missing file, an unreachable camera), not programming errors.",[22,13023,13024,13036,13037,13039],{},[25,13025,3455,13026,13028,13029,13031,13032,1051,13034,79],{},[95,13027,12715],{}," runs even on an early ",[95,13030,2717],{}," inside ",[95,13033,12573],{},[95,13035,12559],{}," Cleanup code that must always run belongs in ",[95,13038,12715],{},", not duplicated at the end of every branch.",[69,13041,450],{"id":449},[19,13043,13044,13047,13058,13070,13078],{},[22,13045,13046],{},"Throwing an exception creates an object describing the problem and hands it to the runtime, which searches the call stack for a matching handler; an unhandled exception crashes the program (a red \"Robot Code\" indicator, on a robot).",[22,13048,13049,13051,13052,13054,13055,13057],{},[95,13050,12573],{}," wraps risky code; one or more ",[95,13053,12559],{}," blocks handle specific exception types; an optional ",[95,13056,12715],{}," block always runs, for cleanup.",[22,13059,13060,13061,13063,13064,13066,13067,13069],{},"Checked exceptions (like ",[95,13062,12636],{},") must be caught or declared with ",[95,13065,12832],{},"; unchecked exceptions (",[95,13068,12842],{}," and its subclasses) don't require either, since they usually signal a real bug rather than a recoverable situation.",[22,13071,13072,13075,13076,79],{},[95,13073,13074],{},"throw someObject;"," triggers an exception yourself, given any ",[95,13077,12928],{},[22,13079,13080],{},"Never catch-and-ignore — recover meaningfully, or at least report the problem.",[15,13082,493,13083,497,13085,275,13088,275,13091,275,13094,275,13097,13100,13101,13103],{},[95,13084,12493],{},[95,13086,13087],{},"oracle-java-tutorials\u002Fexceptions\u002F01-what-is-an-exception.md",[95,13089,13090],{},"03-catching-and-handling-exceptions.md",[95,13092,13093],{},"09-specifying-the-exceptions-thrown-by-a-method.md",[95,13095,13096],{},"10-how-to-throw-exceptions.md",[95,13098,13099],{},"13-unchecked-exceptions-the-controversy.md"," (ORACLE 11.1-16)\n",[25,13102,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js, slide 11 (\"Exceptions & try\u002Fcatch\")",[503,13105,505],{},{"title":48,"searchDepth":49,"depth":49,"links":13107},[13108,13109,13110,13111,13112,13114,13116,13117],{"id":12530,"depth":49,"text":12531},{"id":12567,"depth":49,"text":12568},{"id":12715,"depth":49,"text":12715},{"id":12811,"depth":49,"text":12812},{"id":12866,"depth":49,"text":13113},"The throws Clause",{"id":12915,"depth":49,"text":13115},"The throw Statement",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":13119,"status":519},"12 — Exceptions & try\u002Fcatch (ORACLE 11.1-16)","\u002Fshockwave-curriculum\u002Flessons\u002Fch12-exceptions-and-try-catch\u002F12-exceptions-and-try-catch",{"title":12522,"description":48},"shockwave-curriculum\u002Flessons\u002Fch12-exceptions-and-try-catch\u002F12-exceptions-and-try-catch","dg2VweXAmHFeqzceVgmb1XLz-Li8J4oG-Sf-RiG7hSg",{"id":13125,"title":13126,"body":13127,"description":13411,"extension":51,"meta":13412,"navigation":55,"path":13414,"seo":13415,"stem":13416,"__hash__":13417},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch13-common-gotchas\u002F13-common-gotchas.md","Common Gotchas",{"type":8,"value":13128,"toc":13403},[13129,13132,13139,13143,13165,13190,13202,13206,13215,13230,13243,13245,13254,13269,13283,13287,13304,13319,13329,13331,13353,13355,13392,13401],[11,13130,13126],{"id":13131},"common-gotchas",[15,13133,13134,13135,13138],{},"This chapter is a quick-reference checklist, not new material — each item below is taught in full elsewhere in this curriculum. Its job is to put the most common real mistakes side by side, since they tend to resurface long after the lesson that first covered them. ",[25,13136,13137],{},"Note:"," this list is expected to grow once real code-review and exercise practice surfaces more of the mistakes people actually make — it currently only covers what the original deck flagged.",[69,13140,13142],{"id":13141},"vs-equals","== vs. .equals()",[15,13144,13145,13147,13148,275,13150,275,13152,13154,13155,13157,13158,13160,13161,13164],{},[95,13146,1568],{}," compares primitives (",[95,13149,552],{},[95,13151,580],{},[95,13153,606],{},") by value, which is correct and sufficient for them. For objects — including ",[95,13156,315],{}," — ",[95,13159,1568],{}," instead checks whether two variables point at the ",[262,13162,13163],{},"exact same object in memory",", which is almost never what you actually want to ask:",[104,13166,13168],{"className":106,"code":13167,"language":108,"meta":48,"style":48},"String a = new String(\"BlueAlliance-Left\");\nString b = new String(\"BlueAlliance-Left\");\na == b;        \u002F\u002F false — two different objects, even with identical text\na.equals(b);   \u002F\u002F true — compares the actual characters\n",[95,13169,13170,13175,13180,13185],{"__ignoreMap":48},[112,13171,13172],{"class":114,"line":115},[112,13173,13174],{},"String a = new String(\"BlueAlliance-Left\");\n",[112,13176,13177],{"class":114,"line":49},[112,13178,13179],{},"String b = new String(\"BlueAlliance-Left\");\n",[112,13181,13182],{"class":114,"line":126},[112,13183,13184],{},"a == b;        \u002F\u002F false — two different objects, even with identical text\n",[112,13186,13187],{"class":114,"line":132},[112,13188,13189],{},"a.equals(b);   \u002F\u002F true — compares the actual characters\n",[15,13191,1171,13192,5327,13194,13196,13197,486,13199,13201],{},[95,13193,5424],{},[95,13195,5424],{},"-style comparisons) for any object type, including boxed numbers like ",[95,13198,8723],{},[95,13200,8726],{},". See Lesson 6.1 for the full explanation.",[69,13203,13205],{"id":13204},"integer-division","Integer Division",[15,13207,13208,13209,13211,13212,13214],{},"Dividing two ",[95,13210,552],{},"s produces an ",[95,13213,552],{}," — the fractional part is silently discarded (truncated), not rounded:",[104,13216,13218],{"className":106,"code":13217,"language":108,"meta":48,"style":48},"int result = 5 \u002F 2;       \u002F\u002F 2, not 2.5 — the .5 is thrown away, not rounded\ndouble result2 = 5.0 \u002F 2.0; \u002F\u002F 2.5 — at least one operand must be a floating-point type\n",[95,13219,13220,13225],{"__ignoreMap":48},[112,13221,13222],{"class":114,"line":115},[112,13223,13224],{},"int result = 5 \u002F 2;       \u002F\u002F 2, not 2.5 — the .5 is thrown away, not rounded\n",[112,13226,13227],{"class":114,"line":49},[112,13228,13229],{},"double result2 = 5.0 \u002F 2.0; \u002F\u002F 2.5 — at least one operand must be a floating-point type\n",[15,13231,13232,13233,13236,13237,13239,13240,13242],{},"This bites often when averaging (",[95,13234,13235],{},"total \u002F count"," where both are ",[95,13238,552],{},") — cast at least one operand to ",[95,13241,580],{}," first. See Lesson 2.4 for casting rules in full.",[69,13244,3414],{"id":3606},[15,13246,13247,13248,13250,13251,13253],{},"Calling a method or accessing a field on a variable that's ",[95,13249,3384],{}," (declared but never assigned a real object) throws ",[95,13252,3414],{}," — one of the most common runtime crashes in any Java program, robot code included:",[104,13255,13257],{"className":106,"code":13256,"language":108,"meta":48,"style":48},"Drivetrain drivetrain; \u002F\u002F declared, but never assigned — currently null\ndrivetrain.stop();      \u002F\u002F NullPointerException — nothing to call stop() on\n",[95,13258,13259,13264],{"__ignoreMap":48},[112,13260,13261],{"class":114,"line":115},[112,13262,13263],{},"Drivetrain drivetrain; \u002F\u002F declared, but never assigned — currently null\n",[112,13265,13266],{"class":114,"line":49},[112,13267,13268],{},"drivetrain.stop();      \u002F\u002F NullPointerException — nothing to call stop() on\n",[15,13270,13271,13272,13275,13276,13278,13279,13282],{},"The fix is always the same shape: make sure every object is actually constructed (",[95,13273,13274],{},"new Drivetrain(...)",") before anything calls a method on it, and check for ",[95,13277,3384],{}," explicitly at any point where a value might legitimately be missing (e.g., a ",[95,13280,13281],{},"HashMap.get()"," that found no match — see Lesson 9.3).",[69,13284,13286],{"id":13285},"off-by-one","Off-by-One",[15,13288,13289,13290,13292,13293,13295,13296,5327,13298,13300,13301,13303],{},"Arrays (and ",[95,13291,8682],{},") are indexed starting at ",[95,13294,1140],{}," — the last valid index is always ",[95,13297,8471],{},[95,13299,10157],{},"), never ",[95,13302,8596],{}," itself:",[104,13305,13307],{"className":106,"code":13306,"language":108,"meta":48,"style":48},"int[] canBusIds = new int[10]; \u002F\u002F valid indices: 0 through 9\ncanBusIds[10]; \u002F\u002F ArrayIndexOutOfBoundsException — 10 is one past the end\n",[95,13308,13309,13314],{"__ignoreMap":48},[112,13310,13311],{"class":114,"line":115},[112,13312,13313],{},"int[] canBusIds = new int[10]; \u002F\u002F valid indices: 0 through 9\n",[112,13315,13316],{"class":114,"line":49},[112,13317,13318],{},"canBusIds[10]; \u002F\u002F ArrayIndexOutOfBoundsException — 10 is one past the end\n",[15,13320,13321,13322,3972,13325,13328],{},"This is the single most common loop-bound mistake — writing ",[95,13323,13324],{},"i \u003C= array.length",[95,13326,13327],{},"i \u003C array.length",". See Lesson 9.1 (arrays) and 9.2 (ArrayList) for the full indexing rules.",[69,13330,412],{"id":411},[19,13332,13333,13339],{},[22,13334,13335,13338],{},[25,13336,13337],{},"Treating this chapter as the complete list of Java mistakes."," It isn't — it's the handful the original deck happened to flag. Real practice will surface plenty more (this chapter is expected to grow).",[22,13340,13341,13344,13345,13347,13348,1051,13350,13352],{},[25,13342,13343],{},"Fixing the symptom instead of the cause."," E.g., wrapping a ",[95,13346,3414],{}," in a ",[95,13349,12573],{},[95,13351,12559],{}," (Lesson 12) instead of fixing why the object was never constructed in the first place.",[69,13354,450],{"id":449},[19,13356,13357,13365,13371,13376,13389],{},[22,13358,1171,13359,13361,13362,13364],{},[95,13360,1568],{}," for primitives, ",[95,13363,5424],{}," for objects (Lesson 6.1).",[22,13366,13367,13370],{},[95,13368,13369],{},"int \u002F int"," truncates; make at least one operand a floating-point type to keep the fractional part (Lesson 2.4).",[22,13372,13373,13375],{},[95,13374,3414],{}," means something was used before it was actually constructed — always initialize before use (Lessons 4.4–4.6, 9.1).",[22,13377,13378,13379,3883,13381,5327,13383,13385,13386,13388],{},"Valid indices run from ",[95,13380,1140],{},[95,13382,8471],{},[95,13384,10157],{},") — never ",[95,13387,8596],{}," itself (Lessons 9.1, 9.2).",[22,13390,13391],{},"This is a living checklist, not a finished one — expect it to grow as more real gotchas surface through practice.",[15,13393,493,13394,497,13397,13400],{},[95,13395,13396],{},"mechacoder-test",[95,13398,13399],{},"src\u002Flessons\u002Fjava-1.js",", slide 13 (\"Common Gotchas\") — original deck content, no external citation",[503,13402,505],{},{"title":48,"searchDepth":49,"depth":49,"links":13404},[13405,13406,13407,13408,13409,13410],{"id":13141,"depth":49,"text":13142},{"id":13204,"depth":49,"text":13205},{"id":3606,"depth":49,"text":3414},{"id":13285,"depth":49,"text":13286},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"This chapter is a quick-reference checklist, not new material — each item below is taught in full elsewhere in this curriculum. Its job is to put the most common real mistakes side by side, since they tend to resurface long after the lesson that first covered them. Note: this list is expected to grow once real code-review and exercise practice surfaces more of the mistakes people actually make — it currently only covers what the original deck flagged.",{"outlineRef":13413,"status":519},"13 — Common Gotchas (no citation — deck-original content)","\u002Fshockwave-curriculum\u002Flessons\u002Fch13-common-gotchas\u002F13-common-gotchas",{"title":13126,"description":13411},"shockwave-curriculum\u002Flessons\u002Fch13-common-gotchas\u002F13-common-gotchas","MWUAvDz00kc9GctAy8cwVXU4-iN6QA_mx9P3bFxsuVI",{"id":13419,"title":13420,"body":13421,"description":48,"extension":51,"meta":13544,"navigation":55,"path":13546,"seo":13547,"stem":13548,"__hash__":13549},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch14-why-design-patterns\u002F14-why-design-patterns.md","Why Design Patterns?",{"type":8,"value":13422,"toc":13537},[13423,13426,13430,13437,13447,13453,13460,13464,13474,13480,13490,13494,13497,13499,13513,13515,13529],[11,13424,13420],{"id":13425},"why-design-patterns",[69,13427,13429],{"id":13428},"what-this-chapter-starts","What This Chapter Starts",[15,13431,13432,13433,13436],{},"Everything up to Ch.13 was single-class, mostly single-file Java: variables, control flow, arrays, one class with a few methods. From here on (\"Java II\"), the curriculum shifts to how ",[262,13434,13435],{},"multiple"," classes work together as a codebase grows — the concerns become organization, reuse, and change over time, not just \"does this one method work.\"",[15,13438,355,13439,13442,13443,13446],{},[25,13440,13441],{},"design pattern"," is a named, reusable solution to a problem that keeps showing up across different programs — not a specific piece of code to copy-paste, but a ",[262,13444,13445],{},"shape"," of solution (which classes exist, how they relate) that's been proven to work well for that kind of problem. The chapters that follow each cover one real pattern actually used in FRC codebases: the Builder Pattern, Static Factories, the IO-Layer Pattern, and eventually the biggest one, Command-Based Programming itself.",[13448,13449,13450],"blockquote",{},[15,13451,13452],{},"\"Code is read much more often than it is written.\" — Guido van Rossum (adapted)",[15,13454,13455,13456,13459],{},"That quote is the real motivation for this whole unit. A robot's codebase gets read by every teammate who touches it, every mentor reviewing it, and by ",[262,13457,13458],{},"you"," again in six months — far more often than it gets freshly written. Patterns exist because they make code easier to read and change later, not just easier to write once.",[69,13461,13463],{"id":13462},"why-bother","Why Bother",[15,13465,13466,13469,13470,13473],{},[25,13467,13468],{},"Scalability."," A single ",[95,13471,13472],{},"Robot.java"," file with everything crammed inside works fine for a \"blink an LED\" program. It stops working once a robot has a drivetrain, an intake, a shooter, vision processing, and autonomous routines all interacting — patterns are how experienced teams keep that complexity organized instead of it collapsing into an unmaintainable mess.",[15,13475,13476,13479],{},[25,13477,13478],{},"A common language."," Telling another mentor \"I'm using a Factory here\" or \"this is a Builder\" communicates an entire shape of design in a few words — they immediately know how the pieces relate, without you having to walk through every class. Patterns are shared vocabulary across the whole FRC (and broader software) community, not something invented per-team.",[15,13481,13482,13485,13486,13489],{},[25,13483,13484],{},"Testability."," Code built around patterns tends to be more ",[25,13487,13488],{},"decoupled"," — pieces don't reach directly into each other's internals, so they can be swapped, simulated, or tested independently. A drivetrain built with a clean pattern can be tested in simulation, with no real motors or robot required; one where every class directly depends on every other class often can't be tested at all without the physical hardware present.",[69,13491,13493],{"id":13492},"what-this-chapter-is-not","What This Chapter Is Not",[15,13495,13496],{},"This chapter doesn't teach a specific pattern — the chapters immediately following it do that one at a time. Its only job is to answer \"why does any of this matter,\" before the actual mechanics of Advanced Collections, Generics, Inheritance, and the named patterns begin.",[69,13498,412],{"id":411},[19,13500,13501,13507],{},[22,13502,13503,13506],{},[25,13504,13505],{},"Reaching for a pattern before there's a real problem it solves."," Patterns exist to manage genuine complexity — forcing one onto a two-class program just because \"patterns are good practice\" usually adds complexity instead of removing it.",[22,13508,13509,13512],{},[25,13510,13511],{},"Treating pattern names as a vocabulary test rather than a design tool."," The value of saying \"this is a Factory\" is that it communicates real structure to a teammate — not that it sounds impressive.",[69,13514,450],{"id":449},[19,13516,13517,13523,13526],{},[22,13518,13519,13520,13522],{},"A design pattern is a reusable ",[262,13521,13445],{}," of solution to a recurring design problem, not a snippet of code to copy.",[22,13524,13525],{},"Patterns matter for three concrete reasons: keeping a growing codebase organized (scalability), giving the team shared vocabulary (common language), and making code easier to test in isolation (decoupling).",[22,13527,13528],{},"The chapters that follow each teach one specific, real pattern used in actual FRC codebases.",[15,13530,493,13531,497,13533,13536],{},[95,13532,13396],{},[95,13534,13535],{},"src\u002Flessons\u002Fjava-2.js",", slide 1 (\"Why Design Patterns?\") — original deck content, no external citation",{"title":48,"searchDepth":49,"depth":49,"links":13538},[13539,13540,13541,13542,13543],{"id":13428,"depth":49,"text":13429},{"id":13462,"depth":49,"text":13463},{"id":13492,"depth":49,"text":13493},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":13545,"status":519},"14 — Why Design Patterns? (no citation — deck-original content)","\u002Fshockwave-curriculum\u002Flessons\u002Fch14-why-design-patterns\u002F14-why-design-patterns",{"title":13420,"description":48},"shockwave-curriculum\u002Flessons\u002Fch14-why-design-patterns\u002F14-why-design-patterns","rfiF9tlwKQ9Q7eyl0SNrW1CAN4klvDMJiNt8ZjOoQ9s",{"id":13551,"title":13552,"body":13553,"description":14256,"extension":51,"meta":14257,"navigation":55,"path":14259,"seo":14260,"stem":14261,"__hash__":14262},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch15-advanced-collections\u002F15-advanced-collections.md","Advanced Collections (Set\u002FQueue\u002FMap)",{"type":8,"value":13554,"toc":14248},[13555,13558,13590,13594,13605,13625,13631,13672,13686,13717,13721,13730,13799,13841,13851,13855,13869,13947,13950,13979,13992,13996,14018,14059,14068,14083,14107,14109,14165,14167,14229,14246],[11,13556,13552],{"id":13557},"advanced-collections-setqueuemap",[15,13559,13560,13561,13563,13564,13566,13567,13572,13573,1051,13578,13583,13584,13589],{},"Ch.9 covered ",[95,13562,8682],{}," and a basic ",[95,13565,9043],{},". Three more collection types round out the toolbox, each solving a problem the others don't: ",[25,13568,13569],{},[95,13570,13571],{},"Set"," (no duplicates, ever), ",[25,13574,13575],{},[95,13576,13577],{},"Queue",[25,13579,13580],{},[95,13581,13582],{},"Deque"," (order of processing matters more than random access), and a deeper look at ",[25,13585,13586],{},[95,13587,13588],{},"Map"," (iterating both keys and values together, and choosing an ordering).",[69,13591,13593],{"id":13592},"set-no-duplicates-ever","Set: No Duplicates, Ever",[15,13595,355,13596,13598,13599,13601,13602,13604],{},[95,13597,13571],{}," is a collection that flatly refuses duplicate elements — calling ",[95,13600,8883],{}," with something already present just does nothing (and returns ",[95,13603,613],{},"), rather than adding a second copy:",[104,13606,13608],{"className":106,"code":13607,"language":108,"meta":48,"style":48},"Set\u003CInteger> usedCanIds = new HashSet\u003CInteger>();\nusedCanIds.add(5);  \u002F\u002F true — added\nusedCanIds.add(5);  \u002F\u002F false — already present, nothing changed\n",[95,13609,13610,13615,13620],{"__ignoreMap":48},[112,13611,13612],{"class":114,"line":115},[112,13613,13614],{},"Set\u003CInteger> usedCanIds = new HashSet\u003CInteger>();\n",[112,13616,13617],{"class":114,"line":49},[112,13618,13619],{},"usedCanIds.add(5);  \u002F\u002F true — added\n",[112,13621,13622],{"class":114,"line":126},[112,13623,13624],{},"usedCanIds.add(5);  \u002F\u002F false — already present, nothing changed\n",[15,13626,13627,13628,13630],{},"That makes ",[95,13629,13571],{}," the natural tool for catching configuration conflicts — e.g. verifying no two devices on the robot were accidentally wired to the same CAN ID:",[104,13632,13634],{"className":106,"code":13633,"language":108,"meta":48,"style":48},"Set\u003CInteger> seenIds = new HashSet\u003CInteger>();\nfor (int id : allConfiguredCanIds)\n{\n    if (!seenIds.add(id)) \u002F\u002F add() returns false if it was already there\n    {\n        reportWarning(\"Duplicate CAN ID detected: \" + id);\n    }\n}\n",[95,13635,13636,13641,13646,13650,13655,13659,13664,13668],{"__ignoreMap":48},[112,13637,13638],{"class":114,"line":115},[112,13639,13640],{},"Set\u003CInteger> seenIds = new HashSet\u003CInteger>();\n",[112,13642,13643],{"class":114,"line":49},[112,13644,13645],{},"for (int id : allConfiguredCanIds)\n",[112,13647,13648],{"class":114,"line":126},[112,13649,123],{},[112,13651,13652],{"class":114,"line":132},[112,13653,13654],{},"    if (!seenIds.add(id)) \u002F\u002F add() returns false if it was already there\n",[112,13656,13657],{"class":114,"line":138},[112,13658,135],{},[112,13660,13661],{"class":114,"line":144},[112,13662,13663],{},"        reportWarning(\"Duplicate CAN ID detected: \" + id);\n",[112,13665,13666],{"class":114,"line":150},[112,13667,147],{},[112,13669,13670],{"class":114,"line":1819},[112,13671,153],{},[15,13673,13674,13677,13678,13681,13682,13685],{},[95,13675,13676],{},"HashSet"," (fastest, no ordering guarantee) is the usual default; ",[95,13679,13680],{},"LinkedHashSet"," remembers insertion order; ",[95,13683,13684],{},"TreeSet"," keeps elements sorted. All three still refuse duplicates — they only differ in iteration order.",[15,13687,13688,13690,13691,13694,13695,13698,13699,13702,13703,13706,13707,13710,13711,13714,13715,3179],{},[95,13689,13571],{}," also supports set algebra directly as methods: ",[95,13692,13693],{},"s1.containsAll(s2)"," (is ",[95,13696,13697],{},"s2"," a subset of ",[95,13700,13701],{},"s1","?), ",[95,13704,13705],{},"s1.addAll(s2)"," (union), ",[95,13708,13709],{},"s1.retainAll(s2)"," (intersection — keep only what's in both), ",[95,13712,13713],{},"s1.removeAll(s2)"," (difference — remove anything also in ",[95,13716,13697],{},[69,13718,13720],{"id":13719},"queue-first-in-first-out","Queue: First-In, First-Out",[15,13722,355,13723,13725,13726,13729],{},[95,13724,13577],{}," holds elements for later processing, normally in ",[25,13727,13728],{},"FIFO"," order (first-in-first-out) — think of a queue of autonomous routine steps waiting to run in the order they were scheduled. Every operation comes in two flavors: one throws an exception on failure, the other returns a safe placeholder value instead.",[8805,13731,13732,13744],{},[8808,13733,13734],{},[8811,13735,13736,13738,13741],{},[8814,13737,8816],{},[8814,13739,13740],{},"Throws on failure",[8814,13742,13743],{},"Returns a placeholder",[8823,13745,13746,13764,13782],{},[8811,13747,13748,13751,13756],{},[8828,13749,13750],{},"Insert",[8828,13752,13753],{},[95,13754,13755],{},"add(e)",[8828,13757,13758,13761,13762,1081],{},[95,13759,13760],{},"offer(e)"," (returns ",[95,13763,613],{},[8811,13765,13766,13769,13774],{},[8828,13767,13768],{},"Remove",[8828,13770,13771],{},[95,13772,13773],{},"remove()",[8828,13775,13776,13761,13779,13781],{},[95,13777,13778],{},"poll()",[95,13780,3384],{}," if empty)",[8811,13783,13784,13787,13792],{},[8828,13785,13786],{},"Peek (don't remove)",[8828,13788,13789],{},[95,13790,13791],{},"element()",[8828,13793,13794,13761,13797,13781],{},[95,13795,13796],{},"peek()",[95,13798,3384],{},[104,13800,13802],{"className":106,"code":13801,"language":108,"meta":48,"style":48},"Queue\u003CString> pendingFaults = new LinkedList\u003CString>();\npendingFaults.add(\"Camera 1 disconnected\");\npendingFaults.add(\"Low battery voltage\");\n\nwhile (!pendingFaults.isEmpty())\n{\n    System.out.println(\"Handling: \" + pendingFaults.poll()); \u002F\u002F removes and returns the oldest fault first\n}\n",[95,13803,13804,13809,13814,13819,13823,13828,13832,13837],{"__ignoreMap":48},[112,13805,13806],{"class":114,"line":115},[112,13807,13808],{},"Queue\u003CString> pendingFaults = new LinkedList\u003CString>();\n",[112,13810,13811],{"class":114,"line":49},[112,13812,13813],{},"pendingFaults.add(\"Camera 1 disconnected\");\n",[112,13815,13816],{"class":114,"line":126},[112,13817,13818],{},"pendingFaults.add(\"Low battery voltage\");\n",[112,13820,13821],{"class":114,"line":132},[112,13822,820],{"emptyLinePlaceholder":55},[112,13824,13825],{"class":114,"line":138},[112,13826,13827],{},"while (!pendingFaults.isEmpty())\n",[112,13829,13830],{"class":114,"line":144},[112,13831,123],{},[112,13833,13834],{"class":114,"line":150},[112,13835,13836],{},"    System.out.println(\"Handling: \" + pendingFaults.poll()); \u002F\u002F removes and returns the oldest fault first\n",[112,13838,13839],{"class":114,"line":1819},[112,13840,153],{},[15,13842,13843,1051,13845,13847,13848,13850],{},[95,13844,13778],{},[95,13846,13796],{}," are usually the safer default in real code — they hand back ",[95,13849,3384],{}," instead of throwing when the queue happens to be empty, which is often a completely normal state (no faults right now) rather than an error.",[69,13852,13854],{"id":13853},"deque-both-ends-at-once","Deque: Both Ends at Once",[15,13856,355,13857,13861,13862,13865,13866,13868],{},[25,13858,13859],{},[95,13860,13582],{}," (\"deck,\" double-ended queue) supports inserting and removing from ",[262,13863,13864],{},"either"," end, which means a single ",[95,13867,13582],{}," can act as a FIFO queue, a LIFO stack, or both:",[8805,13870,13871,13883],{},[8808,13872,13873],{},[8811,13874,13875,13877,13880],{},[8814,13876,8816],{},[8814,13878,13879],{},"First (front)",[8814,13881,13882],{},"Last (back)",[8823,13884,13885,13906,13926],{},[8811,13886,13887,13889,13898],{},[8828,13888,13750],{},[8828,13890,13891,13894,13895],{},[95,13892,13893],{},"addFirst(e)"," \u002F ",[95,13896,13897],{},"offerFirst(e)",[8828,13899,13900,13894,13903],{},[95,13901,13902],{},"addLast(e)",[95,13904,13905],{},"offerLast(e)",[8811,13907,13908,13910,13918],{},[8828,13909,13768],{},[8828,13911,13912,13894,13915],{},[95,13913,13914],{},"removeFirst()",[95,13916,13917],{},"pollFirst()",[8828,13919,13920,13894,13923],{},[95,13921,13922],{},"removeLast()",[95,13924,13925],{},"pollLast()",[8811,13927,13928,13931,13939],{},[8828,13929,13930],{},"Examine",[8828,13932,13933,13894,13936],{},[95,13934,13935],{},"getFirst()",[95,13937,13938],{},"peekFirst()",[8828,13940,13941,13894,13944],{},[95,13942,13943],{},"getLast()",[95,13945,13946],{},"peekLast()",[15,13948,13949],{},"A common use: an undo stack for the last few climb-sequence steps, where you only ever add\u002Fremove from one end (LIFO — last one added is the first one undone):",[104,13951,13953],{"className":106,"code":13952,"language":108,"meta":48,"style":48},"Deque\u003CString> climbSteps = new ArrayDeque\u003CString>();\nclimbSteps.addLast(\"Extend to high bar\");\nclimbSteps.addLast(\"Release from mid bar\");\n\nString lastStep = climbSteps.removeLast(); \u002F\u002F \"Release from mid bar\" — undo the most recent step\n",[95,13954,13955,13960,13965,13970,13974],{"__ignoreMap":48},[112,13956,13957],{"class":114,"line":115},[112,13958,13959],{},"Deque\u003CString> climbSteps = new ArrayDeque\u003CString>();\n",[112,13961,13962],{"class":114,"line":49},[112,13963,13964],{},"climbSteps.addLast(\"Extend to high bar\");\n",[112,13966,13967],{"class":114,"line":126},[112,13968,13969],{},"climbSteps.addLast(\"Release from mid bar\");\n",[112,13971,13972],{"class":114,"line":132},[112,13973,820],{"emptyLinePlaceholder":55},[112,13975,13976],{"class":114,"line":138},[112,13977,13978],{},"String lastStep = climbSteps.removeLast(); \u002F\u002F \"Release from mid bar\" — undo the most recent step\n",[15,13980,13981,13984,13985,13987,13988,13991],{},[95,13982,13983],{},"ArrayDeque"," is the standard general-purpose ",[95,13986,13582],{}," implementation — generally faster than ",[95,13989,13990],{},"LinkedList"," for this purpose, with no capacity limit.",[69,13993,13995],{"id":13994},"map-revisited-iterating-both-keys-and-values","Map, Revisited: Iterating Both Keys and Values",[15,13997,13998,13999,1051,14002,14004,14005,778,14007,14010,14011,14014,14015,14017],{},"Ch.9.3 covered ",[95,14000,14001],{},"put",[95,14003,3669],{}," and looping over ",[95,14006,9141],{},[95,14008,14009],{},"Map.entrySet()"," gives every key ",[262,14012,14013],{},"and"," value together in one pass, avoiding a repeated ",[95,14016,9145],{}," call for each key:",[104,14019,14021],{"className":106,"code":14020,"language":108,"meta":48,"style":48},"Map\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\nmotorOffsets.put(5, 0.02);\nmotorOffsets.put(6, -0.01);\n\nfor (Map.Entry\u003CInteger, Double> entry : motorOffsets.entrySet())\n{\n    System.out.println(\"CAN ID \" + entry.getKey() + \" -> offset \" + entry.getValue());\n}\n",[95,14022,14023,14028,14033,14037,14041,14046,14050,14055],{"__ignoreMap":48},[112,14024,14025],{"class":114,"line":115},[112,14026,14027],{},"Map\u003CInteger, Double> motorOffsets = new HashMap\u003CInteger, Double>();\n",[112,14029,14030],{"class":114,"line":49},[112,14031,14032],{},"motorOffsets.put(5, 0.02);\n",[112,14034,14035],{"class":114,"line":126},[112,14036,9080],{},[112,14038,14039],{"class":114,"line":132},[112,14040,820],{"emptyLinePlaceholder":55},[112,14042,14043],{"class":114,"line":138},[112,14044,14045],{},"for (Map.Entry\u003CInteger, Double> entry : motorOffsets.entrySet())\n",[112,14047,14048],{"class":114,"line":144},[112,14049,123],{},[112,14051,14052],{"class":114,"line":150},[112,14053,14054],{},"    System.out.println(\"CAN ID \" + entry.getKey() + \" -> offset \" + entry.getValue());\n",[112,14056,14057],{"class":114,"line":1819},[112,14058,153],{},[15,14060,14061,14062,14064,14065,14067],{},"Just like ",[95,14063,13571],{},", a plain ",[95,14066,9043],{}," gives no ordering guarantee. Swapping the implementation type is enough to change that, with no other code changes needed:",[104,14069,14071],{"className":106,"code":14070,"language":108,"meta":48,"style":48},"Map\u003CInteger, Double> sorted = new TreeMap\u003CInteger, Double>(motorOffsets);       \u002F\u002F sorted by key\nMap\u003CInteger, Double> byInsertOrder = new LinkedHashMap\u003CInteger, Double>(motorOffsets); \u002F\u002F insertion order\n",[95,14072,14073,14078],{"__ignoreMap":48},[112,14074,14075],{"class":114,"line":115},[112,14076,14077],{},"Map\u003CInteger, Double> sorted = new TreeMap\u003CInteger, Double>(motorOffsets);       \u002F\u002F sorted by key\n",[112,14079,14080],{"class":114,"line":49},[112,14081,14082],{},"Map\u003CInteger, Double> byInsertOrder = new LinkedHashMap\u003CInteger, Double>(motorOffsets); \u002F\u002F insertion order\n",[15,14084,14085,14086,275,14089,275,14092,14095,14096,275,14098,275,14100,14102,14103,14106],{},"This is the payoff of always declaring a variable by its interface type (",[95,14087,14088],{},"Map\u003CK, V>",[95,14090,14091],{},"Set\u003CE>",[95,14093,14094],{},"Queue\u003CE>",") rather than its concrete implementation (",[95,14097,9043],{},[95,14099,13676],{},[95,14101,13990],{},") — changing which concrete class gets constructed is a one-line change, because every line that ",[262,14104,14105],{},"uses"," the collection only ever depends on the interface.",[69,14108,412],{"id":411},[19,14110,14111,14132,14147],{},[22,14112,14113,14119,14120,1051,14122,14125,14126,1051,14128,14131],{},[25,14114,9183,14115,207,14117,9186],{},[95,14116,13676],{},[95,14118,9043],{}," Neither does — reach for ",[95,14121,13680],{},[95,14123,14124],{},"LinkedHashMap"," if insertion order actually matters, or ",[95,14127,13684],{},[95,14129,14130],{},"TreeMap"," if sorted order does.",[22,14133,14134,14141,14142,1051,14144,14146],{},[25,14135,4590,14136,1051,14138,14140],{},[95,14137,13773],{},[95,14139,13791],{}," on a queue that might be empty."," Both throw when empty — prefer ",[95,14143,13778],{},[95,14145,13796],{}," unless an empty queue genuinely represents a bug that should crash loudly.",[22,14148,14149,426,14152,14155,14156,3883,14158,14160,14161,14164],{},[25,14150,14151],{},"Declaring a collection variable by its concrete type instead of its interface.",[95,14153,14154],{},"HashMap\u003CK,V> m = new HashMap\u003C>();"," locks every line that touches ",[95,14157,3494],{},[95,14159,9043],{},"'s specific behavior — declare it ",[95,14162,14163],{},"Map\u003CK,V> m = new HashMap\u003C>();"," instead, so the implementation can change later without touching anything else.",[69,14166,450],{"id":449},[19,14168,14169,14183,14206,14214,14226],{},[22,14170,14171,14173,14174,14176,14177,14179,14180,14182],{},[95,14172,13571],{}," guarantees no duplicates; ",[95,14175,13676],{}," is fastest with no ordering, ",[95,14178,13680],{}," keeps insertion order, ",[95,14181,13684],{}," keeps sorted order.",[22,14184,14185,14187,14188,1051,14190,1051,14192,14195,14196,1051,14199,1051,14202,14205],{},[95,14186,13577],{}," processes elements FIFO by default; every operation has a throwing form (",[95,14189,8883],{},[95,14191,8886],{},[95,14193,14194],{},"element",") and a safe form (",[95,14197,14198],{},"offer",[95,14200,14201],{},"poll",[95,14203,14204],{},"peek",") that returns a placeholder instead of throwing.",[22,14207,14208,14210,14211,14213],{},[95,14209,13582],{}," supports both ends at once, letting one type serve as either a queue or a stack; ",[95,14212,13983],{}," is the standard general-purpose implementation.",[22,14215,14216,14218,14219,275,14221,278,14223,14225],{},[95,14217,14009],{}," iterates keys and values together; switching between ",[95,14220,9043],{},[95,14222,14130],{},[95,14224,14124],{}," changes ordering with no other code changes.",[22,14227,14228],{},"Always declare collection variables by their interface type, not their concrete implementation — it's what makes swapping implementations a one-line change.",[15,14230,493,14231,497,14233,275,14236,275,14239,275,14242,14245],{},[95,14232,12493],{},[95,14234,14235],{},"oracle-java-tutorials\u002Fcollections-interfaces\u002F01-the-set-interface.md",[95,14237,14238],{},"02-the-queue-interface.md",[95,14240,14241],{},"03-the-deque-interface.md",[95,14243,14244],{},"04-the-map-interface.md"," (ORACLE 13.1-4)",[503,14247,505],{},{"title":48,"searchDepth":49,"depth":49,"links":14249},[14250,14251,14252,14253,14254,14255],{"id":13592,"depth":49,"text":13593},{"id":13719,"depth":49,"text":13720},{"id":13853,"depth":49,"text":13854},{"id":13994,"depth":49,"text":13995},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"Ch.9 covered ArrayList and a basic HashMap. Three more collection types round out the toolbox, each solving a problem the others don't: Set (no duplicates, ever), Queue\u002FDeque (order of processing matters more than random access), and a deeper look at Map (iterating both keys and values together, and choosing an ordering).",{"outlineRef":14258,"status":11220},"15 — Advanced Collections (Set\u002FQueue\u002FMap) (ORACLE 13.1-4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch15-advanced-collections\u002F15-advanced-collections",{"title":13552,"description":14256},"shockwave-curriculum\u002Flessons\u002Fch15-advanced-collections\u002F15-advanced-collections","iljc43nEFsJeFk6_A_SZmUZrmwQtzqbtpoYyqc541tk",{"id":14264,"title":14265,"body":14266,"description":14829,"extension":51,"meta":14830,"navigation":55,"path":14832,"seo":14833,"stem":14834,"__hash__":14835},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch16-writing-your-own-generics\u002F16-writing-your-own-generics.md","Writing Your Own Generics",{"type":8,"value":14267,"toc":14820},[14268,14271,14287,14291,14298,14318,14324,14343,14347,14359,14396,14406,14426,14450,14456,14534,14538,14541,14577,14588,14592,14611,14649,14673,14677,14698,14700,14760,14762,14795,14818],[11,14269,14265],{"id":14270},"writing-your-own-generics",[15,14272,14273,275,14276,275,14279,14282,14283,14286],{},[95,14274,14275],{},"List\u003CString>",[95,14277,14278],{},"Map\u003CInteger, Double>",[95,14280,14281],{},"ArrayList\u003CTalonFX>"," — every collection since Ch.9 has ",[262,14284,14285],{},"used"," a generic type someone else wrote. This chapter is about writing your own.",[69,14288,14290],{"id":14289},"why-generics-exist","Why Generics Exist",[15,14292,14293,14294,14297],{},"Before generics, a reusable container had to work with the generic ",[95,14295,14296],{},"Object"," type, requiring an explicit cast every time you got something back out — and nothing stopped the wrong type from going in in the first place:",[104,14299,14301],{"className":106,"code":14300,"language":108,"meta":48,"style":48},"List list = new ArrayList();         \u002F\u002F no generics\nlist.add(\"hello\");\nString s = (String) list.get(0);     \u002F\u002F cast required, and could fail at runtime\n",[95,14302,14303,14308,14313],{"__ignoreMap":48},[112,14304,14305],{"class":114,"line":115},[112,14306,14307],{},"List list = new ArrayList();         \u002F\u002F no generics\n",[112,14309,14310],{"class":114,"line":49},[112,14311,14312],{},"list.add(\"hello\");\n",[112,14314,14315],{"class":114,"line":126},[112,14316,14317],{},"String s = (String) list.get(0);     \u002F\u002F cast required, and could fail at runtime\n",[15,14319,14320,14321,14323],{},"With a type parameter, the compiler enforces correctness ",[262,14322,1504],{}," the program ever runs, and the cast disappears entirely:",[104,14325,14327],{"className":106,"code":14326,"language":108,"meta":48,"style":48},"List\u003CString> list = new ArrayList\u003CString>();\nlist.add(\"hello\");\nString s = list.get(0);              \u002F\u002F no cast — the compiler already knows it's a String\n",[95,14328,14329,14334,14338],{"__ignoreMap":48},[112,14330,14331],{"class":114,"line":115},[112,14332,14333],{},"List\u003CString> list = new ArrayList\u003CString>();\n",[112,14335,14336],{"class":114,"line":49},[112,14337,14312],{},[112,14339,14340],{"class":114,"line":126},[112,14341,14342],{},"String s = list.get(0);              \u002F\u002F no cast — the compiler already knows it's a String\n",[69,14344,14346],{"id":14345},"writing-a-generic-class","Writing a Generic Class",[15,14348,14349,14350,14353,14354,207,14356,14358],{},"A generic class introduces one or more ",[25,14351,14352],{},"type parameters"," in angle brackets after the class name. Here's a value wrapper — a natural fit for logging a tunable robot value alongside its current setpoint, using a placeholder type instead of committing to ",[95,14355,580],{},[95,14357,315],{}," up front:",[104,14360,14362],{"className":106,"code":14361,"language":108,"meta":48,"style":48},"public class LoggedValue\u003CT>\n{\n    private T value;\n\n    public void set(T v) { value = v; }\n    public T get() { return value; }\n}\n",[95,14363,14364,14369,14373,14378,14382,14387,14392],{"__ignoreMap":48},[112,14365,14366],{"class":114,"line":115},[112,14367,14368],{},"public class LoggedValue\u003CT>\n",[112,14370,14371],{"class":114,"line":49},[112,14372,123],{},[112,14374,14375],{"class":114,"line":126},[112,14376,14377],{},"    private T value;\n",[112,14379,14380],{"class":114,"line":132},[112,14381,820],{"emptyLinePlaceholder":55},[112,14383,14384],{"class":114,"line":138},[112,14385,14386],{},"    public void set(T v) { value = v; }\n",[112,14388,14389],{"class":114,"line":144},[112,14390,14391],{},"    public T get() { return value; }\n",[112,14393,14394],{"class":114,"line":150},[112,14395,153],{},[15,14397,14398,14401,14402,14405],{},[95,14399,14400],{},"T"," isn't a real type — it's a ",[25,14403,14404],{},"type variable",", a placeholder standing in for whatever concrete type gets supplied when the class is actually used:",[104,14407,14409],{"className":106,"code":14408,"language":108,"meta":48,"style":48},"LoggedValue\u003CDouble> setpoint = new LoggedValue\u003C>(); \u002F\u002F the \"diamond\" \u003C> — compiler infers Double from the left side\nsetpoint.set(3.5);    \u002F\u002F OK\nsetpoint.set(\"fast\"); \u002F\u002F compile error — a String doesn't belong in a LoggedValue\u003CDouble>\n",[95,14410,14411,14416,14421],{"__ignoreMap":48},[112,14412,14413],{"class":114,"line":115},[112,14414,14415],{},"LoggedValue\u003CDouble> setpoint = new LoggedValue\u003C>(); \u002F\u002F the \"diamond\" \u003C> — compiler infers Double from the left side\n",[112,14417,14418],{"class":114,"line":49},[112,14419,14420],{},"setpoint.set(3.5);    \u002F\u002F OK\n",[112,14422,14423],{"class":114,"line":126},[112,14424,14425],{},"setpoint.set(\"fast\"); \u002F\u002F compile error — a String doesn't belong in a LoggedValue\u003CDouble>\n",[15,14427,14428,14429,14431,14432,14435,14436,1051,14439,14442,14443,14445,14446,14449],{},"By convention, type parameters are single uppercase letters — ",[95,14430,14400],{}," (Type), ",[95,14433,14434],{},"E"," (Element, used throughout the collections you already know), ",[95,14437,14438],{},"K",[95,14440,14441],{},"V"," (Key\u002FValue, as in ",[95,14444,14088],{},"), ",[95,14447,14448],{},"N"," (Number). This convention exists specifically so a type variable is instantly recognizable and never confused with a real class name.",[15,14451,14452,14453,14455],{},"A generic class can take more than one type parameter, exactly like ",[95,14454,14088],{}," does:",[104,14457,14459],{"className":106,"code":14458,"language":108,"meta":48,"style":48},"public class Pair\u003CK, V>\n{\n    private K key;\n    private V value;\n\n    public Pair(K key, V value)\n    {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey()   { return key; }\n    public V getValue() { return value; }\n}\n\nPair\u003CString, Double> reading = new Pair\u003C>(\"Front-Left Current\", 12.4);\n",[95,14460,14461,14466,14470,14475,14480,14484,14489,14493,14498,14503,14507,14511,14516,14521,14525,14529],{"__ignoreMap":48},[112,14462,14463],{"class":114,"line":115},[112,14464,14465],{},"public class Pair\u003CK, V>\n",[112,14467,14468],{"class":114,"line":49},[112,14469,123],{},[112,14471,14472],{"class":114,"line":126},[112,14473,14474],{},"    private K key;\n",[112,14476,14477],{"class":114,"line":132},[112,14478,14479],{},"    private V value;\n",[112,14481,14482],{"class":114,"line":138},[112,14483,820],{"emptyLinePlaceholder":55},[112,14485,14486],{"class":114,"line":144},[112,14487,14488],{},"    public Pair(K key, V value)\n",[112,14490,14491],{"class":114,"line":150},[112,14492,135],{},[112,14494,14495],{"class":114,"line":1819},[112,14496,14497],{},"        this.key = key;\n",[112,14499,14500],{"class":114,"line":1825},[112,14501,14502],{},"        this.value = value;\n",[112,14504,14505],{"class":114,"line":1831},[112,14506,147],{},[112,14508,14509],{"class":114,"line":4742},[112,14510,820],{"emptyLinePlaceholder":55},[112,14512,14513],{"class":114,"line":4748},[112,14514,14515],{},"    public K getKey()   { return key; }\n",[112,14517,14518],{"class":114,"line":6935},[112,14519,14520],{},"    public V getValue() { return value; }\n",[112,14522,14523],{"class":114,"line":6940},[112,14524,153],{},[112,14526,14527],{"class":114,"line":6946},[112,14528,820],{"emptyLinePlaceholder":55},[112,14530,14531],{"class":114,"line":6952},[112,14532,14533],{},"Pair\u003CString, Double> reading = new Pair\u003C>(\"Front-Left Current\", 12.4);\n",[69,14535,14537],{"id":14536},"generic-methods","Generic Methods",[15,14539,14540],{},"A single method — even inside an otherwise non-generic class — can introduce its own type parameter, written in angle brackets right before the return type. Its scope is limited to that one method:",[104,14542,14544],{"className":106,"code":14543,"language":108,"meta":48,"style":48},"public class Util\n{\n    public static \u003CK, V> boolean sameEntry(Pair\u003CK, V> p1, Pair\u003CK, V> p2)\n    {\n        return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue());\n    }\n}\n",[95,14545,14546,14551,14555,14560,14564,14569,14573],{"__ignoreMap":48},[112,14547,14548],{"class":114,"line":115},[112,14549,14550],{},"public class Util\n",[112,14552,14553],{"class":114,"line":49},[112,14554,123],{},[112,14556,14557],{"class":114,"line":126},[112,14558,14559],{},"    public static \u003CK, V> boolean sameEntry(Pair\u003CK, V> p1, Pair\u003CK, V> p2)\n",[112,14561,14562],{"class":114,"line":132},[112,14563,135],{},[112,14565,14566],{"class":114,"line":138},[112,14567,14568],{},"        return p1.getKey().equals(p2.getKey()) && p1.getValue().equals(p2.getValue());\n",[112,14570,14571],{"class":114,"line":144},[112,14572,147],{},[112,14574,14575],{"class":114,"line":150},[112,14576,153],{},[15,14578,14579,14580,14583,14584,14587],{},"Almost always, the compiler figures out the type on its own from how you call it — this is ",[25,14581,14582],{},"type inference"," — so you can call ",[95,14585,14586],{},"Util.sameEntry(p1, p2)"," directly, without ever writing the type parameter yourself.",[69,14589,14591],{"id":14590},"bounded-type-parameters","Bounded Type Parameters",[15,14593,14594,14595,14598,14599,14601,14602,14605,14606,275,14608,14610],{},"Sometimes a generic type shouldn't accept ",[262,14596,14597],{},"just anything"," — a method built around numeric comparisons only makes sense for actual numbers. ",[95,14600,12389],{}," restricts a type parameter to a specific type (or subtype of it) — here meaning \"any subtype of ",[95,14603,14604],{},"Number",",\" which covers ",[95,14607,8723],{},[95,14609,8726],{},", and the rest:",[104,14612,14614],{"className":106,"code":14613,"language":108,"meta":48,"style":48},"public static \u003CT extends Number> double clampedValue(T value, double min, double max)\n{\n    double v = value.doubleValue(); \u002F\u002F legal — Number guarantees a doubleValue() method\n    if (v \u003C min) return min;\n    if (v > max) return max;\n    return v;\n}\n",[95,14615,14616,14621,14625,14630,14635,14640,14645],{"__ignoreMap":48},[112,14617,14618],{"class":114,"line":115},[112,14619,14620],{},"public static \u003CT extends Number> double clampedValue(T value, double min, double max)\n",[112,14622,14623],{"class":114,"line":49},[112,14624,123],{},[112,14626,14627],{"class":114,"line":126},[112,14628,14629],{},"    double v = value.doubleValue(); \u002F\u002F legal — Number guarantees a doubleValue() method\n",[112,14631,14632],{"class":114,"line":132},[112,14633,14634],{},"    if (v \u003C min) return min;\n",[112,14636,14637],{"class":114,"line":138},[112,14638,14639],{},"    if (v > max) return max;\n",[112,14641,14642],{"class":114,"line":144},[112,14643,14644],{},"    return v;\n",[112,14646,14647],{"class":114,"line":150},[112,14648,153],{},[15,14650,14651,14652,14655,14656,14659,14660,1090,14662,14665,14666,14669,14670,14672],{},"Without the ",[95,14653,14654],{},"extends Number"," bound, ",[95,14657,14658],{},"value.doubleValue()"," wouldn't compile at all — the compiler would only know ",[95,14661,7418],{},[262,14663,14664],{},"some"," type, with no guarantee it has a ",[95,14667,14668],{},"doubleValue()"," method to call. The bound is what unlocks calling methods that only ",[95,14671,14604],{}," (and its subtypes) actually have.",[69,14674,14676],{"id":14675},"wildcards-a-quick-preview","Wildcards: A Quick Preview",[15,14678,1936,14679,14682,14683,14686,14687,14689,14690,14693,14694,14697],{},[95,14680,14681],{},"?"," wildcard represents an unknown type, mostly useful for parameters and fields where you want to accept \"a ",[95,14684,14685],{},"List"," of anything\" without pinning down exactly what. Wildcard variations (upper-bounded, lower-bounded) go beyond what this chapter covers — the short version to remember for now is: ",[95,14688,14681],{}," is never used when ",[262,14691,14692],{},"creating"," a generic type (",[95,14695,14696],{},"new Box\u003C?>()"," isn't a thing) — only when referring to one you don't need to be specific about.",[69,14699,412],{"id":411},[19,14701,14702,14722,14738],{},[22,14703,14704,426,14711,14714,14715,14717,14718,14721],{},[25,14705,14706,14707,14710],{},"Forgetting the ",[95,14708,14709],{},"\u003CT>"," on the class declaration itself.",[95,14712,14713],{},"public class Box { private T t; }"," doesn't compile — ",[95,14716,14400],{}," has to be introduced with ",[95,14719,14720],{},"public class Box\u003CT>"," before it can be used anywhere inside the class.",[22,14723,14724,426,14727,14730,14731,14734,14735,14737],{},[25,14725,14726],{},"Using a primitive as a type argument.",[95,14728,14729],{},"LoggedValue\u003Cdouble>"," doesn't compile — type arguments must be reference types, so use the wrapper (",[95,14732,14733],{},"LoggedValue\u003CDouble>",") instead, same rule as ",[95,14736,8682],{}," (Lesson 9.2).",[22,14739,14740,426,14743,14745,14746,14748,14749,14751,14752,1090,14754,14756,14757,14759],{},[25,14741,14742],{},"Calling a bound-specific method without the bound.",[95,14744,14658],{}," only compiles once ",[95,14747,14400],{}," is declared ",[95,14750,14654],{}," — without the bound, the compiler only knows ",[95,14753,14400],{},[262,14755,14664],{}," type, with no guaranteed methods beyond what every ",[95,14758,14296],{}," has.",[69,14761,450],{"id":449},[19,14763,14764,14771,14777,14780,14790],{},[22,14765,14766,14767,14770],{},"A generic class introduces type parameters in angle brackets after its name (",[95,14768,14769],{},"class LoggedValue\u003CT>","); the type variable then stands in for a real type anywhere in the class.",[22,14772,14773,14774,14776],{},"Generic types replace the old cast-from-",[95,14775,14296],{}," pattern with compile-time type safety — a wrong type is now a compile error, not a runtime surprise.",[22,14778,14779],{},"A generic method can introduce its own type parameter, scoped to just that method; the compiler usually infers the type automatically.",[22,14781,14782,14785,14786,14789],{},[95,14783,14784],{},"\u003CT extends SomeType>"," restricts what a type parameter can be, and unlocks calling ",[95,14787,14788],{},"SomeType","'s own methods on values of that type.",[22,14791,1936,14792,14794],{},[95,14793,14681],{}," wildcard represents an unknown type for referring to a generic type generically — it's never used when constructing one.",[15,14796,493,14797,497,14799,275,14802,275,14805,275,14808,275,14811,14814,14815,14817],{},[95,14798,12493],{},[95,14800,14801],{},"oracle-java-tutorials\u002Fgenerics\u002F01-why-use-generics.md",[95,14803,14804],{},"02-generic-types.md",[95,14806,14807],{},"03-generic-methods.md",[95,14809,14810],{},"04-bounded-type-parameters.md",[95,14812,14813],{},"05-wildcards.md"," (ORACLE 14.1-5)\n",[25,14816,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 2 (\"Writing Your Own Generics\")",[503,14819,505],{},{"title":48,"searchDepth":49,"depth":49,"links":14821},[14822,14823,14824,14825,14826,14827,14828],{"id":14289,"depth":49,"text":14290},{"id":14345,"depth":49,"text":14346},{"id":14536,"depth":49,"text":14537},{"id":14590,"depth":49,"text":14591},{"id":14675,"depth":49,"text":14676},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"List\u003CString>, Map\u003CInteger, Double>, ArrayList\u003CTalonFX> — every collection since Ch.9 has used a generic type someone else wrote. This chapter is about writing your own.",{"outlineRef":14831,"status":519},"16 — Writing Your Own Generics (ORACLE 14.1-5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch16-writing-your-own-generics\u002F16-writing-your-own-generics",{"title":14265,"description":14829},"shockwave-curriculum\u002Flessons\u002Fch16-writing-your-own-generics\u002F16-writing-your-own-generics","EO-5I0lNBpCTNXHNjJQffCyyiyAMR_RhGWZxZ1yzBnA",{"id":14837,"title":14838,"body":14839,"description":48,"extension":51,"meta":15199,"navigation":55,"path":15201,"seo":15202,"stem":15203,"__hash__":15204},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.1-inheritance-superclass-subclass.md","Inheritance, Superclass, Subclass",{"type":8,"value":14840,"toc":15191},[14841,14844,14848,14869,14932,14949,14953,15004,15008,15031,15059,15072,15074,15077,15113,15115,15152,15154,15178,15189],[11,14842,14838],{"id":14843},"inheritance-superclass-subclass",[69,14845,14847],{"id":14846},"what-inheritance-does","What Inheritance Does",[15,14849,14850,14853,14854,14857,14858,14861,14862,14865,14866,14868],{},[25,14851,14852],{},"Inheritance"," lets one class inherit fields and methods from another. The class being inherited from is the ",[25,14855,14856],{},"superclass"," (or parent class); the class doing the inheriting is the ",[25,14859,14860],{},"subclass"," (or child class). Every FRC robot's subsystems share real structure — a name for logging, a ",[95,14863,14864],{},"stop()"," method, a ",[95,14867,12563],{}," method WPILib calls every loop — which makes them a natural fit for a shared superclass:",[104,14870,14872],{"className":106,"code":14871,"language":108,"meta":48,"style":48},"public abstract class Subsystem\n{\n    private String name;\n\n    public Subsystem(String name) { this.name = name; }\n    public String getName() { return name; }\n    public void log(String msg) { System.out.println(\"[\" + name + \"] \" + msg); }\n}\n\npublic class Intake extends Subsystem\n{\n    \u002F\u002F inherits getName() and log() for free\n}\n",[95,14873,14874,14879,14883,14887,14891,14896,14901,14906,14910,14914,14919,14923,14928],{"__ignoreMap":48},[112,14875,14876],{"class":114,"line":115},[112,14877,14878],{},"public abstract class Subsystem\n",[112,14880,14881],{"class":114,"line":49},[112,14882,123],{},[112,14884,14885],{"class":114,"line":126},[112,14886,7399],{},[112,14888,14889],{"class":114,"line":132},[112,14890,820],{"emptyLinePlaceholder":55},[112,14892,14893],{"class":114,"line":138},[112,14894,14895],{},"    public Subsystem(String name) { this.name = name; }\n",[112,14897,14898],{"class":114,"line":144},[112,14899,14900],{},"    public String getName() { return name; }\n",[112,14902,14903],{"class":114,"line":150},[112,14904,14905],{},"    public void log(String msg) { System.out.println(\"[\" + name + \"] \" + msg); }\n",[112,14907,14908],{"class":114,"line":1819},[112,14909,153],{},[112,14911,14912],{"class":114,"line":1825},[112,14913,820],{"emptyLinePlaceholder":55},[112,14915,14916],{"class":114,"line":1831},[112,14917,14918],{},"public class Intake extends Subsystem\n",[112,14920,14921],{"class":114,"line":4742},[112,14922,123],{},[112,14924,14925],{"class":114,"line":4748},[112,14926,14927],{},"    \u002F\u002F inherits getName() and log() for free\n",[112,14929,14930],{"class":114,"line":6935},[112,14931,153],{},[15,14933,14934,14936,14937,426,14939,14942,14943,14945,14946,14948],{},[95,14935,12389],{}," is the keyword that sets up inheritance. A Java class can only ",[95,14938,12389],{},[25,14940,14941],{},"one"," superclass — unlike a person with two biological parents, there's no multiple inheritance of this kind in Java. Omitting ",[95,14944,12389],{}," entirely doesn't mean \"no parent\" — it means the class implicitly inherits from Java's built-in ",[95,14947,14296],{}," class (Lesson 17.4).",[69,14950,14952],{"id":14951},"the-is-a-relationship","The is-a Relationship",[15,14954,14955,14956,14959,14960,426,14962,426,14965,14967,14968,426,14971,426,14973,14975,14976,14979,14980,14982,14983,14986,14987,14989,14990,14993,14994,14997,14998,426,15001,15003],{},"Inheritance should only model a genuine ",[25,14957,14958],{},"is-a"," relationship: an ",[95,14961,6739],{},[262,14963,14964],{},"is a",[95,14966,7343],{},", a ",[95,14969,14970],{},"Climber",[262,14972,14964],{},[95,14974,7343],{},". The test to apply: could you substitute the subclass anywhere the superclass is expected, and have it still make sense? A ",[95,14977,14978],{},"Vision"," processor being asked to ",[95,14981,14864],{}," and get ",[95,14984,14985],{},"log()","ed makes sense as a ",[95,14988,7343],{}," — but a ",[95,14991,14992],{},"Robot"," class itself, or a ",[95,14995,14996],{},"Controller"," wrapping a joystick, isn't a ",[262,14999,15000],{},"kind of",[95,15002,7343],{},", even if it happens to interact with one.",[69,15005,15007],{"id":15006},"is-a-vs-has-a","is-a vs. has-a",[15,15009,1936,15010,15012,15013,15016,15017,426,15019,426,15022,15024,15025,464,15027,15030],{},[25,15011,7339],{}," relationship (also called ",[25,15014,15015],{},"association",") is different: it's when one class simply holds a reference to another, without being a specialized kind of it. A ",[95,15018,14992],{},[262,15020,15021],{},"has a",[95,15023,319],{},", an ",[95,15026,6739],{},[95,15028,15029],{},"Shooter"," — it isn't a subclass of any of them:",[104,15032,15034],{"className":106,"code":15033,"language":108,"meta":48,"style":48},"public class Robot\n{\n    private Drivetrain drivetrain;  \u002F\u002F has-a: Robot holds a Drivetrain, isn't one\n    private Intake intake;          \u002F\u002F has-a\n}\n",[95,15035,15036,15041,15045,15050,15055],{"__ignoreMap":48},[112,15037,15038],{"class":114,"line":115},[112,15039,15040],{},"public class Robot\n",[112,15042,15043],{"class":114,"line":49},[112,15044,123],{},[112,15046,15047],{"class":114,"line":126},[112,15048,15049],{},"    private Drivetrain drivetrain;  \u002F\u002F has-a: Robot holds a Drivetrain, isn't one\n",[112,15051,15052],{"class":114,"line":132},[112,15053,15054],{},"    private Intake intake;          \u002F\u002F has-a\n",[112,15056,15057],{"class":114,"line":138},[112,15058,153],{},[15,15060,15061,15062,15065,15066,15068,15069,15071],{},"Compare that to ",[95,15063,15064],{},"Intake extends Subsystem"," — that's is-a: an ",[95,15067,6739],{}," really is a specialized kind of ",[95,15070,7343],{},", not just something that happens to reference one.",[69,15073,13463],{"id":13462},[15,15075,15076],{},"Two forces motivate reaching for a superclass:",[19,15078,15079,15098],{},[22,15080,15081,15084,15085,275,15087,278,15089,15091,15092,15094,15095,15097],{},[25,15082,15083],{},"Generalization"," — several classes already share data\u002Fbehavior, so pull the shared parts up into one common parent. ",[95,15086,6739],{},[95,15088,15029],{},[95,15090,14970],{}," all need a name and a ",[95,15093,14985],{}," method — that's exactly what ",[95,15096,7343],{}," is for.",[22,15099,15100,15103,15104,15106,15107,15109,15110,15112],{},[25,15101,15102],{},"Specialization"," — a class wants most of a parent's behavior, but needs to add something of its own or do one thing differently. ",[95,15105,6739],{}," inherits ",[95,15108,14985],{}," unchanged, but still needs its own ",[95,15111,14864],{}," that's specific to its own motor.",[69,15114,412],{"id":411},[19,15116,15117,15125,15137],{},[22,15118,15119,15122,15123,79],{},[25,15120,15121],{},"Using inheritance purely to reuse code, without a real is-a relationship."," If the substitution test fails — the subclass wouldn't actually make sense wherever the superclass is expected — model it as has-a (a field) instead of ",[95,15124,12389],{},[22,15126,15127,15130,15131,15133,15134,15136],{},[25,15128,15129],{},"Forgetting a class always has exactly one superclass."," Omitting ",[95,15132,12389],{}," doesn't mean \"no parent\" — it means the implicit parent is ",[95,15135,14296],{}," (Lesson 17.4).",[22,15138,15139,426,15142,15145,15146,15148,15149,15151],{},[25,15140,15141],{},"Assuming a class can extend more than one class.",[95,15143,15144],{},"class Intake extends Subsystem, Loggable"," doesn't compile — Java allows only one ",[95,15147,12389],{},", though a class can ",[95,15150,12393],{}," multiple interfaces.",[69,15153,450],{"id":449},[19,15155,15156,15161,15172,15175],{},[22,15157,15158,15160],{},[95,15159,12389],{}," declares inheritance: the subclass gains the superclass's fields and methods.",[22,15162,15163,15164,15166,15167,15169,15170,79],{},"A class can only ",[95,15165,12389],{}," one superclass; omitting ",[95,15168,12389],{}," implicitly means extending ",[95,15171,14296],{},[22,15173,15174],{},"Use inheritance only for a genuine is-a relationship — verify with the substitution test (does the subclass make sense wherever the superclass is expected?).",[22,15176,15177],{},"has-a (association: one class simply holding a reference to another) is the right model when is-a doesn't genuinely apply.",[15,15179,493,15180,497,15182,15185,15186,15188],{},[95,15181,496],{},[95,15183,15184],{},"unit-5-inheritance-optional\u002F5.01-inheritance-superclass-subclass.md"," (CSA 5.1)\n",[25,15187,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 4 (\"Inheritance & Abstractions\")",[503,15190,505],{},{"title":48,"searchDepth":49,"depth":49,"links":15192},[15193,15194,15195,15196,15197,15198],{"id":14846,"depth":49,"text":14847},{"id":14951,"depth":49,"text":14952},{"id":15006,"depth":49,"text":15007},{"id":13462,"depth":49,"text":13463},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":15200,"status":519},"17.1 — Inheritance, Superclass, Subclass (CSA 5.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F1-inheritance-superclass-subclass",{"title":14838,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.1-inheritance-superclass-subclass","SP29z4YYddrkWdVN0pnIXfnpEj5gtDz4-MW2jGzPuYs",{"id":15206,"title":15207,"body":15208,"description":48,"extension":51,"meta":15487,"navigation":55,"path":15489,"seo":15490,"stem":15491,"__hash__":15492},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.2-inheritance-and-constructors.md","Inheritance and Constructors",{"type":8,"value":15209,"toc":15477},[15210,15213,15217,15230,15237,15244,15324,15339,15346,15362,15366,15379,15394,15396,15442,15444,15467,15475],[11,15211,15207],{"id":15212},"inheritance-and-constructors",[69,15214,15216],{"id":15215},"constructors-are-never-inherited","Constructors Are Never Inherited",[15,15218,15219,15220,15222,15223,15226,15227,15229],{},"A subclass inherits its superclass's ",[95,15221,274],{}," methods and fields, but it does ",[25,15224,15225],{},"not"," inherit constructors, and it can't directly touch the superclass's ",[95,15228,6806],{}," fields. Yet those inherited private fields still need to be properly set up before anything uses them — so how does a subclass initialize state that belongs to its superclass?",[69,15231,1936,15233,15236],{"id":15232},"the-super-call",[95,15234,15235],{},"super(...)"," Call",[15,15238,15239,15240,15243],{},"The keyword ",[95,15241,15242],{},"super",", used like a method call, runs the superclass's constructor code in the context of the object already being built:",[104,15245,15247],{"className":106,"code":15246,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    private String name;\n\n    public Subsystem(String name) { this.name = name; }\n    public String getName() { return name; }\n}\n\npublic class Intake extends Subsystem\n{\n    private boolean hasGamePiece;\n\n    public Intake(String name)\n    {\n        super(name);          \u002F\u002F runs Subsystem's constructor, setting the private `name` field\n        hasGamePiece = false;  \u002F\u002F Intake's own field\n    }\n}\n",[95,15248,15249,15253,15257,15261,15265,15269,15273,15277,15281,15285,15289,15293,15297,15302,15306,15311,15316,15320],{"__ignoreMap":48},[112,15250,15251],{"class":114,"line":115},[112,15252,7694],{},[112,15254,15255],{"class":114,"line":49},[112,15256,123],{},[112,15258,15259],{"class":114,"line":126},[112,15260,7399],{},[112,15262,15263],{"class":114,"line":132},[112,15264,820],{"emptyLinePlaceholder":55},[112,15266,15267],{"class":114,"line":138},[112,15268,14895],{},[112,15270,15271],{"class":114,"line":144},[112,15272,14900],{},[112,15274,15275],{"class":114,"line":150},[112,15276,153],{},[112,15278,15279],{"class":114,"line":1819},[112,15280,820],{"emptyLinePlaceholder":55},[112,15282,15283],{"class":114,"line":1825},[112,15284,14918],{},[112,15286,15287],{"class":114,"line":1831},[112,15288,123],{},[112,15290,15291],{"class":114,"line":4742},[112,15292,6795],{},[112,15294,15295],{"class":114,"line":4748},[112,15296,820],{"emptyLinePlaceholder":55},[112,15298,15299],{"class":114,"line":6935},[112,15300,15301],{},"    public Intake(String name)\n",[112,15303,15304],{"class":114,"line":6940},[112,15305,135],{},[112,15307,15308],{"class":114,"line":6946},[112,15309,15310],{},"        super(name);          \u002F\u002F runs Subsystem's constructor, setting the private `name` field\n",[112,15312,15313],{"class":114,"line":6952},[112,15314,15315],{},"        hasGamePiece = false;  \u002F\u002F Intake's own field\n",[112,15317,15318],{"class":114,"line":6957},[112,15319,147],{},[112,15321,15322],{"class":114,"line":6963},[112,15323,153],{},[15,15325,15326,15329,15330,15332,15333,15335,15336,15338],{},[95,15327,15328],{},"super(name)"," isn't creating a second object — it's the one and only way to run ",[95,15331,7343],{},"'s own initialization logic for the object currently under construction. Without it, ",[95,15334,6549],{}," would never get set, since ",[95,15337,6739],{}," has no direct access to that private field to assign it itself.",[69,15340,15342,15343,15236],{"id":15341},"the-implicit-super-call","The Implicit ",[95,15344,15345],{},"super()",[15,15347,15348,15349,15351,15352,15354,15355,15358,15359,15361],{},"If a constructor doesn't start with an explicit ",[95,15350,15235],{}," call, Java automatically inserts a no-argument ",[95,15353,15345],{}," call for you. That only works if the superclass actually ",[262,15356,15357],{},"has"," a no-argument constructor — if it doesn't, any subclass constructor must explicitly call ",[95,15360,15235],{}," with arguments matching a constructor that does exist, or the code won't compile.",[69,15363,15365],{"id":15364},"the-chain-bottoms-out-at-object","The Chain Bottoms Out at Object",[15,15367,15368,15369,15371,15372,15375,15376,15378],{},"Whether called explicitly or inserted implicitly, every chain of ",[95,15370,15242],{}," calls eventually reaches ",[95,15373,15374],{},"java.lang.Object","'s own no-argument constructor — the one class with no superclass of its own (Lesson 17.4). From there, construction \"unwinds\": ",[95,15377,14296],{},"'s constructor logic runs first, then each class going back down the hierarchy, ending with whichever class was actually instantiated. By the time your own constructor's body runs, every inherited field further up the chain has already been properly initialized.",[104,15380,15382],{"className":106,"code":15381,"language":108,"meta":48,"style":48},"Intake intake = new Intake(\"Front Intake\");\n\u002F\u002F Order of execution: Object() -> Subsystem(String) -> Intake(String)\n",[95,15383,15384,15389],{"__ignoreMap":48},[112,15385,15386],{"class":114,"line":115},[112,15387,15388],{},"Intake intake = new Intake(\"Front Intake\");\n",[112,15390,15391],{"class":114,"line":49},[112,15392,15393],{},"\u002F\u002F Order of execution: Object() -> Subsystem(String) -> Intake(String)\n",[69,15395,412],{"id":411},[19,15397,15398,15419,15430],{},[22,15399,15400,426,15403,13031,15406,15408,15409,1090,15411,2902,15413,15415,15416,15418],{},[25,15401,15402],{},"Trying to assign a superclass's private field directly.",[95,15404,15405],{},"this.name = name;",[95,15407,6739],{},"'s constructor doesn't compile if ",[95,15410,6549],{},[95,15412,6806],{},[95,15414,7343],{}," — only ",[95,15417,15328],{}," can reach it.",[22,15420,15421,15426,15427,15429],{},[25,15422,3455,15423,15425],{},[95,15424,15235],{}," must be the first statement."," A subclass constructor calling ",[95,15428,15235],{}," after other statements doesn't compile — it must be the very first line, since the superclass has to finish initializing before the subclass's own code can safely run.",[22,15431,15432,15438,15439,15441],{},[25,15433,15434,15435,15437],{},"Assuming a no-argument ",[95,15436,15345],{}," always works."," If the superclass has no no-argument constructor (only ones taking parameters), Java can't insert an implicit call — the subclass must explicitly call ",[95,15440,15235],{}," with matching arguments.",[69,15443,450],{"id":449},[19,15445,15446,15452,15461],{},[22,15447,15448,15449,15451],{},"Constructors are never inherited — only a ",[95,15450,15235],{}," call can run the superclass's constructor logic to initialize its own (even private) fields.",[22,15453,15454,15455,15457,15458,15460],{},"If a subclass constructor doesn't call ",[95,15456,15235],{}," explicitly, Java inserts a no-argument ",[95,15459,15345],{}," call automatically — which only works if the superclass has one.",[22,15462,15463,15464,15466],{},"Every construction chain eventually reaches ",[95,15465,14296],{},"'s constructor, which runs first; the subclass's own code only runs after every class above it has finished initializing.",[15,15468,493,15469,497,15471,15474],{},[95,15470,496],{},[95,15472,15473],{},"unit-5-inheritance-optional\u002F5.02-inheritance-and-constructors.md"," (CSA 5.2)",[503,15476,505],{},{"title":48,"searchDepth":49,"depth":49,"links":15478},[15479,15480,15482,15484,15485,15486],{"id":15215,"depth":49,"text":15216},{"id":15232,"depth":49,"text":15481},"The super(...) Call",{"id":15341,"depth":49,"text":15483},"The Implicit super() Call",{"id":15364,"depth":49,"text":15365},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":15488,"status":11220},"17.2 — Inheritance and Constructors (CSA 5.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F2-inheritance-and-constructors",{"title":15207,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.2-inheritance-and-constructors","XOhcFEntdIl8Gr8mHqqfOGW4pv8jjZ7-fIpFJuUsquk",{"id":15494,"title":15495,"body":15496,"description":48,"extension":51,"meta":15775,"navigation":55,"path":15777,"seo":15778,"stem":15779,"__hash__":15780},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.3-inheritance-hierarchies.md","Inheritance Hierarchies",{"type":8,"value":15497,"toc":15767},[15498,15501,15505,15527,15531,15537,15557,15565,15574,15578,15581,15631,15645,15665,15669,15688,15690,15738,15740,15757,15765],[11,15499,15495],{"id":15500},"inheritance-hierarchies",[69,15502,15504],{"id":15503},"multiple-subclasses-one-superclass","Multiple Subclasses, One Superclass",[15,15506,1541,15507,15510,15511,275,15513,278,15515,15517,15518,15520,15521,15523,15524,15526],{},[25,15508,15509],{},"inheritance hierarchy"," forms when several subclasses inherit (directly, or through another subclass) from a common superclass. ",[95,15512,6739],{},[95,15514,15029],{},[95,15516,14970],{}," all extending ",[95,15519,7343],{}," is a small hierarchy; ",[95,15522,14296],{}," sits at the very top of ",[262,15525,9461],{}," hierarchy in Java, since every class ultimately inherits from it (Lesson 17.4).",[69,15528,15530],{"id":15529},"a-superclass-reference-can-hold-any-subclass-object","A Superclass Reference Can Hold Any Subclass Object",[15,15532,15533,15534,687],{},"A variable typed as the superclass can refer to an object of that class ",[262,15535,15536],{},"or any of its subclasses",[104,15538,15540],{"className":106,"code":15539,"language":108,"meta":48,"style":48},"Subsystem s1 = new Subsystem(\"Generic\");\nSubsystem s2 = new Intake(\"Front Intake\");   \u002F\u002F legal — an Intake IS-A Subsystem\nSubsystem s3 = new Climber(\"Left Climber\");  \u002F\u002F legal — a Climber IS-A Subsystem\n",[95,15541,15542,15547,15552],{"__ignoreMap":48},[112,15543,15544],{"class":114,"line":115},[112,15545,15546],{},"Subsystem s1 = new Subsystem(\"Generic\");\n",[112,15548,15549],{"class":114,"line":49},[112,15550,15551],{},"Subsystem s2 = new Intake(\"Front Intake\");   \u002F\u002F legal — an Intake IS-A Subsystem\n",[112,15553,15554],{"class":114,"line":126},[112,15555,15556],{},"Subsystem s3 = new Climber(\"Left Climber\");  \u002F\u002F legal — a Climber IS-A Subsystem\n",[15,15558,15559,15560,15562,15563,687],{},"The reverse doesn't work — a subclass-typed variable cannot hold a plain superclass object, since not every ",[95,15561,7343],{}," is specifically an ",[95,15564,6739],{},[104,15566,15568],{"className":106,"code":15567,"language":108,"meta":48,"style":48},"Intake i = new Subsystem(\"Generic\"); \u002F\u002F ERROR — a Subsystem isn't necessarily an Intake\n",[95,15569,15570],{"__ignoreMap":48},[112,15571,15572],{"class":114,"line":115},[112,15573,15567],{},[69,15575,15577],{"id":15576},"why-this-matters-one-parameter-type-every-subclass","Why This Matters: One Parameter Type, Every Subclass",[15,15579,15580],{},"A method, array, or collection typed against the superclass automatically accepts every subclass too — this is what makes managing a whole robot's subsystems from one place possible:",[104,15582,15584],{"className":106,"code":15583,"language":108,"meta":48,"style":48},"public void stopAll(Subsystem[] subsystems)\n{\n    for (Subsystem s : subsystems)\n    {\n        s.stop(); \u002F\u002F works for an Intake, a Climber, a Shooter — anything extending Subsystem\n    }\n}\n\nSubsystem[] robotSubsystems = { new Intake(\"Front\"), new Climber(\"Left\"), new Shooter(\"Main\") };\nstopAll(robotSubsystems);\n",[95,15585,15586,15591,15595,15600,15604,15609,15613,15617,15621,15626],{"__ignoreMap":48},[112,15587,15588],{"class":114,"line":115},[112,15589,15590],{},"public void stopAll(Subsystem[] subsystems)\n",[112,15592,15593],{"class":114,"line":49},[112,15594,123],{},[112,15596,15597],{"class":114,"line":126},[112,15598,15599],{},"    for (Subsystem s : subsystems)\n",[112,15601,15602],{"class":114,"line":132},[112,15603,135],{},[112,15605,15606],{"class":114,"line":138},[112,15607,15608],{},"        s.stop(); \u002F\u002F works for an Intake, a Climber, a Shooter — anything extending Subsystem\n",[112,15610,15611],{"class":114,"line":144},[112,15612,147],{},[112,15614,15615],{"class":114,"line":150},[112,15616,153],{},[112,15618,15619],{"class":114,"line":1819},[112,15620,820],{"emptyLinePlaceholder":55},[112,15622,15623],{"class":114,"line":1825},[112,15624,15625],{},"Subsystem[] robotSubsystems = { new Intake(\"Front\"), new Climber(\"Left\"), new Shooter(\"Main\") };\n",[112,15627,15628],{"class":114,"line":1831},[112,15629,15630],{},"stopAll(robotSubsystems);\n",[15,15632,15633,15634,15637,15638,275,15640,278,15642,15644],{},"The same holds for collections — an ",[95,15635,15636],{},"ArrayList\u003CSubsystem>"," happily holds ",[95,15639,6739],{},[95,15641,14970],{},[95,15643,15029],{}," objects side by side:",[104,15646,15648],{"className":106,"code":15647,"language":108,"meta":48,"style":48},"ArrayList\u003CSubsystem> allSubsystems = new ArrayList\u003CSubsystem>();\nallSubsystems.add(new Intake(\"Front\"));\nallSubsystems.add(new Climber(\"Left\"));\n",[95,15649,15650,15655,15660],{"__ignoreMap":48},[112,15651,15652],{"class":114,"line":115},[112,15653,15654],{},"ArrayList\u003CSubsystem> allSubsystems = new ArrayList\u003CSubsystem>();\n",[112,15656,15657],{"class":114,"line":49},[112,15658,15659],{},"allSubsystems.add(new Intake(\"Front\"));\n",[112,15661,15662],{"class":114,"line":126},[112,15663,15664],{},"allSubsystems.add(new Climber(\"Left\"));\n",[69,15666,15668],{"id":15667},"which-method-actually-runs","Which Method Actually Runs?",[15,15670,15671,15672,15674,15675,15678,15679,15681,15682,15684,15685,15687],{},"When a method typed against the superclass is called on an object that's actually a subclass instance, Java runs ",[262,15673,3583],{}," actual version of the method — decided by its real runtime type, not the variable's declared type. This is the foundation of ",[25,15676,15677],{},"polymorphism",", covered in full in Lesson 18.3 — for now, the key idea is just that a ",[95,15680,7343],{},"-typed variable holding an ",[95,15683,6739],{}," object still calls ",[95,15686,6739],{},"'s own overridden methods, if it has any.",[69,15689,412],{"id":411},[19,15691,15692,15707,15723],{},[22,15693,15694,426,15697,15700,15701,15703,15704,15706],{},[25,15695,15696],{},"Trying to assign a superclass object to a subclass-typed variable.",[95,15698,15699],{},"Intake i = new Subsystem(...);"," is a compile error — not every ",[95,15702,7343],{}," is an ",[95,15705,6739],{},". This only ever works the other direction (superclass variable, subclass object).",[22,15708,15709,15719,15720,15722],{},[25,15710,15711,15712,15715,15716,15718],{},"Thinking a ",[95,15713,15714],{},"Subsystem[]"," array can only hold plain ",[95,15717,7343],{}," objects."," It can hold any mix of ",[95,15721,7343],{}," and its subclasses — that flexibility is the entire point of typing the array against the superclass.",[22,15724,15725,15728,15729,15731,15732,15734,15735,15737],{},[25,15726,15727],{},"Forgetting which method version actually runs."," Even though a variable is declared ",[95,15730,7343],{},", calling a method on it runs the object's ",[262,15733,7527],{}," class's version — not necessarily ",[95,15736,7343],{},"'s own.",[69,15739,450],{"id":449},[19,15741,15742,15748,15751,15754],{},[22,15743,15744,15745,15747],{},"Several subclasses inheriting from one common superclass form an inheritance hierarchy, with ",[95,15746,14296],{}," at the top of every hierarchy in Java.",[22,15749,15750],{},"A superclass-typed variable, array, or collection can hold objects of that class or any of its subclasses — never the reverse.",[22,15752,15753],{},"This lets one method signature, one array type, or one collection type work seamlessly across an entire family of related subsystem classes.",[22,15755,15756],{},"Which method actually executes depends on the object's real runtime type, not the variable's declared type — the basis of polymorphism (Lesson 18.3).",[15,15758,493,15759,497,15761,15764],{},[95,15760,496],{},[95,15762,15763],{},"unit-5-inheritance-optional\u002F5.05-inheritance-hierarchies.md"," (CSA 5.5)",[503,15766,505],{},{"title":48,"searchDepth":49,"depth":49,"links":15768},[15769,15770,15771,15772,15773,15774],{"id":15503,"depth":49,"text":15504},{"id":15529,"depth":49,"text":15530},{"id":15576,"depth":49,"text":15577},{"id":15667,"depth":49,"text":15668},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":15776,"status":11220},"17.3 — Inheritance Hierarchies (CSA 5.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F3-inheritance-hierarchies",{"title":15495,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.3-inheritance-hierarchies","gg-b_PLQGmSEIr3PiQT_YDvJ-IOBYh-NMuMVshGUloU",{"id":15782,"title":15783,"body":15784,"description":48,"extension":51,"meta":16263,"navigation":55,"path":16265,"seo":16266,"stem":16267,"__hash__":16268},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.4-object-superclass.md","Object Superclass",{"type":8,"value":15785,"toc":16254},[15786,15789,15793,15812,15816,15828,15871,15881,15937,15941,15955,15959,16009,16012,16055,16068,16072,16132,16134,16187,16189,16244,16252],[11,15787,15783],{"id":15788},"object-superclass",[69,15790,15792],{"id":15791},"every-classs-ultimate-parent","Every Class's Ultimate Parent",[15,15794,15795,10566,15797,15799,15800,15802,15803,15805,15806,486,15809,79],{},[95,15796,14296],{},[95,15798,2361],{},") is the superclass of every class in Java — any class without an explicit ",[95,15801,12389],{}," inherits from it automatically. Two of ",[95,15804,14296],{},"'s methods matter enough to override in almost every class you write: ",[95,15807,15808],{},"toString()",[95,15810,15811],{},"equals(Object other)",[69,15813,15815],{"id":15814},"overriding-tostring","Overriding toString()",[15,15817,15818,15820,15821,15823,15824,15827],{},[95,15819,14296],{},"'s default ",[95,15822,15808],{}," produces an unhelpful string like ",[95,15825,15826],{},"Subsystem@1a2b3c"," (the class name plus a memory-address-derived hash). Overriding it to describe the object's real state is good practice in nearly every class:",[104,15829,15831],{"className":106,"code":15830,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    private String name;\n\n    public Subsystem(String name) { this.name = name; }\n\n    @Override\n    public String toString() { return name; }\n}\n",[95,15832,15833,15837,15841,15845,15849,15853,15857,15862,15867],{"__ignoreMap":48},[112,15834,15835],{"class":114,"line":115},[112,15836,7694],{},[112,15838,15839],{"class":114,"line":49},[112,15840,123],{},[112,15842,15843],{"class":114,"line":126},[112,15844,7399],{},[112,15846,15847],{"class":114,"line":132},[112,15848,820],{"emptyLinePlaceholder":55},[112,15850,15851],{"class":114,"line":138},[112,15852,14895],{},[112,15854,15855],{"class":114,"line":144},[112,15856,820],{"emptyLinePlaceholder":55},[112,15858,15859],{"class":114,"line":150},[112,15860,15861],{},"    @Override\n",[112,15863,15864],{"class":114,"line":1819},[112,15865,15866],{},"    public String toString() { return name; }\n",[112,15868,15869],{"class":114,"line":1825},[112,15870,153],{},[15,15872,15873,15874,15876,15877,15880],{},"A subclass's own ",[95,15875,15808],{}," can call ",[95,15878,15879],{},"super.toString()"," and build on it, rather than starting from scratch:",[104,15882,15884],{"className":106,"code":15883,"language":108,"meta":48,"style":48},"public class Intake extends Subsystem\n{\n    private boolean hasGamePiece;\n\n    public Intake(String name) { super(name); }\n\n    @Override\n    public String toString()\n    {\n        return super.toString() + \" (hasGamePiece=\" + hasGamePiece + \")\";\n    }\n}\n",[95,15885,15886,15890,15894,15898,15902,15907,15911,15915,15920,15924,15929,15933],{"__ignoreMap":48},[112,15887,15888],{"class":114,"line":115},[112,15889,14918],{},[112,15891,15892],{"class":114,"line":49},[112,15893,123],{},[112,15895,15896],{"class":114,"line":126},[112,15897,6795],{},[112,15899,15900],{"class":114,"line":132},[112,15901,820],{"emptyLinePlaceholder":55},[112,15903,15904],{"class":114,"line":138},[112,15905,15906],{},"    public Intake(String name) { super(name); }\n",[112,15908,15909],{"class":114,"line":144},[112,15910,820],{"emptyLinePlaceholder":55},[112,15912,15913],{"class":114,"line":150},[112,15914,15861],{},[112,15916,15917],{"class":114,"line":1819},[112,15918,15919],{},"    public String toString()\n",[112,15921,15922],{"class":114,"line":1825},[112,15923,135],{},[112,15925,15926],{"class":114,"line":1831},[112,15927,15928],{},"        return super.toString() + \" (hasGamePiece=\" + hasGamePiece + \")\";\n",[112,15930,15931],{"class":114,"line":4742},[112,15932,147],{},[112,15934,15935],{"class":114,"line":4748},[112,15936,153],{},[69,15938,15940],{"id":15939},"the-equals-method","The equals() Method",[15,15942,15943,15945,15946,15948,15949,15951,15952,15954],{},[95,15944,15811],{},", inherited from ",[95,15947,14296],{},", tests whether two references point to the exact same object — the same result as ",[95,15950,1568],{}," (Lesson 13's \"== vs. .equals()\" gotcha exists precisely because many classes, like ",[95,15953,315],{},", override this default with something more useful).",[69,15956,15958],{"id":15957},"overriding-equals-correctly","Overriding equals() Correctly",[15,15960,15961,15962,15965,15966,15968,15969,12839,15972,15975,15976,14445,15978,12839,15981,15984,15985,14445,15988,12839,15991,486,15993,15996,15997,14445,16000,16003,16004,79],{},"Overriding ",[95,15963,15964],{},"equals"," is more involved than ",[95,15967,7195],{},", since it has to satisfy five formal requirements to remain safe to use anywhere: ",[25,15970,15971],{},"reflexive",[95,15973,15974],{},"o.equals(o)"," is always ",[95,15977,610],{},[25,15979,15980],{},"symmetric",[95,15982,15983],{},"a.equals(b)"," matches ",[95,15986,15987],{},"b.equals(a)",[25,15989,15990],{},"transitive",[95,15992,15983],{},[95,15994,15995],{},"b.equals(c)"," implies ",[95,15998,15999],{},"a.equals(c)",[25,16001,16002],{},"consistent"," (repeated calls give the same answer, if nothing changed), and ",[25,16005,16006,16007],{},"never equal to ",[95,16008,3384],{},[15,16010,16011],{},"A standard recipe satisfies all five:",[104,16013,16015],{"className":106,"code":16014,"language":108,"meta":48,"style":48},"@Override\npublic boolean equals(Object other)\n{\n    if (this == other) return true;               \u002F\u002F 1. quick check: same object\n    if (!(other instanceof Subsystem)) return false; \u002F\u002F 2. must be the same type\n    Subsystem o = (Subsystem) other;               \u002F\u002F 3. safe to cast now\n    return this.name.equals(o.name);               \u002F\u002F 4. compare the relevant fields\n}\n",[95,16016,16017,16022,16027,16031,16036,16041,16046,16051],{"__ignoreMap":48},[112,16018,16019],{"class":114,"line":115},[112,16020,16021],{},"@Override\n",[112,16023,16024],{"class":114,"line":49},[112,16025,16026],{},"public boolean equals(Object other)\n",[112,16028,16029],{"class":114,"line":126},[112,16030,123],{},[112,16032,16033],{"class":114,"line":132},[112,16034,16035],{},"    if (this == other) return true;               \u002F\u002F 1. quick check: same object\n",[112,16037,16038],{"class":114,"line":138},[112,16039,16040],{},"    if (!(other instanceof Subsystem)) return false; \u002F\u002F 2. must be the same type\n",[112,16042,16043],{"class":114,"line":144},[112,16044,16045],{},"    Subsystem o = (Subsystem) other;               \u002F\u002F 3. safe to cast now\n",[112,16047,16048],{"class":114,"line":150},[112,16049,16050],{},"    return this.name.equals(o.name);               \u002F\u002F 4. compare the relevant fields\n",[112,16052,16053],{"class":114,"line":1819},[112,16054,153],{},[15,16056,16057,16058,16060,16061,16064,16065,16067],{},"Note the parameter type is always ",[95,16059,14296],{},", never the class itself — ",[95,16062,16063],{},"equals(Subsystem other)"," would be a completely different method (overloading, not overriding), not the one ",[95,16066,14296],{}," actually declares.",[69,16069,16071],{"id":16070},"the-subclass-equals-trap","The Subclass equals() Trap",[15,16073,15961,16074,16076,16077,16080,16081,16083,16084,16086,16087,3883,16089,16092,16093,5183,16096,16099,16100,10706,16102,16104,16105,16107,16108,16099,16111,10706,16113,16115,16116,16119,16120,16122,16123,16125,16126,16128,16129,16131],{},[95,16075,15964],{}," again in a subclass of a class that's already overridden it is genuinely difficult to get right, and easy to accidentally break ",[25,16078,16079],{},"symmetry",". If ",[95,16082,6739],{}," (subclass of ",[95,16085,7343],{},") overrode ",[95,16088,15964],{},[262,16090,16091],{},"also"," compare ",[95,16094,16095],{},"hasGamePiece",[95,16097,16098],{},"genericSubsystem.equals(intakeObj)"," would call ",[95,16101,7343],{},[95,16103,15964],{}," (comparing only ",[95,16106,6549],{},"), while ",[95,16109,16110],{},"intakeObj.equals(genericSubsystem)",[95,16112,6739],{},[95,16114,15964],{}," — which checks ",[95,16117,16118],{},"other instanceof Intake"," and returns ",[95,16121,613],{},", since a plain ",[95,16124,7343],{}," isn't an ",[95,16127,6739],{},". The two calls disagree, breaking the symmetry rule. The general guideline: only one class in a hierarchy should provide a real ",[95,16130,15964],{}," override.",[69,16133,412],{"id":411},[19,16135,16136,16157,16177],{},[22,16137,16138,16145,16146,16148,16149,6249,16151,16153,16154,16156],{},[25,16139,16140,16141,3972,16143,79],{},"Writing ",[95,16142,16063],{},[95,16144,15811],{}," That's overloading a new method, not overriding ",[95,16147,14296],{},"'s — code calling ",[95,16150,5424],{},[95,16152,7343],{},"-typed variable would still use ",[95,16155,14296],{},"'s original version.",[22,16158,16159,16165,16166,16169,16170,16173,16174,16176],{},[25,16160,14706,16161,16164],{},[95,16162,16163],{},"instanceof"," check before casting."," Casting ",[95,16167,16168],{},"other"," to your class without checking first throws ",[95,16171,16172],{},"ClassCastException"," if ",[95,16175,16168],{}," turns out to be some unrelated type.",[22,16178,16179,16184,16185,16131],{},[25,16180,15961,16181,16183],{},[95,16182,15964],{}," again further down an inheritance hierarchy."," This tends to violate symmetry — safest to let only one class in the hierarchy own the ",[95,16186,15964],{},[69,16188,450],{"id":449},[19,16190,16191,16201,16209,16223,16238],{},[22,16192,16193,16195,16196,486,16198,16200],{},[95,16194,14296],{}," is the superclass of every class in Java; ",[95,16197,15808],{},[95,16199,15811],{}," are its two methods worth overriding almost everywhere.",[22,16202,16203,16204,15876,16206,16208],{},"A subclass's ",[95,16205,15808],{},[95,16207,15879],{}," and extend it, rather than rebuilding the whole description from scratch.",[22,16210,16211,15820,16213,16215,16216,16218,16219,6607,16221,79],{},[95,16212,14296],{},[95,16214,15964],{}," is identity comparison (same as ",[95,16217,1568],{},"); a correct override must be reflexive, symmetric, transitive, consistent, and never ",[95,16220,610],{},[95,16222,3384],{},[22,16224,16225,16226,16228,16229,16232,16233,16235,16236,79],{},"The standard ",[95,16227,15964],{}," recipe: check ",[95,16230,16231],{},"this == other",", check ",[95,16234,16163],{},", cast, then compare the relevant fields — always with parameter type ",[95,16237,14296],{},[22,16239,16240,16241,16243],{},"Avoid overriding ",[95,16242,15964],{}," more than once down an inheritance hierarchy — it tends to break symmetry.",[15,16245,493,16246,497,16248,16251],{},[95,16247,496],{},[95,16249,16250],{},"unit-5-inheritance-optional\u002F5.07-object-superclass.md"," (CSA 5.7)",[503,16253,505],{},{"title":48,"searchDepth":49,"depth":49,"links":16255},[16256,16257,16258,16259,16260,16261,16262],{"id":15791,"depth":49,"text":15792},{"id":15814,"depth":49,"text":15815},{"id":15939,"depth":49,"text":15940},{"id":15957,"depth":49,"text":15958},{"id":16070,"depth":49,"text":16071},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":16264,"status":11220},"17.4 — Object Superclass (CSA 5.7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F4-object-superclass",{"title":15783,"description":48},"shockwave-curriculum\u002Flessons\u002Fch17-inheritance-and-abstractions\u002F17.4-object-superclass","Zbvju8fFQNYcxrmOQ4WwJovX5pqg8kw5W5eOjXSbDdg",{"id":16270,"title":16271,"body":16272,"description":48,"extension":51,"meta":16574,"navigation":55,"path":16576,"seo":16577,"stem":16578,"__hash__":16579},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.1-overriding-methods.md","Overriding Methods",{"type":8,"value":16273,"toc":16567},[16274,16277,16281,16294,16354,16369,16373,16389,16416,16422,16426,16435,16499,16501,16529,16531,16554,16565],[11,16275,16271],{"id":16276},"overriding-methods",[69,16278,16280],{"id":16279},"what-overriding-is","What Overriding Is",[15,16282,16283,16284,16286,16287,16290,16291,16293],{},"A subclass inherits all its superclass's ",[95,16285,274],{}," methods unchanged — but it can also ",[25,16288,16289],{},"override"," one, replacing the inherited version with its own. Overriding requires matching the superclass method's exact ",[25,16292,2473],{},": same name, same parameter list, and the same (or a subtype of the) return type.",[104,16295,16297],{"className":106,"code":16296,"language":108,"meta":48,"style":48},"public abstract class Subsystem\n{\n    public void stop() { System.out.println(\"Stopping subsystem\"); }\n}\n\npublic class Intake extends Subsystem\n{\n    @Override\n    public void stop()\n    {\n        motor.set(0); \u002F\u002F Intake's own, specific version replaces Subsystem's\n    }\n}\n",[95,16298,16299,16303,16307,16312,16316,16320,16324,16328,16332,16337,16341,16346,16350],{"__ignoreMap":48},[112,16300,16301],{"class":114,"line":115},[112,16302,14878],{},[112,16304,16305],{"class":114,"line":49},[112,16306,123],{},[112,16308,16309],{"class":114,"line":126},[112,16310,16311],{},"    public void stop() { System.out.println(\"Stopping subsystem\"); }\n",[112,16313,16314],{"class":114,"line":132},[112,16315,153],{},[112,16317,16318],{"class":114,"line":138},[112,16319,820],{"emptyLinePlaceholder":55},[112,16321,16322],{"class":114,"line":144},[112,16323,14918],{},[112,16325,16326],{"class":114,"line":150},[112,16327,123],{},[112,16329,16330],{"class":114,"line":1819},[112,16331,15861],{},[112,16333,16334],{"class":114,"line":1825},[112,16335,16336],{},"    public void stop()\n",[112,16338,16339],{"class":114,"line":1831},[112,16340,135],{},[112,16342,16343],{"class":114,"line":4742},[112,16344,16345],{},"        motor.set(0); \u002F\u002F Intake's own, specific version replaces Subsystem's\n",[112,16347,16348],{"class":114,"line":4748},[112,16349,147],{},[112,16351,16352],{"class":114,"line":6935},[112,16353,153],{},[15,16355,16356,16359,16360,3972,16363,16365,16366,16368],{},[95,16357,16358],{},"@Override"," is optional but always worth writing — it tells the compiler \"I intend to override an inherited method here,\" and the compiler then checks the signature truly matches. Without it, a typo in the method name (",[95,16361,16362],{},"stopp()",[95,16364,14864],{},") would silently create a brand-new, unrelated method instead of overriding anything — with ",[95,16367,16358],{},", that same typo becomes a compile error instead of a bug that only shows up at runtime.",[69,16370,16372],{"id":16371},"overriding-vs-overloading","Overriding vs. Overloading",[15,16374,16375,16376,16379,16380,16382,16383,16385,16386,16388],{},"These sound similar but are entirely different things. ",[25,16377,16378],{},"Overriding"," means the exact same signature, in a subclass, replacing the superclass's version. ",[25,16381,2534],{}," means the same method ",[262,16384,6549],{},", in the ",[262,16387,5417],{}," class, with a different parameter list:",[104,16390,16392],{"className":106,"code":16391,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    public void log(String message) { System.out.println(message); }\n    public void log(String message, int code) { System.out.println(message + \" [\" + code + \"]\"); } \u002F\u002F overload — different parameters\n}\n",[95,16393,16394,16398,16402,16407,16412],{"__ignoreMap":48},[112,16395,16396],{"class":114,"line":115},[112,16397,7694],{},[112,16399,16400],{"class":114,"line":49},[112,16401,123],{},[112,16403,16404],{"class":114,"line":126},[112,16405,16406],{},"    public void log(String message) { System.out.println(message); }\n",[112,16408,16409],{"class":114,"line":132},[112,16410,16411],{},"    public void log(String message, int code) { System.out.println(message + \" [\" + code + \"]\"); } \u002F\u002F overload — different parameters\n",[112,16413,16414],{"class":114,"line":138},[112,16415,153],{},[15,16417,16418,16419,16421],{},"Two methods can never differ ",[262,16420,6844],{}," in return type — that alone doesn't count as a valid overload, and doesn't count as an override either (a mismatched return type on an otherwise-identical signature is just a compile error).",[69,16423,16425],{"id":16424},"inherited-getters-and-setters-still-apply","Inherited Getters and Setters Still Apply",[15,16427,16428,16429,16431,16432,16434],{},"A subclass gets its superclass's public getters and setters automatically, and — since the superclass's fields are ",[95,16430,6806],{}," — those accessor methods remain the ",[262,16433,6844],{}," way to reach them, even from the subclass itself:",[104,16436,16438],{"className":106,"code":16437,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    private String name;\n    public String getName() { return name; }\n    public void setName(String name) { this.name = name; }\n}\n\npublic class Intake extends Subsystem\n{\n    public void rename(String newName)\n    {\n        setName(newName); \u002F\u002F must go through the inherited setter — direct access to `name` isn't legal here\n    }\n}\n",[95,16439,16440,16444,16448,16452,16456,16461,16465,16469,16473,16477,16482,16486,16491,16495],{"__ignoreMap":48},[112,16441,16442],{"class":114,"line":115},[112,16443,7694],{},[112,16445,16446],{"class":114,"line":49},[112,16447,123],{},[112,16449,16450],{"class":114,"line":126},[112,16451,7399],{},[112,16453,16454],{"class":114,"line":132},[112,16455,14900],{},[112,16457,16458],{"class":114,"line":138},[112,16459,16460],{},"    public void setName(String name) { this.name = name; }\n",[112,16462,16463],{"class":114,"line":144},[112,16464,153],{},[112,16466,16467],{"class":114,"line":150},[112,16468,820],{"emptyLinePlaceholder":55},[112,16470,16471],{"class":114,"line":1819},[112,16472,14918],{},[112,16474,16475],{"class":114,"line":1825},[112,16476,123],{},[112,16478,16479],{"class":114,"line":1831},[112,16480,16481],{},"    public void rename(String newName)\n",[112,16483,16484],{"class":114,"line":4742},[112,16485,135],{},[112,16487,16488],{"class":114,"line":4748},[112,16489,16490],{},"        setName(newName); \u002F\u002F must go through the inherited setter — direct access to `name` isn't legal here\n",[112,16492,16493],{"class":114,"line":6935},[112,16494,147],{},[112,16496,16497],{"class":114,"line":6940},[112,16498,153],{},[69,16500,412],{"id":411},[19,16502,16503,16509,16516],{},[22,16504,16505,16508],{},[25,16506,16507],{},"Mismatching the signature and expecting an override anyway."," Changing the parameter list (even by adding one parameter) makes it an overload, not an override — the original method is still inherited unchanged, sitting alongside the new one.",[22,16510,16511,16515],{},[25,16512,3455,16513,79],{},[95,16514,16358],{}," Skipping it doesn't break anything when the signature is right, but it removes the compiler's safety net against typos — always include it when overriding.",[22,16517,16518,426,16521,16524,16525,16528],{},[25,16519,16520],{},"Trying to differ only by return type.",[95,16522,16523],{},"public int stop()"," next to a superclass's ",[95,16526,16527],{},"public void stop()"," doesn't compile — that's neither a valid override nor a valid overload.",[69,16530,450],{"id":449},[19,16532,16533,16540,16545,16548,16551],{},[22,16534,16535,16536,16539],{},"Overriding replaces an inherited method with a new version in the subclass, using the ",[262,16537,16538],{},"exact same"," signature (name, parameters, return type).",[22,16541,16542,16544],{},[95,16543,16358],{}," isn't required, but should always be used — it turns a signature typo into a compile error instead of a silent, unrelated new method.",[22,16546,16547],{},"Overloading is different: same name, same class, different parameter list — not to be confused with overriding.",[22,16549,16550],{},"Two methods can never differ only in return type.",[22,16552,16553],{},"Inherited getters\u002Fsetters remain the only way to reach a superclass's private fields, even from within the subclass.",[15,16555,493,16556,497,16558,16561,16562,16564],{},[95,16557,496],{},[95,16559,16560],{},"unit-5-inheritance-optional\u002F5.03-overriding-methods.md"," (CSA 5.3)\n",[25,16563,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 5 (\"Polymorphism: Many Forms\")",[503,16566,505],{},{"title":48,"searchDepth":49,"depth":49,"links":16568},[16569,16570,16571,16572,16573],{"id":16279,"depth":49,"text":16280},{"id":16371,"depth":49,"text":16372},{"id":16424,"depth":49,"text":16425},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":16575,"status":519},"18.1 — Overriding Methods (CSA 5.3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F1-overriding-methods",{"title":16271,"description":48},"shockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.1-overriding-methods","cTmbUryiwRAnVcfDU7g0kN8v9gRYqdVcnof1976j4rs",{"id":16581,"title":16582,"body":16583,"description":48,"extension":51,"meta":16895,"navigation":55,"path":16897,"seo":16898,"stem":16899,"__hash__":16900},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.2-super-keyword.md","super Keyword",{"type":8,"value":16584,"toc":16888},[16585,16588,16592,16603,16666,16683,16687,16690,16756,16777,16781,16808,16810,16851,16853,16876,16886],[11,16586,16582],{"id":16587},"super-keyword",[69,16589,16591],{"id":16590},"extending-not-just-replacing-inherited-behavior","Extending, Not Just Replacing, Inherited Behavior",[15,16593,16594,16595,16598,16599,16602],{},"Overriding a method (Lesson 18.1) completely replaces the superclass's version — but often a subclass wants to run the ",[262,16596,16597],{},"original"," logic too, and add something on top of it, rather than throwing it away entirely. ",[95,16600,16601],{},"super.method()"," calls the superclass's version of a method explicitly, from inside an override:",[104,16604,16606],{"className":106,"code":16605,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    @Override\n    public String toString() { return \"Subsystem\"; }\n}\n\npublic class Intake extends Subsystem\n{\n    @Override\n    public String toString()\n    {\n        return super.toString() + \" (Intake)\"; \u002F\u002F runs Subsystem's version first, then extends it\n    }\n}\n",[95,16607,16608,16612,16616,16620,16625,16629,16633,16637,16641,16645,16649,16653,16658,16662],{"__ignoreMap":48},[112,16609,16610],{"class":114,"line":115},[112,16611,7694],{},[112,16613,16614],{"class":114,"line":49},[112,16615,123],{},[112,16617,16618],{"class":114,"line":126},[112,16619,15861],{},[112,16621,16622],{"class":114,"line":132},[112,16623,16624],{},"    public String toString() { return \"Subsystem\"; }\n",[112,16626,16627],{"class":114,"line":138},[112,16628,153],{},[112,16630,16631],{"class":114,"line":144},[112,16632,820],{"emptyLinePlaceholder":55},[112,16634,16635],{"class":114,"line":150},[112,16636,14918],{},[112,16638,16639],{"class":114,"line":1819},[112,16640,123],{},[112,16642,16643],{"class":114,"line":1825},[112,16644,15861],{},[112,16646,16647],{"class":114,"line":1831},[112,16648,15919],{},[112,16650,16651],{"class":114,"line":4742},[112,16652,135],{},[112,16654,16655],{"class":114,"line":4748},[112,16656,16657],{},"        return super.toString() + \" (Intake)\"; \u002F\u002F runs Subsystem's version first, then extends it\n",[112,16659,16660],{"class":114,"line":6935},[112,16661,147],{},[112,16663,16664],{"class":114,"line":6940},[112,16665,153],{},[15,16667,16668,16670,16671,16673,16674,16676,16677,16679,16680,16682],{},[95,16669,15242],{}," has two distinct uses, both already introduced separately: ",[95,16672,15235],{},", which must be the first line of a constructor and calls a superclass ",[262,16675,3336],{}," (Lesson 17.2); and ",[95,16678,16601],{},", which calls a superclass ",[262,16681,2456],{}," from anywhere inside a subclass method body.",[69,16684,16686],{"id":16685},"how-method-lookup-actually-works","How Method Lookup Actually Works",[15,16688,16689],{},"Every object remembers the actual class it was created with. A method call on that object starts looking there first; if the method isn't found in that exact class, Java searches up the chain — parent, grandparent, and so on — until it finds a match (which it always will, or the code wouldn't have compiled in the first place).",[104,16691,16693],{"className":106,"code":16692,"language":108,"meta":48,"style":48},"public class Subsystem\n{\n    public void periodic() { System.out.println(\"Subsystem periodic\"); }\n}\n\npublic class Climber extends Subsystem\n{\n    @Override\n    public void periodic()\n    {\n        super.periodic();                    \u002F\u002F explicitly runs Subsystem's version first\n        System.out.println(\"Climber periodic\"); \u002F\u002F then adds Climber's own behavior\n    }\n}\n",[95,16694,16695,16699,16703,16708,16712,16716,16721,16725,16729,16734,16738,16743,16748,16752],{"__ignoreMap":48},[112,16696,16697],{"class":114,"line":115},[112,16698,7694],{},[112,16700,16701],{"class":114,"line":49},[112,16702,123],{},[112,16704,16705],{"class":114,"line":126},[112,16706,16707],{},"    public void periodic() { System.out.println(\"Subsystem periodic\"); }\n",[112,16709,16710],{"class":114,"line":132},[112,16711,153],{},[112,16713,16714],{"class":114,"line":138},[112,16715,820],{"emptyLinePlaceholder":55},[112,16717,16718],{"class":114,"line":144},[112,16719,16720],{},"public class Climber extends Subsystem\n",[112,16722,16723],{"class":114,"line":150},[112,16724,123],{},[112,16726,16727],{"class":114,"line":1819},[112,16728,15861],{},[112,16730,16731],{"class":114,"line":1825},[112,16732,16733],{},"    public void periodic()\n",[112,16735,16736],{"class":114,"line":1831},[112,16737,135],{},[112,16739,16740],{"class":114,"line":4742},[112,16741,16742],{},"        super.periodic();                    \u002F\u002F explicitly runs Subsystem's version first\n",[112,16744,16745],{"class":114,"line":4748},[112,16746,16747],{},"        System.out.println(\"Climber periodic\"); \u002F\u002F then adds Climber's own behavior\n",[112,16749,16750],{"class":114,"line":6935},[112,16751,147],{},[112,16753,16754],{"class":114,"line":6940},[112,16755,153],{},[15,16757,9197,16758,16761,16762,16765,16766,16769,16770,16773,16774,16776],{},[95,16759,16760],{},"climberInstance.periodic()"," starts in ",[95,16763,16764],{},"Climber.periodic()","; when execution reaches ",[95,16767,16768],{},"super.periodic()",", it runs ",[95,16771,16772],{},"Subsystem.periodic()",", then returns to finish the rest of ",[95,16775,16764],{},"'s body.",[69,16778,16780],{"id":16779},"a-subtlety-super-only-affects-the-one-call-its-written-on","A Subtlety: super Only Affects the One Call It's Written On",[15,16782,16783,16786,16787,16790,16791,16793,16794,16796,16797,16800,16801,16804,16805,16807],{},[95,16784,16785],{},"super.someMethod()"," only changes which version of ",[262,16788,16789],{},"that specific call"," runs — it doesn't change how any other method call inside the same method resolves. Any call made without ",[95,16792,15242],{}," (an unqualified call, or one through ",[95,16795,2344],{},") still dispatches based on the object's actual runtime type, even from inside inherited code. This is why a ",[95,16798,16799],{},"super.methodOne()"," call that internally calls another method still ends up running the ",[262,16802,16803],{},"subclass's"," override of that other method, not the superclass's — the override \"wins\" everywhere except the one spot ",[95,16806,15242],{}," explicitly overrides it.",[69,16809,412],{"id":411},[19,16811,16812,16826,16840],{},[22,16813,16814,16822,16823,16825],{},[25,16815,3455,16816,16818,16819,16821],{},[95,16817,16601],{}," must be called explicitly — it never happens automatically the way ",[95,16820,15345],{}," does for constructors."," Overriding a method completely discards the superclass's version unless the override calls ",[95,16824,16601],{}," itself.",[22,16827,16828,426,16834,16836,16837,16839],{},[25,16829,16830,16831,16833],{},"Confusing the two ",[95,16832,15242],{}," forms.",[95,16835,15235],{}," (no method name) only ever calls a constructor, and only as a constructor's first line; ",[95,16838,16601],{}," calls a named method, and can appear anywhere inside a method body.",[22,16841,16842,16847,16848,16850],{},[25,16843,1367,16844,16846],{},[95,16845,16601],{}," changes every call inside that method to use the superclass's versions."," It only affects the one call written with ",[95,16849,15242],{}," — any other method call inside that same superclass method still resolves against the object's real runtime type.",[69,16852,450],{"id":449},[19,16854,16855,16860,16863,16871],{},[22,16856,16857,16859],{},[95,16858,16601],{}," explicitly calls the superclass's version of a method, letting a subclass extend rather than fully replace inherited behavior.",[22,16861,16862],{},"Method lookup starts at the object's actual class and searches upward through its ancestors until a match is found.",[22,16864,16865,16867,16868,16870],{},[95,16866,15235],{}," (constructors) and ",[95,16869,16601],{}," (methods) are two distinct, unrelated uses of the same keyword.",[22,16872,355,16873,16875],{},[95,16874,16601],{}," call only affects that one call — any other unqualified method call inside still dispatches to the object's real runtime type.",[15,16877,493,16878,497,16880,16883,16884,16564],{},[95,16879,496],{},[95,16881,16882],{},"unit-5-inheritance-optional\u002F5.04-super-keyword.md"," (CSA 5.4)\n",[25,16885,4022],{},[503,16887,505],{},{"title":48,"searchDepth":49,"depth":49,"links":16889},[16890,16891,16892,16893,16894],{"id":16590,"depth":49,"text":16591},{"id":16685,"depth":49,"text":16686},{"id":16779,"depth":49,"text":16780},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":16896,"status":11220},"18.2 — super Keyword (CSA 5.4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F2-super-keyword",{"title":16582,"description":48},"shockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.2-super-keyword","occ-NwmWIn5WpRkKr_-t8ZAdti9qy7mZ98UASRT6p4k",{"id":16902,"title":16903,"body":16904,"description":48,"extension":51,"meta":17196,"navigation":55,"path":17198,"seo":17199,"stem":17200,"__hash__":17201},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.3-polymorphism.md","Polymorphism",{"type":8,"value":16905,"toc":17188},[16906,16908,16912,16932,16955,16959,16972,16992,16999,17014,17037,17041,17051,17066,17086,17109,17113,17119,17121,17149,17151,17175,17186],[11,16907,16903],{"id":15677},[69,16909,16911],{"id":16910},"many-forms-one-piece-of-code","Many Forms, One Piece of Code",[15,16913,16914,16916,16917,16920,16921,16923,16924,16927,16928,16931],{},[25,16915,16903],{}," (\"many forms\") means the method that actually runs at runtime depends on the object's ",[262,16918,16919],{},"actual"," type — not the type its variable was declared with. This is the concrete payoff of everything Ch.17 and Lessons 18.1-18.2 built toward: real WPILib code treats a ",[95,16922,2010],{}," or a ",[95,16925,16926],{},"SparkMax"," as just a ",[95,16929,16930],{},"MotorController",", and calls the same method on either without caring which one it actually is:",[104,16933,16935],{"className":106,"code":16934,"language":108,"meta":48,"style":48},"public void driveForward(MotorController controller)\n{\n    controller.set(0.5); \u002F\u002F works identically whether controller is a TalonFX or a SparkMax\n}\n",[95,16936,16937,16942,16946,16951],{"__ignoreMap":48},[112,16938,16939],{"class":114,"line":115},[112,16940,16941],{},"public void driveForward(MotorController controller)\n",[112,16943,16944],{"class":114,"line":49},[112,16945,123],{},[112,16947,16948],{"class":114,"line":126},[112,16949,16950],{},"    controller.set(0.5); \u002F\u002F works identically whether controller is a TalonFX or a SparkMax\n",[112,16952,16953],{"class":114,"line":132},[112,16954,153],{},[69,16956,16958],{"id":16957},"declared-type-vs-actual-type","Declared Type vs. Actual Type",[15,16960,16961,16962,16965,16966,16969,16970,687],{},"Every variable has two types that matter: its ",[25,16963,16964],{},"declared (compile-time) type"," — what it's written as in the code — and its ",[25,16967,16968],{},"actual (runtime) type"," — the real class that was actually constructed with ",[95,16971,2860],{},[104,16973,16975],{"className":106,"code":16974,"language":108,"meta":48,"style":48},"Subsystem s = new Intake(\"Front Intake\");\n\u002F\u002F declared type: Subsystem\n\u002F\u002F actual type:   Intake\n",[95,16976,16977,16982,16987],{"__ignoreMap":48},[112,16978,16979],{"class":114,"line":115},[112,16980,16981],{},"Subsystem s = new Intake(\"Front Intake\");\n",[112,16983,16984],{"class":114,"line":49},[112,16985,16986],{},"\u002F\u002F declared type: Subsystem\n",[112,16988,16989],{"class":114,"line":126},[112,16990,16991],{},"\u002F\u002F actual type:   Intake\n",[15,16993,16994,16995,16998],{},"The compiler only ever checks the ",[25,16996,16997],{},"declared"," type when deciding whether code compiles — it verifies that whatever method you're calling actually exists on that declared type (or an ancestor of it):",[104,17000,17002],{"className":106,"code":17001,"language":108,"meta":48,"style":48},"Object message = new String(\"hi\");\nmessage.indexOf(\"h\"); \u002F\u002F COMPILE ERROR — Object has no indexOf method, even though String does\n",[95,17003,17004,17009],{"__ignoreMap":48},[112,17005,17006],{"class":114,"line":115},[112,17007,17008],{},"Object message = new String(\"hi\");\n",[112,17010,17011],{"class":114,"line":49},[112,17012,17013],{},"message.indexOf(\"h\"); \u002F\u002F COMPILE ERROR — Object has no indexOf method, even though String does\n",[15,17015,17016,17017,17019,17020,17022,17023,10706,17026,17028,17029,17031,17032,17034,17035,7613],{},"Even though the real object here is a ",[95,17018,315],{}," (which absolutely does have ",[95,17021,6481],{},"), the compiler only looks at ",[95,17024,17025],{},"message",[262,17027,16997],{}," type, ",[95,17030,14296],{}," — and refuses to compile, since ",[95,17033,14296],{}," never promises an ",[95,17036,6481],{},[69,17038,17040],{"id":17039},"runtime-dispatch-the-actual-type-decides-which-version-runs","Runtime Dispatch: The Actual Type Decides Which Version Runs",[15,17042,17043,17044,17047,17048,17050],{},"Once code ",[262,17045,17046],{},"does"," compile, the JVM decides which overridden version of a method actually executes by looking at the object's real, actual type — starting there and searching upward through its superclasses if needed (same lookup process as Lesson 18.2's ",[95,17049,15242],{},"):",[104,17052,17054],{"className":106,"code":17053,"language":108,"meta":48,"style":48},"Subsystem s = new Intake(\"Front Intake\"); \u002F\u002F declared Subsystem, actually an Intake\ns.stop(); \u002F\u002F the compiler only confirms Subsystem HAS a stop() method — but Intake's own override is what actually runs\n",[95,17055,17056,17061],{"__ignoreMap":48},[112,17057,17058],{"class":114,"line":115},[112,17059,17060],{},"Subsystem s = new Intake(\"Front Intake\"); \u002F\u002F declared Subsystem, actually an Intake\n",[112,17062,17063],{"class":114,"line":49},[112,17064,17065],{},"s.stop(); \u002F\u002F the compiler only confirms Subsystem HAS a stop() method — but Intake's own override is what actually runs\n",[15,17067,17068,17069,1051,17071,17073,17074,17077,17078,17080,17081,1051,17083,17085],{},"This is exactly what makes the earlier ",[95,17070,15714],{},[95,17072,15636],{}," examples (Lesson 17.3) genuinely useful — a single loop calling ",[95,17075,17076],{},"s.stop()"," on each element automatically runs whichever subclass's own ",[95,17079,14864],{}," actually applies, without an ",[95,17082,1766],{},[95,17084,3814],{}," chain checking each one's specific type:",[104,17087,17089],{"className":106,"code":17088,"language":108,"meta":48,"style":48},"for (Subsystem s : allSubsystems)\n{\n    s.stop(); \u002F\u002F Intake's stop(), Climber's stop(), Shooter's stop() — whichever is actually correct for each object\n}\n",[95,17090,17091,17096,17100,17105],{"__ignoreMap":48},[112,17092,17093],{"class":114,"line":115},[112,17094,17095],{},"for (Subsystem s : allSubsystems)\n",[112,17097,17098],{"class":114,"line":49},[112,17099,123],{},[112,17101,17102],{"class":114,"line":126},[112,17103,17104],{},"    s.stop(); \u002F\u002F Intake's stop(), Climber's stop(), Shooter's stop() — whichever is actually correct for each object\n",[112,17106,17107],{"class":114,"line":132},[112,17108,153],{},[69,17110,17112],{"id":17111},"static-methods-dont-get-this","Static Methods Don't Get This",[15,17114,17115,17116,17118],{},"Polymorphic dispatch only applies to regular (instance) methods. A ",[95,17117,2649],{}," method call is resolved entirely by the declared type, at compile time — there's no runtime lookup involved at all, since static methods belong to the class itself, not to any particular object.",[69,17120,412],{"id":411},[19,17122,17123,17133,17143],{},[22,17124,17125,17128,17129,17132],{},[25,17126,17127],{},"Assuming the compiler checks the actual type."," It never does — ",[95,17130,17131],{},"message.indexOf(\"h\")"," fails to compile even when the real object genuinely has that method, because the compiler only ever consults the declared type.",[22,17134,17135,17138,17139,17142],{},[25,17136,17137],{},"Forgetting that runtime dispatch is what actually decides which override runs."," The declared type only gates ",[262,17140,17141],{},"whether the code compiles"," — which specific version executes is always decided by the real, actual object type.",[22,17144,17145,17148],{},[25,17146,17147],{},"Expecting polymorphism to apply to static methods."," Static method calls are resolved by declared type alone, with no runtime dispatch — they don't participate in overriding the way instance methods do.",[69,17150,450],{"id":449},[19,17152,17153,17156,17159,17172],{},[22,17154,17155],{},"Polymorphism means the method that runs depends on an object's actual runtime type, not its variable's declared type.",[22,17157,17158],{},"The compiler only checks the declared type for whether a method call is legal; the JVM decides which overridden version actually runs based on the real, actual type.",[22,17160,17161,17162,17164,17165,275,17167,275,17169,17171],{},"This is why a ",[95,17163,7343],{},"-typed array or method parameter can transparently work with ",[95,17166,6739],{},[95,17168,14970],{},[95,17170,15029],{},", or any other subclass — one piece of code, many possible real behaviors.",[22,17173,17174],{},"Static methods don't participate in this — they're resolved entirely by declared type, at compile time.",[15,17176,493,17177,497,17179,17182,17183,17185],{},[95,17178,496],{},[95,17180,17181],{},"unit-5-inheritance-optional\u002F5.06-polymorphism.md"," (CSA 5.6)\n",[25,17184,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 5 (\"Polymorphism: Many Forms\") — TalonFX\u002FSparkMax-as-MotorController example",[503,17187,505],{},{"title":48,"searchDepth":49,"depth":49,"links":17189},[17190,17191,17192,17193,17194,17195],{"id":16910,"depth":49,"text":16911},{"id":16957,"depth":49,"text":16958},{"id":17039,"depth":49,"text":17040},{"id":17111,"depth":49,"text":17112},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":17197,"status":519},"18.3 — Polymorphism (CSA 5.6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F3-polymorphism",{"title":16903,"description":48},"shockwave-curriculum\u002Flessons\u002Fch18-polymorphism-many-forms\u002F18.3-polymorphism","o9nunxB7-6N3UsOmGfAuDbvW0PZ5AyB5r6jYVtoZQyA",{"id":17203,"title":17204,"body":17205,"description":48,"extension":51,"meta":17537,"navigation":55,"path":17539,"seo":17540,"stem":17541,"__hash__":17542},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19-interfaces-as-contracts.md","Interfaces as Contracts",{"type":8,"value":17206,"toc":17529},[17207,17210,17214,17227,17255,17264,17304,17310,17314,17323,17346,17349,17353,17356,17379,17386,17390,17401,17428,17431,17438,17440,17473,17475,17501,17527],[11,17208,17204],{"id":17209},"interfaces-as-contracts",[69,17211,17213],{"id":17212},"what-vs-how","What vs. How",[15,17215,1541,17216,17219,17220,17222,17223,17226],{},[25,17217,17218],{},"interface"," defines ",[262,17221,3185],{}," an object can do, without specifying ",[262,17224,17225],{},"how"," it does it. It's a \"contract\" — a set of method signatures any implementing class agrees to provide, with no implementation of its own for those methods. This matters enormously in real engineering: it lets two groups write code against a shared agreement without either needing to know the other's internals — a hardware vendor and an application team can each build against the same interface independently, as long as both honor it.",[104,17228,17230],{"className":106,"code":17229,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    void updateInputs(IntakeInputs inputs);\n    void setVoltage(double volts);\n}\n",[95,17231,17232,17237,17241,17246,17251],{"__ignoreMap":48},[112,17233,17234],{"class":114,"line":115},[112,17235,17236],{},"public interface IntakeIO\n",[112,17238,17239],{"class":114,"line":49},[112,17240,123],{},[112,17242,17243],{"class":114,"line":126},[112,17244,17245],{},"    void updateInputs(IntakeInputs inputs);\n",[112,17247,17248],{"class":114,"line":132},[112,17249,17250],{},"    void setVoltage(double volts);\n",[112,17252,17253],{"class":114,"line":138},[112,17254,153],{},[15,17256,17257,17258,17260,17261,687],{},"Method signatures inside an interface have no body — just a semicolon, no braces. ",[95,17259,17218],{}," is the keyword; a class agrees to the contract with ",[95,17262,17263],{},"implements",[104,17265,17267],{"className":106,"code":17266,"language":108,"meta":48,"style":48},"public class RealIntakeIO implements IntakeIO\n{\n    @Override\n    public void updateInputs(IntakeInputs inputs) { \u002F* real sensor reads *\u002F }\n\n    @Override\n    public void setVoltage(double volts) { \u002F* real motor.setVoltage(volts) *\u002F }\n}\n",[95,17268,17269,17274,17278,17282,17287,17291,17295,17300],{"__ignoreMap":48},[112,17270,17271],{"class":114,"line":115},[112,17272,17273],{},"public class RealIntakeIO implements IntakeIO\n",[112,17275,17276],{"class":114,"line":49},[112,17277,123],{},[112,17279,17280],{"class":114,"line":126},[112,17281,15861],{},[112,17283,17284],{"class":114,"line":132},[112,17285,17286],{},"    public void updateInputs(IntakeInputs inputs) { \u002F* real sensor reads *\u002F }\n",[112,17288,17289],{"class":114,"line":138},[112,17290,820],{"emptyLinePlaceholder":55},[112,17292,17293],{"class":114,"line":144},[112,17294,15861],{},[112,17296,17297],{"class":114,"line":150},[112,17298,17299],{},"    public void setVoltage(double volts) { \u002F* real motor.setVoltage(volts) *\u002F }\n",[112,17301,17302],{"class":114,"line":1819},[112,17303,153],{},[15,17305,17306,17307,17309],{},"A class implementing an interface must provide a real method body for ",[262,17308,9461],{}," method the interface declares (default and static methods excepted — see below) — or the class fails to compile.",[69,17311,17313],{"id":17312},"multiple-interfaces-one-superclass","Multiple Interfaces, One Superclass",[15,17315,17316,17317,17319,17320,17322],{},"Unlike ",[95,17318,12389],{}," (limited to exactly one superclass — Lesson 17.1), a class can ",[95,17321,17263],{}," as many interfaces as it needs:",[104,17324,17326],{"className":106,"code":17325,"language":108,"meta":48,"style":48},"public class Robot implements Loggable, Sendable\n{\n    \u002F\u002F must provide every method declared by BOTH Loggable and Sendable\n}\n",[95,17327,17328,17333,17337,17342],{"__ignoreMap":48},[112,17329,17330],{"class":114,"line":115},[112,17331,17332],{},"public class Robot implements Loggable, Sendable\n",[112,17334,17335],{"class":114,"line":49},[112,17336,123],{},[112,17338,17339],{"class":114,"line":126},[112,17340,17341],{},"    \u002F\u002F must provide every method declared by BOTH Loggable and Sendable\n",[112,17343,17344],{"class":114,"line":132},[112,17345,153],{},[15,17347,17348],{},"This is one of the biggest practical differences between inheritance and interfaces: a class has one parent, but can honor any number of separate contracts at once.",[69,17350,17352],{"id":17351},"using-an-interface-as-a-type","Using an Interface as a Type",[15,17354,17355],{},"Just like a superclass (Lesson 17.3), an interface is a real reference type — a variable, parameter, array, or collection can be declared against an interface type, and hold any object whose class implements it:",[104,17357,17359],{"className":106,"code":17358,"language":108,"meta":48,"style":48},"public void configureIntake(IntakeIO io)\n{\n    io.setVoltage(0.0); \u002F\u002F works for RealIntakeIO, SimIntakeIO, or any other IntakeIO implementation\n}\n",[95,17360,17361,17366,17370,17375],{"__ignoreMap":48},[112,17362,17363],{"class":114,"line":115},[112,17364,17365],{},"public void configureIntake(IntakeIO io)\n",[112,17367,17368],{"class":114,"line":49},[112,17369,123],{},[112,17371,17372],{"class":114,"line":126},[112,17373,17374],{},"    io.setVoltage(0.0); \u002F\u002F works for RealIntakeIO, SimIntakeIO, or any other IntakeIO implementation\n",[112,17376,17377],{"class":114,"line":132},[112,17378,153],{},[15,17380,17381,17382,17385],{},"Code written against ",[95,17383,17384],{},"IntakeIO"," never needs to know or care which concrete implementation it's actually working with — real hardware, or a simulated stand-in (this exact pattern is the foundation of the IO-Layer Pattern, Ch.20).",[69,17387,17389],{"id":17388},"default-and-static-methods","Default and Static Methods",[15,17391,17392,17393,17396,17397,17400],{},"Normally every method in an interface is abstract (no body). A ",[25,17394,17395],{},"default method"," is the one exception — it provides a real implementation directly inside the interface, marked with the ",[95,17398,17399],{},"default"," keyword, which implementing classes inherit automatically without being forced to write it themselves:",[104,17402,17404],{"className":106,"code":17403,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    default void updateInputs(IntakeInputs inputs) {}  \u002F\u002F default: does nothing unless overridden\n    default void setVoltage(double volts) {}           \u002F\u002F default: does nothing unless overridden\n}\n",[95,17405,17406,17410,17414,17419,17424],{"__ignoreMap":48},[112,17407,17408],{"class":114,"line":115},[112,17409,17236],{},[112,17411,17412],{"class":114,"line":49},[112,17413,123],{},[112,17415,17416],{"class":114,"line":126},[112,17417,17418],{},"    default void updateInputs(IntakeInputs inputs) {}  \u002F\u002F default: does nothing unless overridden\n",[112,17420,17421],{"class":114,"line":132},[112,17422,17423],{},"    default void setVoltage(double volts) {}           \u002F\u002F default: does nothing unless overridden\n",[112,17425,17426],{"class":114,"line":138},[112,17427,153],{},[15,17429,17430],{},"This matters for a very practical reason: default methods let an interface add new methods later without breaking every class that already implements it — existing implementations simply inherit the default behavior rather than suddenly failing to compile. A class can still override a default method with its own real implementation, exactly like overriding an inherited method from a superclass (Lesson 18.1).",[15,17432,17433,17434,17437],{},"An interface can also declare ",[25,17435,17436],{},"static methods"," — utility methods associated with the interface itself, not with any implementing object, called directly on the interface name rather than through an instance.",[69,17439,412],{"id":411},[19,17441,17442,17448,17464],{},[22,17443,17444,17447],{},[25,17445,17446],{},"Forgetting to implement every abstract method an interface declares."," A class that leaves even one required method unimplemented fails to compile — every non-default, non-static method is a firm requirement.",[22,17449,17450,17457,17458,17460,17461,17463],{},[25,17451,17452,17453,486,17455,79],{},"Confusing ",[95,17454,12389],{},[95,17456,17263],{}," A class ",[95,17459,12389],{}," exactly one class, but can ",[95,17462,17263],{}," any number of interfaces — these are two entirely separate mechanisms.",[22,17465,17466,17469,17470,17472],{},[25,17467,17468],{},"Assuming every interface method needs to be written from scratch."," Default methods (like the empty ones in ",[95,17471,17384],{}," above) come \"for free\" — only override one if the default behavior isn't what you want.",[69,17474,450],{"id":449},[19,17476,17477,17485,17493,17496],{},[22,17478,17479,17480,17482,17483,79],{},"An interface is a contract: method signatures with no implementation (default\u002Fstatic methods aside), specifying ",[262,17481,3185],{}," a class can do, not ",[262,17484,17225],{},[22,17486,17487,17488,17490,17491,79],{},"A class agrees to an interface's contract with ",[95,17489,17263],{},", and can implement any number of interfaces at once — unlike the single-superclass limit of ",[95,17492,12389],{},[22,17494,17495],{},"An interface is a real type — variables, parameters, arrays, and collections can all be declared against it, holding any object whose class implements it.",[22,17497,355,17498,17500],{},[95,17499,17399],{}," method provides a real implementation directly in the interface, letting implementing classes inherit it without writing their own — the mechanism behind adding new interface methods without breaking existing code.",[15,17502,493,17503,497,17505,275,17508,275,17511,275,17514,275,17517,275,17520,17523,17524,17526],{},[95,17504,12493],{},[95,17506,17507],{},"oracle-java-tutorials\u002Finterfaces\u002F01-interfaces.md",[95,17509,17510],{},"02-defining-an-interface.md",[95,17512,17513],{},"03-implementing-an-interface.md",[95,17515,17516],{},"04-using-an-interface-as-a-type.md",[95,17518,17519],{},"05-default-methods.md",[95,17521,17522],{},"06-summary-of-interfaces.md"," (ORACLE 15.1-6)\n",[25,17525,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 6 (\"Interfaces as Contracts\") — IntakeIO example",[503,17528,505],{},{"title":48,"searchDepth":49,"depth":49,"links":17530},[17531,17532,17533,17534,17535,17536],{"id":17212,"depth":49,"text":17213},{"id":17312,"depth":49,"text":17313},{"id":17351,"depth":49,"text":17352},{"id":17388,"depth":49,"text":17389},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":17538,"status":519},"19 — Interfaces as Contracts (ORACLE 15.1-6)","\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19-interfaces-as-contracts",{"title":17204,"description":48},"shockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19-interfaces-as-contracts","11JyqfYBHf-pLLnnz-Z4Ai-bEWkm5WOB0SAnep8_31o",{"id":17544,"title":17545,"body":17546,"description":48,"extension":51,"meta":17938,"navigation":55,"path":17940,"seo":17941,"stem":17942,"__hash__":17943},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19.1-lambdas-and-method-references.md","Lambdas & Method References",{"type":8,"value":17547,"toc":17930},[17548,17551,17555,17569,17592,17638,17644,17648,17655,17664,17696,17729,17732,17764,17768,17771,17791,17795,17809,17824,17838,17840,17881,17883,17917,17928],[11,17549,17545],{"id":17550},"lambdas-method-references",[69,17552,17554],{"id":17553},"the-problem-lambdas-solve","The Problem Lambdas Solve",[15,17556,17557,17558,17560,17561,17564,17565,17568],{},"When an interface declares exactly ",[25,17559,14941],{}," abstract method (a ",[25,17562,17563],{},"functional interface","), implementing it with a full named class — or even an anonymous class — is a lot of ceremony for something conceptually simple: \"here's the one bit of behavior you asked for.\" A ",[25,17566,17567],{},"lambda expression"," lets you write that one method's body directly, with no class declaration at all:",[104,17570,17572],{"className":106,"code":17571,"language":108,"meta":48,"style":48},"public interface DoubleSupplier\n{\n    double getAsDouble(); \u002F\u002F exactly one abstract method — this is a functional interface\n}\n",[95,17573,17574,17579,17583,17588],{"__ignoreMap":48},[112,17575,17576],{"class":114,"line":115},[112,17577,17578],{},"public interface DoubleSupplier\n",[112,17580,17581],{"class":114,"line":49},[112,17582,123],{},[112,17584,17585],{"class":114,"line":126},[112,17586,17587],{},"    double getAsDouble(); \u002F\u002F exactly one abstract method — this is a functional interface\n",[112,17589,17590],{"class":114,"line":132},[112,17591,153],{},[104,17593,17595],{"className":106,"code":17594,"language":108,"meta":48,"style":48},"\u002F\u002F Without a lambda: a full anonymous class just to supply one value\nDoubleSupplier speed = new DoubleSupplier()\n{\n    @Override\n    public double getAsDouble() { return joystick.getY(); }\n};\n\n\u002F\u002F With a lambda: the same thing, far more directly\nDoubleSupplier speed = () -> joystick.getY();\n",[95,17596,17597,17602,17607,17611,17615,17620,17624,17628,17633],{"__ignoreMap":48},[112,17598,17599],{"class":114,"line":115},[112,17600,17601],{},"\u002F\u002F Without a lambda: a full anonymous class just to supply one value\n",[112,17603,17604],{"class":114,"line":49},[112,17605,17606],{},"DoubleSupplier speed = new DoubleSupplier()\n",[112,17608,17609],{"class":114,"line":126},[112,17610,123],{},[112,17612,17613],{"class":114,"line":132},[112,17614,15861],{},[112,17616,17617],{"class":114,"line":138},[112,17618,17619],{},"    public double getAsDouble() { return joystick.getY(); }\n",[112,17621,17622],{"class":114,"line":144},[112,17623,11017],{},[112,17625,17626],{"class":114,"line":150},[112,17627,820],{"emptyLinePlaceholder":55},[112,17629,17630],{"class":114,"line":1819},[112,17631,17632],{},"\u002F\u002F With a lambda: the same thing, far more directly\n",[112,17634,17635],{"class":114,"line":1825},[112,17636,17637],{},"DoubleSupplier speed = () -> joystick.getY();\n",[15,17639,17640,17643],{},[95,17641,17642],{},"WPILib"," commands and suppliers are built almost entirely on this pattern — this is exactly what makes lambdas so central to command-based programming (Ch.25).",[69,17645,17647],{"id":17646},"lambda-syntax","Lambda Syntax",[15,17649,17650,17651,17654],{},"A lambda expression has three parts: a parameter list in parentheses, the arrow ",[95,17652,17653],{},"->",", and a body:",[104,17656,17658],{"className":106,"code":17657,"language":108,"meta":48,"style":48},"(parameters) -> expression\n",[95,17659,17660],{"__ignoreMap":48},[112,17661,17662],{"class":114,"line":115},[112,17663,17657],{},[19,17665,17666,17672,17685],{},[22,17667,17668,17671],{},[25,17669,17670],{},"Parameter types are inferred",", not written — the compiler already knows them from the functional interface being implemented.",[22,17673,17674,17677,17678,17681,17682,79],{},[25,17675,17676],{},"Parentheses can be dropped"," around a single parameter: ",[95,17679,17680],{},"p -> p.getY()"," is valid, just like ",[95,17683,17684],{},"(p) -> p.getY()",[22,17686,17687,17690,17691,17693,17694,687],{},[25,17688,17689],{},"A single expression is the return value automatically"," — no ",[95,17692,2717],{}," keyword needed. A multi-statement body needs braces and an explicit ",[95,17695,2717],{},[104,17697,17699],{"className":106,"code":17698,"language":108,"meta":48,"style":48},"DoubleSupplier speed = () -> joystick.getY();              \u002F\u002F single expression — auto-returned\n\nDoubleSupplier clampedSpeed = () -> {                       \u002F\u002F multi-statement body needs braces + return\n    double raw = joystick.getY();\n    return Math.max(-1.0, Math.min(1.0, raw));\n};\n",[95,17700,17701,17706,17710,17715,17720,17725],{"__ignoreMap":48},[112,17702,17703],{"class":114,"line":115},[112,17704,17705],{},"DoubleSupplier speed = () -> joystick.getY();              \u002F\u002F single expression — auto-returned\n",[112,17707,17708],{"class":114,"line":49},[112,17709,820],{"emptyLinePlaceholder":55},[112,17711,17712],{"class":114,"line":126},[112,17713,17714],{},"DoubleSupplier clampedSpeed = () -> {                       \u002F\u002F multi-statement body needs braces + return\n",[112,17716,17717],{"class":114,"line":132},[112,17718,17719],{},"    double raw = joystick.getY();\n",[112,17721,17722],{"class":114,"line":138},[112,17723,17724],{},"    return Math.max(-1.0, Math.min(1.0, raw));\n",[112,17726,17727],{"class":114,"line":144},[112,17728,11017],{},[15,17730,17731],{},"A lambda with more than one parameter lists them comma-separated inside the parentheses:",[104,17733,17735],{"className":106,"code":17734,"language":108,"meta":48,"style":48},"public interface IntBinaryOperation\n{\n    int apply(int a, int b);\n}\n\nIntBinaryOperation add = (a, b) -> a + b;\n",[95,17736,17737,17742,17746,17751,17755,17759],{"__ignoreMap":48},[112,17738,17739],{"class":114,"line":115},[112,17740,17741],{},"public interface IntBinaryOperation\n",[112,17743,17744],{"class":114,"line":49},[112,17745,123],{},[112,17747,17748],{"class":114,"line":126},[112,17749,17750],{},"    int apply(int a, int b);\n",[112,17752,17753],{"class":114,"line":132},[112,17754,153],{},[112,17756,17757],{"class":114,"line":138},[112,17758,820],{"emptyLinePlaceholder":55},[112,17760,17761],{"class":114,"line":144},[112,17762,17763],{},"IntBinaryOperation add = (a, b) -> a + b;\n",[69,17765,17767],{"id":17766},"common-functional-interfaces-youll-actually-use","Common Functional Interfaces You'll Actually Use",[15,17769,17770],{},"Java (and WPILib) ship several ready-made functional interfaces, so you rarely need to declare your own:",[104,17772,17774],{"className":106,"code":17773,"language":108,"meta":48,"style":48},"Runnable stopAll = () -> intake.stop();                 \u002F\u002F no arguments, no return value\nDoubleSupplier speed = () -> joystick.getY();            \u002F\u002F no arguments, returns a double\nBooleanSupplier hasGamePiece = () -> intake.hasPiece();  \u002F\u002F no arguments, returns a boolean\n",[95,17775,17776,17781,17786],{"__ignoreMap":48},[112,17777,17778],{"class":114,"line":115},[112,17779,17780],{},"Runnable stopAll = () -> intake.stop();                 \u002F\u002F no arguments, no return value\n",[112,17782,17783],{"class":114,"line":49},[112,17784,17785],{},"DoubleSupplier speed = () -> joystick.getY();            \u002F\u002F no arguments, returns a double\n",[112,17787,17788],{"class":114,"line":126},[112,17789,17790],{},"BooleanSupplier hasGamePiece = () -> intake.hasPiece();  \u002F\u002F no arguments, returns a boolean\n",[69,17792,17794],{"id":17793},"method-references-an-even-shorter-form","Method References: An Even Shorter Form",[15,17796,17797,17798,17801,17802,12839,17805,17808],{},"When a lambda's ",[262,17799,17800],{},"entire"," body is just calling one existing method, a ",[25,17803,17804],{},"method reference",[95,17806,17807],{},"::",") says the same thing even more directly:",[104,17810,17812],{"className":106,"code":17811,"language":108,"meta":48,"style":48},"Runnable stopAll = () -> intake.stop(); \u002F\u002F a lambda...\nRunnable stopAll2 = intake::stop;       \u002F\u002F ...is exactly equivalent to this method reference\n",[95,17813,17814,17819],{"__ignoreMap":48},[112,17815,17816],{"class":114,"line":115},[112,17817,17818],{},"Runnable stopAll = () -> intake.stop(); \u002F\u002F a lambda...\n",[112,17820,17821],{"class":114,"line":49},[112,17822,17823],{},"Runnable stopAll2 = intake::stop;       \u002F\u002F ...is exactly equivalent to this method reference\n",[15,17825,17826,17829,17830,17833,17834,17837],{},[95,17827,17828],{},"intake::stop"," reads as \"the ",[95,17831,17832],{},"stop"," method, called on ",[95,17835,17836],{},"intake","\" — Java fills in the call automatically, with whatever arguments the functional interface's method expects. Method references exist purely as a shorthand for a lambda that does nothing but forward to an existing method — anywhere a method reference works, the equivalent lambda would work identically.",[69,17839,412],{"id":411},[19,17841,17842,17858,17872],{},[22,17843,17844,426,17847,17850,17851,17854,17855,17857],{},[25,17845,17846],{},"Writing parameter types into a lambda.",[95,17848,17849],{},"(Person p) -> p.getAge()"," — while technically legal — is unusual style; letting the compiler infer the type (",[95,17852,17853],{},"p -> p.getAge()",") is the normal convention, since the functional interface already pins down what type ",[95,17856,15],{}," has to be.",[22,17859,17860,17865,17866,17868,17869,17871],{},[25,17861,3455,17862,17864],{},[95,17863,2717],{}," in a multi-statement lambda body."," A single-expression lambda auto-returns its value, but a ",[95,17867,4910],{}," block body needs an explicit ",[95,17870,2717],{},", exactly like a regular method.",[22,17873,17874,426,17877,17880],{},[25,17875,17876],{},"Reaching for a method reference when the lambda does more than forward one call.",[95,17878,17879],{},"() -> { intake.stop(); logEvent(\"stopped\"); }"," genuinely needs a lambda — a method reference only replaces a lambda that does nothing but call one existing method.",[69,17882,450],{"id":449},[19,17884,17885,17888,17898,17910],{},[22,17886,17887],{},"A lambda expression is a compact way to implement a functional interface (an interface with exactly one abstract method) inline, without writing a class.",[22,17889,17890,17891,5327,17894,17897],{},"Syntax: ",[95,17892,17893],{},"(parameters) -> expression",[95,17895,17896],{},"{ statements; return value; }"," for a multi-statement body); parameter types are inferred, and parentheses can be dropped for a single parameter.",[22,17899,17900,275,17903,278,17906,17909],{},[95,17901,17902],{},"Runnable",[95,17904,17905],{},"DoubleSupplier",[95,17907,17908],{},"BooleanSupplier"," are common ready-made functional interfaces WPILib code uses constantly.",[22,17911,17912,17913,17916],{},"A method reference (",[95,17914,17915],{},"object::method",") is exact shorthand for a lambda that does nothing but call one existing method.",[15,17918,493,17919,497,17921,17924,17925,17927],{},[95,17920,12493],{},[95,17922,17923],{},"oracle-java-tutorials\u002Flambdas\u002Flambda-expressions.md"," (ORACLE 12.2)\n",[25,17926,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-1.js, slide 12 (\"Lambdas & Method References\")",[503,17929,505],{},{"title":48,"searchDepth":49,"depth":49,"links":17931},[17932,17933,17934,17935,17936,17937],{"id":17553,"depth":49,"text":17554},{"id":17646,"depth":49,"text":17647},{"id":17766,"depth":49,"text":17767},{"id":17793,"depth":49,"text":17794},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":17939,"status":519},"19.1 — Lambdas & Method References (ORACLE 12.1-2) — relocated here since a lambda is really shorthand for a functional interface; teaching it before Interfaces existed had no real grounding","\u002Fshockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F1-lambdas-and-method-references",{"title":17545,"description":48},"shockwave-curriculum\u002Flessons\u002Fch19-interfaces-as-contracts\u002F19.1-lambdas-and-method-references","SBY4AkQIyDpuo0PqWYuTUhaYctZH-BIcGoN16Q_xfUM",{"id":17945,"title":17946,"body":17947,"description":17954,"extension":51,"meta":18320,"navigation":55,"path":18322,"seo":18323,"stem":18324,"__hash__":18325},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch20-the-io-layer-pattern\u002F20-the-io-layer-pattern.md","The IO-Layer Pattern",{"type":8,"value":17948,"toc":18311},[17949,17952,17955,17959,17969,17975,17979,17994,18021,18032,18077,18083,18087,18097,18150,18158,18162,18179,18194,18201,18205,18238,18240,18266,18268,18290,18309],[11,17950,17946],{"id":17951},"the-io-layer-pattern",[15,17953,17954],{},"Everything Ch.17-19 built — inheritance, polymorphism, and especially interfaces as contracts — comes together here in a real, widely-used FRC architecture pattern: keeping hardware access completely separate from the logic that uses it.",[69,17956,17958],{"id":17957},"the-problem-hardware-everywhere-makes-testing-and-logging-hard","The Problem: Hardware Everywhere Makes Testing (and Logging) Hard",[15,17960,17961,17962,17964,17965,17968],{},"A subsystem that talks directly to real motor controllers and sensors is genuinely hard to reason about: it can't run at all without the physical robot present, and there's no clean seam where you could intercept its data. Team 6328's own AdvantageKit logging framework is built around a stronger idea than typical FRC logging — instead of just logging a handful of chosen values, it logs ",[262,17963,9461],{}," input flowing into the robot code, every loop cycle. Since every input is captured, a match can later be ",[25,17966,17967],{},"replayed"," in a simulator with the exact same inputs, running the exact same logic — turning logging from \"a tool for checking specific values\" into a genuine safety net for verifying how any part of the code actually behaved.",[15,17970,17971,17972,15097],{},"That capability only works if hardware access is structured so all input data flows through one well-defined seam. This is what the ",[25,17973,17974],{},"IO layer",[69,17976,17978],{"id":17977},"three-layers-of-a-subsystem","Three Layers of a Subsystem",[15,17980,17981,17982,17985,17986,17989,17990,17993],{},"Traditionally, an FRC subsystem mixes three concerns in one class: its ",[25,17983,17984],{},"public interface"," (methods the rest of the robot calls), its ",[25,17987,17988],{},"control logic"," (deciding what to do with sensor data), and its ",[25,17991,17992],{},"hardware interface"," (actually reading sensors, actually commanding motors). The IO-Layer Pattern pulls that third piece out into its own object:",[104,17995,17997],{"className":106,"code":17996,"language":108,"meta":48,"style":48},"public interface IntakeIO\n{\n    default void updateInputs(IntakeInputs inputs) {}\n    default void setVoltage(double volts) {}\n}\n",[95,17998,17999,18003,18007,18012,18017],{"__ignoreMap":48},[112,18000,18001],{"class":114,"line":115},[112,18002,17236],{},[112,18004,18005],{"class":114,"line":49},[112,18006,123],{},[112,18008,18009],{"class":114,"line":126},[112,18010,18011],{},"    default void updateInputs(IntakeInputs inputs) {}\n",[112,18013,18014],{"class":114,"line":132},[112,18015,18016],{},"    default void setVoltage(double volts) {}\n",[112,18018,18019],{"class":114,"line":138},[112,18020,153],{},[15,18022,18023,18025,18026,18028,18029,18031],{},[95,18024,17384],{}," is exactly the kind of contract from Lesson 19 — it says ",[262,18027,3185],{}," an intake can do (report its inputs, accept a voltage command), without saying ",[262,18030,17225],{},". Two real implementations honor that same contract:",[104,18033,18035],{"className":106,"code":18034,"language":108,"meta":48,"style":48},"public class IntakeIOSparkMax implements IntakeIO\n{\n    \u002F\u002F uses real CAN IDs and hardware APIs to move physical rollers\n}\n\npublic class IntakeIOSim implements IntakeIO\n{\n    \u002F\u002F uses physics math (moment of inertia) to \"fake\" the robot in code\n}\n",[95,18036,18037,18042,18046,18051,18055,18059,18064,18068,18073],{"__ignoreMap":48},[112,18038,18039],{"class":114,"line":115},[112,18040,18041],{},"public class IntakeIOSparkMax implements IntakeIO\n",[112,18043,18044],{"class":114,"line":49},[112,18045,123],{},[112,18047,18048],{"class":114,"line":126},[112,18049,18050],{},"    \u002F\u002F uses real CAN IDs and hardware APIs to move physical rollers\n",[112,18052,18053],{"class":114,"line":132},[112,18054,153],{},[112,18056,18057],{"class":114,"line":138},[112,18058,820],{"emptyLinePlaceholder":55},[112,18060,18061],{"class":114,"line":144},[112,18062,18063],{},"public class IntakeIOSim implements IntakeIO\n",[112,18065,18066],{"class":114,"line":150},[112,18067,123],{},[112,18069,18070],{"class":114,"line":1819},[112,18071,18072],{},"    \u002F\u002F uses physics math (moment of inertia) to \"fake\" the robot in code\n",[112,18074,18075],{"class":114,"line":1825},[112,18076,153],{},[15,18078,18079,18080,18082],{},"The subsystem class itself only ever talks to the ",[95,18081,17384],{}," interface — it never knows, and never needs to know, which concrete implementation is actually running underneath.",[69,18084,18086],{"id":18085},"choosing-the-implementation-once-at-construction","Choosing the Implementation Once, at Construction",[15,18088,18089,18090,18093,18094,18096],{},"The whole point is decided in exactly one place — typically ",[95,18091,18092],{},"RobotContainer",", at startup — by simply constructing the subsystem with a different ",[95,18095,17384],{}," implementation depending on whether the code is running on the real robot or in simulation:",[104,18098,18100],{"className":106,"code":18099,"language":108,"meta":48,"style":48},"public RobotContainer()\n{\n    if (isReal())\n    {\n        intake = new Intake(new IntakeIOSparkMax());\n    }\n    else\n    {\n        intake = new Intake(new IntakeIOSim());\n    }\n}\n",[95,18101,18102,18107,18111,18116,18120,18125,18129,18133,18137,18142,18146],{"__ignoreMap":48},[112,18103,18104],{"class":114,"line":115},[112,18105,18106],{},"public RobotContainer()\n",[112,18108,18109],{"class":114,"line":49},[112,18110,123],{},[112,18112,18113],{"class":114,"line":126},[112,18114,18115],{},"    if (isReal())\n",[112,18117,18118],{"class":114,"line":132},[112,18119,135],{},[112,18121,18122],{"class":114,"line":138},[112,18123,18124],{},"        intake = new Intake(new IntakeIOSparkMax());\n",[112,18126,18127],{"class":114,"line":144},[112,18128,147],{},[112,18130,18131],{"class":114,"line":150},[112,18132,10079],{},[112,18134,18135],{"class":114,"line":1819},[112,18136,135],{},[112,18138,18139],{"class":114,"line":1825},[112,18140,18141],{},"        intake = new Intake(new IntakeIOSim());\n",[112,18143,18144],{"class":114,"line":1831},[112,18145,147],{},[112,18147,18148],{"class":114,"line":4742},[112,18149,153],{},[15,18151,18152,18154,18155,18157],{},[95,18153,6739],{}," (the subsystem) accepts an ",[95,18156,17384],{}," in its constructor and stores it — every call from then on goes through that reference, polymorphically (Lesson 18.3) dispatching to whichever implementation was actually supplied.",[69,18159,18161],{"id":18160},"inputs-flow-through-a-loggable-object","Inputs Flow Through a Loggable Object",[15,18163,18164,18165,18168,18169,18171,18172,1051,18175,18178],{},"Outputs (commands like ",[95,18166,18167],{},"setVoltage",") are simple, one-way method calls. Inputs are handled more carefully, since they need to be logged ",[262,18170,14013],{}," later replayable: each IO interface defines an accompanying inputs class holding public fields for every value that comes off the hardware, plus methods (",[95,18173,18174],{},"toLog",[95,18176,18177],{},"fromLog",") for saving and restoring that data from a log file:",[104,18180,18182],{"className":106,"code":18181,"language":108,"meta":48,"style":48},"io.updateInputs(inputs);                         \u002F\u002F pull fresh data from the IO layer into `inputs`\nLogger.processInputs(\"Intake\", inputs);          \u002F\u002F send it to the logging framework (or restore it, during replay)\n",[95,18183,18184,18189],{"__ignoreMap":48},[112,18185,18186],{"class":114,"line":115},[112,18187,18188],{},"io.updateInputs(inputs);                         \u002F\u002F pull fresh data from the IO layer into `inputs`\n",[112,18190,18191],{"class":114,"line":49},[112,18192,18193],{},"Logger.processInputs(\"Intake\", inputs);          \u002F\u002F send it to the logging framework (or restore it, during replay)\n",[15,18195,18196,18197,18200],{},"The rest of the subsystem then reads from the ",[95,18198,18199],{},"inputs"," object — never straight from the IO layer — for a critical reason: every piece of code within one loop cycle sees the exact same cached values, so a replay from the log looks byte-for-byte identical to what really happened on the field.",[69,18202,18204],{"id":18203},"the-general-pattern-behind-this-ports-and-adapters","The General Pattern Behind This: Ports and Adapters",[15,18206,18207,18208,5327,18211,18214,18215,18218,18219,18221,18222,12839,18225,275,18228,18231,18232,18234,18235,18237],{},"This isn't an FRC-specific trick — it's a specific application of a broader, well-known software architecture idea called ",[25,18209,18210],{},"Hexagonal Architecture",[25,18212,18213],{},"Ports and Adapters","): keep core logic decoupled from whatever external system it happens to talk to (a database, a UI, real hardware), by defining a ",[25,18216,18217],{},"port"," (the interface — ",[95,18220,17384],{},") that any number of ",[25,18223,18224],{},"adapters",[95,18226,18227],{},"IntakeIOSparkMax",[95,18229,18230],{},"IntakeIOSim",") can plug into. The core logic only ever depends on the port, never on any specific adapter — exactly mirroring ",[95,18233,6739],{}," only ever depending on ",[95,18236,17384],{},". The tradeoff is real: it's more abstraction and more files than talking to hardware directly, which is overkill for a one-off script — but it pays for itself the moment testability, simulation, or swappable hardware actually matter, which for a competition robot, they do.",[69,18239,412],{"id":411},[19,18241,18242,18248,18260],{},[22,18243,18244,18247],{},[25,18245,18246],{},"Letting the subsystem read hardware directly, bypassing the IO layer."," That reintroduces exactly the coupling the pattern exists to remove — no sim support, no clean replay.",[22,18249,18250,18253,18254,18257,18258,79],{},[25,18251,18252],{},"Reading straight from the IO layer instead of the cached inputs object."," Values read directly from ",[95,18255,18256],{},"io"," could change mid-cycle in ways a replayed log never could — always read from ",[95,18259,18199],{},[22,18261,18262,18265],{},[25,18263,18264],{},"Treating the IO layer as optional overhead on a small subsystem."," It's genuinely more files and more ceremony — but the payoff (simulation, replay, decoupled testing) is exactly why competitive FRC codebases use it anyway.",[69,18267,450],{"id":449},[19,18269,18270,18273,18276,18287],{},[22,18271,18272],{},"The IO-Layer Pattern separates a subsystem's hardware access into its own interface (the \"IO\" layer), so the subsystem's own logic never touches real hardware APIs directly.",[22,18274,18275],{},"One interface, multiple implementations (real hardware vs. simulated), chosen once at construction — everything else dispatches polymorphically through the shared interface.",[22,18277,18278,18279,6482,18282,1051,18284,18286],{},"Inputs flow through a dedicated, loggable object (",[95,18280,18281],{},"updateInputs",[95,18283,18174],{},[95,18285,18177],{},"), so a match's exact inputs can be replayed later with identical results.",[22,18288,18289],{},"This is FRC's specific application of the general Hexagonal Architecture (Ports and Adapters) pattern: core logic depends only on a port (interface), never on a specific adapter (implementation).",[15,18291,493,18292,497,18294,18297,18298,18301,18302,18305,18306,18308],{},[95,18293,12493],{},[95,18295,18296],{},"advantagekit\u002Fgetting-started\u002F01-what-is-advantagekit.md"," (ADVKIT 40.1), ",[95,18299,18300],{},"advantagekit\u002Fdata-flow\u002F08-io-interfaces.md"," (ADVKIT 40.8), ",[95,18303,18304],{},"java-design-patterns\u002Fhexagonal-architecture.md"," (JDP 50.1)\n",[25,18307,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 7 (\"The IO-Layer Pattern\") — IntakeIOSparkMax\u002FIntakeIOSim example",[503,18310,505],{},{"title":48,"searchDepth":49,"depth":49,"links":18312},[18313,18314,18315,18316,18317,18318,18319],{"id":17957,"depth":49,"text":17958},{"id":17977,"depth":49,"text":17978},{"id":18085,"depth":49,"text":18086},{"id":18160,"depth":49,"text":18161},{"id":18203,"depth":49,"text":18204},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":18321,"status":519},"20 — The IO-Layer Pattern (ADVKIT 40.1-11, JDP 50.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch20-the-io-layer-pattern\u002F20-the-io-layer-pattern",{"title":17946,"description":17954},"shockwave-curriculum\u002Flessons\u002Fch20-the-io-layer-pattern\u002F20-the-io-layer-pattern","CWi-ymVUB_bQSNEoRqlPFDAvmp9z0NX--FghiXdkiRs",{"id":18327,"title":18328,"body":18329,"description":48,"extension":51,"meta":18741,"navigation":55,"path":18743,"seo":18744,"stem":18745,"__hash__":18746},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch21-static-factories\u002F21-static-factories.md","Static Factories",{"type":8,"value":18330,"toc":18733},[18331,18334,18340,18354,18381,18404,18414,18418,18425,18566,18575,18585,18589,18592,18657,18666,18668,18704,18706,18720,18731],[11,18332,18328],{"id":18333},"static-factories",[69,18335,18337,18338,14681],{"id":18336},"why-not-just-new","Why Not Just ",[95,18339,2860],{},[15,18341,355,18342,18345,18346,18349,18350,18353],{},[25,18343,18344],{},"static factory method"," is a ",[95,18347,18348],{},"public static"," method that returns an object, used ",[262,18351,18352],{},"instead of"," calling a constructor directly. At first glance this looks like extra ceremony for no reason — but it buys a few concrete things a plain constructor can't:",[19,18355,18356,18369,18375],{},[22,18357,18358,426,18361,18364,18365,18368],{},[25,18359,18360],{},"A descriptive name.",[95,18362,18363],{},"Command.printMessage(\"Ready\")"," says exactly what you're getting; ",[95,18366,18367],{},"new PrintCommand(\"Ready\")"," (or worse, a constructor overload chosen by argument types alone) doesn't communicate intent nearly as clearly.",[22,18370,18371,18374],{},[25,18372,18373],{},"The freedom to not construct a new object at all."," A factory method can return a cached, already-existing instance instead of a fresh one — a constructor, by contrast, always creates something new.",[22,18376,18377,18380],{},[25,18378,18379],{},"The freedom to return a completely different concrete type",", chosen by logic inside the method — the caller only ever sees the return type (often an interface), never which concrete class was actually picked.",[104,18382,18384],{"className":106,"code":18383,"language":108,"meta":48,"style":48},"public static Command printMessage(String msg)\n{\n    return new InstantCommand(() -> System.out.println(msg));\n}\n",[95,18385,18386,18391,18395,18400],{"__ignoreMap":48},[112,18387,18388],{"class":114,"line":115},[112,18389,18390],{},"public static Command printMessage(String msg)\n",[112,18392,18393],{"class":114,"line":49},[112,18394,123],{},[112,18396,18397],{"class":114,"line":126},[112,18398,18399],{},"    return new InstantCommand(() -> System.out.println(msg));\n",[112,18401,18402],{"class":114,"line":132},[112,18403,153],{},[15,18405,9197,18406,18409,18410,18413],{},[95,18407,18408],{},"printMessage(\"Ready\")"," reads clearly as \"give me a command that prints this message\" — the caller never needs to know or care that it's actually an ",[95,18411,18412],{},"InstantCommand"," wrapping a lambda underneath.",[69,18415,18417],{"id":18416},"the-real-payoff-choosing-an-implementation-by-condition","The Real Payoff: Choosing an Implementation by Condition",[15,18419,18420,18421,18424],{},"The pattern's biggest use in FRC code is picking between real and simulated hardware — deciding ",[262,18422,18423],{},"which"," concrete class to construct, in exactly one place, based on a condition:",[104,18426,18428],{"className":106,"code":18427,"language":108,"meta":48,"style":48},"public interface Drivetrain\n{\n    void drive(double speed, double turn);\n}\n\npublic class RealDrivetrain implements Drivetrain\n{\n    public void drive(double speed, double turn) { \u002F* control real Talons\u002FSparks *\u002F }\n}\n\npublic class SimDrivetrain implements Drivetrain\n{\n    public void drive(double speed, double turn) { \u002F* simulate motion via WPILib sim *\u002F }\n}\n\npublic class DrivetrainFactory\n{\n    public static Drivetrain createDrivetrain()\n    {\n        if (RobotBase.isReal())\n        {\n            return new RealDrivetrain();\n        }\n        else\n        {\n            return new SimDrivetrain();\n        }\n    }\n}\n",[95,18429,18430,18435,18439,18444,18448,18452,18457,18461,18466,18470,18474,18479,18483,18488,18492,18496,18501,18505,18510,18514,18519,18523,18529,18534,18540,18545,18551,18556,18561],{"__ignoreMap":48},[112,18431,18432],{"class":114,"line":115},[112,18433,18434],{},"public interface Drivetrain\n",[112,18436,18437],{"class":114,"line":49},[112,18438,123],{},[112,18440,18441],{"class":114,"line":126},[112,18442,18443],{},"    void drive(double speed, double turn);\n",[112,18445,18446],{"class":114,"line":132},[112,18447,153],{},[112,18449,18450],{"class":114,"line":138},[112,18451,820],{"emptyLinePlaceholder":55},[112,18453,18454],{"class":114,"line":144},[112,18455,18456],{},"public class RealDrivetrain implements Drivetrain\n",[112,18458,18459],{"class":114,"line":150},[112,18460,123],{},[112,18462,18463],{"class":114,"line":1819},[112,18464,18465],{},"    public void drive(double speed, double turn) { \u002F* control real Talons\u002FSparks *\u002F }\n",[112,18467,18468],{"class":114,"line":1825},[112,18469,153],{},[112,18471,18472],{"class":114,"line":1831},[112,18473,820],{"emptyLinePlaceholder":55},[112,18475,18476],{"class":114,"line":4742},[112,18477,18478],{},"public class SimDrivetrain implements Drivetrain\n",[112,18480,18481],{"class":114,"line":4748},[112,18482,123],{},[112,18484,18485],{"class":114,"line":6935},[112,18486,18487],{},"    public void drive(double speed, double turn) { \u002F* simulate motion via WPILib sim *\u002F }\n",[112,18489,18490],{"class":114,"line":6940},[112,18491,153],{},[112,18493,18494],{"class":114,"line":6946},[112,18495,820],{"emptyLinePlaceholder":55},[112,18497,18498],{"class":114,"line":6952},[112,18499,18500],{},"public class DrivetrainFactory\n",[112,18502,18503],{"class":114,"line":6957},[112,18504,123],{},[112,18506,18507],{"class":114,"line":6963},[112,18508,18509],{},"    public static Drivetrain createDrivetrain()\n",[112,18511,18512],{"class":114,"line":6968},[112,18513,135],{},[112,18515,18516],{"class":114,"line":11929},[112,18517,18518],{},"        if (RobotBase.isReal())\n",[112,18520,18521],{"class":114,"line":11935},[112,18522,7860],{},[112,18524,18526],{"class":114,"line":18525},22,[112,18527,18528],{},"            return new RealDrivetrain();\n",[112,18530,18532],{"class":114,"line":18531},23,[112,18533,7870],{},[112,18535,18537],{"class":114,"line":18536},24,[112,18538,18539],{},"        else\n",[112,18541,18543],{"class":114,"line":18542},25,[112,18544,7860],{},[112,18546,18548],{"class":114,"line":18547},26,[112,18549,18550],{},"            return new SimDrivetrain();\n",[112,18552,18554],{"class":114,"line":18553},27,[112,18555,7870],{},[112,18557,18559],{"class":114,"line":18558},28,[112,18560,147],{},[112,18562,18564],{"class":114,"line":18563},29,[112,18565,153],{},[104,18567,18569],{"className":106,"code":18568,"language":108,"meta":48,"style":48},"Drivetrain drivetrain = DrivetrainFactory.createDrivetrain(); \u002F\u002F caller never picks the concrete class itself\n",[95,18570,18571],{"__ignoreMap":48},[112,18572,18573],{"class":114,"line":115},[112,18574,18568],{},[15,18576,18577,18578,18580,18581,18584],{},"This is a genuine alternative to the constructor-injection style from the IO-Layer Pattern (Ch.20) — instead of the caller deciding which ",[95,18579,17384],{}," to pass in, the factory itself makes that decision, centralizing the real-vs-sim logic in one place instead of duplicating an ",[95,18582,18583],{},"if (isReal())"," check everywhere a subsystem gets built.",[69,18586,18588],{"id":18587},"factories-for-more-than-hardware","Factories for More Than Hardware",[15,18590,18591],{},"The same idea works for building the right object out of a whole family of choices — not just two (real\u002Fsim), but any number, selected by some other input:",[104,18593,18595],{"className":106,"code":18594,"language":108,"meta":48,"style":48},"public class AutoFactory\n{\n    public static Command createAuto(String mode)\n    {\n        return switch (mode)\n        {\n            case \"Taxi\" -> new DriveForwardCommand(3.0);\n            case \"2 Ball\" -> new TwoBallAutoCommand();\n            case \"Nothing\" -> new WaitCommand(0.1);\n            default -> new PrintCommand(\"Unknown Auto Mode\");\n        };\n    }\n}\n",[95,18596,18597,18602,18606,18611,18615,18620,18624,18629,18634,18639,18644,18649,18653],{"__ignoreMap":48},[112,18598,18599],{"class":114,"line":115},[112,18600,18601],{},"public class AutoFactory\n",[112,18603,18604],{"class":114,"line":49},[112,18605,123],{},[112,18607,18608],{"class":114,"line":126},[112,18609,18610],{},"    public static Command createAuto(String mode)\n",[112,18612,18613],{"class":114,"line":132},[112,18614,135],{},[112,18616,18617],{"class":114,"line":138},[112,18618,18619],{},"        return switch (mode)\n",[112,18621,18622],{"class":114,"line":144},[112,18623,7860],{},[112,18625,18626],{"class":114,"line":150},[112,18627,18628],{},"            case \"Taxi\" -> new DriveForwardCommand(3.0);\n",[112,18630,18631],{"class":114,"line":1819},[112,18632,18633],{},"            case \"2 Ball\" -> new TwoBallAutoCommand();\n",[112,18635,18636],{"class":114,"line":1825},[112,18637,18638],{},"            case \"Nothing\" -> new WaitCommand(0.1);\n",[112,18640,18641],{"class":114,"line":1831},[112,18642,18643],{},"            default -> new PrintCommand(\"Unknown Auto Mode\");\n",[112,18645,18646],{"class":114,"line":4742},[112,18647,18648],{},"        };\n",[112,18650,18651],{"class":114,"line":4748},[112,18652,147],{},[112,18654,18655],{"class":114,"line":6935},[112,18656,153],{},[104,18658,18660],{"className":106,"code":18659,"language":108,"meta":48,"style":48},"Command auto = AutoFactory.createAuto(chooser.getSelected()); \u002F\u002F built from whatever the driver station selected\n",[95,18661,18662],{"__ignoreMap":48},[112,18663,18664],{"class":114,"line":115},[112,18665,18659],{},[69,18667,412],{"id":411},[19,18669,18670,18682,18695],{},[22,18671,18672,426,18675,18678,18679,18681],{},[25,18673,18674],{},"Returning a concrete class instead of an interface.",[95,18676,18677],{},"public static RealDrivetrain createDrivetrain()"," locks callers into one specific implementation — return the interface type (",[95,18680,319],{},") so the real choice stays hidden inside the factory.",[22,18683,18684,18690,18691,18694],{},[25,18685,18686,18687,18689],{},"Duplicating the same real-vs-sim ",[95,18688,1766],{}," check in multiple places."," The whole point of a factory is centralizing that decision in one method — scattering ",[95,18692,18693],{},"RobotBase.isReal()"," checks throughout the codebase defeats the purpose.",[22,18696,18697,18700,18701,18703],{},[25,18698,18699],{},"Confusing a factory with a constructor."," A factory method is just a regular ",[95,18702,2649],{}," method — it can validate arguments, return a cached instance, or pick any subtype, none of which a constructor is free to do (a constructor always returns a new instance of its own exact class).",[69,18705,450],{"id":449},[19,18707,18708,18711,18714,18717],{},[22,18709,18710],{},"A static factory method returns an object in place of a direct constructor call, with a descriptive name, the option to return a cached instance, and the freedom to choose the actual concrete type internally.",[22,18712,18713],{},"Its most common FRC use: centralizing real-vs-simulated (or comp-bot-vs-practice-bot) selection logic in one place, so callers only ever depend on an interface.",[22,18715,18716],{},"Factories generalize beyond hardware — anything selected by a condition (an autonomous mode, a config option) is a natural fit.",[22,18718,18719],{},"Always return the interface type from a factory method, not a specific concrete class, so the actual implementation choice stays hidden from callers.",[15,18721,493,18722,497,18724,18727,18728,18730],{},[95,18723,12493],{},[95,18725,18726],{},"team-5817-training\u002Fdesign-patterns\u002Ffactory.md"," (T5817 30.2)\n",[25,18729,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 7 (\"Static Factories\")",[503,18732,505],{},{"title":48,"searchDepth":49,"depth":49,"links":18734},[18735,18737,18738,18739,18740],{"id":18336,"depth":49,"text":18736},"Why Not Just new?",{"id":18416,"depth":49,"text":18417},{"id":18587,"depth":49,"text":18588},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":18742,"status":519},"21 — Static Factories (T5817 30.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch21-static-factories\u002F21-static-factories",{"title":18328,"description":48},"shockwave-curriculum\u002Flessons\u002Fch21-static-factories\u002F21-static-factories","aBLVbcZymIbGxGMB8_-m6AoxWcPeyxAqiDSrGquVSOs",{"id":18748,"title":18749,"body":18750,"description":48,"extension":51,"meta":19224,"navigation":55,"path":19226,"seo":19227,"stem":19228,"__hash__":19229},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch22-the-builder-pattern\u002F22-the-builder-pattern.md","The Builder Pattern",{"type":8,"value":18751,"toc":19212},[18752,18755,18759,18762,18771,18774,18778,18800,18845,18856,18860,18875,19033,19041,19063,19067,19084,19088,19094,19114,19123,19127,19130,19132,19162,19164,19199,19210],[11,18753,18749],{"id":18754},"the-builder-pattern",[69,18756,18758],{"id":18757},"the-problem-constructor-hell","The Problem: \"Constructor Hell\"",[15,18760,18761],{},"A constructor with many parameters — especially several of the same type, or several optional ones — becomes genuinely hard to read and easy to get wrong:",[104,18763,18765],{"className":106,"code":18764,"language":108,"meta":48,"style":48},"Shooter shooter = new Shooter(0.01, 0.3, 0.02, true, false, 12.0, 0.5);\n",[95,18766,18767],{"__ignoreMap":48},[112,18768,18769],{"class":114,"line":115},[112,18770,18764],{},[15,18772,18773],{},"What does each number actually mean? Swap two arguments of the same type by mistake, and the compiler won't catch it — it'll just silently misconfigure the shooter. This is sometimes called \"constructor hell,\" and it gets worse the more optional settings a class has, since a constructor either forces every caller to specify every parameter, or multiplies into a pile of overloads trying to cover every combination.",[69,18775,18777],{"id":18776},"the-builder-pattern-construct-step-by-step","The Builder Pattern: Construct Step by Step",[15,18779,1936,18780,18783,18784,18787,18788,18791,18792,18795,18796,18799],{},[25,18781,18782],{},"Builder Pattern"," separates ",[262,18785,18786],{},"building"," an object from ",[262,18789,18790],{},"using"," it — a separate ",[95,18793,18794],{},"Builder"," object collects settings one at a time, through named, chainable methods, then produces the final object only once, via a ",[95,18797,18798],{},"build()"," call:",[104,18801,18803],{"className":106,"code":18802,"language":108,"meta":48,"style":48},"Shooter shooter = new Shooter.Builder()\n    .setKP(0.01)\n    .setKI(0.3)\n    .setKD(0.02)\n    .enableFeedforward(true)\n    .setMaxRPM(12.0)\n    .setMinRPM(0.5)\n    .build();\n",[95,18804,18805,18810,18815,18820,18825,18830,18835,18840],{"__ignoreMap":48},[112,18806,18807],{"class":114,"line":115},[112,18808,18809],{},"Shooter shooter = new Shooter.Builder()\n",[112,18811,18812],{"class":114,"line":49},[112,18813,18814],{},"    .setKP(0.01)\n",[112,18816,18817],{"class":114,"line":126},[112,18818,18819],{},"    .setKI(0.3)\n",[112,18821,18822],{"class":114,"line":132},[112,18823,18824],{},"    .setKD(0.02)\n",[112,18826,18827],{"class":114,"line":138},[112,18828,18829],{},"    .enableFeedforward(true)\n",[112,18831,18832],{"class":114,"line":144},[112,18833,18834],{},"    .setMaxRPM(12.0)\n",[112,18836,18837],{"class":114,"line":150},[112,18838,18839],{},"    .setMinRPM(0.5)\n",[112,18841,18842],{"class":114,"line":1819},[112,18843,18844],{},"    .build();\n",[15,18846,18847,18848,18851,18852,18855],{},"Every call is now self-documenting — ",[95,18849,18850],{},".setKP(0.01)"," says exactly what ",[95,18853,18854],{},"0.01"," means, in a way a bare constructor argument never could.",[69,18857,18859],{"id":18858},"implementing-a-builder","Implementing a Builder",[15,18861,18862,18863,18865,18866,18868,18869,18871,18872,18874],{},"The target class (",[95,18864,15029],{},") gets a ",[95,18867,6806],{}," constructor — callers can no longer construct it directly, only through the builder — plus a ",[95,18870,18348],{}," nested ",[95,18873,18794],{}," class that collects the settings:",[104,18876,18878],{"className":106,"code":18877,"language":108,"meta":48,"style":48},"public class Shooter\n{\n    private final double kP, kI, kD;\n    private final boolean feedforward;\n    private final double maxRPM, minRPM;\n\n    private Shooter(Builder builder)\n    {\n        this.kP = builder.kP;\n        this.kI = builder.kI;\n        this.kD = builder.kD;\n        this.feedforward = builder.feedforward;\n        this.maxRPM = builder.maxRPM;\n        this.minRPM = builder.minRPM;\n    }\n\n    public static class Builder\n    {\n        private double kP = 0, kI = 0, kD = 0;\n        private boolean feedforward = false;\n        private double maxRPM = 0, minRPM = 0;\n\n        public Builder setKP(double kP) { this.kP = kP; return this; }\n        public Builder setKI(double kI) { this.kI = kI; return this; }\n        public Builder setKD(double kD) { this.kD = kD; return this; }\n        public Builder enableFeedforward(boolean ff) { this.feedforward = ff; return this; }\n        public Builder setMaxRPM(double max) { this.maxRPM = max; return this; }\n        public Builder setMinRPM(double min) { this.minRPM = min; return this; }\n\n        public Shooter build() { return new Shooter(this); }\n    }\n}\n",[95,18879,18880,18885,18889,18894,18899,18904,18908,18913,18917,18922,18927,18932,18937,18942,18947,18951,18955,18960,18964,18969,18974,18979,18983,18988,18993,18998,19003,19008,19013,19017,19023,19028],{"__ignoreMap":48},[112,18881,18882],{"class":114,"line":115},[112,18883,18884],{},"public class Shooter\n",[112,18886,18887],{"class":114,"line":49},[112,18888,123],{},[112,18890,18891],{"class":114,"line":126},[112,18892,18893],{},"    private final double kP, kI, kD;\n",[112,18895,18896],{"class":114,"line":132},[112,18897,18898],{},"    private final boolean feedforward;\n",[112,18900,18901],{"class":114,"line":138},[112,18902,18903],{},"    private final double maxRPM, minRPM;\n",[112,18905,18906],{"class":114,"line":144},[112,18907,820],{"emptyLinePlaceholder":55},[112,18909,18910],{"class":114,"line":150},[112,18911,18912],{},"    private Shooter(Builder builder)\n",[112,18914,18915],{"class":114,"line":1819},[112,18916,135],{},[112,18918,18919],{"class":114,"line":1825},[112,18920,18921],{},"        this.kP = builder.kP;\n",[112,18923,18924],{"class":114,"line":1831},[112,18925,18926],{},"        this.kI = builder.kI;\n",[112,18928,18929],{"class":114,"line":4742},[112,18930,18931],{},"        this.kD = builder.kD;\n",[112,18933,18934],{"class":114,"line":4748},[112,18935,18936],{},"        this.feedforward = builder.feedforward;\n",[112,18938,18939],{"class":114,"line":6935},[112,18940,18941],{},"        this.maxRPM = builder.maxRPM;\n",[112,18943,18944],{"class":114,"line":6940},[112,18945,18946],{},"        this.minRPM = builder.minRPM;\n",[112,18948,18949],{"class":114,"line":6946},[112,18950,147],{},[112,18952,18953],{"class":114,"line":6952},[112,18954,820],{"emptyLinePlaceholder":55},[112,18956,18957],{"class":114,"line":6957},[112,18958,18959],{},"    public static class Builder\n",[112,18961,18962],{"class":114,"line":6963},[112,18963,135],{},[112,18965,18966],{"class":114,"line":6968},[112,18967,18968],{},"        private double kP = 0, kI = 0, kD = 0;\n",[112,18970,18971],{"class":114,"line":11929},[112,18972,18973],{},"        private boolean feedforward = false;\n",[112,18975,18976],{"class":114,"line":11935},[112,18977,18978],{},"        private double maxRPM = 0, minRPM = 0;\n",[112,18980,18981],{"class":114,"line":18525},[112,18982,820],{"emptyLinePlaceholder":55},[112,18984,18985],{"class":114,"line":18531},[112,18986,18987],{},"        public Builder setKP(double kP) { this.kP = kP; return this; }\n",[112,18989,18990],{"class":114,"line":18536},[112,18991,18992],{},"        public Builder setKI(double kI) { this.kI = kI; return this; }\n",[112,18994,18995],{"class":114,"line":18542},[112,18996,18997],{},"        public Builder setKD(double kD) { this.kD = kD; return this; }\n",[112,18999,19000],{"class":114,"line":18547},[112,19001,19002],{},"        public Builder enableFeedforward(boolean ff) { this.feedforward = ff; return this; }\n",[112,19004,19005],{"class":114,"line":18553},[112,19006,19007],{},"        public Builder setMaxRPM(double max) { this.maxRPM = max; return this; }\n",[112,19009,19010],{"class":114,"line":18558},[112,19011,19012],{},"        public Builder setMinRPM(double min) { this.minRPM = min; return this; }\n",[112,19014,19015],{"class":114,"line":18563},[112,19016,820],{"emptyLinePlaceholder":55},[112,19018,19020],{"class":114,"line":19019},30,[112,19021,19022],{},"        public Shooter build() { return new Shooter(this); }\n",[112,19024,19026],{"class":114,"line":19025},31,[112,19027,147],{},[112,19029,19031],{"class":114,"line":19030},32,[112,19032,153],{},[69,19034,19036,19037,19040],{"id":19035},"the-fluent-chain-why-return-this-matters","The Fluent Chain: Why ",[95,19038,19039],{},"return this;"," Matters",[15,19042,19043,19044,19046,19047,19049,19050,19052,19053,19056,19057,19059,19060,79],{},"Every ",[95,19045,18794],{}," method ends with ",[95,19048,19039],{}," — returning the same builder object it was just called on. That's exactly what makes chaining possible: each call's result is another ",[95,19051,18794],{},", ready for the next call in the chain, all the way until ",[95,19054,19055],{},".build()"," finally produces the real ",[95,19058,15029],{},". This style (a method call chain, each step returning the object it was called on) is called a ",[25,19061,19062],{},"fluent interface",[69,19064,19066],{"id":19065},"why-the-result-is-safer-not-just-prettier","Why the Result Is Safer, Not Just Prettier",[19,19068,19069,19072,19075],{},[22,19070,19071],{},"Every setting has a readable name at the call site, instead of an anonymous position in an argument list.",[22,19073,19074],{},"Optional settings simply aren't called, rather than needing a separate constructor overload for every combination.",[22,19076,19077,19078,19080,19081,19083],{},"The final object (",[95,19079,15029],{},") is typically built as immutable — every field is ",[95,19082,7887],{}," and set exactly once, inside the private constructor, from the builder's already-finished values.",[69,19085,19087],{"id":19086},"real-patterns-this-mirrors-in-wpilib","Real Patterns This Mirrors in WPILib",[15,19089,19090,19091,19093],{},"Several real WPILib classes already use builder-like chaining, even without a nested ",[95,19092,18794],{}," class:",[104,19095,19097],{"className":106,"code":19096,"language":108,"meta":48,"style":48},"TrajectoryConfig config = new TrajectoryConfig(maxSpeed, maxAccel)\n    .setKinematics(driveKinematics)\n    .addConstraint(voltageConstraint);\n",[95,19098,19099,19104,19109],{"__ignoreMap":48},[112,19100,19101],{"class":114,"line":115},[112,19102,19103],{},"TrajectoryConfig config = new TrajectoryConfig(maxSpeed, maxAccel)\n",[112,19105,19106],{"class":114,"line":49},[112,19107,19108],{},"    .setKinematics(driveKinematics)\n",[112,19110,19111],{"class":114,"line":126},[112,19112,19113],{},"    .addConstraint(voltageConstraint);\n",[15,19115,19116,486,19119,19122],{},[95,19117,19118],{},"SequentialCommandGroup",[95,19120,19121],{},"ParallelCommandGroup"," follow the same underlying idea — building up a larger thing step by step, out of smaller declared pieces, rather than one giant constructor call.",[69,19124,19126],{"id":19125},"when-not-to-reach-for-a-builder","When Not to Reach for a Builder",[15,19128,19129],{},"A builder is genuine overhead — a whole extra nested class — that only pays for itself once a constructor's parameter list gets long or has several optional pieces. For a class with 2-3 simple, always-required parameters, a plain constructor (or, per Ch.21, a static factory method) is simpler and should be preferred.",[69,19131,412],{"id":411},[19,19133,19134,19145,19156],{},[22,19135,19136,19141,19142,19144],{},[25,19137,3455,19138,19140],{},[95,19139,19039],{}," in a builder method."," Without it, the method returns ",[95,19143,281],{},", and chaining the next call fails to compile.",[22,19146,19147,19153,19154,79],{},[25,19148,19149,19150,19152],{},"Making the target class's constructor ",[95,19151,274],{}," alongside the builder."," That defeats the pattern's purpose — callers should only ever construct the object through the builder, which is why the real constructor stays ",[95,19155,6806],{},[22,19157,19158,19161],{},[25,19159,19160],{},"Reaching for a builder on a simple, 2-3-parameter class."," That's exactly the case the pattern isn't meant for — the extra ceremony isn't worth it there.",[69,19163,450],{"id":449},[19,19165,19166,19169,19180,19189,19196],{},[22,19167,19168],{},"The Builder Pattern separates step-by-step construction from a class's actual usage, avoiding \"constructor hell\" (many same-typed or optional parameters).",[22,19170,19171,19172,19174,19175,19177,19178,79],{},"A builder is a nested ",[95,19173,2649],{}," class collecting settings via named, chainable methods (each returning ",[95,19176,2344],{}," — a fluent interface), finishing with ",[95,19179,18798],{},[22,19181,19182,19183,19185,19186,19188],{},"The target class's real constructor is ",[95,19184,6806],{},", taking the finished builder and copying its values into ",[95,19187,7887],{}," fields — producing an immutable, safely-configured result.",[22,19190,19191,19192,19195],{},"Real WPILib classes (",[95,19193,19194],{},"TrajectoryConfig",", command groups) already use this same chaining idea.",[22,19197,19198],{},"Skip the builder for simple classes with few, always-required parameters — a constructor or static factory (Ch.21) is simpler there.",[15,19200,493,19201,497,19203,19206,19207,19209],{},[95,19202,12493],{},[95,19204,19205],{},"team-5817-training\u002Fdesign-patterns\u002Fbuilder.md"," (T5817 30.1)\n",[25,19208,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 8 (\"The Builder Pattern\") — MotorConfig fluent-builder example",[503,19211,505],{},{"title":48,"searchDepth":49,"depth":49,"links":19213},[19214,19215,19216,19217,19219,19220,19221,19222,19223],{"id":18757,"depth":49,"text":18758},{"id":18776,"depth":49,"text":18777},{"id":18858,"depth":49,"text":18859},{"id":19035,"depth":49,"text":19218},"The Fluent Chain: Why return this; Matters",{"id":19065,"depth":49,"text":19066},{"id":19086,"depth":49,"text":19087},{"id":19125,"depth":49,"text":19126},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":19225,"status":519},"22 — The Builder Pattern (T5817 30.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch22-the-builder-pattern\u002F22-the-builder-pattern",{"title":18749,"description":48},"shockwave-curriculum\u002Flessons\u002Fch22-the-builder-pattern\u002F22-the-builder-pattern","FTvpTiecaeQ-xr_NP6Or2hx0SEuJYVcxDChJzY6EclQ",{"id":19231,"title":19232,"body":19233,"description":48,"extension":51,"meta":19679,"navigation":55,"path":19681,"seo":19682,"stem":19683,"__hash__":19684},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch23-encapsulation-and-final\u002F23.1-scope-and-access.md","Scope and Access",{"type":8,"value":19234,"toc":19668},[19235,19238,19242,19253,19257,19319,19354,19358,19404,19410,19414,19424,19475,19482,19486,19511,19517,19523,19555,19581,19583,19618,19620,19655,19666],[11,19236,19232],{"id":19237},"scope-and-access",[69,19239,19241],{"id":19240},"what-scope-means","What Scope Means",[15,19243,19244,19245,19248,19249,19252],{},"A variable's ",[25,19246,19247],{},"scope"," is where it's accessible — where it \"lives and exists.\" Scope is determined by the nearest enclosing pair of curly braces ",[95,19250,19251],{},"{}"," around wherever the variable was declared. Trying to use a variable outside its scope isn't just bad practice — the variable genuinely doesn't exist there, and the code won't compile.",[69,19254,19256],{"id":19255},"three-levels-of-scope","Three Levels of Scope",[104,19258,19260],{"className":106,"code":19259,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private boolean hasGamePiece;             \u002F\u002F CLASS scope — visible to every method in Intake\n\n    public void setState(boolean detected)    \u002F\u002F `detected` is a parameter — METHOD scope\n    {\n        for (int i = 0; i \u003C 3; i++)           \u002F\u002F `i` is a loop variable — BLOCK scope\n        {\n            boolean sample = detected;        \u002F\u002F BLOCK scope — only exists inside this loop's braces\n        }\n        hasGamePiece = detected;              \u002F\u002F fine: class-scope field, reachable anywhere in the class\n    }\n}\n",[95,19261,19262,19266,19270,19275,19279,19284,19288,19293,19297,19302,19306,19311,19315],{"__ignoreMap":48},[112,19263,19264],{"class":114,"line":115},[112,19265,6697],{},[112,19267,19268],{"class":114,"line":49},[112,19269,123],{},[112,19271,19272],{"class":114,"line":126},[112,19273,19274],{},"    private boolean hasGamePiece;             \u002F\u002F CLASS scope — visible to every method in Intake\n",[112,19276,19277],{"class":114,"line":132},[112,19278,820],{"emptyLinePlaceholder":55},[112,19280,19281],{"class":114,"line":138},[112,19282,19283],{},"    public void setState(boolean detected)    \u002F\u002F `detected` is a parameter — METHOD scope\n",[112,19285,19286],{"class":114,"line":144},[112,19287,135],{},[112,19289,19290],{"class":114,"line":150},[112,19291,19292],{},"        for (int i = 0; i \u003C 3; i++)           \u002F\u002F `i` is a loop variable — BLOCK scope\n",[112,19294,19295],{"class":114,"line":1819},[112,19296,7860],{},[112,19298,19299],{"class":114,"line":1825},[112,19300,19301],{},"            boolean sample = detected;        \u002F\u002F BLOCK scope — only exists inside this loop's braces\n",[112,19303,19304],{"class":114,"line":1831},[112,19305,7870],{},[112,19307,19308],{"class":114,"line":4742},[112,19309,19310],{},"        hasGamePiece = detected;              \u002F\u002F fine: class-scope field, reachable anywhere in the class\n",[112,19312,19313],{"class":114,"line":4748},[112,19314,147],{},[112,19316,19317],{"class":114,"line":6935},[112,19318,153],{},[19,19320,19321,19331,19342],{},[22,19322,19323,19326,19327,207,19329,79],{},[25,19324,19325],{},"Class scope"," — instance variables (fields), visible to every method in the class, regardless of whether they're ",[95,19328,274],{},[95,19330,6806],{},[22,19332,19333,19336,19337,1051,19339,19341],{},[25,19334,19335],{},"Method scope"," — local variables and parameters, declared inside a method or constructor; they exist only for that one method call, and can never be declared ",[95,19338,274],{},[95,19340,6806],{}," themselves.",[22,19343,19344,19347,19348,19350,19351,19353],{},[25,19345,19346],{},"Block scope"," — variables declared inside any ",[95,19349,19251],{}," block narrower than a whole method (a loop, an ",[95,19352,1766],{},", etc.); they stop existing the instant that block ends.",[69,19355,19357],{"id":19356},"local-variables-only-live-where-theyre-declared","Local Variables Only Live Where They're Declared",[104,19359,19361],{"className":106,"code":19360,"language":108,"meta":48,"style":48},"public String getStatus()\n{\n    for (int i = 0; i \u003C 3; i++)\n    {\n        int sample = i;\n    }\n    System.out.println(sample); \u002F\u002F COMPILE ERROR — `sample` only existed inside the loop's braces\n    return \"done\";\n}\n",[95,19362,19363,19368,19372,19377,19381,19386,19390,19395,19400],{"__ignoreMap":48},[112,19364,19365],{"class":114,"line":115},[112,19366,19367],{},"public String getStatus()\n",[112,19369,19370],{"class":114,"line":49},[112,19371,123],{},[112,19373,19374],{"class":114,"line":126},[112,19375,19376],{},"    for (int i = 0; i \u003C 3; i++)\n",[112,19378,19379],{"class":114,"line":132},[112,19380,135],{},[112,19382,19383],{"class":114,"line":138},[112,19384,19385],{},"        int sample = i;\n",[112,19387,19388],{"class":114,"line":144},[112,19389,147],{},[112,19391,19392],{"class":114,"line":150},[112,19393,19394],{},"    System.out.println(sample); \u002F\u002F COMPILE ERROR — `sample` only existed inside the loop's braces\n",[112,19396,19397],{"class":114,"line":1819},[112,19398,19399],{},"    return \"done\";\n",[112,19401,19402],{"class":114,"line":1825},[112,19403,153],{},[15,19405,19406,19407,19409],{},"Parameters follow the same rule: a constructor's parameter only exists for that constructor call, and isn't reachable from any other method in the class — including ",[95,19408,15808],{}," or any other method that seems related.",[69,19411,19413],{"id":19412},"shadowing-when-a-local-name-matches-a-field-name","Shadowing: When a Local Name Matches a Field Name",[15,19415,19416,19417,19420,19421,687],{},"If a local variable (or parameter) shares a name with an instance variable, the ",[262,19418,19419],{},"local"," one wins inside that method — this is called ",[25,19422,19423],{},"shadowing",[104,19425,19427],{"className":106,"code":19426,"language":108,"meta":48,"style":48},"public class Intake\n{\n    private String name;\n\n    @Override\n    public String toString()\n    {\n        String name = \"unknown\";  \u002F\u002F this local variable shadows the instance variable `name`\n        return name;              \u002F\u002F returns \"unknown\", NOT the instance variable's real value\n    }\n}\n",[95,19428,19429,19433,19437,19441,19445,19449,19453,19457,19462,19467,19471],{"__ignoreMap":48},[112,19430,19431],{"class":114,"line":115},[112,19432,6697],{},[112,19434,19435],{"class":114,"line":49},[112,19436,123],{},[112,19438,19439],{"class":114,"line":126},[112,19440,7399],{},[112,19442,19443],{"class":114,"line":132},[112,19444,820],{"emptyLinePlaceholder":55},[112,19446,19447],{"class":114,"line":138},[112,19448,15861],{},[112,19450,19451],{"class":114,"line":144},[112,19452,15919],{},[112,19454,19455],{"class":114,"line":150},[112,19456,135],{},[112,19458,19459],{"class":114,"line":1819},[112,19460,19461],{},"        String name = \"unknown\";  \u002F\u002F this local variable shadows the instance variable `name`\n",[112,19463,19464],{"class":114,"line":1825},[112,19465,19466],{},"        return name;              \u002F\u002F returns \"unknown\", NOT the instance variable's real value\n",[112,19468,19469],{"class":114,"line":1831},[112,19470,147],{},[112,19472,19473],{"class":114,"line":4742},[112,19474,153],{},[15,19476,19477,19478,19481],{},"Ch.8 already introduced the fix for this exact situation inside constructors — ",[95,19479,19480],{},"this.name"," explicitly reaches the instance variable even when a same-named local variable or parameter is shadowing it.",[69,19483,19485],{"id":19484},"connecting-scope-to-encapsulation","Connecting Scope to Encapsulation",[15,19487,19488,19489,19491,19492,19494,19495,19498,19499,1051,19501,19503,19504,19507,19508,79],{},"Encapsulation (Ch.7) is really scope applied deliberately: marking a field ",[95,19490,6806],{}," doesn't change its ",[262,19493,97],{}," scope (every method in the class can still see it) — it restricts ",[262,19496,19497],{},"outside"," code from reaching it directly, forcing access through public getters\u002Fsetters instead. Scope and access modifiers (",[95,19500,274],{},[95,19502,6806],{},") are two separate but related ideas: scope is about ",[262,19505,19506],{},"where a variable exists at all","; access modifiers are about ",[262,19509,19510],{},"who outside the class is allowed to touch it",[69,19512,1936,19514,19516],{"id":19513},"the-final-keyword",[95,19515,7887],{}," Keyword",[15,19518,19519,19520,19522],{},"A field, parameter, or local variable marked ",[95,19521,7887],{}," can be assigned exactly once — any attempt to reassign it afterward is a compile error. This matters for anything that genuinely should never change after it's set:",[104,19524,19526],{"className":106,"code":19525,"language":108,"meta":48,"style":48},"private final TalonFX motor = new TalonFX(1); \u002F\u002F this reference can never be reassigned to a different motor\n\npublic double getVelocity()\n{\n    return motor.getVelocity().getValue();\n}\n",[95,19527,19528,19533,19537,19542,19546,19551],{"__ignoreMap":48},[112,19529,19530],{"class":114,"line":115},[112,19531,19532],{},"private final TalonFX motor = new TalonFX(1); \u002F\u002F this reference can never be reassigned to a different motor\n",[112,19534,19535],{"class":114,"line":49},[112,19536,820],{"emptyLinePlaceholder":55},[112,19538,19539],{"class":114,"line":126},[112,19540,19541],{},"public double getVelocity()\n",[112,19543,19544],{"class":114,"line":132},[112,19545,123],{},[112,19547,19548],{"class":114,"line":138},[112,19549,19550],{},"    return motor.getVelocity().getValue();\n",[112,19552,19553],{"class":114,"line":144},[112,19554,153],{},[15,19556,19557,19559,19560,19562,19563,19566,19567,19569,19570,19572,19573,19576,19577,19580],{},[95,19558,7887],{}," on an object reference only locks the ",[262,19561,3211],{}," itself — it doesn't make the object's own internal state unchangeable (",[95,19564,19565],{},"motor"," can't be pointed at a different ",[95,19568,2010],{},", but the real ",[95,19571,2010],{}," object it points to can still have its own state change via its own methods). True ",[25,19574,19575],{},"immutability"," — an object whose internal state can never change at all once constructed — is a stronger guarantee, and it's exactly why immutable classes like WPILib's ",[95,19578,19579],{},"Pose2d"," are thread-safe and predictable: nothing can ever be halfway through changing one, because nothing can change it at all.",[69,19582,412],{"id":411},[19,19584,19585,19594,19604],{},[22,19586,19587,19590,19591,19593],{},[25,19588,19589],{},"Trying to use a loop or block-scoped variable after its block ends."," It stops existing the instant the enclosing ",[95,19592,19251],{}," closes — declare it at method scope instead if it needs to survive past the block.",[22,19595,19596,19599,19600,19603],{},[25,19597,19598],{},"Assuming a shadowed local variable is the instance variable."," Inside a method with a same-named local variable\u002Fparameter, the local one always wins — use ",[95,19601,19602],{},"this.fieldName"," to reach the instance variable explicitly.",[22,19605,19606,426,19611,19613,19614,19617],{},[25,19607,17452,19608,19610],{},[95,19609,7887],{}," with true immutability.",[95,19612,7887],{}," only prevents ",[262,19615,19616],{},"reassigning"," a reference — the object it refers to can still have its own internal state changed, unless that object's own class was specifically designed to be immutable.",[69,19619,450],{"id":449},[19,19621,19622,19628,19631,19641,19646],{},[22,19623,19624,19625,19627],{},"A variable's scope — class, method, or block — is set by the nearest enclosing ",[95,19626,19251],{}," around its declaration; using it outside that scope doesn't compile.",[22,19629,19630],{},"Local variables and parameters exist only for their method\u002Fconstructor call; instance variables exist for the whole object, reachable from every method regardless of access modifier.",[22,19632,19633,19634,19637,19638,19640],{},"A local variable or parameter sharing a name with an instance variable ",[262,19635,19636],{},"shadows"," it inside that method — ",[95,19639,19602],{}," is how to reach the real instance variable when that happens.",[22,19642,19643,19645],{},[95,19644,7887],{}," allows exactly one assignment to a variable — for object references, it locks the reference, not necessarily the referenced object's internal state.",[22,19647,19648,19649,19651,19652,19654],{},"True immutability (an object whose state can never change after construction) is a stronger, separate guarantee from ",[95,19650,7887],{}," — and it's what makes classes like ",[95,19653,19579],{}," safe to share and reason about.",[15,19656,493,19657,497,19659,19662,19663,19665],{},[95,19658,496],{},[95,19660,19661],{},"unit-3-class-creation\u002F3.08-scope-and-access.md"," (CSA 3.8)\n",[25,19664,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 9 (\"Encapsulation & Final\") — final TalonFX\u002FPose2d example",[503,19667,505],{},{"title":48,"searchDepth":49,"depth":49,"links":19669},[19670,19671,19672,19673,19674,19675,19677,19678],{"id":19240,"depth":49,"text":19241},{"id":19255,"depth":49,"text":19256},{"id":19356,"depth":49,"text":19357},{"id":19412,"depth":49,"text":19413},{"id":19484,"depth":49,"text":19485},{"id":19513,"depth":49,"text":19676},"The final Keyword",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":19680,"status":519},"23.1 — Scope and Access (CSA 3.8)","\u002Fshockwave-curriculum\u002Flessons\u002Fch23-encapsulation-and-final\u002F1-scope-and-access",{"title":19232,"description":48},"shockwave-curriculum\u002Flessons\u002Fch23-encapsulation-and-final\u002F23.1-scope-and-access","e3dkZNS1SD2TW3fgvyfZmsA0vqVDOHS67OaF-8dsefM",{"id":19686,"title":19687,"body":19688,"description":48,"extension":51,"meta":20129,"navigation":55,"path":20131,"seo":20132,"stem":20133,"__hash__":20134},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch24-optional-avoiding-null-pointer-exceptions\u002F24-optional-avoiding-null-pointer-exceptions.md","Optional: Avoiding Null Pointer Exceptions",{"type":8,"value":19689,"toc":20119},[19690,19693,19697,19716,19726,19730,19743,19784,19791,19795,19815,19827,19831,19883,19901,19905,19933,19942,19959,19963,19980,20000,20006,20008,20050,20052,20106,20117],[11,19691,19687],{"id":19692},"optional-avoiding-null-pointer-exceptions",[69,19694,19696],{"id":19695},"the-null-problem","The Null Problem",[15,19698,19699,19700,19702,19703,19705,19706,19709,19710,19712,19713,19715],{},"Returning ",[95,19701,3384],{}," to mean \"there's no value here\" is one of the most common sources of bugs in any Java program — Tony Hoare, who introduced the null reference in 1965, later called it his \"billion-dollar mistake.\" The trouble is that ",[95,19704,3384],{}," is invisible in a method's signature: nothing about ",[95,19707,19708],{},"Pose2d getVisionPose()"," warns a caller that it might come back ",[95,19711,3384],{},", so it's easy to forget the check and get a ",[95,19714,3414],{}," (Ch.12\u002F13) instead.",[15,19717,19718,19719,19722,19723,19725],{},"The classic FRC case: a vision pose estimator can only report a robot position if a camera actually sees an AprilTag ",[262,19720,19721],{},"this frame"," — plenty of frames, it can't. Returning ",[95,19724,3384],{}," on those frames leaves every caller responsible for remembering to check first.",[69,19727,19729],{"id":19728},"optional-making-might-be-absent-part-of-the-type","Optional: Making \"Might Be Absent\" Part of the Type",[15,19731,19732,19735,19736,19739,19740,19742],{},[95,19733,19734],{},"java.util.Optional\u003CT>"," is a container that either holds a value, or is explicitly ",[25,19737,19738],{},"empty"," — and unlike ",[95,19741,3384],{},", that possibility is written directly into the method's return type:",[104,19744,19746],{"className":106,"code":19745,"language":108,"meta":48,"style":48},"public Optional\u003CPose2d> getPose()\n{\n    if (!hasTargetThisFrame())\n    {\n        return Optional.empty();       \u002F\u002F explicitly \"no value\" — not null\n    }\n    return Optional.of(currentPose);   \u002F\u002F wraps a real, non-null value\n}\n",[95,19747,19748,19753,19757,19762,19766,19771,19775,19780],{"__ignoreMap":48},[112,19749,19750],{"class":114,"line":115},[112,19751,19752],{},"public Optional\u003CPose2d> getPose()\n",[112,19754,19755],{"class":114,"line":49},[112,19756,123],{},[112,19758,19759],{"class":114,"line":126},[112,19760,19761],{},"    if (!hasTargetThisFrame())\n",[112,19763,19764],{"class":114,"line":132},[112,19765,135],{},[112,19767,19768],{"class":114,"line":138},[112,19769,19770],{},"        return Optional.empty();       \u002F\u002F explicitly \"no value\" — not null\n",[112,19772,19773],{"class":114,"line":144},[112,19774,147],{},[112,19776,19777],{"class":114,"line":150},[112,19778,19779],{},"    return Optional.of(currentPose);   \u002F\u002F wraps a real, non-null value\n",[112,19781,19782],{"class":114,"line":1819},[112,19783,153],{},[15,19785,19786,19787,19790],{},"Just by reading ",[95,19788,19789],{},"Optional\u003CPose2d> getPose()","'s signature, a caller already knows the pose might not be there this frame — the type itself documents it, instead of relying on a comment or tribal knowledge.",[69,19792,19794],{"id":19793},"creating-an-optional","Creating an Optional",[104,19796,19798],{"className":106,"code":19797,"language":108,"meta":48,"style":48},"Optional\u003CPose2d> empty = Optional.empty();           \u002F\u002F definitely no value\nOptional\u003CPose2d> present = Optional.of(currentPose);  \u002F\u002F wraps a value — throws immediately if currentPose is null\nOptional\u003CPose2d> maybe = Optional.ofNullable(currentPose); \u002F\u002F empty if currentPose is null, present otherwise\n",[95,19799,19800,19805,19810],{"__ignoreMap":48},[112,19801,19802],{"class":114,"line":115},[112,19803,19804],{},"Optional\u003CPose2d> empty = Optional.empty();           \u002F\u002F definitely no value\n",[112,19806,19807],{"class":114,"line":49},[112,19808,19809],{},"Optional\u003CPose2d> present = Optional.of(currentPose);  \u002F\u002F wraps a value — throws immediately if currentPose is null\n",[112,19811,19812],{"class":114,"line":126},[112,19813,19814],{},"Optional\u003CPose2d> maybe = Optional.ofNullable(currentPose); \u002F\u002F empty if currentPose is null, present otherwise\n",[15,19816,19817,19820,19821,19823,19824,19826],{},[95,19818,19819],{},"Optional.of(...)"," is a deliberate safety check: if you accidentally pass it a ",[95,19822,3384],{},", it throws right away — better to fail loudly at the source than to silently wrap a ",[95,19825,3384],{}," and have it surface as a confusing failure somewhere else later.",[69,19828,19830],{"id":19829},"handling-both-cases-honestly","Handling Both Cases Honestly",[104,19832,19834],{"className":106,"code":19833,"language":108,"meta":48,"style":48},"Optional\u003CPose2d> visionPose = vision.getPose();\n\n\u002F\u002F Run logic only when a value exists\nvisionPose.ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n\n\u002F\u002F Or supply a fallback value for the empty case\nPose2d pose = visionPose.orElse(lastKnownPose);\n\n\u002F\u002F Or throw a specific exception if a value was truly required\nPose2d requiredPose = visionPose.orElseThrow(IllegalStateException::new);\n",[95,19835,19836,19841,19845,19850,19855,19859,19864,19869,19873,19878],{"__ignoreMap":48},[112,19837,19838],{"class":114,"line":115},[112,19839,19840],{},"Optional\u003CPose2d> visionPose = vision.getPose();\n",[112,19842,19843],{"class":114,"line":49},[112,19844,820],{"emptyLinePlaceholder":55},[112,19846,19847],{"class":114,"line":126},[112,19848,19849],{},"\u002F\u002F Run logic only when a value exists\n",[112,19851,19852],{"class":114,"line":132},[112,19853,19854],{},"visionPose.ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n",[112,19856,19857],{"class":114,"line":138},[112,19858,820],{"emptyLinePlaceholder":55},[112,19860,19861],{"class":114,"line":144},[112,19862,19863],{},"\u002F\u002F Or supply a fallback value for the empty case\n",[112,19865,19866],{"class":114,"line":150},[112,19867,19868],{},"Pose2d pose = visionPose.orElse(lastKnownPose);\n",[112,19870,19871],{"class":114,"line":1819},[112,19872,820],{"emptyLinePlaceholder":55},[112,19874,19875],{"class":114,"line":1825},[112,19876,19877],{},"\u002F\u002F Or throw a specific exception if a value was truly required\n",[112,19879,19880],{"class":114,"line":1831},[112,19881,19882],{},"Pose2d requiredPose = visionPose.orElseThrow(IllegalStateException::new);\n",[15,19884,19885,19888,19889,19892,19893,19896,19897,19900],{},[95,19886,19887],{},"ifPresent"," runs a lambda (Lesson 19.1) only if a value is actually there — nothing happens otherwise. ",[95,19890,19891],{},"orElse"," supplies a fallback value for the empty case. ",[95,19894,19895],{},"orElseThrow"," is for the rarer case where an empty ",[95,19898,19899],{},"Optional"," really does mean something has gone wrong, and continuing anyway wouldn't make sense.",[69,19902,19904],{"id":19903},"the-one-pitfall-that-defeats-the-whole-point","The One Pitfall That Defeats the Whole Point",[15,19906,19907,19909,19910,19913,19914,19916,19917,19919,19920,19922,19923,19926,19927,19929,19930,19932],{},[95,19908,19899],{}," has an ",[95,19911,19912],{},"isPresent()"," check and a ",[95,19915,9145],{}," method that returns the wrapped value — but calling ",[95,19918,9145],{}," without checking ",[95,19921,19912],{}," first throws ",[95,19924,19925],{},"NoSuchElementException"," on an empty ",[95,19928,19899],{},", which is exactly the same class of crash ",[95,19931,19899],{}," exists to prevent, just under a different exception name:",[104,19934,19936],{"className":106,"code":19935,"language":108,"meta":48,"style":48},"Pose2d pose = visionPose.get(); \u002F\u002F never do this blind — this is a NullPointerException with extra steps\n",[95,19937,19938],{"__ignoreMap":48},[112,19939,19940],{"class":114,"line":115},[112,19941,19935],{},[15,19943,19944,19945,6482,19947,19949,19950,275,19952,278,19954,19956,19957,79],{},"Even the safer ",[95,19946,19912],{},[95,19948,9145],{}," pairing is discouraged — it's really just a nested-null-check in disguise. ",[95,19951,19887],{},[95,19953,19891],{},[95,19955,19895],{}," all handle both cases directly, without ever needing to call bare ",[95,19958,9145],{},[69,19960,19962],{"id":19961},"filtering-and-transforming-a-brief-look","Filtering and Transforming (a Brief Look)",[15,19964,19965,19966,19968,19969,19972,19973,19976,19977,19979],{},"Beyond the core methods above, ",[95,19967,19899],{}," supports ",[95,19970,19971],{},"filter"," (keep the value only if it matches a condition, otherwise become empty) and ",[95,19974,19975],{},"map"," (transform the value, if present, into something else) — useful for chaining a couple of extra checks without falling back into nested ",[95,19978,1766],{}," statements:",[104,19981,19983],{"className":106,"code":19982,"language":108,"meta":48,"style":48},"visionPose\n    .filter(pose -> pose.getX() >= 0)         \u002F\u002F only proceed if the pose has a valid X coordinate\n    .ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n",[95,19984,19985,19990,19995],{"__ignoreMap":48},[112,19986,19987],{"class":114,"line":115},[112,19988,19989],{},"visionPose\n",[112,19991,19992],{"class":114,"line":49},[112,19993,19994],{},"    .filter(pose -> pose.getX() >= 0)         \u002F\u002F only proceed if the pose has a valid X coordinate\n",[112,19996,19997],{"class":114,"line":126},[112,19998,19999],{},"    .ifPresent(pose -> estimator.addVisionMeasurement(pose, timestamp));\n",[15,20001,20002,20003,20005],{},"These compose well for simple cases; genuinely complex chains of ",[95,20004,19899],{}," transformations are a more advanced topic than this curriculum covers in depth.",[69,20007,412],{"id":411},[19,20009,20010,20022,20034],{},[22,20011,20012,20018,20019,20021],{},[25,20013,9197,20014,20017],{},[95,20015,20016],{},".get()"," without checking first."," This throws on an empty ",[95,20020,19899],{},", defeating the entire purpose of using one.",[22,20023,20024,20029,20030,20033],{},[25,20025,4590,20026,20028],{},[95,20027,19899],{}," for every field or parameter, out of habit."," It's meant for genuinely optional ",[262,20031,20032],{},"results"," (especially return values) — not a blanket replacement for every reference type in a program.",[22,20035,20036,20043,20044,20047,20048,79],{},[25,20037,20038,20039,3883,20041,79],{},"Passing a ",[95,20040,3384],{},[95,20042,19819],{}," That throws immediately — use ",[95,20045,20046],{},"Optional.ofNullable(...)"," instead when the value genuinely might be ",[95,20049,3384],{},[69,20051,450],{"id":449},[19,20053,20054,20063,20080,20096],{},[22,20055,20056,20059,20060,20062],{},[95,20057,20058],{},"Optional\u003CT>"," makes \"this might not have a value\" visible directly in a method's return type, instead of relying on an invisible, easy-to-forget ",[95,20061,3384],{}," check.",[22,20064,20065,20066,275,20069,20072,20073,20075,20076,20079],{},"Create one with ",[95,20067,20068],{},"Optional.empty()",[95,20070,20071],{},"Optional.of(value)"," (throws if ",[95,20074,7418],{}," is null), or ",[95,20077,20078],{},"Optional.ofNullable(value)"," (safe either way).",[22,20081,20082,20083,275,20086,20089,20090,20093,20094,20017],{},"Handle both cases with ",[95,20084,20085],{},"ifPresent(...)",[95,20087,20088],{},"orElse(fallback)",", or ",[95,20091,20092],{},"orElseThrow(...)"," — never call bare ",[95,20095,20016],{},[22,20097,20098,486,20100,20102,20103,20105],{},[95,20099,19971],{},[95,20101,19975],{}," let you chain a couple of extra conditions\u002Ftransformations without falling back into nested ",[95,20104,1766],{}," checks.",[15,20107,493,20108,497,20110,20113,20114,20116],{},[95,20109,12493],{},[95,20111,20112],{},"oracle-java-tutorials\u002Foptional\u002Fjava8-optional.md"," (ORACLE 16.1)\n",[25,20115,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 9b (\"Optional: Maybe a Value\") — vision pose estimator example",[503,20118,505],{},{"title":48,"searchDepth":49,"depth":49,"links":20120},[20121,20122,20123,20124,20125,20126,20127,20128],{"id":19695,"depth":49,"text":19696},{"id":19728,"depth":49,"text":19729},{"id":19793,"depth":49,"text":19794},{"id":19829,"depth":49,"text":19830},{"id":19903,"depth":49,"text":19904},{"id":19961,"depth":49,"text":19962},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":20130,"status":519},"24 — Optional: Avoiding Null Pointer Exceptions (ORACLE 16.1) — renamed from \"Optional: Maybe a Value\" to disambiguate from optional method parameters; the deck's actual slide heading is unchanged","\u002Fshockwave-curriculum\u002Flessons\u002Fch24-optional-avoiding-null-pointer-exceptions\u002F24-optional-avoiding-null-pointer-exceptions",{"title":19687,"description":48},"shockwave-curriculum\u002Flessons\u002Fch24-optional-avoiding-null-pointer-exceptions\u002F24-optional-avoiding-null-pointer-exceptions","4_fFjwmdxcimD7Y1SAZUvmAciflldZvi2i9BWOEFn8E",{"id":20136,"title":20137,"body":20138,"description":48,"extension":51,"meta":20366,"navigation":55,"path":20368,"seo":20369,"stem":20370,"__hash__":20371},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.1-what-is-command-based-programming.md","What Is Command-Based Programming?",{"type":8,"value":20139,"toc":20357},[20140,20143,20147,20154,20158,20168,20183,20246,20253,20257,20260,20273,20280,20284,20290,20294,20301,20303,20331,20333,20347,20355],[11,20141,20137],{"id":20142},"what-is-command-based-programming",[69,20144,20146],{"id":20145},"the-big-payoff-of-everything-so-far","The Big Payoff of Everything So Far",[15,20148,20149,20150,20153],{},"Every idea from Ch.17-24 — inheritance, interfaces, the IO-Layer Pattern, static factories, builders — leads here. ",[25,20151,20152],{},"Command-based programming"," is WPILib's own official architecture pattern for structuring an entire robot's code. It's not the only way to write a robot program, but it's the one WPILib itself provides deep library support for, and the one most competitive FRC codebases are built around.",[69,20155,20157],{"id":20156},"declarative-not-imperative","Declarative, Not Imperative",[15,20159,20160,20161,20164,20165,20167],{},"Command-based is a ",[25,20162,20163],{},"declarative"," paradigm: you describe ",[262,20166,3185],{}," should happen under what condition, and the library handles checking that condition every single loop, on your behalf. Compare these two ways of saying \"extend the piston when a condition becomes true\":",[104,20169,20171],{"className":106,"code":20170,"language":108,"meta":48,"style":48},"\u002F\u002F Declarative (command-based): say what should happen, once\nnew Trigger(condition::get).onTrue(Commands.runOnce(() -> piston.set(DoubleSolenoid.Value.kForward)));\n",[95,20172,20173,20178],{"__ignoreMap":48},[112,20174,20175],{"class":114,"line":115},[112,20176,20177],{},"\u002F\u002F Declarative (command-based): say what should happen, once\n",[112,20179,20180],{"class":114,"line":49},[112,20181,20182],{},"new Trigger(condition::get).onTrue(Commands.runOnce(() -> piston.set(DoubleSolenoid.Value.kForward)));\n",[104,20184,20186],{"className":106,"code":20185,"language":108,"meta":48,"style":48},"\u002F\u002F Imperative (without command-based): manually track state every single loop\nif (condition.get())\n{\n    if (!pressed)\n    {\n        piston.set(DoubleSolenoid.Value.kForward);\n        pressed = true;\n    }\n}\nelse\n{\n    pressed = false;\n}\n",[95,20187,20188,20193,20198,20202,20207,20211,20216,20221,20225,20229,20233,20237,20242],{"__ignoreMap":48},[112,20189,20190],{"class":114,"line":115},[112,20191,20192],{},"\u002F\u002F Imperative (without command-based): manually track state every single loop\n",[112,20194,20195],{"class":114,"line":49},[112,20196,20197],{},"if (condition.get())\n",[112,20199,20200],{"class":114,"line":126},[112,20201,123],{},[112,20203,20204],{"class":114,"line":132},[112,20205,20206],{},"    if (!pressed)\n",[112,20208,20209],{"class":114,"line":138},[112,20210,135],{},[112,20212,20213],{"class":114,"line":144},[112,20214,20215],{},"        piston.set(DoubleSolenoid.Value.kForward);\n",[112,20217,20218],{"class":114,"line":150},[112,20219,20220],{},"        pressed = true;\n",[112,20222,20223],{"class":114,"line":1819},[112,20224,147],{},[112,20226,20227],{"class":114,"line":1825},[112,20228,153],{},[112,20230,20231],{"class":114,"line":1831},[112,20232,3841],{},[112,20234,20235],{"class":114,"line":4742},[112,20236,123],{},[112,20238,20239],{"class":114,"line":4748},[112,20240,20241],{},"    pressed = false;\n",[112,20243,20244],{"class":114,"line":6935},[112,20245,153],{},[15,20247,20248,20249,20252],{},"The declarative version is written once and never touched again; the imperative version requires you to manually manage a ",[95,20250,20251],{},"pressed"," flag correctly, forever, in every place a similar check is needed. Multiply that by dozens of buttons and sensors across a real robot, and the difference in maintainability is enormous.",[69,20254,20256],{"id":20255},"two-core-abstractions-subsystems-and-commands","Two Core Abstractions: Subsystems and Commands",[15,20258,20259],{},"Command-based organizes an entire robot around exactly two ideas:",[19,20261,20262,20267],{},[22,20263,355,20264,20266],{},[25,20265,7343],{}," represents an independently-controlled piece of hardware (or group of hardware) — a drivetrain, an intake, a climber. Ch.20's IO-Layer Pattern already showed how a subsystem hides its hardware details behind a clean interface; command-based builds directly on that.",[22,20268,355,20269,20272],{},[25,20270,20271],{},"Command"," represents an action the robot can take — something that runs when scheduled, until it's interrupted or its own end condition is met.",[15,20274,20275,20276,20279],{},"Commands declare which subsystem(s) they need (their ",[25,20277,20278],{},"requirements","), and this is what makes resource management automatic: the scheduler guarantees only one command can control a given subsystem at a time, so two different pieces of code can never fight over the same motor's output.",[69,20281,20283],{"id":20282},"how-it-all-runs-the-scheduler","How It All Runs: The Scheduler",[15,20285,1936,20286,20289],{},[25,20287,20288],{},"CommandScheduler"," is the engine underneath all of this — a singleton object that, once per loop (every 20ms), checks all registered triggers for commands that should start, runs the currently-active commands, and ends any that have finished. Lesson 25.3 covers the scheduler's actual run sequence in depth.",[69,20291,20293],{"id":20292},"composability","Composability",[15,20295,20296,20297,20300],{},"Commands are ",[25,20298,20299],{},"recursively composable"," — a complex robot action (like \"intake a game piece, then aim the shooter, then fire\") can be built out of several small, simple commands combined together, and that composite is itself just another command, usable anywhere a command is expected. Lesson 25.2 covers this in depth.",[69,20302,412],{"id":411},[19,20304,20305,20319,20325],{},[22,20306,20307,20312,20313,20315,20316,79],{},[25,20308,20309,20310,79],{},"Writing large amounts of imperative logic directly in ",[95,20311,13472],{}," This works against the entire declarative philosophy command-based is built on — the goal is to describe ",[262,20314,3185],{}," happens, and let the scheduler handle ",[262,20317,20318],{},"when",[22,20320,20321,20324],{},[25,20322,20323],{},"Forgetting that commands need declared requirements."," A command that touches a subsystem without declaring it as a requirement bypasses the resource-management system entirely, risking two commands fighting over the same hardware.",[22,20326,20327,20330],{},[25,20328,20329],{},"Assuming command-based is the only valid way to write robot code."," It isn't — but it's the pattern this curriculum focuses on, since it's what WPILib itself is built to support.",[69,20332,450],{"id":449},[19,20334,20335,20338,20341,20344],{},[22,20336,20337],{},"Command-based programming is WPILib's own declarative architecture pattern: describe what should happen under what condition, once, and the library handles checking it every loop.",[22,20339,20340],{},"The two core abstractions are Subsystems (hardware, building on Ch.20's IO-Layer Pattern) and Commands (actions), tied together by the CommandScheduler.",[22,20342,20343],{},"A command declares its subsystem requirements, which is what lets the scheduler guarantee only one command controls a given subsystem at a time.",[22,20345,20346],{},"Commands are recursively composable — small commands combine into larger ones, which are themselves still just commands.",[15,20348,493,20349,497,20351,20354],{},[95,20350,12493],{},[95,20352,20353],{},"wpilib\u002Fcommand-based\u002F01-what-is-command-based.md"," (WPILIB 20.1)",[503,20356,505],{},{"title":48,"searchDepth":49,"depth":49,"links":20358},[20359,20360,20361,20362,20363,20364,20365],{"id":20145,"depth":49,"text":20146},{"id":20156,"depth":49,"text":20157},{"id":20255,"depth":49,"text":20256},{"id":20282,"depth":49,"text":20283},{"id":20292,"depth":49,"text":20293},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":20367,"status":11220},"25.1 — What Is Command-Based Programming? (WPILIB 20.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F1-what-is-command-based-programming",{"title":20137,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.1-what-is-command-based-programming","Qqe9qWwkPzASuWzWlmfbrl65tXrstjZji5qTi4xA8Uk",{"id":20373,"title":20374,"body":20375,"description":48,"extension":51,"meta":20797,"navigation":55,"path":20799,"seo":20800,"stem":20801,"__hash__":20802},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.2-commands-and-command-compositions.md","Commands & Command Compositions",{"type":8,"value":20376,"toc":20789},[20377,20380,20384,20392,20439,20515,20522,20526,20533,20537,20547,20597,20603,20607,20616,20670,20673,20688,20691,20693,20732,20734,20776,20787],[11,20378,20374],{"id":20379},"commands-command-compositions",[69,20381,20383],{"id":20382},"the-four-lifecycle-methods","The Four Lifecycle Methods",[15,20385,355,20386,20388,20389,20391],{},[95,20387,20271],{}," defines what it does through four overridable methods, all of which default to doing nothing (or ",[95,20390,613],{},") so you only override the ones you actually need:",[19,20393,20394,20402,20410,20427],{},[22,20395,20396,20401],{},[25,20397,20398],{},[95,20399,20400],{},"initialize()"," — called exactly once, when the command starts. Use it to set the command's starting state.",[22,20403,20404,20409],{},[25,20405,20406],{},[95,20407,20408],{},"execute()"," — called repeatedly, once per scheduler run, for as long as the command is scheduled. Use it for anything that needs to happen continuously (following joystick input, running a control loop).",[22,20411,20412,20417,20418,20420,20421,20423,20424,20426],{},[25,20413,20414],{},[95,20415,20416],{},"isFinished()"," — called every loop, after ",[95,20419,20408],{},". As soon as it returns ",[95,20422,610],{},", the command ends. Defaults to ",[95,20425,613],{},", meaning a command runs forever unless something else interrupts it.",[22,20428,20429,20434,20435,20438],{},[25,20430,20431],{},[95,20432,20433],{},"end(boolean interrupted)"," — called exactly once, when the command stops, whether it finished naturally or was interrupted. The ",[95,20436,20437],{},"interrupted"," flag distinguishes the two cases. Use it to clean up (stop a motor, reset a flag).",[104,20440,20442],{"className":106,"code":20441,"language":108,"meta":48,"style":48},"public class GrabHatch extends Command\n{\n    private final HatchSubsystem hatchSubsystem;\n\n    public GrabHatch(HatchSubsystem subsystem)\n    {\n        hatchSubsystem = subsystem;\n        addRequirements(hatchSubsystem); \u002F\u002F declares the resource this command needs\n    }\n\n    @Override\n    public void initialize() { hatchSubsystem.grabHatch(); }\n\n    @Override\n    public boolean isFinished() { return true; } \u002F\u002F runs once, then immediately ends\n}\n",[95,20443,20444,20449,20453,20458,20462,20467,20471,20476,20481,20485,20489,20493,20498,20502,20506,20511],{"__ignoreMap":48},[112,20445,20446],{"class":114,"line":115},[112,20447,20448],{},"public class GrabHatch extends Command\n",[112,20450,20451],{"class":114,"line":49},[112,20452,123],{},[112,20454,20455],{"class":114,"line":126},[112,20456,20457],{},"    private final HatchSubsystem hatchSubsystem;\n",[112,20459,20460],{"class":114,"line":132},[112,20461,820],{"emptyLinePlaceholder":55},[112,20463,20464],{"class":114,"line":138},[112,20465,20466],{},"    public GrabHatch(HatchSubsystem subsystem)\n",[112,20468,20469],{"class":114,"line":144},[112,20470,135],{},[112,20472,20473],{"class":114,"line":150},[112,20474,20475],{},"        hatchSubsystem = subsystem;\n",[112,20477,20478],{"class":114,"line":1819},[112,20479,20480],{},"        addRequirements(hatchSubsystem); \u002F\u002F declares the resource this command needs\n",[112,20482,20483],{"class":114,"line":1825},[112,20484,147],{},[112,20486,20487],{"class":114,"line":1831},[112,20488,820],{"emptyLinePlaceholder":55},[112,20490,20491],{"class":114,"line":4742},[112,20492,15861],{},[112,20494,20495],{"class":114,"line":4748},[112,20496,20497],{},"    public void initialize() { hatchSubsystem.grabHatch(); }\n",[112,20499,20500],{"class":114,"line":6935},[112,20501,820],{"emptyLinePlaceholder":55},[112,20503,20504],{"class":114,"line":6940},[112,20505,15861],{},[112,20507,20508],{"class":114,"line":6946},[112,20509,20510],{},"    public boolean isFinished() { return true; } \u002F\u002F runs once, then immediately ends\n",[112,20512,20513],{"class":114,"line":6952},[112,20514,153],{},[15,20516,20517,20518,20521],{},"Notice the subsystem is passed into the command's constructor — this is ",[25,20519,20520],{},"dependency injection"," (a pattern you'll see again in Lesson 25.7), and it's what lets a command reach a subsystem's methods without that subsystem being a global variable anywhere.",[69,20523,20525],{"id":20524},"requirements-the-resource-management-backbone","Requirements: The Resource-Management Backbone",[15,20527,20528,20529,20532],{},"Every command declares which subsystems it needs, via ",[95,20530,20531],{},"addRequirements(...)",". This is what backs the scheduler's promise that no two commands ever fight over the same subsystem at once (Lesson 25.3 covers exactly how conflicts get resolved).",[69,20534,20536],{"id":20535},"built-in-command-factories-you-rarely-need-a-custom-class","Built-In Command Factories: You Rarely Need a Custom Class",[15,20538,20539,20540,20542,20543,20546],{},"Writing a full ",[95,20541,20271],{}," subclass (like ",[95,20544,20545],{},"GrabHatch"," above) for every simple action is unnecessarily verbose. The library provides factory methods, built on lambdas, that cover almost every real case:",[104,20548,20550],{"className":106,"code":20549,"language":108,"meta":48,"style":48},"Commands.runOnce(() -> hatchSolenoid.set(kForward), hatchSubsystem);       \u002F\u002F runs a lambda once, then finishes\nCommands.run(() -> drive.arcadeDrive(joystick.getY(), joystick.getX()), drive); \u002F\u002F repeats until interrupted — a natural default command\nCommands.startEnd(\n    () -> shooter.setSpeed(0.5),  \u002F\u002F runs once at the start\n    () -> shooter.setSpeed(0.0),  \u002F\u002F runs once when the command ends\n    shooter\n);\nCommands.waitSeconds(5.0);       \u002F\u002F finishes 5 seconds after being scheduled\nCommands.waitUntil(limitSwitch::get); \u002F\u002F finishes once the given condition becomes true\n",[95,20551,20552,20557,20562,20567,20572,20577,20582,20587,20592],{"__ignoreMap":48},[112,20553,20554],{"class":114,"line":115},[112,20555,20556],{},"Commands.runOnce(() -> hatchSolenoid.set(kForward), hatchSubsystem);       \u002F\u002F runs a lambda once, then finishes\n",[112,20558,20559],{"class":114,"line":49},[112,20560,20561],{},"Commands.run(() -> drive.arcadeDrive(joystick.getY(), joystick.getX()), drive); \u002F\u002F repeats until interrupted — a natural default command\n",[112,20563,20564],{"class":114,"line":126},[112,20565,20566],{},"Commands.startEnd(\n",[112,20568,20569],{"class":114,"line":132},[112,20570,20571],{},"    () -> shooter.setSpeed(0.5),  \u002F\u002F runs once at the start\n",[112,20573,20574],{"class":114,"line":138},[112,20575,20576],{},"    () -> shooter.setSpeed(0.0),  \u002F\u002F runs once when the command ends\n",[112,20578,20579],{"class":114,"line":144},[112,20580,20581],{},"    shooter\n",[112,20583,20584],{"class":114,"line":150},[112,20585,20586],{},");\n",[112,20588,20589],{"class":114,"line":1819},[112,20590,20591],{},"Commands.waitSeconds(5.0);       \u002F\u002F finishes 5 seconds after being scheduled\n",[112,20593,20594],{"class":114,"line":1825},[112,20595,20596],{},"Commands.waitUntil(limitSwitch::get); \u002F\u002F finishes once the given condition becomes true\n",[15,20598,20599,20602],{},[95,20600,20601],{},"FunctionalCommand"," covers the general case — four lambdas, one for each of the four lifecycle methods — for when a command needs real custom behavior in more than one of them.",[69,20604,20606],{"id":20605},"command-compositions-building-bigger-actions-from-smaller-ones","Command Compositions: Building Bigger Actions From Smaller Ones",[15,20608,355,20609,20612,20613,20615],{},[25,20610,20611],{},"command composition"," combines several commands into one — and since a composition is itself a ",[95,20614,20271],{},", compositions can be nested arbitrarily deep. Three shapes matter most:",[19,20617,20618,20633,20651],{},[22,20619,20620,20623,20624],{},[25,20621,20622],{},"Sequential"," — runs each command in order, one after another, finishing when the last one finishes:\n",[104,20625,20627],{"className":106,"code":20626,"language":108,"meta":48,"style":48},"fooCommand.andThen(barCommand); \u002F\u002F runs fooCommand, then barCommand\n",[95,20628,20629],{"__ignoreMap":48},[112,20630,20631],{"class":114,"line":115},[112,20632,20626],{},[22,20634,20635,20638,20639,20641,20642],{},[25,20636,20637],{},"Parallel"," — runs several commands at once, finishing once ",[262,20640,4771],{}," of them finish:\n",[104,20643,20645],{"className":106,"code":20644,"language":108,"meta":48,"style":48},"Commands.parallel(twoSecCommand, oneSecCommand, threeSecCommand); \u002F\u002F finishes after 3 seconds\n",[95,20646,20647],{"__ignoreMap":48},[112,20648,20649],{"class":114,"line":115},[112,20650,20644],{},[22,20652,20653,20656,20657,20660,20661],{},[25,20654,20655],{},"Race"," — runs several commands at once, finishing as soon as ",[262,20658,20659],{},"any one"," of them finishes (interrupting the rest):\n",[104,20662,20664],{"className":106,"code":20663,"language":108,"meta":48,"style":48},"Commands.race(twoSecCommand, oneSecCommand, threeSecCommand); \u002F\u002F finishes after 1 second\n",[95,20665,20666],{"__ignoreMap":48},[112,20667,20668],{"class":114,"line":115},[112,20669,20663],{},[15,20671,20672],{},"Two useful decorators add extra end conditions to any command:",[104,20674,20676],{"className":106,"code":20675,"language":108,"meta":48,"style":48},"command.until(limitSwitch::get); \u002F\u002F ends early if the limit switch trips\ncommand.withTimeout(5);          \u002F\u002F ends after 5 seconds no matter what\n",[95,20677,20678,20683],{"__ignoreMap":48},[112,20679,20680],{"class":114,"line":115},[112,20681,20682],{},"command.until(limitSwitch::get); \u002F\u002F ends early if the limit switch trips\n",[112,20684,20685],{"class":114,"line":49},[112,20686,20687],{},"command.withTimeout(5);          \u002F\u002F ends after 5 seconds no matter what\n",[15,20689,20690],{},"A composition inherits the union of every component's requirements — a sequence that uses the intake, then the indexer, then the shooter reserves all three subsystems for the composition's entire duration, not just while each is actively in use.",[69,20692,412],{"id":411},[19,20694,20695,20701,20723],{},[22,20696,20697,20700],{},[25,20698,20699],{},"Scheduling a command that's already inside a composition."," Once a command is part of a composition, it can't also be independently scheduled — attempting to do so throws and crashes the program, since the same command instance would be running from two places at once.",[22,20702,20703,20709,20710,275,20713,275,20716,275,20719,20722],{},[25,20704,20705,20706,20708],{},"Writing a full custom ",[95,20707,20271],{}," subclass for something a factory already covers."," The built-in factories (",[95,20711,20712],{},"runOnce",[95,20714,20715],{},"run",[95,20717,20718],{},"startEnd",[95,20720,20721],{},"waitUntil",", etc.) cover the overwhelming majority of real cases with far less code.",[22,20724,20725,20728,20729,20731],{},[25,20726,20727],{},"Forgetting that a sequential composition needs every step to actually finish."," If one command in a sequence never calls its ",[95,20730,20416],{}," true, every command after it in the sequence never runs.",[69,20733,450],{"id":449},[19,20735,20736,20751,20756,20773],{},[22,20737,355,20738,20740,20741,275,20743,275,20745,275,20747,20750],{},[95,20739,20271],{},"'s behavior is defined by four lifecycle methods: ",[95,20742,20400],{},[95,20744,20408],{},[95,20746,20416],{},[95,20748,20749],{},"end(interrupted)"," — all default to reasonable no-ops.",[22,20752,20753,20755],{},[95,20754,20531],{}," declares which subsystems a command needs, backing the scheduler's resource-conflict prevention.",[22,20757,20758,20759,275,20761,275,20763,275,20765,275,20768,275,20770,20772],{},"Built-in factories (",[95,20760,20712],{},[95,20762,20715],{},[95,20764,20718],{},[95,20766,20767],{},"waitSeconds",[95,20769,20721],{},[95,20771,20601],{},") cover almost every use case without writing a custom class.",[22,20774,20775],{},"Compositions (sequential, parallel, race) combine commands into bigger ones, and are themselves ordinary commands — usable recursively, nested as deep as needed.",[15,20777,493,20778,497,20780,275,20783,20786],{},[95,20779,12493],{},[95,20781,20782],{},"wpilib\u002Fcommand-based\u002F02-commands.md",[95,20784,20785],{},"03-command-compositions.md"," (WPILIB 20.2-3)",[503,20788,505],{},{"title":48,"searchDepth":49,"depth":49,"links":20790},[20791,20792,20793,20794,20795,20796],{"id":20382,"depth":49,"text":20383},{"id":20524,"depth":49,"text":20525},{"id":20535,"depth":49,"text":20536},{"id":20605,"depth":49,"text":20606},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":20798,"status":11220},"25.2 — Commands & Command Compositions (WPILIB 20.2-3)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F2-commands-and-command-compositions",{"title":20374,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.2-commands-and-command-compositions","CFOaxGhRnrC7W3MGFxvICQc6vTJ_nspB3GPupJolJO0",{"id":20804,"title":20805,"body":20806,"description":48,"extension":51,"meta":21014,"navigation":55,"path":21016,"seo":21017,"stem":21018,"__hash__":21019},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.3-the-command-scheduler.md","The Command Scheduler",{"type":8,"value":20807,"toc":21006},[20808,20811,20815,20828,20832,20835,20843,20856,20875,20881,20885,20904,20908,20917,20919,20969,20971,20998],[11,20809,20805],{"id":20810},"the-command-scheduler",[69,20812,20814],{"id":20813},"the-engine-underneath-everything","The Engine Underneath Everything",[15,20816,1936,20817,20819,20820,20823,20824,20827],{},[95,20818,20288],{}," is the singleton object that actually runs commands — everything in Lessons 25.1-25.2 depends on it silently doing its job every single loop. It must be told to run explicitly: ",[95,20821,20822],{},"CommandScheduler.getInstance().run()"," needs to be called from ",[95,20825,20826],{},"robotPeriodic()"," (Lesson 25.7 shows exactly where), or nothing in the whole command-based framework ever executes.",[69,20829,20831],{"id":20830},"one-scheduler-iteration-step-by-step","One Scheduler Iteration, Step by Step",[15,20833,20834],{},"Every 20ms (WPILib's default loop rate), the scheduler works through four steps, always in this order:",[15,20836,20837,20842],{},[25,20838,20839,20840,79],{},"Step 1 — Run every registered Subsystem's ",[95,20841,12563],{}," This happens first, so subsystems can update their own state (like odometry) before any commands act on it this loop.",[15,20844,20845,20848,20849,20852,20853,20855],{},[25,20846,20847],{},"Step 2 — Poll triggers for new commands to schedule."," Every registered ",[95,20850,20851],{},"Trigger"," (Lesson 25.6) is checked; if a binding's condition is met, its command is scheduled and that command's ",[95,20854,20400],{}," runs immediately.",[15,20857,20858,20861,20862,20864,20865,20867,20868,20870,20871,20874],{},[25,20859,20860],{},"Step 3 — Run every currently-scheduled command."," For each one: call ",[95,20863,20408],{},", then check ",[95,20866,20416],{},". If it's ",[95,20869,610],{},", call ",[95,20872,20873],{},"end(false)"," and remove the command, freeing its subsystem requirements for anything else.",[15,20876,20877,20880],{},[25,20878,20879],{},"Step 4 — Schedule default commands."," Any subsystem not currently claimed by another command gets its default command scheduled (if it has one) — this is how a drivetrain \"just keeps driving from joystick input\" whenever nothing more specific is happening.",[69,20882,20884],{"id":20883},"how-requirement-conflicts-get-resolved","How Requirement Conflicts Get Resolved",[15,20886,20887,20888,20891,20892,20895,20896,20899,20900,20903],{},"When a new command is scheduled and it needs a subsystem some other running command already has, the scheduler checks each conflicting command's ",[25,20889,20890],{},"interruption behavior"," (Lesson 25.2 briefly touched requirements; this is what happens when they collide): by default (",[95,20893,20894],{},"kCancelSelf","), the already-running command is canceled — its ",[95,20897,20898],{},"end(true)"," runs — and the new command takes over. A command can instead be marked ",[95,20901,20902],{},"kCancelIncoming",", in which case the new command simply fails to schedule, and the original keeps running.",[69,20905,20907],{"id":20906},"why-the-call-order-matters","Why the Call Order Matters",[15,20909,20910,20911,20913,20914,20916],{},"Subsystem ",[95,20912,12563],{}," methods run ",[262,20915,1504],{}," triggers are polled and commands execute, each loop — so a subsystem's periodic logic (like updating odometry) is always based on the previous loop's final state, and any command reading that subsystem's state this loop sees it freshly updated. This ordering is part of why command-based code behaves predictably: the sequence is the same, every single loop, without exception.",[69,20918,412],{"id":411},[19,20920,20921,20931,20948],{},[22,20922,20923,20930],{},[25,20924,20925,20926,2902,20928,79],{},"Forgetting to call ",[95,20927,20822],{},[95,20929,20826],{}," Without this one line, nothing in the entire command-based framework does anything — commands never execute, triggers never fire.",[22,20932,20933,20943,20944,20947],{},[25,20934,20935,20936,20938,20939,20942],{},"Assuming a command's ",[95,20937,20400],{}," runs exactly when the scheduler's ",[95,20940,20941],{},"run()"," is called."," It actually runs the moment the command is ",[262,20945,20946],{},"scheduled"," — which for a trigger-bound command happens during Step 2 of whichever loop the trigger condition first becomes true.",[22,20949,20950,20960,20961,20963,20964,20966,20967,79],{},[25,20951,20952,20953,20956,20957,79],{},"Expecting a canceled command's ",[95,20954,20955],{},"end()"," to report ",[95,20958,20959],{},"interrupted = false"," A command that's forcibly interrupted (by a conflicting command, or an explicit cancel) always gets ",[95,20962,20898],{}," — only a command that finishes on its own via ",[95,20965,20416],{}," gets ",[95,20968,20873],{},[69,20970,450],{"id":449},[19,20972,20973,20984,20990,20995],{},[22,20974,1936,20975,20977,20978,20980,20981,20983],{},[95,20976,20288],{}," is a singleton that must be run explicitly (",[95,20979,20822],{},", from ",[95,20982,20826],{},") — without this call, the framework does nothing.",[22,20985,20986,20987,20989],{},"Each iteration runs in a fixed order: subsystem ",[95,20988,12563],{}," methods, then poll triggers for new commands, then execute\u002Ffinish already-scheduled commands, then schedule any subsystem's default command if it's free.",[22,20991,20992,20993,79],{},"Requirement conflicts are resolved by interruption behavior: the default cancels the already-running command in favor of the new one, unless that behavior is set to ",[95,20994,20902],{},[22,20996,20997],{},"This fixed, predictable run order is a big part of why command-based code behaves consistently loop after loop.",[15,20999,493,21000,497,21002,21005],{},[95,21001,12493],{},[95,21003,21004],{},"wpilib\u002Fcommand-based\u002F08-command-scheduler.md"," (WPILIB 20.8)",{"title":48,"searchDepth":49,"depth":49,"links":21007},[21008,21009,21010,21011,21012,21013],{"id":20813,"depth":49,"text":20814},{"id":20830,"depth":49,"text":20831},{"id":20883,"depth":49,"text":20884},{"id":20906,"depth":49,"text":20907},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":21015,"status":11220},"25.3 — The Command Scheduler (WPILIB 20.8)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F3-the-command-scheduler",{"title":20805,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.3-the-command-scheduler","NlXbL__r6p_2bNZ0ZGw9WM_TmQX6Uldy0xc82H4puVQ",{"id":21021,"title":21022,"body":21023,"description":48,"extension":51,"meta":21221,"navigation":55,"path":21223,"seo":21224,"stem":21225,"__hash__":21226},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.4-state-machines-logic.md","State Machines: Logic",{"type":8,"value":21024,"toc":21213},[21025,21028,21032,21035,21060,21076,21080,21083,21130,21137,21141,21148,21152,21155,21157,21184,21186,21197,21211],[11,21026,21022],{"id":21027},"state-machines-logic",[69,21029,21031],{"id":21030},"the-problem-tracking-state-with-booleans-doesnt-scale","The Problem: Tracking State With Booleans Doesn't Scale",[15,21033,21034],{},"A subsystem often needs to remember \"what am I currently doing\" — an intake might be idle, actively intaking, holding a game piece, or scoring. Tracking that with a pile of booleans gets unmanageable fast:",[104,21036,21038],{"className":106,"code":21037,"language":108,"meta":48,"style":48},"private boolean isIdle;\nprivate boolean isIntaking;\nprivate boolean isHolding;\nprivate boolean isScoring;\n",[95,21039,21040,21045,21050,21055],{"__ignoreMap":48},[112,21041,21042],{"class":114,"line":115},[112,21043,21044],{},"private boolean isIdle;\n",[112,21046,21047],{"class":114,"line":49},[112,21048,21049],{},"private boolean isIntaking;\n",[112,21051,21052],{"class":114,"line":126},[112,21053,21054],{},"private boolean isHolding;\n",[112,21056,21057],{"class":114,"line":132},[112,21058,21059],{},"private boolean isScoring;\n",[15,21061,21062,21063,21065,21066,486,21069,21072,21073,21075],{},"Nothing stops two of these from accidentally being ",[95,21064,610],{}," at the same time — a bug that's easy to introduce and hard to spot, since \"impossible\" combinations (",[95,21067,21068],{},"isIdle",[95,21070,21071],{},"isScoring"," both ",[95,21074,610],{},") compile just fine.",[69,21077,21079],{"id":21078},"the-fix-one-enum-one-set-of-named-states","The Fix: One Enum, One Set of Named States",[15,21081,21082],{},"Enums (Ch.11) are exactly the tool for this — a fixed, named set of mutually exclusive states, with the compiler enforcing that a variable can only ever be one of them:",[104,21084,21086],{"className":106,"code":21085,"language":108,"meta":48,"style":48},"public enum IntakeState\n{\n    IDLE,\n    INTAKING,\n    HOLDING,\n    SCORING\n}\n\nprivate IntakeState currentState = IntakeState.IDLE;\n",[95,21087,21088,21093,21097,21102,21107,21112,21117,21121,21125],{"__ignoreMap":48},[112,21089,21090],{"class":114,"line":115},[112,21091,21092],{},"public enum IntakeState\n",[112,21094,21095],{"class":114,"line":49},[112,21096,123],{},[112,21098,21099],{"class":114,"line":126},[112,21100,21101],{},"    IDLE,\n",[112,21103,21104],{"class":114,"line":132},[112,21105,21106],{},"    INTAKING,\n",[112,21108,21109],{"class":114,"line":138},[112,21110,21111],{},"    HOLDING,\n",[112,21113,21114],{"class":114,"line":144},[112,21115,21116],{},"    SCORING\n",[112,21118,21119],{"class":114,"line":150},[112,21120,153],{},[112,21122,21123],{"class":114,"line":1819},[112,21124,820],{"emptyLinePlaceholder":55},[112,21126,21127],{"class":114,"line":1825},[112,21128,21129],{},"private IntakeState currentState = IntakeState.IDLE;\n",[15,21131,21132,21133,21136],{},"Now the subsystem's state is a single variable, and it's structurally impossible for it to be two states at once. This is a ",[25,21134,21135],{},"state machine",": a system that's always in exactly one of a fixed set of named states, and moves between them according to defined rules.",[69,21138,21140],{"id":21139},"real-codebases-do-this-at-scale","Real Codebases Do This at Scale",[15,21142,21143,21144,21147],{},"This exact pattern — an enum representing a fixed set of named states for a subsystem — is how real, competitive FRC codebases (like Team 5817's own production code) structure their subsystems, just with more states and richer per-state behavior than this introductory example: an elevator's states might be tied to interpolated target heights that shift based on scoring distance, or a roller's states might each carry their own target voltage. The underlying idea is identical to ",[95,21145,21146],{},"IntakeState"," above — a state machine core built on an enum — dressed up with more sophisticated per-state data as a subsystem's real requirements grow.",[69,21149,21151],{"id":21150},"what-comes-next","What Comes Next",[15,21153,21154],{},"Having a named state is only half the picture — a state machine also needs logic that reads the current state and decides what to do (and when to move to a different state). That's the subject of Lesson 25.5.",[69,21156,412],{"id":411},[19,21158,21159,21165],{},[22,21160,21161,21164],{},[25,21162,21163],{},"Reaching for several independent booleans instead of one enum."," This lets impossible\u002Fcontradictory combinations exist in the code, even though only one is ever supposed to be true — an enum makes that mistake structurally impossible.",[22,21166,21167,426,21170,21173,21174,21177,21178,21180,21181,21183],{},[25,21168,21169],{},"Forgetting a state machine needs an initial value.",[95,21171,21172],{},"currentState"," should always be initialized to a real starting state (like ",[95,21175,21176],{},"IDLE",") — an uninitialized state variable is a ",[95,21179,3384],{}," waiting to cause a ",[95,21182,3414],{}," (Ch.12\u002F13) the first time anything reads it.",[69,21185,450],{"id":449},[19,21187,21188,21191,21194],{},[22,21189,21190],{},"Tracking \"what state am I in\" with multiple independent booleans allows impossible combinations and doesn't scale.",[22,21192,21193],{},"A single enum field, initialized to a sensible starting value, makes a subsystem's current state both self-documenting and structurally guaranteed to be exactly one thing at a time.",[22,21195,21196],{},"This pattern — enum-based state machines for subsystems — is exactly what real, competitive FRC codebases use, just with richer per-state data as requirements grow.",[15,21198,493,21199,497,21201,275,21204,21207,21208,21210],{},[95,21200,12493],{},[95,21202,21203],{},"team-5817-training\u002Fsubsystems\u002F02-state-based-servo-subsystems.md",[95,21205,21206],{},"03-state-based-roller-subsystems.md"," (T5817 31.1-4)\n",[25,21209,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 10 (\"State Machines: Logic\") — IntakeState enum example",[503,21212,505],{},{"title":48,"searchDepth":49,"depth":49,"links":21214},[21215,21216,21217,21218,21219,21220],{"id":21030,"depth":49,"text":21031},{"id":21078,"depth":49,"text":21079},{"id":21139,"depth":49,"text":21140},{"id":21150,"depth":49,"text":21151},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":21222,"status":519},"25.4 — State Machines: Logic (enum) (T5817 31.1-4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F4-state-machines-logic",{"title":21022,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.4-state-machines-logic","xc6jvIQ0LI9NHCe4tEgKmTmU9-bayNHg9FUs4ObGbuQ",{"id":21228,"title":21229,"body":21230,"description":48,"extension":51,"meta":21512,"navigation":55,"path":21514,"seo":21515,"stem":21516,"__hash__":21517},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.5-managing-transitions.md","Managing Transitions",{"type":8,"value":21231,"toc":21504},[21232,21235,21239,21256,21366,21385,21389,21398,21404,21409,21411,21458,21460,21491,21502],[11,21233,21229],{"id":21234},"managing-transitions",[69,21236,21238],{"id":21237},"reading-the-current-state-every-loop","Reading the Current State, Every Loop",[15,21240,21241,21242,21245,21246,21249,21250,21252,21253,21255],{},"Lesson 25.4 gave a subsystem a single enum field representing its current state. The natural place to ",[262,21243,21244],{},"act"," on that state — and decide when to ",[262,21247,21248],{},"transition"," to a different one — is a ",[95,21251,12167],{}," (Ch.5) inside the subsystem's ",[95,21254,12563],{}," method, which the scheduler calls once every loop (Lesson 25.3):",[104,21257,21259],{"className":106,"code":21258,"language":108,"meta":48,"style":48},"@Override\npublic void periodic()\n{\n    switch (currentState)\n    {\n        case INTAKING:\n            motor.set(0.5);\n            if (sensor.get())\n            {\n                currentState = IntakeState.HOLDING; \u002F\u002F transition: a sensor reading changed the state\n            }\n            break;\n        case IDLE:\n            motor.set(0);\n            break;\n        case HOLDING:\n            motor.set(0.1); \u002F\u002F gentle hold pressure\n            break;\n        case SCORING:\n            motor.set(-0.5);\n            break;\n    }\n}\n",[95,21260,21261,21265,21270,21274,21279,21283,21288,21293,21298,21302,21307,21311,21316,21321,21326,21330,21335,21340,21344,21349,21354,21358,21362],{"__ignoreMap":48},[112,21262,21263],{"class":114,"line":115},[112,21264,16021],{},[112,21266,21267],{"class":114,"line":49},[112,21268,21269],{},"public void periodic()\n",[112,21271,21272],{"class":114,"line":126},[112,21273,123],{},[112,21275,21276],{"class":114,"line":132},[112,21277,21278],{},"    switch (currentState)\n",[112,21280,21281],{"class":114,"line":138},[112,21282,135],{},[112,21284,21285],{"class":114,"line":144},[112,21286,21287],{},"        case INTAKING:\n",[112,21289,21290],{"class":114,"line":150},[112,21291,21292],{},"            motor.set(0.5);\n",[112,21294,21295],{"class":114,"line":1819},[112,21296,21297],{},"            if (sensor.get())\n",[112,21299,21300],{"class":114,"line":1825},[112,21301,11704],{},[112,21303,21304],{"class":114,"line":1831},[112,21305,21306],{},"                currentState = IntakeState.HOLDING; \u002F\u002F transition: a sensor reading changed the state\n",[112,21308,21309],{"class":114,"line":4742},[112,21310,11714],{},[112,21312,21313],{"class":114,"line":4748},[112,21314,21315],{},"            break;\n",[112,21317,21318],{"class":114,"line":6935},[112,21319,21320],{},"        case IDLE:\n",[112,21322,21323],{"class":114,"line":6940},[112,21324,21325],{},"            motor.set(0);\n",[112,21327,21328],{"class":114,"line":6946},[112,21329,21315],{},[112,21331,21332],{"class":114,"line":6952},[112,21333,21334],{},"        case HOLDING:\n",[112,21336,21337],{"class":114,"line":6957},[112,21338,21339],{},"            motor.set(0.1); \u002F\u002F gentle hold pressure\n",[112,21341,21342],{"class":114,"line":6963},[112,21343,21315],{},[112,21345,21346],{"class":114,"line":6968},[112,21347,21348],{},"        case SCORING:\n",[112,21350,21351],{"class":114,"line":11929},[112,21352,21353],{},"            motor.set(-0.5);\n",[112,21355,21356],{"class":114,"line":11935},[112,21357,21315],{},[112,21359,21360],{"class":114,"line":18525},[112,21361,147],{},[112,21363,21364],{"class":114,"line":18531},[112,21365,153],{},[15,21367,21368,21369,21371,21372,21375,21376,21378,21379,3883,21382,3179],{},"Each ",[95,21370,12171],{}," does two jobs: it runs whatever behavior belongs to that state (",[95,21373,21374],{},"motor.set(...)","), and it checks whether a ",[25,21377,21248],{}," to a different state should happen (here, a sensor detecting a game piece moves the intake from ",[95,21380,21381],{},"INTAKING",[95,21383,21384],{},"HOLDING",[69,21386,21388],{"id":21387},"transitions-are-just-reassigning-the-state-field","Transitions Are Just Reassigning the State Field",[15,21390,21391,21392,21394,21395,21397],{},"A transition is nothing more than assigning a new value to the state field — no special syntax beyond what Ch.2\u002FCh.11 already covered. What makes a state machine's behavior correct is ",[262,21393,9417],{}," those reassignments happen: inside the specific ",[95,21396,12171],{}," for the state that condition applies to, based on whatever real-world signal (a sensor, a timer, a driver input) should trigger the change.",[69,21399,21401,21402],{"id":21400},"why-this-belongs-in-periodic","Why This Belongs in ",[95,21403,12563],{},[15,21405,21406,21408],{},[95,21407,12563],{}," runs every single scheduler loop, which is exactly the cadence a state machine needs — checking \"should I transition now?\" once per loop is what makes a sensor-triggered transition (like the intake noticing a game piece) responsive in real time, rather than only checked occasionally.",[69,21410,412],{"id":411},[19,21412,21413,21433,21441],{},[22,21414,21415,21423,21424,21426,21427,21429,21430,21432],{},[25,21416,3455,21417,13347,21420,21422],{},[95,21418,21419],{},"break;",[95,21421,12167],{}," (Ch.5)."," Without it, execution falls through into the next ",[95,21425,12171],{},"'s code — a ",[95,21428,12167],{},"-based state machine with a missing ",[95,21431,12175],{}," can silently run the wrong state's behavior on top of the intended one.",[22,21434,21435,21440],{},[25,21436,21437,21438,79],{},"Putting transition logic in the wrong ",[95,21439,12171],{}," A transition condition checked inside the wrong state's case either never triggers, or triggers behavior meant for a different state entirely.",[22,21442,21443,21448,21449,21452,21453,2902,21455,21457],{},[25,21444,21445,21446,79],{},"Mutating the state field from outside ",[95,21447,12563],{}," Scattering ",[95,21450,21451],{},"currentState = ..."," assignments across multiple methods makes it much harder to reason about when and why transitions actually happen — keeping all transition logic inside the one ",[95,21454,12167],{},[95,21456,12563],{}," keeps the whole state machine's behavior in one place.",[69,21459,450],{"id":449},[19,21461,21462,21470,21476,21482],{},[22,21463,355,21464,21466,21467,21469],{},[95,21465,12167],{}," over the state enum, inside ",[95,21468,12563],{},", is the natural place to both run each state's behavior and check for transitions to a different state.",[22,21471,21472,21473,21475],{},"A transition is just a plain reassignment of the state field — the important part is placing it inside the correct state's ",[95,21474,12171],{},", gated on the right real-world condition.",[22,21477,21478,21479,21481],{},"Running this logic in ",[95,21480,12563],{}," (called every scheduler loop) is what makes transitions responsive to sensors and other real-time signals.",[22,21483,21484,21485,21487,21488,21490],{},"Missing a ",[95,21486,21419],{}," is the single most common bug in a ",[95,21489,12167],{},"-based state machine.",[15,21492,493,21493,497,21495,275,21497,21207,21499,21501],{},[95,21494,12493],{},[95,21496,21203],{},[95,21498,21206],{},[25,21500,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 11 (\"Managing Transitions\") — IntakeState switch example",[503,21503,505],{},{"title":48,"searchDepth":49,"depth":49,"links":21505},[21506,21507,21508,21510,21511],{"id":21237,"depth":49,"text":21238},{"id":21387,"depth":49,"text":21388},{"id":21400,"depth":49,"text":21509},"Why This Belongs in periodic()",{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":21513,"status":519},"25.5 — Managing Transitions (switch) (T5817 31.1-4)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F5-managing-transitions",{"title":21229,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.5-managing-transitions","hyScUn0kHkxnFELG_uSdU8K3r4UcC6q1aAEWZoEJxao",{"id":21519,"title":21520,"body":21521,"description":48,"extension":51,"meta":21807,"navigation":55,"path":21809,"seo":21810,"stem":21811,"__hash__":21812},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.6-binding-commands-to-triggers.md","Binding Commands to Triggers",{"type":8,"value":21522,"toc":21798},[21523,21526,21530,21535,21564,21568,21571,21614,21624,21628,21641,21656,21660,21663,21683,21687,21694,21703,21705,21744,21746,21785,21796],[11,21524,21520],{"id":21525},"binding-commands-to-triggers",[69,21527,21529],{"id":21528},"triggers-the-declarative-glue","Triggers: The Declarative Glue",[15,21531,355,21532,21534],{},[95,21533,20851],{}," wraps any boolean condition — a button, a sensor, an arbitrary check — so a command can be bound to it once, declaratively, during setup. From then on, the scheduler itself checks the condition every loop (Lesson 25.3's Step 2) and schedules or cancels the command as needed — no manual polling code required anywhere else.",[104,21536,21538],{"className":106,"code":21537,"language":108,"meta":48,"style":48},"\u002F\u002F From a controller button\nTrigger xButton = driverController.x();\n\n\u002F\u002F From an arbitrary condition — any BooleanSupplier (Lesson 19.1) works\nTrigger loaded = new Trigger(intake::isLoaded);\n",[95,21539,21540,21545,21550,21554,21559],{"__ignoreMap":48},[112,21541,21542],{"class":114,"line":115},[112,21543,21544],{},"\u002F\u002F From a controller button\n",[112,21546,21547],{"class":114,"line":49},[112,21548,21549],{},"Trigger xButton = driverController.x();\n",[112,21551,21552],{"class":114,"line":126},[112,21553,820],{"emptyLinePlaceholder":55},[112,21555,21556],{"class":114,"line":132},[112,21557,21558],{},"\u002F\u002F From an arbitrary condition — any BooleanSupplier (Lesson 19.1) works\n",[112,21560,21561],{"class":114,"line":138},[112,21562,21563],{},"Trigger loaded = new Trigger(intake::isLoaded);\n",[69,21565,21567],{"id":21566},"the-core-bindings","The Core Bindings",[15,21569,21570],{},"Each binding schedules a command in response to a specific kind of state change:",[104,21572,21574],{"className":106,"code":21573,"language":108,"meta":48,"style":48},"\u002F\u002F Schedules once, the instant the trigger becomes true (e.g. the button is first pressed)\ndriverController.y().onTrue(intake.retractCommand());\n\n\u002F\u002F Schedules while the trigger is true, cancels the instant it becomes false\ndriverController.b().whileTrue(intake.runIntakeCommand());\n\n\u002F\u002F Schedules once, the instant the trigger becomes false — the mirror of onTrue\ndriverController.a().onFalse(shooter.stopCommand());\n",[95,21575,21576,21581,21586,21590,21595,21600,21604,21609],{"__ignoreMap":48},[112,21577,21578],{"class":114,"line":115},[112,21579,21580],{},"\u002F\u002F Schedules once, the instant the trigger becomes true (e.g. the button is first pressed)\n",[112,21582,21583],{"class":114,"line":49},[112,21584,21585],{},"driverController.y().onTrue(intake.retractCommand());\n",[112,21587,21588],{"class":114,"line":126},[112,21589,820],{"emptyLinePlaceholder":55},[112,21591,21592],{"class":114,"line":132},[112,21593,21594],{},"\u002F\u002F Schedules while the trigger is true, cancels the instant it becomes false\n",[112,21596,21597],{"class":114,"line":138},[112,21598,21599],{},"driverController.b().whileTrue(intake.runIntakeCommand());\n",[112,21601,21602],{"class":114,"line":144},[112,21603,820],{"emptyLinePlaceholder":55},[112,21605,21606],{"class":114,"line":150},[112,21607,21608],{},"\u002F\u002F Schedules once, the instant the trigger becomes false — the mirror of onTrue\n",[112,21610,21611],{"class":114,"line":1819},[112,21612,21613],{},"driverController.a().onFalse(shooter.stopCommand());\n",[15,21615,21616,21619,21620,21623],{},[95,21617,21618],{},"onTrue"," fires once on the rising edge and doesn't re-fire unless the trigger goes false and true again. ",[95,21621,21622],{},"whileTrue"," keeps a command running for as long as the condition holds, and cancels it the moment the condition ends — this is the natural fit for \"run the intake while this button is held down.\"",[69,21625,21627],{"id":21626},"composing-triggers","Composing Triggers",[15,21629,21630,21631,275,21634,278,21637,21640],{},"Triggers combine with ",[95,21632,21633],{},"and()",[95,21635,21636],{},"or()",[95,21638,21639],{},"negate()",", just like boolean expressions (Ch.5):",[104,21642,21644],{"className":106,"code":21643,"language":108,"meta":48,"style":48},"\u002F\u002F Only schedules when BOTH buttons are pressed together\ndriverController.x().and(driverController.y()).onTrue(new ExampleCommand());\n",[95,21645,21646,21651],{"__ignoreMap":48},[112,21647,21648],{"class":114,"line":115},[112,21649,21650],{},"\u002F\u002F Only schedules when BOTH buttons are pressed together\n",[112,21652,21653],{"class":114,"line":49},[112,21654,21655],{},"driverController.x().and(driverController.y()).onTrue(new ExampleCommand());\n",[69,21657,21659],{"id":21658},"chaining-multiple-bindings-on-one-trigger","Chaining Multiple Bindings on One Trigger",[15,21661,21662],{},"Binding methods return the same trigger they were called on, so several different bindings can be chained onto one trigger:",[104,21664,21666],{"className":106,"code":21665,"language":108,"meta":48,"style":48},"exampleButton\n    .onTrue(new FooCommand())   \u002F\u002F runs when pressed\n    .onFalse(new BarCommand()); \u002F\u002F runs when released\n",[95,21667,21668,21673,21678],{"__ignoreMap":48},[112,21669,21670],{"class":114,"line":115},[112,21671,21672],{},"exampleButton\n",[112,21674,21675],{"class":114,"line":49},[112,21676,21677],{},"    .onTrue(new FooCommand())   \u002F\u002F runs when pressed\n",[112,21679,21680],{"class":114,"line":126},[112,21681,21682],{},"    .onFalse(new BarCommand()); \u002F\u002F runs when released\n",[69,21684,21686],{"id":21685},"debouncing-filtering-out-noise","Debouncing: Filtering Out Noise",[15,21688,21689,21690,21693],{},"A digital sensor's raw signal can flicker rapidly right at the transition point — a ",[95,21691,21692],{},"debounce"," filters that out, requiring the condition to hold steady for a set duration before it's treated as a real change:",[104,21695,21697],{"className":106,"code":21696,"language":108,"meta":48,"style":48},"exampleButton.debounce(0.1).onTrue(new ExampleCommand()); \u002F\u002F ignores flickers under 0.1s\n",[95,21698,21699],{"__ignoreMap":48},[112,21700,21701],{"class":114,"line":115},[112,21702,21696],{},[69,21704,412],{"id":411},[19,21706,21707,21718,21734],{},[22,21708,21709,21715,21716,79],{},[25,21710,21711,21712,21714],{},"Expecting ",[95,21713,21618],{}," to re-fire while a button stays held."," It only fires once, on the transition from false to true — for continuous behavior while held, use ",[95,21717,21622],{},[22,21719,21720,2788,21726,21728,21729,275,21731,21733],{},[25,21721,21722,21723,21725],{},"Confusing a ",[95,21724,20851],{},"'s boolean condition with the command it's bound to.",[95,21727,20851],{}," is just a wrapped condition; binding methods (",[95,21730,21618],{},[95,21732,21622],{},", etc.) are what actually connect it to a command.",[22,21735,21736,21739,21740,21743],{},[25,21737,21738],{},"Not debouncing a noisy digital sensor."," A sensor near its trip point can rapidly flicker true\u002Ffalse, causing repeated unwanted scheduling — ",[95,21741,21742],{},"debounce(...)"," exists specifically for this.",[69,21745,450],{"id":449},[19,21747,21748,21753,21767,21777,21780],{},[22,21749,355,21750,21752],{},[95,21751,20851],{}," wraps any boolean condition (a button, a sensor, an arbitrary check) so a command can be bound to it once, declaratively.",[22,21754,21755,1051,21757,21760,21761,1051,21763,21766],{},[95,21756,21618],{},[95,21758,21759],{},"onFalse"," fire once on a transition; ",[95,21762,21622],{},[95,21764,21765],{},"whileFalse"," schedule for as long as the condition holds and cancel the moment it changes.",[22,21768,21769,21770,275,21772,275,21774,21776],{},"Triggers compose with ",[95,21771,21633],{},[95,21773,21636],{},[95,21775,21639],{}," — same boolean logic as Ch.5.",[22,21778,21779],{},"Binding methods return the same trigger, so multiple bindings can be chained onto one trigger.",[22,21781,21782,21784],{},[95,21783,21742],{}," filters out rapid flickering near a condition's trip point.",[15,21786,493,21787,497,21789,21792,21793,21795],{},[95,21788,12493],{},[95,21790,21791],{},"wpilib\u002Fcommand-based\u002F05-binding-commands-to-triggers.md"," (WPILIB 20.5)\n",[25,21794,4022],{}," mechacoder-test\u002Fsrc\u002Flessons\u002Fjava-2.js, slide 12 (\"Event Loops & Triggers\")",[503,21797,505],{},{"title":48,"searchDepth":49,"depth":49,"links":21799},[21800,21801,21802,21803,21804,21805,21806],{"id":21528,"depth":49,"text":21529},{"id":21566,"depth":49,"text":21567},{"id":21626,"depth":49,"text":21627},{"id":21658,"depth":49,"text":21659},{"id":21685,"depth":49,"text":21686},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":21808,"status":519},"25.6 — Binding Commands to Triggers (WPILIB 20.5)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F6-binding-commands-to-triggers",{"title":21520,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.6-binding-commands-to-triggers","QGK-vAd0F1toC3-4NUtoGPo3NFIcPLBsaAAA19bo5oc",{"id":21814,"title":21815,"body":21816,"description":48,"extension":51,"meta":22360,"navigation":55,"path":22362,"seo":22363,"stem":22364,"__hash__":22365},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.7-structuring-a-command-based-robot-project.md","Structuring a Command-Based Robot Project",{"type":8,"value":21817,"toc":22351},[21818,21821,21825,21828,21869,21873,21879,22010,22018,22022,22031,22085,22094,22098,22126,22135,22139,22142,22175,22211,22262,22264,22290,22292,22333,22349],[11,21819,21815],{"id":21820},"structuring-a-command-based-robot-project",[69,21822,21824],{"id":21823},"the-standard-project-shape","The Standard Project Shape",[15,21826,21827],{},"WPILib's own project template organizes a command-based robot around four root-level classes plus two subdirectories:",[19,21829,21830,21837,21844,21856],{},[22,21831,21832,21836],{},[25,21833,21834],{},[95,21835,14992],{}," — the entry point, kept intentionally thin (see below).",[22,21838,21839,21843],{},[25,21840,21841],{},[95,21842,18092],{}," — where subsystems, commands, and trigger bindings are actually declared.",[22,21845,21846,21851,21852,21855],{},[25,21847,21848],{},[95,21849,21850],{},"Constants"," — globally-accessible, ",[95,21853,21854],{},"public static final"," constants (motor ports, PID gains, speeds).",[22,21857,21858,486,21863,21868],{},[25,21859,21860],{},[95,21861,21862],{},"Subsystems\u002F",[25,21864,21865],{},[95,21866,21867],{},"Commands\u002F"," — one file per user-defined subsystem or command class.",[69,21870,21872],{"id":21871},"robot-deliberately-thin","Robot: Deliberately Thin",[15,21874,21875,21876,21878],{},"Because command-based is declarative, ",[95,21877,13472],{}," should contain almost nothing beyond a handful of required calls:",[104,21880,21882],{"className":106,"code":21881,"language":108,"meta":48,"style":48},"public Robot()\n{\n    robotContainer = new RobotContainer(); \u002F\u002F performs all the actual setup\n}\n\n@Override\npublic void robotPeriodic()\n{\n    CommandScheduler.getInstance().run(); \u002F\u002F THE single most important line in the whole project\n}\n\n@Override\npublic void autonomousInit()\n{\n    autonomousCommand = robotContainer.getAutonomousCommand();\n    if (autonomousCommand != null)\n    {\n        CommandScheduler.getInstance().schedule(autonomousCommand);\n    }\n}\n\n@Override\npublic void teleopInit()\n{\n    if (autonomousCommand != null)\n    {\n        autonomousCommand.cancel(); \u002F\u002F stop auto once teleop begins\n    }\n}\n",[95,21883,21884,21889,21893,21898,21902,21906,21910,21915,21919,21924,21928,21932,21936,21941,21945,21950,21955,21959,21964,21968,21972,21976,21980,21985,21989,21993,21997,22002,22006],{"__ignoreMap":48},[112,21885,21886],{"class":114,"line":115},[112,21887,21888],{},"public Robot()\n",[112,21890,21891],{"class":114,"line":49},[112,21892,123],{},[112,21894,21895],{"class":114,"line":126},[112,21896,21897],{},"    robotContainer = new RobotContainer(); \u002F\u002F performs all the actual setup\n",[112,21899,21900],{"class":114,"line":132},[112,21901,153],{},[112,21903,21904],{"class":114,"line":138},[112,21905,820],{"emptyLinePlaceholder":55},[112,21907,21908],{"class":114,"line":144},[112,21909,16021],{},[112,21911,21912],{"class":114,"line":150},[112,21913,21914],{},"public void robotPeriodic()\n",[112,21916,21917],{"class":114,"line":1819},[112,21918,123],{},[112,21920,21921],{"class":114,"line":1825},[112,21922,21923],{},"    CommandScheduler.getInstance().run(); \u002F\u002F THE single most important line in the whole project\n",[112,21925,21926],{"class":114,"line":1831},[112,21927,153],{},[112,21929,21930],{"class":114,"line":4742},[112,21931,820],{"emptyLinePlaceholder":55},[112,21933,21934],{"class":114,"line":4748},[112,21935,16021],{},[112,21937,21938],{"class":114,"line":6935},[112,21939,21940],{},"public void autonomousInit()\n",[112,21942,21943],{"class":114,"line":6940},[112,21944,123],{},[112,21946,21947],{"class":114,"line":6946},[112,21948,21949],{},"    autonomousCommand = robotContainer.getAutonomousCommand();\n",[112,21951,21952],{"class":114,"line":6952},[112,21953,21954],{},"    if (autonomousCommand != null)\n",[112,21956,21957],{"class":114,"line":6957},[112,21958,135],{},[112,21960,21961],{"class":114,"line":6963},[112,21962,21963],{},"        CommandScheduler.getInstance().schedule(autonomousCommand);\n",[112,21965,21966],{"class":114,"line":6968},[112,21967,147],{},[112,21969,21970],{"class":114,"line":11929},[112,21971,153],{},[112,21973,21974],{"class":114,"line":11935},[112,21975,820],{"emptyLinePlaceholder":55},[112,21977,21978],{"class":114,"line":18525},[112,21979,16021],{},[112,21981,21982],{"class":114,"line":18531},[112,21983,21984],{},"public void teleopInit()\n",[112,21986,21987],{"class":114,"line":18536},[112,21988,123],{},[112,21990,21991],{"class":114,"line":18542},[112,21992,21954],{},[112,21994,21995],{"class":114,"line":18547},[112,21996,135],{},[112,21998,21999],{"class":114,"line":18553},[112,22000,22001],{},"        autonomousCommand.cancel(); \u002F\u002F stop auto once teleop begins\n",[112,22003,22004],{"class":114,"line":18558},[112,22005,147],{},[112,22007,22008],{"class":114,"line":18563},[112,22009,153],{},[15,22011,22012,22013,22015,22016,79],{},"Piling large amounts of imperative logic directly into ",[95,22014,13472],{}," fights the entire declarative philosophy (Lesson 25.1) — real setup belongs in ",[95,22017,18092],{},[69,22019,22021],{"id":22020},"robotcontainer-where-setup-actually-happens","RobotContainer: Where Setup Actually Happens",[15,22023,22024,22025,22027,22028,22030],{},"Subsystems are declared as ",[95,22026,6806],{}," fields here — deliberately ",[262,22029,15225],{}," global variables:",[104,22032,22034],{"className":106,"code":22033,"language":108,"meta":48,"style":48},"private final Intake intake = new Intake();\n\nprivate void configureBindings()\n{\n    driverController.b().whileTrue(intake.runIntakeCommand());\n}\n\npublic Command getAutonomousCommand()\n{\n    return AutoRoutines.driveAndIntake(drivetrain, intake);\n}\n",[95,22035,22036,22041,22045,22050,22054,22059,22063,22067,22072,22076,22081],{"__ignoreMap":48},[112,22037,22038],{"class":114,"line":115},[112,22039,22040],{},"private final Intake intake = new Intake();\n",[112,22042,22043],{"class":114,"line":49},[112,22044,820],{"emptyLinePlaceholder":55},[112,22046,22047],{"class":114,"line":126},[112,22048,22049],{},"private void configureBindings()\n",[112,22051,22052],{"class":114,"line":132},[112,22053,123],{},[112,22055,22056],{"class":114,"line":138},[112,22057,22058],{},"    driverController.b().whileTrue(intake.runIntakeCommand());\n",[112,22060,22061],{"class":114,"line":144},[112,22062,153],{},[112,22064,22065],{"class":114,"line":150},[112,22066,820],{"emptyLinePlaceholder":55},[112,22068,22069],{"class":114,"line":1819},[112,22070,22071],{},"public Command getAutonomousCommand()\n",[112,22073,22074],{"class":114,"line":1825},[112,22075,123],{},[112,22077,22078],{"class":114,"line":1831},[112,22079,22080],{},"    return AutoRoutines.driveAndIntake(drivetrain, intake);\n",[112,22082,22083],{"class":114,"line":4742},[112,22084,153],{},[15,22086,22087,22088,22090,22091,22093],{},"Keeping subsystems ",[95,22089,6806],{}," and passing them explicitly to whatever needs them (",[25,22092,20520],{},", first introduced in Lesson 25.2) is deliberate: if subsystems were globally accessible, any code anywhere could call subsystem methods directly, completely bypassing the scheduler's resource-management guarantees — exactly the two-commands-fighting-over-one-motor problem command-based exists to prevent.",[69,22095,22097],{"id":22096},"constants-one-place-for-every-tunable-number","Constants: One Place for Every Tunable Number",[104,22099,22101],{"className":106,"code":22100,"language":108,"meta":48,"style":48},"public static final class IntakeConstants\n{\n    public static final int kMotorId = 5;\n    public static final double kIntakeSpeed = 0.8;\n}\n",[95,22102,22103,22108,22112,22117,22122],{"__ignoreMap":48},[112,22104,22105],{"class":114,"line":115},[112,22106,22107],{},"public static final class IntakeConstants\n",[112,22109,22110],{"class":114,"line":49},[112,22111,123],{},[112,22113,22114],{"class":114,"line":126},[112,22115,22116],{},"    public static final int kMotorId = 5;\n",[112,22118,22119],{"class":114,"line":132},[112,22120,22121],{},"    public static final double kIntakeSpeed = 0.8;\n",[112,22123,22124],{"class":114,"line":138},[112,22125,153],{},[15,22127,22128,22129,22131,22132,22134],{},"Every constant is ",[95,22130,21854],{}," — globally reachable, and impossible to accidentally reassign (Ch.23's ",[95,22133,7887],{},"). Grouping related constants into nested classes (one per subsystem, typically) keeps names shorter and organizes them logically.",[69,22136,22138],{"id":22137},"choosing-how-to-define-a-reusable-command","Choosing How to Define a Reusable Command",[15,22140,22141],{},"For a command that's used in more than one place (a button binding, an autonomous routine, a self-test), a few options exist, each suited to a different case:",[19,22143,22144,22157,22166],{},[22,22145,22146,22149,22150,22153,22154,79],{},[25,22147,22148],{},"Instance factory method on a single subsystem"," (like Ch.20's ",[95,22151,22152],{},"Subsystem.runOnce"," usage) — best for a command tied to exactly one subsystem: ",[95,22155,22156],{},"intake.runIntakeCommand()",[22,22158,22159,22162,22163,22165],{},[25,22160,22161],{},"Static factory method"," (Ch.21) — best when a command needs to coordinate ",[262,22164,13435],{}," subsystems at once, so it doesn't naturally belong to any single one of them.",[22,22167,22168,22174],{},[25,22169,22170,22171,22173],{},"A full ",[95,22172,20271],{}," subclass"," — best when a command needs its own genuine internal state (not subsystem state) or unusually complex logic.",[104,22176,22178],{"className":106,"code":22177,"language":108,"meta":48,"style":48},"public class Intake extends SubsystemBase\n{\n    public Command runIntakeCommand()\n    {\n        return this.startEnd(() -> this.set(1.0), () -> this.set(0.0)); \u002F\u002F implicitly requires `this`\n    }\n}\n",[95,22179,22180,22185,22189,22194,22198,22203,22207],{"__ignoreMap":48},[112,22181,22182],{"class":114,"line":115},[112,22183,22184],{},"public class Intake extends SubsystemBase\n",[112,22186,22187],{"class":114,"line":49},[112,22188,123],{},[112,22190,22191],{"class":114,"line":126},[112,22192,22193],{},"    public Command runIntakeCommand()\n",[112,22195,22196],{"class":114,"line":132},[112,22197,135],{},[112,22199,22200],{"class":114,"line":138},[112,22201,22202],{},"        return this.startEnd(() -> this.set(1.0), () -> this.set(0.0)); \u002F\u002F implicitly requires `this`\n",[112,22204,22205],{"class":114,"line":144},[112,22206,147],{},[112,22208,22209],{"class":114,"line":150},[112,22210,153],{},[104,22212,22214],{"className":106,"code":22213,"language":108,"meta":48,"style":48},"public class AutoRoutines\n{\n    public static Command driveAndIntake(Drivetrain drivetrain, Intake intake)\n    {\n        return Commands.sequence(\n            Commands.parallel(drivetrain.driveCommand(0.5, 0.5), intake.runIntakeCommand()).withTimeout(5.0),\n            Commands.parallel(drivetrain.stopCommand(), intake.stopCommand())\n        );\n    }\n}\n",[95,22215,22216,22221,22225,22230,22234,22239,22244,22249,22254,22258],{"__ignoreMap":48},[112,22217,22218],{"class":114,"line":115},[112,22219,22220],{},"public class AutoRoutines\n",[112,22222,22223],{"class":114,"line":49},[112,22224,123],{},[112,22226,22227],{"class":114,"line":126},[112,22228,22229],{},"    public static Command driveAndIntake(Drivetrain drivetrain, Intake intake)\n",[112,22231,22232],{"class":114,"line":132},[112,22233,135],{},[112,22235,22236],{"class":114,"line":138},[112,22237,22238],{},"        return Commands.sequence(\n",[112,22240,22241],{"class":114,"line":144},[112,22242,22243],{},"            Commands.parallel(drivetrain.driveCommand(0.5, 0.5), intake.runIntakeCommand()).withTimeout(5.0),\n",[112,22245,22246],{"class":114,"line":150},[112,22247,22248],{},"            Commands.parallel(drivetrain.stopCommand(), intake.stopCommand())\n",[112,22250,22251],{"class":114,"line":1819},[112,22252,22253],{},"        );\n",[112,22255,22256],{"class":114,"line":1825},[112,22257,147],{},[112,22259,22260],{"class":114,"line":1831},[112,22261,153],{},[69,22263,412],{"id":411},[19,22265,22266,22272,22281],{},[22,22267,22268,22271],{},[25,22269,22270],{},"Declaring subsystems as global\u002Fstatic fields for easy access."," This defeats the resource-management system's whole purpose — pass subsystems explicitly (dependency injection) instead.",[22,22273,22274,22280],{},[25,22275,22276,22277,79],{},"Forgetting to cancel the autonomous command in ",[95,22278,22279],{},"teleopInit()"," Without it, an unfinished autonomous command can keep running (and keep its subsystem requirements locked) into teleop.",[22,22282,22283,22289],{},[25,22284,22285,22286,22288],{},"Scattering constants across many files instead of one ",[95,22287,21850],{}," class."," Changing one tunable value (like an intake speed) should mean editing exactly one line, not hunting across the codebase.",[69,22291,450],{"id":449},[19,22293,22294,22313,22322,22330],{},[22,22295,22296,22297,22299,22300,22302,22303,22305,22306,1051,22309,22312],{},"A standard command-based project has ",[95,22298,14992],{}," (thin, mostly boilerplate), ",[95,22301,18092],{}," (real setup, subsystems, bindings), ",[95,22304,21850],{}," (all tunables), and ",[95,22307,22308],{},"Subsystems",[95,22310,22311],{},"Commands"," directories.",[22,22314,22315,22318,22319,22321],{},[95,22316,22317],{},"Robot.robotPeriodic()"," must call ",[95,22320,20822],{}," — nothing works without this line.",[22,22323,22324,22325,2902,22327,22329],{},"Subsystems stay ",[95,22326,6806],{},[95,22328,18092],{},"; other code reaches them only by dependency injection, never as globals — this is what preserves the scheduler's resource-management guarantees.",[22,22331,22332],{},"Choose how to define a reusable command based on its shape: instance factory (single subsystem), static factory (multiple subsystems), or a full class (real internal state or complex logic).",[15,22334,493,22335,497,22337,22340,22341,22344,22345,22348],{},[95,22336,12493],{},[95,22338,22339],{},"wpilib\u002Fcommand-based\u002F04-subsystems.md"," (WPILIB 20.4), ",[95,22342,22343],{},"06-structuring-command-based-project.md"," (WPILIB 20.6), ",[95,22346,22347],{},"07-organizing-command-based.md"," (WPILIB 20.7)",[503,22350,505],{},{"title":48,"searchDepth":49,"depth":49,"links":22352},[22353,22354,22355,22356,22357,22358,22359],{"id":21823,"depth":49,"text":21824},{"id":21871,"depth":49,"text":21872},{"id":22020,"depth":49,"text":22021},{"id":22096,"depth":49,"text":22097},{"id":22137,"depth":49,"text":22138},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":22361,"status":11220},"25.7 — Structuring a Command-Based Robot Project (WPILIB 20.4,6-7)","\u002Fshockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F7-structuring-a-command-based-robot-project",{"title":21815,"description":48},"shockwave-curriculum\u002Flessons\u002Fch25-command-based-programming\u002F25.7-structuring-a-command-based-robot-project","rVx47S6jo1oQlLsZQy9dz10ebEMhafoTL7gTinRZcqw",{"id":22367,"title":22368,"body":22369,"description":22376,"extension":51,"meta":22571,"navigation":55,"path":22573,"seo":22574,"stem":22575,"__hash__":22576},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch26-architecture-takeaways\u002F26-architecture-takeaways.md","Architecture Takeaways",{"type":8,"value":22370,"toc":22563},[22371,22374,22377,22381,22387,22436,22440,22449,22453,22456,22465,22480,22486,22492,22505,22509,22512,22514,22538,22540,22554,22561],[11,22372,22368],{"id":22373},"architecture-takeaways",[15,22375,22376],{},"Java II opened (Ch.14) with why patterns matter at all. This closing chapter names the general software-engineering principles that everything since — inheritance, interfaces, the IO-Layer Pattern, factories, builders, command-based itself — has actually been demonstrating in FRC-specific form. These aren't FRC-specific or Java-specific ideas; they're widely known across the software industry, which is exactly why they're worth naming explicitly.",[69,22378,22380],{"id":22379},"dry-dont-repeat-yourself","DRY: Don't Repeat Yourself",[15,22382,22383,22384,22386],{},"If the same logic (or the same literal value) appears in more than one place, a future change has to remember to update every copy — and it's easy to miss one. The fix is almost always one of the tools this curriculum already covered: pull shared behavior into a common superclass (Ch.17), a shared utility method, or a single ",[95,22385,21850],{}," class (Ch.25.7) instead of copy-pasting a magic number into five different files.",[104,22388,22390],{"className":106,"code":22389,"language":108,"meta":48,"style":48},"\u002F\u002F NOT DRY — the same speed value is hardcoded in three places\nintakeMotor.set(0.8);\nindexerMotor.set(0.8);\nfeederMotor.set(0.8);\n\n\u002F\u002F DRY — one named constant, one place to change it\nintakeMotor.set(IntakeConstants.kRollerSpeed);\nindexerMotor.set(IntakeConstants.kRollerSpeed);\nfeederMotor.set(IntakeConstants.kRollerSpeed);\n",[95,22391,22392,22397,22402,22407,22412,22416,22421,22426,22431],{"__ignoreMap":48},[112,22393,22394],{"class":114,"line":115},[112,22395,22396],{},"\u002F\u002F NOT DRY — the same speed value is hardcoded in three places\n",[112,22398,22399],{"class":114,"line":49},[112,22400,22401],{},"intakeMotor.set(0.8);\n",[112,22403,22404],{"class":114,"line":126},[112,22405,22406],{},"indexerMotor.set(0.8);\n",[112,22408,22409],{"class":114,"line":132},[112,22410,22411],{},"feederMotor.set(0.8);\n",[112,22413,22414],{"class":114,"line":138},[112,22415,820],{"emptyLinePlaceholder":55},[112,22417,22418],{"class":114,"line":144},[112,22419,22420],{},"\u002F\u002F DRY — one named constant, one place to change it\n",[112,22422,22423],{"class":114,"line":150},[112,22424,22425],{},"intakeMotor.set(IntakeConstants.kRollerSpeed);\n",[112,22427,22428],{"class":114,"line":1819},[112,22429,22430],{},"indexerMotor.set(IntakeConstants.kRollerSpeed);\n",[112,22432,22433],{"class":114,"line":1825},[112,22434,22435],{},"feederMotor.set(IntakeConstants.kRollerSpeed);\n",[69,22437,22439],{"id":22438},"yagni-you-aint-gonna-need-it","YAGNI: You Ain't Gonna Need It",[15,22441,22442,22443,22445,22446,22448],{},"Don't build flexibility or abstraction for a requirement that doesn't exist yet — every layer of abstraction (a ",[95,22444,18794],{},", Ch.22; a generic type, Ch.16; an extra interface) has a real cost in complexity, and that cost is only worth paying once the actual need shows up. A ",[95,22447,18794],{}," for a 2-parameter class, or a factory (Ch.21) that only ever returns one concrete implementation, is YAGNI in practice: solving a problem the code doesn't actually have yet, at the expense of a codebase that's harder to read today for a payoff that may never arrive.",[69,22450,22452],{"id":22451},"solid-five-principles-one-letter-each","SOLID: Five Principles, One Letter Each",[15,22454,22455],{},"SOLID isn't a single idea — it's an acronym for five distinct principles, each addressing a different way a class or module's design can go wrong. All five show up somewhere in this curriculum already, even though they weren't named until now:",[15,22457,22458,22461,22462,22464],{},[25,22459,22460],{},"S — Single Responsibility."," A class should have one, and only one, reason to change. A ",[95,22463,7343],{}," (Ch.20\u002F25) that only manages one piece of hardware is a direct application of this — its only job is that hardware, not also handling button bindings or autonomous logic.",[15,22466,22467,22470,22471,22473,22474,22476,22477,22479],{},[25,22468,22469],{},"O — Open\u002FClosed."," A module should be open for extension, but closed for modification — you should be able to add new behavior without editing code that already works. The IO-Layer Pattern (Ch.20) is a textbook example: adding a brand-new ",[95,22472,18230],{}," implementation never requires touching ",[95,22475,6739],{},"'s own logic, since both implementations honor the same ",[95,22478,17384],{}," contract.",[15,22481,22482,22485],{},[25,22483,22484],{},"L — Liskov Substitution."," A subclass should be usable anywhere its superclass is expected, without breaking anything. This is exactly the is-a substitution test from Ch.17.1 — if substituting a subclass object somewhere a superclass is expected changes the correctness of the code, the inheritance relationship was wrong to begin with.",[15,22487,22488,22491],{},[25,22489,22490],{},"I — Interface Segregation."," Don't force a class to implement methods it doesn't actually need, just because they're bundled into one large interface. Several small, focused interfaces (each describing one real capability) are preferable to one bloated interface everything is forced to implement in full.",[15,22493,22494,22497,22498,22500,22501,22504],{},[25,22495,22496],{},"D — Dependency Inversion."," Code should depend on abstractions (interfaces), not concrete implementations. Every constructor that accepts an ",[95,22499,17384],{}," instead of hardcoding ",[95,22502,22503],{},"new IntakeIOSparkMax()"," directly (Ch.20\u002F21), and every static factory returning an interface type rather than a specific class (Ch.21), is dependency inversion in action.",[69,22506,22508],{"id":22507},"why-name-these-at-all","Why Name These at All",[15,22510,22511],{},"None of DRY, YAGNI, or SOLID are FRC-specific or even Java-specific — they're widely-used vocabulary across the whole software industry, which is exactly the \"common language\" benefit Ch.14 opened with. Being able to say \"this violates single responsibility\" or \"that's YAGNI\" communicates a specific, well-understood critique in a few words, to any programmer familiar with these terms — not just people who've read this particular curriculum.",[69,22513,412],{"id":411},[19,22515,22516,22522,22532],{},[22,22517,22518,22521],{},[25,22519,22520],{},"Applying DRY so aggressively that unrelated code gets forced together."," Two pieces of code that happen to look similar today, but for unrelated reasons, don't necessarily belong in one shared abstraction — premature DRY-ing can create awkward, tangled dependencies between things that should stay separate.",[22,22523,22524,22527,22528,22531],{},[25,22525,22526],{},"Treating YAGNI as an excuse to never plan ahead."," YAGNI argues against building unneeded flexibility ",[262,22529,22530],{},"now"," — it doesn't mean ignoring architecture altogether; the IO-Layer Pattern (Ch.20) is worth its overhead in FRC precisely because simulation and hardware-swapping are real, common needs, not speculative ones.",[22,22533,22534,22537],{},[25,22535,22536],{},"Only remembering the \"S\" of SOLID."," The deck's own shorthand (\"one class, one responsibility\") is genuinely just Single Responsibility — SOLID names four more distinct principles beyond that one.",[69,22539,450],{"id":449},[19,22541,22542,22545,22548,22551],{},[22,22543,22544],{},"DRY: don't duplicate logic or values — a single source of truth (a constant, a shared method, a superclass) means one place to fix or change something.",[22,22546,22547],{},"YAGNI: don't build abstraction or flexibility for a need that doesn't exist yet — every layer of indirection has a real cost, worth paying only once it's actually needed.",[22,22549,22550],{},"SOLID is five separate principles — Single Responsibility, Open\u002FClosed, Liskov Substitution, Interface Segregation, Dependency Inversion — each already demonstrated somewhere in this curriculum's FRC examples.",[22,22552,22553],{},"These principles are industry-standard vocabulary, not FRC- or Java-specific — naming them precisely is itself a form of the \"common language\" benefit patterns provide (Ch.14).",[15,22555,493,22556,497,22558,22560],{},[95,22557,13396],{},[95,22559,13535],{},", slide 13 (\"Architecture Takeaways\") — original deck content, expanded here since SOLID is a real five-principle acronym the original slide only partially named",[503,22562,505],{},{"title":48,"searchDepth":49,"depth":49,"links":22564},[22565,22566,22567,22568,22569,22570],{"id":22379,"depth":49,"text":22380},{"id":22438,"depth":49,"text":22439},{"id":22451,"depth":49,"text":22452},{"id":22507,"depth":49,"text":22508},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":22572,"status":519},"26 — Architecture Takeaways (DRY\u002FYAGNI\u002FSOLID) (no citation — deck-original content; neither WPILib nor T5817 teach these as named general principles)","\u002Fshockwave-curriculum\u002Flessons\u002Fch26-architecture-takeaways\u002F26-architecture-takeaways",{"title":22368,"description":22376},"shockwave-curriculum\u002Flessons\u002Fch26-architecture-takeaways\u002F26-architecture-takeaways","LM6-daDeRWAwQmJIUrW2wNpZ18pCMZ53hlcBAGcKe2A",{"id":22578,"title":22579,"body":22580,"description":22793,"extension":51,"meta":22794,"navigation":55,"path":22796,"seo":22797,"stem":22798,"__hash__":22799},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.1-abstraction-and-program-design.md","Abstraction and Program Design",{"type":8,"value":22581,"toc":22784},[22582,22585,22591,22595,22617,22621,22633,22637,22663,22667,22682,22702,22709,22713,22731,22733,22760,22762,22776],[11,22583,22579],{"id":22584},"abstraction-and-program-design",[15,22586,22587,22590],{},[25,22588,22589],{},"⚠ Optional chapter."," This chapter sits conceptually between Java I and Java II — it's the general, from-scratch program-design thinking that applies to any object-oriented code, not just FRC robot code. It's informational, not a required gateway, since real FRC teams build on top of WPILib's already-imposed architecture (command-based, Ch.25) regardless.",[69,22592,22594],{"id":22593},"designing-before-writing-object-oriented-design","Designing Before Writing: Object-Oriented Design",[15,22596,22597,22598,22600,22601,22604,22605,275,22608,278,22610,22613,22614,22616],{},"Before writing a single class, it helps to first decide ",[262,22599,18423],{}," classes a program actually needs, and what data\u002Fbehavior each one owns. A reliable trick: read the problem description and look for the ",[25,22602,22603],{},"nouns"," — they're usually your classes. Given \"the robot has a drivetrain, an intake that picks up game pieces, and a shooter that scores them,\" the nouns ",[95,22606,22607],{},"drivetrain",[95,22609,17836],{},[95,22611,22612],{},"shooter"," are exactly the ",[95,22615,7343],{}," subclasses (Ch.17\u002F20) a real codebase would end up with.",[69,22618,22620],{"id":22619},"uml-class-diagrams","UML Class Diagrams",[15,22622,355,22623,22626,22627,22629,22630,22632],{},[25,22624,22625],{},"UML class diagram"," is a simple box-based sketch of a class — its attributes (instance variables) and methods, with ",[95,22628,1057],{}," marking private members and ",[95,22631,848],{}," marking public ones. These diagrams don't need to be formal; a whiteboard sketch before writing code is often enough to catch a design problem before it's baked into actual Java.",[69,22634,22636],{"id":22635},"data-abstraction-naming-data-without-its-details","Data Abstraction: Naming Data Without Its Details",[15,22638,22639,22642,22643,22645,22646,22649,22650,22652,22653,22655,22656,22659,22660,22662],{},[25,22640,22641],{},"Data abstraction"," separates a data type's abstract properties from the concrete details of how it's represented — you can use an ",[95,22644,6739],{}," object without knowing exactly how its internal state is stored. Ch.7 already introduced the specific vocabulary this curriculum uses for this: ",[25,22647,22648],{},"instance variables"," (unique per object — each ",[95,22651,6739],{},"'s own ",[95,22654,16095],{}," flag) and ",[25,22657,22658],{},"class\u002Fstatic variables"," (shared across every instance — a running count of how many ",[95,22661,6739],{}," objects exist).",[69,22664,22666],{"id":22665},"procedural-abstraction-naming-a-process-without-its-details","Procedural Abstraction: Naming a Process Without Its Details",[15,22668,22669,22672,22673,22675,22676,3498,22678,22681],{},[25,22670,22671],{},"Procedural abstraction"," gives a process a name, letting it be used by knowing ",[262,22674,3185],{}," it does without needing to know ",[262,22677,17225],{},[95,22679,22680],{},"intake.retract()"," doesn't require knowing exactly how the retraction is implemented underneath. This is exactly the value of a well-named method (Ch.4\u002F7): three real benefits fall out of it:",[19,22683,22684,22690,22696],{},[22,22685,22686,22689],{},[25,22687,22688],{},"Organization"," — breaking a large behavior into smaller, named methods keeps any one piece of code manageable.",[22,22691,22692,22695],{},[25,22693,22694],{},"Reuse"," — a method written once can be called from many places, instead of duplicating the same logic (Ch.26's DRY, in disguise).",[22,22697,22698,22701],{},[25,22699,22700],{},"Maintainability"," — smaller, well-named methods are far easier to read, debug, and reason about than one sprawling method doing everything.",[15,22703,22704,22705,22708],{},"Procedural abstraction also means a method's ",[262,22706,22707],{},"internal"," implementation can change freely — made faster, refactored, rewritten — without breaking any code that calls it, as long as the method's signature and its observable behavior stay the same. Adding parameters extends this even further, letting one method generalize across a whole range of inputs instead of needing a separate near-duplicate method for each specific case.",[69,22710,22712],{"id":22711},"applying-this-to-an-frc-robot","Applying This to an FRC Robot",[15,22714,22715,22716,22718,22719,275,22721,275,22723,275,22725,22727,22728,22730],{},"Before writing ",[95,22717,13472],{},", sketching out \"what are the nouns\" for an actual robot — ",[95,22720,319],{},[95,22722,6739],{},[95,22724,15029],{},[95,22726,14970],{}," — and roughly what data\u002Fbehavior each needs, is exactly the kind of upfront design this lesson describes. It's the same thinking that led to the ",[95,22729,7343],{}," abstraction in Ch.17 and Ch.20 in the first place — those weren't arbitrary class boundaries, they came from identifying the real, distinct \"nouns\" in a robot's actual hardware.",[69,22732,412],{"id":411},[19,22734,22735,22741,22750],{},[22,22736,22737,22740],{},[25,22738,22739],{},"Skipping design entirely and writing code directly."," Even a rough five-minute sketch of \"what classes do I need, what does each own\" catches structural mistakes far more cheaply than discovering them after a class already has fifteen unrelated responsibilities.",[22,22742,22743,22746,22747,22749],{},[25,22744,22745],{},"Confusing data abstraction with encapsulation."," They're related but distinct: data abstraction is about naming data without exposing its representation; encapsulation (Ch.7\u002F23) is the specific mechanism (",[95,22748,6806],{}," fields, public accessors) that enforces it.",[22,22751,22752,22755,22756,22759],{},[25,22753,22754],{},"Assuming procedural abstraction only matters for long methods."," Even a short method benefits — naming a two-line calculation ",[95,22757,22758],{},"calculateShooterRPM(distance)"," documents intent in a way the raw calculation alone never does.",[69,22761,450],{"id":449},[19,22763,22764,22767,22770,22773],{},[22,22765,22766],{},"Object-oriented design starts by identifying the nouns in a problem description — they're usually the classes a program needs.",[22,22768,22769],{},"A UML class diagram is a simple, informal way to sketch a class's attributes and methods before writing real code.",[22,22771,22772],{},"Data abstraction separates what data represents from how it's stored; procedural abstraction separates what a method does from how it's implemented.",[22,22774,22775],{},"Procedural abstraction's real payoff: organization, code reuse, and the freedom to change a method's internals without breaking its callers.",[15,22777,493,22778,497,22780,22783],{},[95,22779,496],{},[95,22781,22782],{},"unit-3-class-creation\u002F3.01-abstraction-and-program-design.md"," (CSA 3.1)",{"title":48,"searchDepth":49,"depth":49,"links":22785},[22786,22787,22788,22789,22790,22791,22792],{"id":22593,"depth":49,"text":22594},{"id":22619,"depth":49,"text":22620},{"id":22635,"depth":49,"text":22636},{"id":22665,"depth":49,"text":22666},{"id":22711,"depth":49,"text":22712},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"⚠ Optional chapter. This chapter sits conceptually between Java I and Java II — it's the general, from-scratch program-design thinking that applies to any object-oriented code, not just FRC robot code. It's informational, not a required gateway, since real FRC teams build on top of WPILib's already-imposed architecture (command-based, Ch.25) regardless.",{"outlineRef":22795,"status":11220},"27.1 — Abstraction and Program Design (CSA 3.1)","\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F1-abstraction-and-program-design",{"title":22579,"description":22793},"shockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.1-abstraction-and-program-design","ox12SDWm2_Ia-BvLo1-iST9O8al0eyt42dsTK9dQyMY",{"id":22801,"title":22802,"body":22803,"description":22906,"extension":51,"meta":22907,"navigation":55,"path":22909,"seo":22910,"stem":22911,"__hash__":22912},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.2-impact-of-program-design.md","Impact of Program Design",{"type":8,"value":22804,"toc":22898},[22805,22808,22813,22817,22823,22827,22830,22834,22845,22849,22852,22854,22874,22876,22890],[11,22806,22802],{"id":22807},"impact-of-program-design",[15,22809,22810,22812],{},[25,22811,22589],{}," Like 27.1, this is general software-engineering context rather than FRC-specific mechanics.",[69,22814,22816],{"id":22815},"system-reliability","System Reliability",[15,22818,22819,22822],{},[25,22820,22821],{},"System reliability"," means a program performs its intended task correctly, under stated conditions, without failure. On a competition robot, reliability isn't abstract — code that only works \"most of the time\" is code that costs matches. Testing under a real range of conditions (a dead battery, a jammed mechanism, a sensor that's disconnected) is what catches failures before they happen on the field rather than during a match.",[69,22824,22826],{"id":22825},"code-has-real-consequences","Code Has Real Consequences",[15,22828,22829],{},"Software increasingly has direct impacts on people, not just abstract \"users\" — and the effects of a program can be beneficial, harmful, or both, sometimes in ways its authors never intended. An FRC robot is a literal example of code controlling a real physical machine: a bug in motor-output code isn't just a wrong number on a screen, it's a real mechanism moving in an unexpected or unsafe way. This is exactly why WPILib's safety defaults exist (motors disabled unless explicitly commanded, a watchdog that stops the robot if code stops responding) — real design decisions made because the code's failures have real physical consequences.",[69,22831,22833],{"id":22832},"legal-and-licensing-considerations","Legal and Licensing Considerations",[15,22835,22836,22837,22840,22841,22844],{},"Reusing other people's code is extremely common — this entire curriculum's provenance system (every lesson's \"Derived from\" line) exists because ",[262,22838,22839],{},"properly attributing what you build on"," matters, whether that's an open-source library, WPILib itself, or another team's published code. ",[25,22842,22843],{},"Open source"," code is free to use (often under specific license terms worth actually reading); code that isn't published as open source generally requires explicit permission — sometimes payment — before it can be legally incorporated into another program. This matters directly in FRC: vendor libraries (motor controller SDKs, sensor libraries) each carry their own license terms, and most FRC teams' own robot code is itself published openly for other teams to learn from — the culture this very curriculum is a part of (this whole project builds on Mechanical Advantage's own published lesson deck).",[69,22846,22848],{"id":22847},"ethical-questions-in-ai-and-automation","Ethical Questions in AI and Automation",[15,22850,22851],{},"As software takes on more autonomous decision-making — self-driving cars being the most commonly cited example — genuinely hard ethical questions arise: who's responsible when an autonomous system has to make a split-second decision with real consequences? These aren't questions with a clean technical answer, but they're worth being aware of as automation (including AI-assisted coding itself) becomes a bigger part of how software gets built.",[69,22853,412],{"id":411},[19,22855,22856,22862,22868],{},[22,22857,22858,22861],{},[25,22859,22860],{},"Treating \"it compiled\" as equivalent to \"it's reliable.\""," Compiling successfully only means the code is syntactically valid — reliability requires actually testing behavior under realistic (and edge-case) conditions.",[22,22863,22864,22867],{},[25,22865,22866],{},"Reusing code without checking its license or attribution requirements."," Even code that's technically easy to copy-paste may carry real legal obligations about attribution or reuse terms.",[22,22869,22870,22873],{},[25,22871,22872],{},"Assuming design choices are ethically neutral."," A default behavior, a permission granted too broadly, or an untested edge case can carry real consequences for whoever the software ultimately affects.",[69,22875,450],{"id":449},[19,22877,22878,22881,22884,22887],{},[22,22879,22880],{},"System reliability means performing correctly under real, tested conditions — not just \"it worked once.\"",[22,22882,22883],{},"Software's real-world impact can be beneficial or harmful, often in ways beyond its original intended use — this is especially concrete for FRC, where code directly controls physical hardware.",[22,22885,22886],{},"Reusing code carries real legal\u002Flicensing obligations — open-source code is free to use (under its license terms), other code generally requires explicit permission.",[22,22888,22889],{},"Increasingly autonomous software (AI included) raises genuine ethical questions worth being aware of, even without a clean technical answer.",[15,22891,493,22892,497,22894,22897],{},[95,22893,496],{},[95,22895,22896],{},"unit-3-class-creation\u002F3.02-impact-of-program-design.md"," (CSA 3.2)",{"title":48,"searchDepth":49,"depth":49,"links":22899},[22900,22901,22902,22903,22904,22905],{"id":22815,"depth":49,"text":22816},{"id":22825,"depth":49,"text":22826},{"id":22832,"depth":49,"text":22833},{"id":22847,"depth":49,"text":22848},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"⚠ Optional chapter. Like 27.1, this is general software-engineering context rather than FRC-specific mechanics.",{"outlineRef":22908,"status":11220},"27.2 — Impact of Program Design (CSA 3.2)","\u002Fshockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F2-impact-of-program-design",{"title":22802,"description":22906},"shockwave-curriculum\u002Flessons\u002Fch27-program-design-and-abstraction\u002F27.2-impact-of-program-design","ee-qL7XZ9ulM9X4cBjWwiGgxEVGhvfY7ZCYlxdBa5oY",{"id":22914,"title":22915,"body":22916,"description":23398,"extension":51,"meta":23399,"navigation":55,"path":23401,"seo":23402,"stem":23403,"__hash__":23404},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.1-searching-algorithms.md","Searching Algorithms",{"type":8,"value":22917,"toc":23390},[22918,22921,22926,22930,22936,22990,23001,23004,23008,23011,23076,23080,23097,23201,23225,23229,23247,23302,23309,23311,23345,23347,23380,23388],[11,22919,22915],{"id":22920},"searching-algorithms",[15,22922,22923,22925],{},[25,22924,22589],{}," This chapter deepens the array\u002F2D-array work from Ch.9\u002FCh.10 with two classic algorithms — informational, not required for FRC programming itself.",[69,22927,22929],{"id":22928},"linear-sequential-search","Linear (Sequential) Search",[15,22931,22932,22935],{},[25,22933,22934],{},"Linear search"," checks each element in order until it finds the target or runs out of elements — the same \"check every element\" shape from Ch.9.5, applied specifically to finding a value:",[104,22937,22939],{"className":106,"code":22938,"language":108,"meta":48,"style":48},"public static int sequentialSearch(int[] canBusIds, int target)\n{\n    for (int j = 0; j \u003C canBusIds.length; j++)\n    {\n        if (canBusIds[j] == target)\n        {\n            return j;\n        }\n    }\n    return -1; \u002F\u002F not found\n}\n",[95,22940,22941,22946,22950,22955,22959,22964,22968,22973,22977,22981,22986],{"__ignoreMap":48},[112,22942,22943],{"class":114,"line":115},[112,22944,22945],{},"public static int sequentialSearch(int[] canBusIds, int target)\n",[112,22947,22948],{"class":114,"line":49},[112,22949,123],{},[112,22951,22952],{"class":114,"line":126},[112,22953,22954],{},"    for (int j = 0; j \u003C canBusIds.length; j++)\n",[112,22956,22957],{"class":114,"line":132},[112,22958,135],{},[112,22960,22961],{"class":114,"line":138},[112,22962,22963],{},"        if (canBusIds[j] == target)\n",[112,22965,22966],{"class":114,"line":144},[112,22967,7860],{},[112,22969,22970],{"class":114,"line":150},[112,22971,22972],{},"            return j;\n",[112,22974,22975],{"class":114,"line":1819},[112,22976,7870],{},[112,22978,22979],{"class":114,"line":1825},[112,22980,147],{},[112,22982,22983],{"class":114,"line":1831},[112,22984,22985],{},"    return -1; \u002F\u002F not found\n",[112,22987,22988],{"class":114,"line":4742},[112,22989,153],{},[15,22991,22992,22993,22995,22996,3972,22998,23000],{},"Searching for a ",[95,22994,315],{}," (like an autonomous route name) needs ",[95,22997,5424],{},[95,22999,1568],{}," (Lesson 6.1\u002F13) — comparing object content, not identity.",[15,23002,23003],{},"Linear search's slowest case is a target that isn't present at all — the loop has to check every single element before concluding that. Its fastest case is the target sitting at index 0.",[69,23005,23007],{"id":23006},"linear-search-over-a-2d-array","Linear Search Over a 2D Array",[15,23009,23010],{},"Extending linear search to a 2D array (Ch.10) just means looping through every row and searching within it — the same nested-loop shape from Ch.10.3:",[104,23012,23014],{"className":106,"code":23013,"language":108,"meta":48,"style":48},"public static boolean containsFault(double[][] moduleCurrents, double faultValue)\n{\n    for (int row = 0; row \u003C moduleCurrents.length; row++)\n    {\n        for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n        {\n            if (moduleCurrents[row][col] == faultValue)\n            {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n",[95,23015,23016,23021,23025,23029,23033,23038,23042,23047,23051,23056,23060,23064,23068,23072],{"__ignoreMap":48},[112,23017,23018],{"class":114,"line":115},[112,23019,23020],{},"public static boolean containsFault(double[][] moduleCurrents, double faultValue)\n",[112,23022,23023],{"class":114,"line":49},[112,23024,123],{},[112,23026,23027],{"class":114,"line":126},[112,23028,11347],{},[112,23030,23031],{"class":114,"line":132},[112,23032,135],{},[112,23034,23035],{"class":114,"line":138},[112,23036,23037],{},"        for (int col = 0; col \u003C moduleCurrents[0].length; col++)\n",[112,23039,23040],{"class":114,"line":144},[112,23041,7860],{},[112,23043,23044],{"class":114,"line":150},[112,23045,23046],{},"            if (moduleCurrents[row][col] == faultValue)\n",[112,23048,23049],{"class":114,"line":1819},[112,23050,11704],{},[112,23052,23053],{"class":114,"line":1825},[112,23054,23055],{},"                return true;\n",[112,23057,23058],{"class":114,"line":1831},[112,23059,11714],{},[112,23061,23062],{"class":114,"line":4742},[112,23063,7870],{},[112,23065,23066],{"class":114,"line":4748},[112,23067,147],{},[112,23069,23070],{"class":114,"line":6935},[112,23071,11932],{},[112,23073,23074],{"class":114,"line":6940},[112,23075,153],{},[69,23077,23079],{"id":23078},"binary-search-only-works-on-sorted-data","Binary Search: Only Works on Sorted Data",[15,23081,23082,23085,23086,23089,23090,1051,23093,23096],{},[25,23083,23084],{},"Binary search"," is dramatically faster than linear search, but only works on data that's already ",[25,23087,23088],{},"sorted"," — like looking up a name in a phone book by jumping to roughly the right spot, instead of checking every page from the start. It keeps ",[95,23091,23092],{},"left",[95,23094,23095],{},"right"," bounds, checks the middle element, and eliminates half the remaining range every time:",[104,23098,23100],{"className":106,"code":23099,"language":108,"meta":48,"style":48},"public static int binarySearch(int[] sortedTemps, int target)\n{\n    int left = 0;\n    int right = sortedTemps.length - 1;\n    while (left \u003C= right)\n    {\n        int middle = (left + right) \u002F 2;\n        if (target \u003C sortedTemps[middle])\n        {\n            right = middle - 1; \u002F\u002F target must be in the left half\n        }\n        else if (target > sortedTemps[middle])\n        {\n            left = middle + 1;  \u002F\u002F target must be in the right half\n        }\n        else\n        {\n            return middle;      \u002F\u002F found it\n        }\n    }\n    return -1; \u002F\u002F left > right means the range is exhausted — not found\n}\n",[95,23101,23102,23107,23111,23116,23121,23126,23130,23135,23140,23144,23149,23153,23158,23162,23167,23171,23175,23179,23184,23188,23192,23197],{"__ignoreMap":48},[112,23103,23104],{"class":114,"line":115},[112,23105,23106],{},"public static int binarySearch(int[] sortedTemps, int target)\n",[112,23108,23109],{"class":114,"line":49},[112,23110,123],{},[112,23112,23113],{"class":114,"line":126},[112,23114,23115],{},"    int left = 0;\n",[112,23117,23118],{"class":114,"line":132},[112,23119,23120],{},"    int right = sortedTemps.length - 1;\n",[112,23122,23123],{"class":114,"line":138},[112,23124,23125],{},"    while (left \u003C= right)\n",[112,23127,23128],{"class":114,"line":144},[112,23129,135],{},[112,23131,23132],{"class":114,"line":150},[112,23133,23134],{},"        int middle = (left + right) \u002F 2;\n",[112,23136,23137],{"class":114,"line":1819},[112,23138,23139],{},"        if (target \u003C sortedTemps[middle])\n",[112,23141,23142],{"class":114,"line":1825},[112,23143,7860],{},[112,23145,23146],{"class":114,"line":1831},[112,23147,23148],{},"            right = middle - 1; \u002F\u002F target must be in the left half\n",[112,23150,23151],{"class":114,"line":4742},[112,23152,7870],{},[112,23154,23155],{"class":114,"line":4748},[112,23156,23157],{},"        else if (target > sortedTemps[middle])\n",[112,23159,23160],{"class":114,"line":6935},[112,23161,7860],{},[112,23163,23164],{"class":114,"line":6940},[112,23165,23166],{},"            left = middle + 1;  \u002F\u002F target must be in the right half\n",[112,23168,23169],{"class":114,"line":6946},[112,23170,7870],{},[112,23172,23173],{"class":114,"line":6952},[112,23174,18539],{},[112,23176,23177],{"class":114,"line":6957},[112,23178,7860],{},[112,23180,23181],{"class":114,"line":6963},[112,23182,23183],{},"            return middle;      \u002F\u002F found it\n",[112,23185,23186],{"class":114,"line":6968},[112,23187,7870],{},[112,23189,23190],{"class":114,"line":11929},[112,23191,147],{},[112,23193,23194],{"class":114,"line":11935},[112,23195,23196],{},"    return -1; \u002F\u002F left > right means the range is exhausted — not found\n",[112,23198,23199],{"class":114,"line":18525},[112,23200,153],{},[15,23202,23203,23204,275,23206,23209,23210,1051,23212,23214,23215,23218,23219,23222,23223,79],{},"For a ",[95,23205,10713],{},[95,23207,23208],{},"compareTo"," replaces ",[95,23211,3945],{},[95,23213,5507],{}," (which only work on primitives): ",[95,23216,23217],{},"str.compareTo(other)"," returns negative, zero, or positive depending on whether ",[95,23220,23221],{},"str"," sorts before, equal to, or after ",[95,23224,16168],{},[69,23226,23228],{"id":23227},"why-binary-search-is-so-much-faster","Why Binary Search Is So Much Faster",[15,23230,23231,23232,23235,23236,23238,23239,23242,23243,23246],{},"Linear search's worst case takes ",[95,23233,23234],{},"n"," comparisons for ",[95,23237,23234],{}," elements. Binary search's worst case only takes roughly ",[95,23240,23241],{},"log₂(n)"," — each comparison eliminates ",[262,23244,23245],{},"half"," the remaining data, not just one element:",[8805,23248,23249,23262],{},[8808,23250,23251],{},[8811,23252,23253,23256,23259],{},[8814,23254,23255],{},"Elements (n)",[8814,23257,23258],{},"Linear Search",[8814,23260,23261],{},"Binary Search",[8823,23263,23264,23273,23282,23292],{},[8811,23265,23266,23269,23271],{},[8828,23267,23268],{},"8",[8828,23270,23268],{},[8828,23272,1478],{},[8811,23274,23275,23278,23280],{},[8828,23276,23277],{},"16",[8828,23279,23277],{},[8828,23281,556],{},[8811,23283,23284,23287,23289],{},[8828,23285,23286],{},"100",[8828,23288,23286],{},[8828,23290,23291],{},"7",[8811,23293,23294,23297,23299],{},[8828,23295,23296],{},"500",[8828,23298,23296],{},[8828,23300,23301],{},"~9",[15,23303,23304,23305,23308],{},"Doubling the data size costs linear search twice the work, but only costs binary search ",[262,23306,23307],{},"one more comparison",". This growth-rate distinction — O(n) vs. O(log n) in formal terms — is why sorted, frequently-searched data (a large lookup table, a big sorted config file) is worth keeping sorted specifically so binary search stays available.",[69,23310,412],{"id":411},[19,23312,23313,23319,23331],{},[22,23314,23315,23318],{},[25,23316,23317],{},"Running binary search on unsorted data."," It will return wrong or missing results — binary search's entire correctness depends on the data already being sorted.",[22,23320,23321,23324,23325,23327,23328,23330],{},[25,23322,23323],{},"Assuming binary search requires integers."," It works on anything with a well-defined ordering — ",[95,23326,315],{},"s via ",[95,23329,23208],{},", for instance.",[22,23332,23333,23336,23337,23340,23341,23344],{},[25,23334,23335],{},"Forgetting the loop-ending condition."," Binary search's ",[95,23338,23339],{},"while (left \u003C= right)"," stops the moment the range is exhausted (",[95,23342,23343],{},"left > right",") — a search for something not present must still terminate, not loop forever.",[69,23346,450],{"id":449},[19,23348,23349,23355,23361,23377],{},[22,23350,23351,23352,23354],{},"Linear search checks every element in order; its worst case (not found) requires checking all ",[95,23353,23234],{}," elements.",[22,23356,23357,23358,23360],{},"Binary search only works on sorted data, but eliminates half the remaining range with each comparison — roughly ",[95,23359,23241],{}," comparisons worst case, vastly faster for large data sets.",[22,23362,1171,23363,1051,23365,168,23368,23370,23371,1051,23373,1051,23375,79],{},[95,23364,5424],{},[95,23366,23367],{},"compareTo()",[95,23369,315],{}," comparisons in either algorithm, never ",[95,23372,1568],{},[95,23374,3945],{},[95,23376,5507],{},[22,23378,23379],{},"The gap between linear and binary search's growth rates is exactly why sorted data (Lesson 28.2 covers how to get it that way) is worth maintaining when it's searched often.",[15,23381,493,23382,497,23384,23387],{},[95,23383,496],{},[95,23385,23386],{},"unit-4-data-collections\u002F4.14-searching-algorithms.md"," (CSA 4.14)",[503,23389,505],{},{"title":48,"searchDepth":49,"depth":49,"links":23391},[23392,23393,23394,23395,23396,23397],{"id":22928,"depth":49,"text":22929},{"id":23006,"depth":49,"text":23007},{"id":23078,"depth":49,"text":23079},{"id":23227,"depth":49,"text":23228},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"⚠ Optional chapter. This chapter deepens the array\u002F2D-array work from Ch.9\u002FCh.10 with two classic algorithms — informational, not required for FRC programming itself.",{"outlineRef":23400,"status":11220},"28.1 — Searching Algorithms (CSA 4.14)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F1-searching-algorithms",{"title":22915,"description":23398},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.1-searching-algorithms","Eb5g7SOoZ36fkimpRvk4d63Lex6srkteiior55A5dfc",{"id":23406,"title":23407,"body":23408,"description":22589,"extension":51,"meta":23748,"navigation":55,"path":23750,"seo":23751,"stem":23752,"__hash__":23753},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.2-sorting-algorithms.md","Sorting Algorithms",{"type":8,"value":23409,"toc":23740},[23410,23413,23417,23421,23424,23428,23434,23516,23530,23533,23537,23543,23611,23621,23625,23634,23680,23682,23711,23713,23730,23738],[11,23411,23407],{"id":23412},"sorting-algorithms",[15,23414,23415],{},[25,23416,22589],{},[69,23418,23420],{"id":23419},"why-sort-at-all","Why Sort at All",[15,23422,23423],{},"Binary search (Lesson 28.1) needs sorted data to work, and sorted match-scouting data, sensor logs, or leaderboard scores are simply easier for a human to read. Two straightforward sorting algorithms cover the core idea; a third, more efficient one (merge sort) is covered in Lesson 28.4.",[69,23425,23427],{"id":23426},"selection-sort","Selection Sort",[15,23429,23430,23433],{},[25,23431,23432],{},"Selection sort"," repeatedly finds the smallest remaining value and swaps it into its correct, final position — first position 0, then position 1, and so on:",[104,23435,23437],{"className":106,"code":23436,"language":108,"meta":48,"style":48},"public static void selectionSort(double[] sensorReadings)\n{\n    for (int j = 0; j \u003C sensorReadings.length - 1; j++)\n    {\n        int minIndex = j; \u002F\u002F assume the current position holds the smallest remaining value\n        for (int k = j + 1; k \u003C sensorReadings.length; k++)\n        {\n            if (sensorReadings[k] \u003C sensorReadings[minIndex])\n            {\n                minIndex = k; \u002F\u002F found something smaller — remember its index\n            }\n        }\n        double temp = sensorReadings[j];\n        sensorReadings[j] = sensorReadings[minIndex];\n        sensorReadings[minIndex] = temp;\n    }\n}\n",[95,23438,23439,23444,23448,23453,23457,23462,23467,23471,23476,23480,23485,23489,23493,23498,23503,23508,23512],{"__ignoreMap":48},[112,23440,23441],{"class":114,"line":115},[112,23442,23443],{},"public static void selectionSort(double[] sensorReadings)\n",[112,23445,23446],{"class":114,"line":49},[112,23447,123],{},[112,23449,23450],{"class":114,"line":126},[112,23451,23452],{},"    for (int j = 0; j \u003C sensorReadings.length - 1; j++)\n",[112,23454,23455],{"class":114,"line":132},[112,23456,135],{},[112,23458,23459],{"class":114,"line":138},[112,23460,23461],{},"        int minIndex = j; \u002F\u002F assume the current position holds the smallest remaining value\n",[112,23463,23464],{"class":114,"line":144},[112,23465,23466],{},"        for (int k = j + 1; k \u003C sensorReadings.length; k++)\n",[112,23468,23469],{"class":114,"line":150},[112,23470,7860],{},[112,23472,23473],{"class":114,"line":1819},[112,23474,23475],{},"            if (sensorReadings[k] \u003C sensorReadings[minIndex])\n",[112,23477,23478],{"class":114,"line":1825},[112,23479,11704],{},[112,23481,23482],{"class":114,"line":1831},[112,23483,23484],{},"                minIndex = k; \u002F\u002F found something smaller — remember its index\n",[112,23486,23487],{"class":114,"line":4742},[112,23488,11714],{},[112,23490,23491],{"class":114,"line":4748},[112,23492,7870],{},[112,23494,23495],{"class":114,"line":6935},[112,23496,23497],{},"        double temp = sensorReadings[j];\n",[112,23499,23500],{"class":114,"line":6940},[112,23501,23502],{},"        sensorReadings[j] = sensorReadings[minIndex];\n",[112,23504,23505],{"class":114,"line":6946},[112,23506,23507],{},"        sensorReadings[minIndex] = temp;\n",[112,23509,23510],{"class":114,"line":6952},[112,23511,147],{},[112,23513,23514],{"class":114,"line":6957},[112,23515,153],{},[15,23517,23518,23519,23522,23523,23526,23527,23529],{},"This is the exact ",[95,23520,23521],{},"findMin"," pattern from Ch.9.5, done once per position: the outer loop tracks which position is being filled next; the inner loop always starts at ",[95,23524,23525],{},"j + 1",", since everything before ",[95,23528,4143],{}," is already sorted and shouldn't be re-scanned.",[15,23531,23532],{},"Selection sort takes the same amount of work regardless of the data's initial order — it always scans the entire unsorted remainder to find the minimum, every single pass.",[69,23534,23536],{"id":23535},"insertion-sort","Insertion Sort",[15,23538,23539,23542],{},[25,23540,23541],{},"Insertion sort"," instead takes each element and inserts it into its correct position among the already-sorted elements to its left, shifting larger values right to make room:",[104,23544,23546],{"className":106,"code":23545,"language":108,"meta":48,"style":48},"public static void insertionSort(double[] sensorReadings)\n{\n    for (int j = 1; j \u003C sensorReadings.length; j++)\n    {\n        double temp = sensorReadings[j];\n        int possibleIndex = j;\n        while (possibleIndex > 0 && temp \u003C sensorReadings[possibleIndex - 1])\n        {\n            sensorReadings[possibleIndex] = sensorReadings[possibleIndex - 1]; \u002F\u002F shift right\n            possibleIndex--;\n        }\n        sensorReadings[possibleIndex] = temp; \u002F\u002F place temp in its final spot for this pass\n    }\n}\n",[95,23547,23548,23553,23557,23562,23566,23570,23575,23580,23584,23589,23594,23598,23603,23607],{"__ignoreMap":48},[112,23549,23550],{"class":114,"line":115},[112,23551,23552],{},"public static void insertionSort(double[] sensorReadings)\n",[112,23554,23555],{"class":114,"line":49},[112,23556,123],{},[112,23558,23559],{"class":114,"line":126},[112,23560,23561],{},"    for (int j = 1; j \u003C sensorReadings.length; j++)\n",[112,23563,23564],{"class":114,"line":132},[112,23565,135],{},[112,23567,23568],{"class":114,"line":138},[112,23569,23497],{},[112,23571,23572],{"class":114,"line":144},[112,23573,23574],{},"        int possibleIndex = j;\n",[112,23576,23577],{"class":114,"line":150},[112,23578,23579],{},"        while (possibleIndex > 0 && temp \u003C sensorReadings[possibleIndex - 1])\n",[112,23581,23582],{"class":114,"line":1819},[112,23583,7860],{},[112,23585,23586],{"class":114,"line":1825},[112,23587,23588],{},"            sensorReadings[possibleIndex] = sensorReadings[possibleIndex - 1]; \u002F\u002F shift right\n",[112,23590,23591],{"class":114,"line":1831},[112,23592,23593],{},"            possibleIndex--;\n",[112,23595,23596],{"class":114,"line":4742},[112,23597,7870],{},[112,23599,23600],{"class":114,"line":4748},[112,23601,23602],{},"        sensorReadings[possibleIndex] = temp; \u002F\u002F place temp in its final spot for this pass\n",[112,23604,23605],{"class":114,"line":6935},[112,23606,147],{},[112,23608,23609],{"class":114,"line":6940},[112,23610,153],{},[15,23612,23613,23614,23617,23618,23620],{},"Unlike selection sort, insertion sort is ",[25,23615,23616],{},"adaptive"," — if the data is already (or nearly) sorted, the ",[95,23619,5565],{}," loop's condition fails almost immediately for most elements, doing very little actual shifting. Data that's already sorted descending is insertion sort's worst case, since every element has to shift all the way to the front.",[69,23622,23624],{"id":23623},"comparing-the-two","Comparing the Two",[15,23626,23627,23628,23235,23631,23633],{},"Both algorithms have similar overall growth (roughly ",[95,23629,23630],{},"n²",[95,23632,23234],{}," elements, in the worst case) — but they behave differently depending on the input:",[8805,23635,23636,23646],{},[8808,23637,23638],{},[8811,23639,23640,23642,23644],{},[8814,23641],{},[8814,23643,23427],{},[8814,23645,23536],{},[8823,23647,23648,23659,23669],{},[8811,23649,23650,23653,23656],{},[8828,23651,23652],{},"Already sorted ascending",[8828,23654,23655],{},"No speedup — same work every time",[8828,23657,23658],{},"Much faster — adaptive",[8811,23660,23661,23664,23666],{},[8828,23662,23663],{},"Already sorted descending",[8828,23665,23655],{},[8828,23667,23668],{},"Worst case — maximum shifting",[8811,23670,23671,23674,23677],{},[8828,23672,23673],{},"Typical use",[8828,23675,23676],{},"Simple, predictable cost",[8828,23678,23679],{},"Good when data is already mostly sorted",[69,23681,412],{"id":411},[19,23683,23684,23692,23705],{},[22,23685,23686,23691],{},[25,23687,23688,23689,79],{},"Starting selection sort's inner loop at index 0 instead of ",[95,23690,23525],{}," That re-scans (and can undo) already-correctly-placed elements from earlier passes.",[22,23693,23694,23697,23698,23701,23702,23704],{},[25,23695,23696],{},"Stopping insertion sort's outer loop one element too early."," The loop must run through the entire array (",[95,23699,23700],{},"j \u003C length","), not ",[95,23703,8471],{},", or the very last element never gets inserted into its sorted position.",[22,23706,23707,23710],{},[25,23708,23709],{},"Assuming either algorithm's runtime depends on input order the same way."," Selection sort's cost is fixed regardless of order; insertion sort's genuinely isn't — that's the entire point of calling it adaptive.",[69,23712,450],{"id":449},[19,23714,23715,23718,23721,23727],{},[22,23716,23717],{},"Selection sort repeatedly finds the minimum of the remaining unsorted portion and swaps it into place — same cost regardless of initial order.",[22,23719,23720],{},"Insertion sort inserts each element into its correct position among already-sorted elements to its left, shifting as needed — adaptive, much faster on nearly-sorted data.",[22,23722,23723,23724,23726],{},"Both run roughly ",[95,23725,23630],{}," in the worst case, but real-world performance can differ significantly depending on how sorted the input already is.",[22,23728,23729],{},"Sorted data unlocks binary search (Lesson 28.1) — one reason sorting matters beyond just readability.",[15,23731,493,23732,497,23734,23737],{},[95,23733,496],{},[95,23735,23736],{},"unit-4-data-collections\u002F4.15-sorting-algorithms.md"," (CSA 4.15)",[503,23739,505],{},{"title":48,"searchDepth":49,"depth":49,"links":23741},[23742,23743,23744,23745,23746,23747],{"id":23419,"depth":49,"text":23420},{"id":23426,"depth":49,"text":23427},{"id":23535,"depth":49,"text":23536},{"id":23623,"depth":49,"text":23624},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":23749,"status":11220},"28.2 — Sorting Algorithms (CSA 4.15)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F2-sorting-algorithms",{"title":23407,"description":22589},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.2-sorting-algorithms","JH91lSQk13V0pRTmtn2SEwBg9EVcomdkn5gpUl0YsdQ",{"id":23755,"title":23756,"body":23757,"description":22589,"extension":51,"meta":24020,"navigation":55,"path":24022,"seo":24023,"stem":24024,"__hash__":24025},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.3-recursion.md","Recursion",{"type":8,"value":23758,"toc":24012},[23759,23762,23766,23770,23775,23803,23814,23818,23829,23882,23897,23901,23910,23916,23919,23925,23933,23937,23954,23956,23983,23985,24002,24010],[11,23760,23756],{"id":23761},"recursion",[15,23763,23764],{},[25,23765,22589],{},[69,23767,23769],{"id":23768},"a-method-that-calls-itself","A Method That Calls Itself",[15,23771,23772,23774],{},[25,23773,23756],{}," is when a method calls itself — another form of repetition, alongside loops (Ch.5). Without care, this goes wrong immediately:",[104,23776,23778],{"className":106,"code":23777,"language":108,"meta":48,"style":48},"public static void neverEnd()\n{\n    System.out.println(\"This never stops!\");\n    neverEnd(); \u002F\u002F calls itself again, forever\n}\n",[95,23779,23780,23785,23789,23794,23799],{"__ignoreMap":48},[112,23781,23782],{"class":114,"line":115},[112,23783,23784],{},"public static void neverEnd()\n",[112,23786,23787],{"class":114,"line":49},[112,23788,123],{},[112,23790,23791],{"class":114,"line":126},[112,23792,23793],{},"    System.out.println(\"This never stops!\");\n",[112,23795,23796],{"class":114,"line":132},[112,23797,23798],{},"    neverEnd(); \u002F\u002F calls itself again, forever\n",[112,23800,23801],{"class":114,"line":138},[112,23802,153],{},[15,23804,23805,23806,23809,23810,23813],{},"This is ",[25,23807,23808],{},"infinite recursion"," — it eventually crashes with ",[95,23811,23812],{},"StackOverflowError",", since a program can only recurse so deep before running out of space to track all those in-progress calls.",[69,23815,23817],{"id":23816},"two-required-ingredients","Two Required Ingredients",[15,23819,23820,23821,23824,23825,23828],{},"Every well-behaved recursive method needs at least one ",[25,23822,23823],{},"base case"," (a condition that stops the recursion and returns directly, no further self-call) and at least one ",[25,23826,23827],{},"recursive call"," (that moves the problem closer to the base case). The classic example, factorial:",[104,23830,23832],{"className":106,"code":23831,"language":108,"meta":48,"style":48},"public static int factorial(int n)\n{\n    if (n == 0)         \u002F\u002F base case — the smallest input this method answers directly\n    {\n        return 1;\n    }\n    else\n    {\n        return n * factorial(n - 1); \u002F\u002F recursive call — moves toward the base case\n    }\n}\n",[95,23833,23834,23839,23843,23848,23852,23857,23861,23865,23869,23874,23878],{"__ignoreMap":48},[112,23835,23836],{"class":114,"line":115},[112,23837,23838],{},"public static int factorial(int n)\n",[112,23840,23841],{"class":114,"line":49},[112,23842,123],{},[112,23844,23845],{"class":114,"line":126},[112,23846,23847],{},"    if (n == 0)         \u002F\u002F base case — the smallest input this method answers directly\n",[112,23849,23850],{"class":114,"line":132},[112,23851,135],{},[112,23853,23854],{"class":114,"line":138},[112,23855,23856],{},"        return 1;\n",[112,23858,23859],{"class":114,"line":144},[112,23860,147],{},[112,23862,23863],{"class":114,"line":150},[112,23864,10079],{},[112,23866,23867],{"class":114,"line":1819},[112,23868,135],{},[112,23870,23871],{"class":114,"line":1825},[112,23872,23873],{},"        return n * factorial(n - 1); \u002F\u002F recursive call — moves toward the base case\n",[112,23875,23876],{"class":114,"line":1831},[112,23877,147],{},[112,23879,23880],{"class":114,"line":4742},[112,23881,153],{},[15,23883,23884,23885,23888,23889,23892,23893,23896],{},"Every recursive call should shrink the problem: ",[95,23886,23887],{},"factorial","'s call passes ",[95,23890,23891],{},"n - 1",", one step closer to the ",[95,23894,23895],{},"n == 0"," base case that eventually stops the recursion.",[69,23898,23900],{"id":23899},"tracing-the-call-stack","Tracing: The Call Stack",[15,23902,23903,23904,23906,23907,687],{},"Each recursive call gets pushed onto the ",[25,23905,12551],{}," with its own independent copy of local variables and parameters — exactly like the method-call mechanics from Ch.4\u002F17.2, just calling the same method repeatedly. Tracing ",[95,23908,23909],{},"factorial(3)",[104,23911,23914],{"className":23912,"code":23913,"language":4393},[4391],"factorial(3) returns 3 * factorial(2)\nfactorial(2) returns 2 * factorial(1)\nfactorial(1) returns 1 * factorial(0)\nfactorial(0) returns 1\n",[95,23915,23913],{"__ignoreMap":48},[15,23917,23918],{},"Then substituting values back upward from the base case:",[104,23920,23923],{"className":23921,"code":23922,"language":4393},[4391],"factorial(1) returns 1 * factorial(0) = 1 * 1 = 1\nfactorial(2) returns 2 * factorial(1) = 2 * 1 = 2\nfactorial(3) returns 3 * factorial(2) = 3 * 2 = 6\n",[95,23924,23922],{"__ignoreMap":48},[15,23926,23927,23929,23930,79],{},[95,23928,23909],{}," returns ",[95,23931,23932],{},"6",[69,23934,23936],{"id":23935},"why-bother-loops-for-trees","Why Bother? Loops for Trees",[15,23938,23939,23940,23943,23944,23946,23947,23950,23951,23953],{},"Any loop can, in principle, be rewritten recursively, and vice versa — so why use recursion at all? It shines on ",[25,23941,23942],{},"branching"," structures (computer scientists call these \"trees\") rather than simple linear ones. A useful mental model: a ",[95,23945,3899],{}," loop for a linear structure like an array (Ch.9), nested loops for a 2D array (Ch.10), and recursion for something that branches — like calculating the total number of subsystems nested inside an equipment group that can itself contain further nested groups, where each nested group is ",[262,23948,23949],{},"the same problem",", just smaller. A ",[95,23952,3899],{}," loop naturally handles \"walk through this flat list\"; it struggles to naturally express \"walk through this, and every branch inside it, and every branch inside those.\"",[69,23955,412],{"id":411},[19,23957,23958,23968,23974],{},[22,23959,23960,23963,23964,23967],{},[25,23961,23962],{},"Forgetting the base case entirely."," Without one, every recursive method is really just ",[95,23965,23966],{},"neverEnd()"," in disguise — infinite recursion and a crash.",[22,23969,23970,23973],{},[25,23971,23972],{},"A recursive call that doesn't actually shrink the problem."," If the argument passed to the next call doesn't move closer to the base case, the recursion never terminates, even with a base case defined.",[22,23975,23976,23979,23980,23982],{},[25,23977,23978],{},"Confusing \"recursion is elegant here\" with \"recursion is required here.\""," Simple linear traversal (an array, a ",[95,23981,315],{},") is usually clearer and more efficient as a loop — recursion earns its keep on genuinely branching structures.",[69,23984,450],{"id":449},[19,23986,23987,23990,23993,23996],{},[22,23988,23989],{},"Recursion is a method calling itself — repetition, like a loop, but structured around self-calls instead of a loop construct.",[22,23991,23992],{},"Every correct recursive method needs a base case (stops the recursion) and a recursive call that moves toward it.",[22,23994,23995],{},"Each recursive call gets its own independent local variables\u002Fparameters, tracked via the call stack — tracing means writing out each call, then substituting values back up from the base case.",[22,23997,23998,23999,24001],{},"Recursion is most valuable for branching (\"tree\") structures — a simple ",[95,24000,3899],{}," loop remains the better tool for flat, linear ones.",[15,24003,493,24004,497,24006,24009],{},[95,24005,496],{},[95,24007,24008],{},"unit-4-data-collections\u002F4.16-recursion.md"," (CSA 4.16)",[503,24011,505],{},{"title":48,"searchDepth":49,"depth":49,"links":24013},[24014,24015,24016,24017,24018,24019],{"id":23768,"depth":49,"text":23769},{"id":23816,"depth":49,"text":23817},{"id":23899,"depth":49,"text":23900},{"id":23935,"depth":49,"text":23936},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},{"outlineRef":24021,"status":11220},"28.3 — Recursion (CSA 4.16)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F3-recursion",{"title":23756,"description":22589},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.3-recursion","EpkEjdREmuudqmYCiZC0srpmh3paoafZkCg-1K5ajxY",{"id":24027,"title":24028,"body":24029,"description":24364,"extension":51,"meta":24365,"navigation":55,"path":24367,"seo":24368,"stem":24369,"__hash__":24370},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.4-recursive-searching-and-sorting.md","Recursive Searching and Sorting",{"type":8,"value":24030,"toc":24357},[24031,24034,24039,24043,24054,24148,24159,24163,24181,24196,24271,24278,24284,24290,24294,24300,24302,24326,24328,24347,24355],[11,24032,24028],{"id":24033},"recursive-searching-and-sorting",[15,24035,24036,24038],{},[25,24037,22589],{}," Closes out the curriculum by combining Lessons 28.1-28.3: the same searching\u002Fsorting ideas, rewritten recursively.",[69,24040,24042],{"id":24041},"recursive-binary-search","Recursive Binary Search",[15,24044,24045,24046,1051,24048,24050,24051,24053],{},"The iterative binary search from Lesson 28.1 tracks ",[95,24047,23092],{},[95,24049,23095],{}," bounds in loop variables. A recursive version instead passes the shrinking range as parameters, with the range itself doing the job a ",[95,24052,5565],{}," loop's condition did before:",[104,24055,24057],{"className":106,"code":24056,"language":108,"meta":48,"style":48},"public static int recursiveBinarySearch(int[] elements, int start, int end, int target)\n{\n    if (end \u003C start)                          \u002F\u002F base case 1: range is empty — not found\n    {\n        return -1;\n    }\n    int middle = (start + end) \u002F 2;\n    if (target == elements[middle])            \u002F\u002F base case 2: found it\n    {\n        return middle;\n    }\n    else if (target \u003C elements[middle])\n    {\n        return recursiveBinarySearch(elements, start, middle - 1, target); \u002F\u002F search the left half\n    }\n    else\n    {\n        return recursiveBinarySearch(elements, middle + 1, end, target);   \u002F\u002F search the right half\n    }\n}\n",[95,24058,24059,24064,24068,24073,24077,24082,24086,24091,24096,24100,24105,24109,24114,24118,24123,24127,24131,24135,24140,24144],{"__ignoreMap":48},[112,24060,24061],{"class":114,"line":115},[112,24062,24063],{},"public static int recursiveBinarySearch(int[] elements, int start, int end, int target)\n",[112,24065,24066],{"class":114,"line":49},[112,24067,123],{},[112,24069,24070],{"class":114,"line":126},[112,24071,24072],{},"    if (end \u003C start)                          \u002F\u002F base case 1: range is empty — not found\n",[112,24074,24075],{"class":114,"line":132},[112,24076,135],{},[112,24078,24079],{"class":114,"line":138},[112,24080,24081],{},"        return -1;\n",[112,24083,24084],{"class":114,"line":144},[112,24085,147],{},[112,24087,24088],{"class":114,"line":150},[112,24089,24090],{},"    int middle = (start + end) \u002F 2;\n",[112,24092,24093],{"class":114,"line":1819},[112,24094,24095],{},"    if (target == elements[middle])            \u002F\u002F base case 2: found it\n",[112,24097,24098],{"class":114,"line":1825},[112,24099,135],{},[112,24101,24102],{"class":114,"line":1831},[112,24103,24104],{},"        return middle;\n",[112,24106,24107],{"class":114,"line":4742},[112,24108,147],{},[112,24110,24111],{"class":114,"line":4748},[112,24112,24113],{},"    else if (target \u003C elements[middle])\n",[112,24115,24116],{"class":114,"line":6935},[112,24117,135],{},[112,24119,24120],{"class":114,"line":6940},[112,24121,24122],{},"        return recursiveBinarySearch(elements, start, middle - 1, target); \u002F\u002F search the left half\n",[112,24124,24125],{"class":114,"line":6946},[112,24126,147],{},[112,24128,24129],{"class":114,"line":6952},[112,24130,10079],{},[112,24132,24133],{"class":114,"line":6957},[112,24134,135],{},[112,24136,24137],{"class":114,"line":6963},[112,24138,24139],{},"        return recursiveBinarySearch(elements, middle + 1, end, target);   \u002F\u002F search the right half\n",[112,24141,24142],{"class":114,"line":6968},[112,24143,147],{},[112,24145,24146],{"class":114,"line":11929},[112,24147,153],{},[15,24149,24150,24151,24154,24155,24158],{},"This has ",[25,24152,24153],{},"two base cases"," (Ch.25.4's enum state machines had a preview of \"more than one stopping condition\" — the same idea applies here): a match at the middle, or an exhausted range. Removing the ",[95,24156,24157],{},"end \u003C start"," check would mean a not-found search keeps recursing into an already-empty range forever — exactly the missing-base-case bug from Lesson 28.3.",[69,24160,24162],{"id":24161},"merge-sort-a-third-sorting-algorithm","Merge Sort: A Third Sorting Algorithm",[15,24164,24165,24166,24168,24169,18345,24172,24175,24176,3972,24179,17050],{},"Selection sort and insertion sort (Lesson 28.2) both cost roughly ",[95,24167,23630],{}," in the worst case. ",[25,24170,24171],{},"Merge sort",[25,24173,24174],{},"divide-and-conquer"," algorithm — like binary search, it splits the problem in half repeatedly, which makes it substantially faster on large data (roughly ",[95,24177,24178],{},"n log n",[95,24180,23630],{},[24182,24183,24184,24187,24190],"ol",{},[22,24185,24186],{},"Split the array into two halves.",[22,24188,24189],{},"Recursively sort each half (a single-element array is trivially already sorted — the base case).",[22,24191,24192,24195],{},[25,24193,24194],{},"Merge"," the two now-sorted halves back together, in order.",[104,24197,24199],{"className":106,"code":24198,"language":108,"meta":48,"style":48},"public static void mergeSort(int[] elements)\n{\n    int n = elements.length;\n    int[] temp = new int[n]; \u002F\u002F scratch space used during merging\n    mergeSortHelper(elements, 0, n - 1, temp);\n}\n\nprivate static void mergeSortHelper(int[] elements, int from, int to, int[] temp)\n{\n    if (from >= to) return; \u002F\u002F base case: a range of 0 or 1 elements is already sorted\n    int middle = (from + to) \u002F 2;\n    mergeSortHelper(elements, from, middle, temp);      \u002F\u002F recursively sort the left half\n    mergeSortHelper(elements, middle + 1, to, temp);    \u002F\u002F recursively sort the right half\n    merge(elements, from, middle, to, temp);            \u002F\u002F combine the two sorted halves\n}\n",[95,24200,24201,24206,24210,24215,24220,24225,24229,24233,24238,24242,24247,24252,24257,24262,24267],{"__ignoreMap":48},[112,24202,24203],{"class":114,"line":115},[112,24204,24205],{},"public static void mergeSort(int[] elements)\n",[112,24207,24208],{"class":114,"line":49},[112,24209,123],{},[112,24211,24212],{"class":114,"line":126},[112,24213,24214],{},"    int n = elements.length;\n",[112,24216,24217],{"class":114,"line":132},[112,24218,24219],{},"    int[] temp = new int[n]; \u002F\u002F scratch space used during merging\n",[112,24221,24222],{"class":114,"line":138},[112,24223,24224],{},"    mergeSortHelper(elements, 0, n - 1, temp);\n",[112,24226,24227],{"class":114,"line":144},[112,24228,153],{},[112,24230,24231],{"class":114,"line":150},[112,24232,820],{"emptyLinePlaceholder":55},[112,24234,24235],{"class":114,"line":1819},[112,24236,24237],{},"private static void mergeSortHelper(int[] elements, int from, int to, int[] temp)\n",[112,24239,24240],{"class":114,"line":1825},[112,24241,123],{},[112,24243,24244],{"class":114,"line":1831},[112,24245,24246],{},"    if (from >= to) return; \u002F\u002F base case: a range of 0 or 1 elements is already sorted\n",[112,24248,24249],{"class":114,"line":4742},[112,24250,24251],{},"    int middle = (from + to) \u002F 2;\n",[112,24253,24254],{"class":114,"line":4748},[112,24255,24256],{},"    mergeSortHelper(elements, from, middle, temp);      \u002F\u002F recursively sort the left half\n",[112,24258,24259],{"class":114,"line":6935},[112,24260,24261],{},"    mergeSortHelper(elements, middle + 1, to, temp);    \u002F\u002F recursively sort the right half\n",[112,24263,24264],{"class":114,"line":6940},[112,24265,24266],{},"    merge(elements, from, middle, to, temp);            \u002F\u002F combine the two sorted halves\n",[112,24268,24269],{"class":114,"line":6946},[112,24270,153],{},[15,24272,24273,24274,24277],{},"Tracing the split-then-merge structure for ",[95,24275,24276],{},"{86, 3, 43, 5}",", using nested braces:",[104,24279,24282],{"className":24280,"code":24281,"language":4393},[4391],"Split:  { {86, 3} , {43, 5} }\nSplit:  { { {86}, {3} } , { {43}, {5} } }   \u003C- single elements: base case reached\nMerge:  { {3, 86} , {5, 43} }\nMerge:  { 3, 5, 43, 86 }\n",[95,24283,24281],{"__ignoreMap":48},[15,24285,24286,24287,24289],{},"Like selection sort, merge sort's structure doesn't depend on the input's initial order — it always splits and merges the same way. But because its divide-and-conquer approach scales so much better than ",[95,24288,23630],{}," sorting, it's the fastest of the three algorithms in this curriculum, most of the time, especially as the data set grows.",[69,24291,24293],{"id":24292},"iterative-vs-recursive-same-algorithm-different-shape","Iterative vs. Recursive: Same Algorithm, Different Shape",[15,24295,24296,24297,24299],{},"Binary search exists in both forms (Lesson 28.1's iterative version, this lesson's recursive one) — a good concrete reminder of Lesson 28.3's point that many algorithms can be written either way. Iteration is usually preferred in real code (no risk of ",[95,24298,23812],{},", generally a bit more efficient) — but a recursive version can be more compact and can make a divide-and-conquer structure (like merge sort's) much more natural to express than an iterative equivalent would be.",[69,24301,412],{"id":411},[19,24303,24304,24310,24320],{},[22,24305,24306,24309],{},[25,24307,24308],{},"Forgetting either base case in recursive binary search."," Both the \"found it\" and \"range exhausted\" cases are needed — missing the exhausted-range check risks infinite recursion on a not-found search.",[22,24311,24312,24315,24316,24319],{},[25,24313,24314],{},"Merging without first ensuring both halves are actually sorted."," Merge sort's ",[95,24317,24318],{},"merge"," step assumes its two inputs are already individually sorted — that's exactly what the recursive calls before it guarantee.",[22,24321,24322,24325],{},[25,24323,24324],{},"Assuming recursive is always \"better\" than iterative, or vice versa."," Each has real tradeoffs (stack depth risk vs. code clarity) — the right choice depends on the specific algorithm and data size.",[69,24327,450],{"id":449},[19,24329,24330,24333,24336,24344],{},[22,24331,24332],{},"Recursive binary search replaces loop-tracked bounds with a shrinking range passed as parameters, and needs two base cases: a match, or an exhausted range.",[22,24334,24335],{},"Merge sort is a recursive, divide-and-conquer sort: split in half, recursively sort each half (base case: 1 element), then merge the sorted halves back together.",[22,24337,24338,24339,3864,24341,24343],{},"Merge sort scales better than selection\u002Finsertion sort on large data (",[95,24340,24178],{},[95,24342,23630],{},"), and its performance doesn't depend on the input's initial order.",[22,24345,24346],{},"The same algorithm can often be written iteratively or recursively — the choice is a real tradeoff, not a universal \"better\" answer either way.",[15,24348,493,24349,497,24351,24354],{},[95,24350,496],{},[95,24352,24353],{},"unit-4-data-collections\u002F4.17-recursive-searching-and-sorting.md"," (CSA 4.17)",[503,24356,505],{},{"title":48,"searchDepth":49,"depth":49,"links":24358},[24359,24360,24361,24362,24363],{"id":24041,"depth":49,"text":24042},{"id":24161,"depth":49,"text":24162},{"id":24292,"depth":49,"text":24293},{"id":411,"depth":49,"text":412},{"id":449,"depth":49,"text":450},"⚠ Optional chapter. Closes out the curriculum by combining Lessons 28.1-28.3: the same searching\u002Fsorting ideas, rewritten recursively.",{"outlineRef":24366,"status":11220},"28.4 — Recursive Searching and Sorting (CSA 4.17)","\u002Fshockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F4-recursive-searching-and-sorting",{"title":24028,"description":24364},"shockwave-curriculum\u002Flessons\u002Fch28-algorithms-searching-sorting-recursion\u002F28.4-recursive-searching-and-sorting","upMiPZlUiVOt73D6lyoJl0bQAD-H0f4roIAt8V0ycMY",{"id":24372,"title":24373,"body":24374,"description":24395,"extension":51,"meta":24396,"navigation":55,"path":24397,"seo":24398,"stem":24399,"__hash__":24400},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch29-git-and-github-basics\u002F29.1-coming-soon.md","Git & GitHub Basics — Coming Soon",{"type":8,"value":24375,"toc":24393},[24376,24379],[11,24377,24373],{"id":24378},"git-github-basics-coming-soon",[15,24380,24381,24384,24385,24388,24389,24392],{},[25,24382,24383],{},"Status:"," placeholder chapter, not authored yet. Pulled from ",[95,24386,24387],{},"mechacoder-full-deck.html","\ninto ",[95,24390,24391],{},"curriculum-ledger.html"," as ch.29 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24394},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.29 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch29-git-and-github-basics\u002F1-coming-soon",{"title":24373,"description":24395},"shockwave-curriculum\u002Flessons\u002Fch29-git-and-github-basics\u002F29.1-coming-soon","M80FQl3ZkysV11VnHHsw-c5nyOXe3uWR9LIfeCWGIl8",{"id":24402,"title":24403,"body":24404,"description":24420,"extension":51,"meta":24421,"navigation":55,"path":24422,"seo":24423,"stem":24424,"__hash__":24425},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch30-git-history-and-merging\u002F30.1-coming-soon.md","Git — History & Merging — Coming Soon",{"type":8,"value":24405,"toc":24418},[24406,24409],[11,24407,24403],{"id":24408},"git-history-merging-coming-soon",[15,24410,24411,24384,24413,24388,24415,24417],{},[25,24412,24383],{},[95,24414,24387],{},[95,24416,24391],{}," as ch.30 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24419},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.30 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch30-git-history-and-merging\u002F1-coming-soon",{"title":24403,"description":24420},"shockwave-curriculum\u002Flessons\u002Fch30-git-history-and-merging\u002F30.1-coming-soon","0W3bu2Me9piXXQ2MU9MnSwW7jUcHJmS0jfmkbNR8QyU",{"id":24427,"title":24428,"body":24429,"description":24445,"extension":51,"meta":24446,"navigation":55,"path":24447,"seo":24448,"stem":24449,"__hash__":24450},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch31-dev-environment-and-tooling\u002F31.1-coming-soon.md","Dev Environment & Tooling — Coming Soon",{"type":8,"value":24430,"toc":24443},[24431,24434],[11,24432,24428],{"id":24433},"dev-environment-tooling-coming-soon",[15,24435,24436,24384,24438,24388,24440,24442],{},[25,24437,24383],{},[95,24439,24387],{},[95,24441,24391],{}," as ch.31 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24444},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.31 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch31-dev-environment-and-tooling\u002F1-coming-soon",{"title":24428,"description":24445},"shockwave-curriculum\u002Flessons\u002Fch31-dev-environment-and-tooling\u002F31.1-coming-soon","WpBIbU9fVXk_mwyqTHFIDlJTrEPBrqbqh9U7u2INiBU",{"id":24452,"title":24453,"body":24454,"description":24470,"extension":51,"meta":24471,"navigation":55,"path":24472,"seo":24473,"stem":24474,"__hash__":24475},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch32-unit-testing\u002F32.1-coming-soon.md","Unit Testing — Coming Soon",{"type":8,"value":24455,"toc":24468},[24456,24459],[11,24457,24453],{"id":24458},"unit-testing-coming-soon",[15,24460,24461,24384,24463,24388,24465,24467],{},[25,24462,24383],{},[95,24464,24387],{},[95,24466,24391],{}," as ch.32 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24469},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.32 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch32-unit-testing\u002F1-coming-soon",{"title":24453,"description":24470},"shockwave-curriculum\u002Flessons\u002Fch32-unit-testing\u002F32.1-coming-soon","krv1mHUxxP_GQszyFHcnsWKitL79FJTU_gmePxXrsIU",{"id":24477,"title":24478,"body":24479,"description":24495,"extension":51,"meta":24496,"navigation":55,"path":24497,"seo":24498,"stem":24499,"__hash__":24500},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch33-advantagekit-autologging\u002F33.1-coming-soon.md","AdvantageKit — AutoLogging — Coming Soon",{"type":8,"value":24480,"toc":24493},[24481,24484],[11,24482,24478],{"id":24483},"advantagekit-autologging-coming-soon",[15,24485,24486,24384,24488,24388,24490,24492],{},[25,24487,24383],{},[95,24489,24387],{},[95,24491,24391],{}," as ch.33 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24494},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.33 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch33-advantagekit-autologging\u002F1-coming-soon",{"title":24478,"description":24495},"shockwave-curriculum\u002Flessons\u002Fch33-advantagekit-autologging\u002F33.1-coming-soon","spoNagkq5hdYTZ0yQ-P3IuIGmL1Ktv_V9fRwYfujpLQ",{"id":24502,"title":24503,"body":24504,"description":24520,"extension":51,"meta":24521,"navigation":55,"path":24522,"seo":24523,"stem":24524,"__hash__":24525},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch34-log-replay\u002F34.1-coming-soon.md","Log Replay — Coming Soon",{"type":8,"value":24505,"toc":24518},[24506,24509],[11,24507,24503],{"id":24508},"log-replay-coming-soon",[15,24510,24511,24384,24513,24388,24515,24517],{},[25,24512,24383],{},[95,24514,24387],{},[95,24516,24391],{}," as ch.34 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24519},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.34 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch34-log-replay\u002F1-coming-soon",{"title":24503,"description":24520},"shockwave-curriculum\u002Flessons\u002Fch34-log-replay\u002F34.1-coming-soon","xgT1sABD2-1MJmFDGkbBid7vJuEqta641bi43kY5U_w",{"id":24527,"title":24528,"body":24529,"description":24545,"extension":51,"meta":24546,"navigation":55,"path":24547,"seo":24548,"stem":24549,"__hash__":24550},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch35-advantagescope-i-visualization\u002F35.1-coming-soon.md","AdvantageScope I: Visualization — Coming Soon",{"type":8,"value":24530,"toc":24543},[24531,24534],[11,24532,24528],{"id":24533},"advantagescope-i-visualization-coming-soon",[15,24535,24536,24384,24538,24388,24540,24542],{},[25,24537,24383],{},[95,24539,24387],{},[95,24541,24391],{}," as ch.35 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24544},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.35 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch35-advantagescope-i-visualization\u002F1-coming-soon",{"title":24528,"description":24545},"shockwave-curriculum\u002Flessons\u002Fch35-advantagescope-i-visualization\u002F35.1-coming-soon","BX1LcLs2zKIRFnQjOxLMIVCms_rgec36zjt98dUnh2Y",{"id":24552,"title":24553,"body":24554,"description":24570,"extension":51,"meta":24571,"navigation":55,"path":24572,"seo":24573,"stem":24574,"__hash__":24575},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch36-advantagescope-ii-custom-3d-assets\u002F36.1-coming-soon.md","AdvantageScope II: Custom 3D Assets — Coming Soon",{"type":8,"value":24555,"toc":24568},[24556,24559],[11,24557,24553],{"id":24558},"advantagescope-ii-custom-3d-assets-coming-soon",[15,24560,24561,24384,24563,24388,24565,24567],{},[25,24562,24383],{},[95,24564,24387],{},[95,24566,24391],{}," as ch.36 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24569},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.36 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch36-advantagescope-ii-custom-3d-assets\u002F1-coming-soon",{"title":24553,"description":24570},"shockwave-curriculum\u002Flessons\u002Fch36-advantagescope-ii-custom-3d-assets\u002F36.1-coming-soon","Qeov6DR_HjzJPA4kBoxrXU6AaNgTmZui6noDGVpG5ng",{"id":24577,"title":24578,"body":24579,"description":24595,"extension":51,"meta":24596,"navigation":55,"path":24597,"seo":24598,"stem":24599,"__hash__":24600},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch37-autonomous-i\u002F37.1-coming-soon.md","Autonomous I — Coming Soon",{"type":8,"value":24580,"toc":24593},[24581,24584],[11,24582,24578],{"id":24583},"autonomous-i-coming-soon",[15,24585,24586,24384,24588,24388,24590,24592],{},[25,24587,24383],{},[95,24589,24387],{},[95,24591,24391],{}," as ch.37 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24594},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.37 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch37-autonomous-i\u002F1-coming-soon",{"title":24578,"description":24595},"shockwave-curriculum\u002Flessons\u002Fch37-autonomous-i\u002F37.1-coming-soon","EPLFRNClsViJoQFtbe6f9McYqBM9sZEWNAG-TiJc5Og",{"id":24602,"title":24603,"body":24604,"description":24620,"extension":51,"meta":24621,"navigation":55,"path":24622,"seo":24623,"stem":24624,"__hash__":24625},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch38-autonomous-ii-pathplanner-and-trajectories\u002F38.1-coming-soon.md","Autonomous II: PathPlanner & Trajectories — Coming Soon",{"type":8,"value":24605,"toc":24618},[24606,24609],[11,24607,24603],{"id":24608},"autonomous-ii-pathplanner-trajectories-coming-soon",[15,24610,24611,24384,24613,24388,24615,24617],{},[25,24612,24383],{},[95,24614,24387],{},[95,24616,24391],{}," as ch.38 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24619},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.38 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch38-autonomous-ii-pathplanner-and-trajectories\u002F1-coming-soon",{"title":24603,"description":24620},"shockwave-curriculum\u002Flessons\u002Fch38-autonomous-ii-pathplanner-and-trajectories\u002F38.1-coming-soon","SQN8PGhvaHnKtm1dU5SF7zuqLONkbc61Lg_cdpoUDsM",{"id":24627,"title":24628,"body":24629,"description":24645,"extension":51,"meta":24646,"navigation":55,"path":24647,"seo":24648,"stem":24649,"__hash__":24650},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch39-control-fundamentals\u002F39.1-coming-soon.md","Control Fundamentals — Coming Soon",{"type":8,"value":24630,"toc":24643},[24631,24634],[11,24632,24628],{"id":24633},"control-fundamentals-coming-soon",[15,24635,24636,24384,24638,24388,24640,24642],{},[25,24637,24383],{},[95,24639,24387],{},[95,24641,24391],{}," as ch.39 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24644},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.39 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch39-control-fundamentals\u002F1-coming-soon",{"title":24628,"description":24645},"shockwave-curriculum\u002Flessons\u002Fch39-control-fundamentals\u002F39.1-coming-soon","TT7Zmbb1lJ45jAkP_FQdVt0qZkmxNTzWk0MnFuwTF50",{"id":24652,"title":24653,"body":24654,"description":24670,"extension":51,"meta":24671,"navigation":55,"path":24672,"seo":24673,"stem":24674,"__hash__":24675},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch40-motion-profiles\u002F40.1-coming-soon.md","Motion Profiles — Coming Soon",{"type":8,"value":24655,"toc":24668},[24656,24659],[11,24657,24653],{"id":24658},"motion-profiles-coming-soon",[15,24660,24661,24384,24663,24388,24665,24667],{},[25,24662,24383],{},[95,24664,24387],{},[95,24666,24391],{}," as ch.40 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24669},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.40 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch40-motion-profiles\u002F1-coming-soon",{"title":24653,"description":24670},"shockwave-curriculum\u002Flessons\u002Fch40-motion-profiles\u002F40.1-coming-soon","NhrGUcwG7OU105vTdRAV_KvPX3C2hbgVIjOJPe_myiQ",{"id":24677,"title":24678,"body":24679,"description":24695,"extension":51,"meta":24696,"navigation":55,"path":24697,"seo":24698,"stem":24699,"__hash__":24700},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch41-hardware-fundamentals\u002F41.1-coming-soon.md","Hardware Fundamentals — Coming Soon",{"type":8,"value":24680,"toc":24693},[24681,24684],[11,24682,24678],{"id":24683},"hardware-fundamentals-coming-soon",[15,24685,24686,24384,24688,24388,24690,24692],{},[25,24687,24383],{},[95,24689,24387],{},[95,24691,24391],{}," as ch.41 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24694},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.41 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch41-hardware-fundamentals\u002F1-coming-soon",{"title":24678,"description":24695},"shockwave-curriculum\u002Flessons\u002Fch41-hardware-fundamentals\u002F41.1-coming-soon","kttwOTGKjLgSRr9PcG9A2sPauf4-YKPxVkopx8hXFvE",{"id":24702,"title":24703,"body":24704,"description":24720,"extension":51,"meta":24721,"navigation":55,"path":24722,"seo":24723,"stem":24724,"__hash__":24725},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch42-photonvision\u002F42.1-coming-soon.md","PhotonVision — Coming Soon",{"type":8,"value":24705,"toc":24718},[24706,24709],[11,24707,24703],{"id":24708},"photonvision-coming-soon",[15,24710,24711,24384,24713,24388,24715,24717],{},[25,24712,24383],{},[95,24714,24387],{},[95,24716,24391],{}," as ch.42 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24719},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.42 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch42-photonvision\u002F1-coming-soon",{"title":24703,"description":24720},"shockwave-curriculum\u002Flessons\u002Fch42-photonvision\u002F42.1-coming-soon","1HBCN3KMJFWhYm4KGfFnGWOOxx42zFZ_mBkiJUVKgbg",{"id":24727,"title":24728,"body":24729,"description":24745,"extension":51,"meta":24746,"navigation":55,"path":24747,"seo":24748,"stem":24749,"__hash__":24750},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch43-apriltags-and-pose\u002F43.1-coming-soon.md","AprilTags & Pose — Coming Soon",{"type":8,"value":24730,"toc":24743},[24731,24734],[11,24732,24728],{"id":24733},"apriltags-pose-coming-soon",[15,24735,24736,24384,24738,24388,24740,24742],{},[25,24737,24383],{},[95,24739,24387],{},[95,24741,24391],{}," as ch.43 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24744},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.43 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch43-apriltags-and-pose\u002F1-coming-soon",{"title":24728,"description":24745},"shockwave-curriculum\u002Flessons\u002Fch43-apriltags-and-pose\u002F43.1-coming-soon","ldbsoniEmAn8CnpwGalpBmHuRMVbq_rPUazzWuK6nj8",{"id":24752,"title":24753,"body":24754,"description":24770,"extension":51,"meta":24771,"navigation":55,"path":24772,"seo":24773,"stem":24774,"__hash__":24775},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch44-subsystems-i\u002F44.1-coming-soon.md","Subsystems I — Coming Soon",{"type":8,"value":24755,"toc":24768},[24756,24759],[11,24757,24753],{"id":24758},"subsystems-i-coming-soon",[15,24760,24761,24384,24763,24388,24765,24767],{},[25,24762,24383],{},[95,24764,24387],{},[95,24766,24391],{}," as ch.44 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24769},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.44 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch44-subsystems-i\u002F1-coming-soon",{"title":24753,"description":24770},"shockwave-curriculum\u002Flessons\u002Fch44-subsystems-i\u002F44.1-coming-soon","xV8OV_rbBnVvGQxeuH8EuMtNJOdD3zLIOBkc8QhN5II",{"id":24777,"title":24778,"body":24779,"description":24795,"extension":51,"meta":24796,"navigation":55,"path":24797,"seo":24798,"stem":24799,"__hash__":24800},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch45-subsystems-ii-advanced\u002F45.1-coming-soon.md","Subsystems II — Advanced — Coming Soon",{"type":8,"value":24780,"toc":24793},[24781,24784],[11,24782,24778],{"id":24783},"subsystems-ii-advanced-coming-soon",[15,24785,24786,24384,24788,24388,24790,24792],{},[25,24787,24383],{},[95,24789,24387],{},[95,24791,24391],{}," as ch.45 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24794},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.45 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch45-subsystems-ii-advanced\u002F1-coming-soon",{"title":24778,"description":24795},"shockwave-curriculum\u002Flessons\u002Fch45-subsystems-ii-advanced\u002F45.1-coming-soon","-w_0_3ykKGX5OMf983zV9QL_1MsNiz781OtYHGJWnwI",{"id":24802,"title":24803,"body":24804,"description":24820,"extension":51,"meta":24821,"navigation":55,"path":24822,"seo":24823,"stem":24824,"__hash__":24825},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch46-team-utilities-i\u002F46.1-coming-soon.md","Team Utilities I — Coming Soon",{"type":8,"value":24805,"toc":24818},[24806,24809],[11,24807,24803],{"id":24808},"team-utilities-i-coming-soon",[15,24810,24811,24384,24813,24388,24815,24817],{},[25,24812,24383],{},[95,24814,24387],{},[95,24816,24391],{}," as ch.46 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24819},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.46 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch46-team-utilities-i\u002F1-coming-soon",{"title":24803,"description":24820},"shockwave-curriculum\u002Flessons\u002Fch46-team-utilities-i\u002F46.1-coming-soon","48jruSubU_qrwLRTP-ej8RLGcNj62e-QdXLDqShZDc4",{"id":24827,"title":24828,"body":24829,"description":24845,"extension":51,"meta":24846,"navigation":55,"path":24847,"seo":24848,"stem":24849,"__hash__":24850},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch47-field-constants\u002F47.1-coming-soon.md","Field Constants — Coming Soon",{"type":8,"value":24830,"toc":24843},[24831,24834],[11,24832,24828],{"id":24833},"field-constants-coming-soon",[15,24835,24836,24384,24838,24388,24840,24842],{},[25,24837,24383],{},[95,24839,24387],{},[95,24841,24391],{}," as ch.47 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24844},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.47 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch47-field-constants\u002F1-coming-soon",{"title":24828,"description":24845},"shockwave-curriculum\u002Flessons\u002Fch47-field-constants\u002F47.1-coming-soon","a8ktZc3WozG6_JwDyFEAI3z8rI2LeP0hXY9bN-aFEW0",{"id":24852,"title":24853,"body":24854,"description":24870,"extension":51,"meta":24871,"navigation":55,"path":24872,"seo":24873,"stem":24874,"__hash__":24875},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch48-troubleshooting-i-runtime-debug\u002F48.1-coming-soon.md","Troubleshooting I — Runtime Debug — Coming Soon",{"type":8,"value":24855,"toc":24868},[24856,24859],[11,24857,24853],{"id":24858},"troubleshooting-i-runtime-debug-coming-soon",[15,24860,24861,24384,24863,24388,24865,24867],{},[25,24862,24383],{},[95,24864,24387],{},[95,24866,24391],{}," as ch.48 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24869},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.48 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch48-troubleshooting-i-runtime-debug\u002F1-coming-soon",{"title":24853,"description":24870},"shockwave-curriculum\u002Flessons\u002Fch48-troubleshooting-i-runtime-debug\u002F48.1-coming-soon","_4XiuTZOChP577VuOuT8yceslKTaWGotQPfcpQYY5fc",{"id":24877,"title":24878,"body":24879,"description":24895,"extension":51,"meta":24896,"navigation":55,"path":24897,"seo":24898,"stem":24899,"__hash__":24900},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch49-troubleshooting-ii-can-and-sim\u002F49.1-coming-soon.md","Troubleshooting II: CAN & Sim — Coming Soon",{"type":8,"value":24880,"toc":24893},[24881,24884],[11,24882,24878],{"id":24883},"troubleshooting-ii-can-sim-coming-soon",[15,24885,24886,24384,24888,24388,24890,24892],{},[25,24887,24383],{},[95,24889,24387],{},[95,24891,24391],{}," as ch.49 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24894},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.49 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch49-troubleshooting-ii-can-and-sim\u002F1-coming-soon",{"title":24878,"description":24895},"shockwave-curriculum\u002Flessons\u002Fch49-troubleshooting-ii-can-and-sim\u002F49.1-coming-soon","unI0IwJa4Vq84ME-J6VWSbAc8O7TrAOrPJGidYgiHd4",{"id":24902,"title":24903,"body":24904,"description":24920,"extension":51,"meta":24921,"navigation":55,"path":24922,"seo":24923,"stem":24924,"__hash__":24925},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch50-vendor-libraries-talonfx\u002F50.1-coming-soon.md","Vendor Libraries: TalonFX — Coming Soon",{"type":8,"value":24905,"toc":24918},[24906,24909],[11,24907,24903],{"id":24908},"vendor-libraries-talonfx-coming-soon",[15,24910,24911,24384,24913,24388,24915,24917],{},[25,24912,24383],{},[95,24914,24387],{},[95,24916,24391],{}," as ch.50 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24919},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.50 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch50-vendor-libraries-talonfx\u002F1-coming-soon",{"title":24903,"description":24920},"shockwave-curriculum\u002Flessons\u002Fch50-vendor-libraries-talonfx\u002F50.1-coming-soon","1tShFd6NcBTkIuFtydPVN-2xPSvfWSIWtco0Jp-Ahhk",{"id":24927,"title":24928,"body":24929,"description":24945,"extension":51,"meta":24946,"navigation":55,"path":24947,"seo":24948,"stem":24949,"__hash__":24950},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch51-robot-alerts\u002F51.1-coming-soon.md","Robot Alerts — Coming Soon",{"type":8,"value":24930,"toc":24943},[24931,24934],[11,24932,24928],{"id":24933},"robot-alerts-coming-soon",[15,24935,24936,24384,24938,24388,24940,24942],{},[25,24937,24383],{},[95,24939,24387],{},[95,24941,24391],{}," as ch.51 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24944},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.51 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch51-robot-alerts\u002F1-coming-soon",{"title":24928,"description":24945},"shockwave-curriculum\u002Flessons\u002Fch51-robot-alerts\u002F51.1-coming-soon","Z2WiXQpicwCc4bm0SwPxrMeuroLNco-1UUFrEVoCSxU",{"id":24952,"title":24953,"body":24954,"description":24970,"extension":51,"meta":24971,"navigation":55,"path":24972,"seo":24973,"stem":24974,"__hash__":24975},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch52-wpilib-commands\u002F52.1-coming-soon.md","WPILib Commands — Coming Soon",{"type":8,"value":24955,"toc":24968},[24956,24959],[11,24957,24953],{"id":24958},"wpilib-commands-coming-soon",[15,24960,24961,24384,24963,24388,24965,24967],{},[25,24962,24383],{},[95,24964,24387],{},[95,24966,24391],{}," as ch.52 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24969},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.52 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch52-wpilib-commands\u002F1-coming-soon",{"title":24953,"description":24970},"shockwave-curriculum\u002Flessons\u002Fch52-wpilib-commands\u002F52.1-coming-soon","KFzP0K-rOiqivxBmQp6-frv-pEC0fYGs3cqbn7qEX1o",{"id":24977,"title":24978,"body":24979,"description":24995,"extension":51,"meta":24996,"navigation":55,"path":24997,"seo":24998,"stem":24999,"__hash__":25000},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch53-wpilib-geometry\u002F53.1-coming-soon.md","WPILib Geometry — Coming Soon",{"type":8,"value":24980,"toc":24993},[24981,24984],[11,24982,24978],{"id":24983},"wpilib-geometry-coming-soon",[15,24985,24986,24384,24988,24388,24990,24992],{},[25,24987,24383],{},[95,24989,24387],{},[95,24991,24391],{}," as ch.53 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":24994},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.53 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch53-wpilib-geometry\u002F1-coming-soon",{"title":24978,"description":24995},"shockwave-curriculum\u002Flessons\u002Fch53-wpilib-geometry\u002F53.1-coming-soon","mF5JxRfkrR2HwXw4ER9LwnzYi6DwB7YriGn5zayFM5g",{"id":25002,"title":25003,"body":25004,"description":25020,"extension":51,"meta":25021,"navigation":55,"path":25022,"seo":25023,"stem":25024,"__hash__":25025},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch54-networktables\u002F54.1-coming-soon.md","NetworkTables — Coming Soon",{"type":8,"value":25005,"toc":25018},[25006,25009],[11,25007,25003],{"id":25008},"networktables-coming-soon",[15,25010,25011,24384,25013,24388,25015,25017],{},[25,25012,24383],{},[95,25014,24387],{},[95,25016,24391],{}," as ch.54 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":25019},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.54 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch54-networktables\u002F1-coming-soon",{"title":25003,"description":25020},"shockwave-curriculum\u002Flessons\u002Fch54-networktables\u002F54.1-coming-soon","QgC6BvwxvNw3dDOIRnZ2nDWKB-ne6weBH25QAVqFPi4",{"id":25027,"title":25028,"body":25029,"description":25045,"extension":51,"meta":25046,"navigation":55,"path":25047,"seo":25048,"stem":25049,"__hash__":25050},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch55-command-scheduler\u002F55.1-coming-soon.md","Command Scheduler — Coming Soon",{"type":8,"value":25030,"toc":25043},[25031,25034],[11,25032,25028],{"id":25033},"command-scheduler-coming-soon",[15,25035,25036,24384,25038,24388,25040,25042],{},[25,25037,24383],{},[95,25039,24387],{},[95,25041,24391],{}," as ch.55 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":25044},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.55 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch55-command-scheduler\u002F1-coming-soon",{"title":25028,"description":25045},"shockwave-curriculum\u002Flessons\u002Fch55-command-scheduler\u002F55.1-coming-soon","fkNl5L5cNx6U6RPevOT85fKF-bu6-3yyNYRDXCzaRCg",{"id":25052,"title":25053,"body":25054,"description":25070,"extension":51,"meta":25071,"navigation":55,"path":25072,"seo":25073,"stem":25074,"__hash__":25075},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch56-wpilib-timers\u002F56.1-coming-soon.md","WPILib Timers — Coming Soon",{"type":8,"value":25055,"toc":25068},[25056,25059],[11,25057,25053],{"id":25058},"wpilib-timers-coming-soon",[15,25060,25061,24384,25063,24388,25065,25067],{},[25,25062,24383],{},[95,25064,24387],{},[95,25066,24391],{}," as ch.56 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":25069},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.56 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch56-wpilib-timers\u002F1-coming-soon",{"title":25053,"description":25070},"shockwave-curriculum\u002Flessons\u002Fch56-wpilib-timers\u002F56.1-coming-soon","j53gGS9XX5XYY1Jnx3xax3GsrbD8Td7yFVBDeWhWqII",{"id":25077,"title":25078,"body":25079,"description":25095,"extension":51,"meta":25096,"navigation":55,"path":25097,"seo":25098,"stem":25099,"__hash__":25100},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch57-wpilib-triggers\u002F57.1-coming-soon.md","WPILib Triggers — Coming Soon",{"type":8,"value":25080,"toc":25093},[25081,25084],[11,25082,25078],{"id":25083},"wpilib-triggers-coming-soon",[15,25085,25086,24384,25088,24388,25090,25092],{},[25,25087,24383],{},[95,25089,24387],{},[95,25091,24391],{}," as ch.57 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":25094},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.57 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch57-wpilib-triggers\u002F1-coming-soon",{"title":25078,"description":25095},"shockwave-curriculum\u002Flessons\u002Fch57-wpilib-triggers\u002F57.1-coming-soon","tr1mylUItEAtKeIM3P-dciBfUXMgdpZercpu6GRZRn0",{"id":25102,"title":25103,"body":25104,"description":25120,"extension":51,"meta":25121,"navigation":55,"path":25122,"seo":25123,"stem":25124,"__hash__":25125},"lessons\u002Fshockwave-curriculum\u002Flessons\u002Fch58-vendor-units-and-conversions\u002F58.1-coming-soon.md","Vendor Units & Conversions — Coming Soon",{"type":8,"value":25105,"toc":25118},[25106,25109],[11,25107,25103],{"id":25108},"vendor-units-conversions-coming-soon",[15,25110,25111,24384,25113,24388,25115,25117],{},[25,25112,24383],{},[95,25114,24387],{},[95,25116,24391],{}," as ch.58 — content for this lesson hasn't been written.",{"title":48,"searchDepth":49,"depth":49,"links":25119},[],"Status: placeholder chapter, not authored yet. Pulled from mechacoder-full-deck.html\ninto curriculum-ledger.html as ch.58 — content for this lesson hasn't been written.",{},"\u002Fshockwave-curriculum\u002Flessons\u002Fch58-vendor-units-and-conversions\u002F1-coming-soon",{"title":25103,"description":25120},"shockwave-curriculum\u002Flessons\u002Fch58-vendor-units-and-conversions\u002F58.1-coming-soon","2OHHF-0EcaVd9T8-rM4dCXRNlRyQm25w59obJ9a2ggk",1790274946612]