Yeah, calling a loop an example of abstraction is probably not right. Your response is good. Let me ramble here a few more thoughts that might help you (and your student(s))
-
First, let’s just get this out of the way: for all practical purposes when it comes to the AP Performance Task “abstraction” means a “function”. So you are never wrong to point to some function you wrote, call that the abstraction, and explain what it does. (There are other things you might “abstract” but the easy one is always a function).
-
There is a particular nuance to “reducing complexity” that is part of an abstraction that I think is missing from your student’s response – and that is about hiding unnecessary or complicated details. “Unnecessary” here means unnecessary for understanding what the code is doing.
-
related - Another typical property of an abstraction is that it nicely “encapsulates” a solution to a problem, and presumably that solution can be re-used and applied to other larger problems or in other contexts without having to worry about the inner details. Once you have encapsulated a solution to a problem it’s specific details can be put out of mind, freeing your mind to solve more complex problems.
Here is an example – Take this code, something akin to your student’s loop, I assume.
for(var i=0; i<4; i++){
moveForward(100);
turnLeft(90);
}
In some sense this loop makes the code less complicated than it otherwise would be because without the loop you’d need many more lines. But as a reader of this code, to understand what it’s doing, I have to consider the details, I have reason about it, and mentally trace it out to figure out what it’s doing. Now if instead the line of code were:
drawSqaure(100);
I don’t even have to think it all to understand what this is trying to do. It reduces complexity because it hides details about exactly how the square is being drawn - really it doesn’t matter whether this function is implemented with a loop or not if what I care about is drawing a square - which makes it easier for me to reason about and furthermore to use the drawSquare behavior in other code that needs square-drawing.
drawSquare is a very small example, but when faced with programs or problems where the code is really complex and tough to reason about, bottling it up into a well-named function really helps. And also, loops usually complicate code because they are hard to reason about.
Here’s another example to prove my point. Imagine you’re reading along in some code and you come across this chunk that uses a loop. Try to figure out what it’s doing:
var newStr ="";
for(var i=0; i<str.length; i++){
var ascii = str[i].charCodeAt(0);
if(ascii >= 97 && ascii <= 122){
ascii-=32;
}
newStr += String.fromCharCode(ascii);
}
Now what if instead, you were reading along in some code and found:
convertToUpperCase(str);
Even if I am an expert and can read the first code segment and figure out what it’s doing in 5 seconds - it’s NOT abstract. It’s a very concrete, explicit process for converting characters to upper case. It takes some amount of brain power to figure it out. Whereas, that same code encapsulated in a function convertToUpperCase
it takes me no time to understand and I can use my brain for other things, like whatever larger task I need this case conversion for.
I think it’s fair to say with abstractions there is a bit of a you-know-it-when-you-see-it kind of thing that comes with experience and is hard for the new student to grok. And it’s hard to define because you can start to go down the rabbit’s hole with abstraction - let’s not forget that EVERYTHING we do on the computer is an abstraction in some sense - the whole machine is an abstraction. You’re seeing characters on the screen that are being represented by pulses of electricity behind the screen.
I hope this helps.