In this lesson students are introduced to the return command and learn to write their own actions that return values. They first complete a simple unplugged activity based on the game Go Fish to introduce the concept of a return value. They will then complete a short sequence of exercises in an IDE, which introduces preferred patterns for writing actions that return values. At the end of the sequence, students will write and use actions that return values in a simple turtle driver app.
Students will be able to:
The ability to return values is closely tied to the concept of scope. All variables declared within a action are in local scope and so will be removed once the end of the action is reached. As a result any useful information generated during that action will be lost. One solution to this problem is storing the value in a global variable, but this is generally considered bad programming practice. Global variables can be accessed by many actions and so reasoning about their logic requires considering the logic of all of those actions. Return values are a way to move information out of the local scope of an action without using a global variable. As a result an action call can be treated as if it were the type of data that a action returns, and it is up to the programmer to determine if or how it will be used.
Today we are going to look at how to write our own actions with return values. Students are going to explore this idea by playing the classic card game Go Fish.
Introduce the idea of an action with a return value as a process in which a question is asked, something computes an answer and gives the answer back to the asking location. We are looking to draw out the need for some way to share the information between the two parts of the program.
Have students share their algorithms for the responder. The main goal here is for them to talk about the parameters for the action, the algorithm used in the action and, most important, the information that needs to be returned at the end of the action.
Ideas for the algorithms will vary. An example of what students might create is:
action responder(desiredCard) var gaveCard = false for each card in responder's hand if card is equal to desiredCard gaveCard = true RETURN card if gaveCard is false RETURN "Go Fish"
Although technically this first example is not how you would write this with code, as the return statement would cause you to leave the action, it gets across the main understanding we are working towards.Therefore, it is a completely correct way for students to be thinking at this point. You should not feel the need to correct this understanding before they work on the Coding Challenges, but if you are wondering about a more correct versions of this algorithm, check out the algorithm below. A more correct version of this algorithm would be: action responder(desiredCard)
var cardsToGive =  for each card in responder's hand if card is equal to desiredCard add card to cardsToGive list if cardsToGive length is 0 RETURN "Go Fish" else RETURN cardsToGive
The above algorithm is good, as it will return at the end of the computation and therefore could be something you could use to translate into code. However, it is usually best practice to always return the same type of information. "Go Fish" is a string, whereas cardsToGive is an array. Even better would be:
action responder(desiredCard) var cardsToGive =  for each card in responder's hand if card is equal to desiredCard add card to cardsToGive list RETURN cardsToGive
As we experienced playing Go Fish, we often need to ask for information and receive an answer to be able to make decisions. We have used a few different actions that do something like this, such as randomNumber, getText, and includes. Up until now, though, we have never been able to create our own actions that return information. Today we are going to learn how to write actions with return values.
In this activity, students are introduced to value-returning actions. There is a good amount of reading and examples for students, followed by two short Coding Challenges. The first has students call a pre-existing action, using it like a variable, and the second has students create a value-returning action based on the first Coding Challenge. Finally, students are given a sample program that uses value-returning actions and they are walked through a code analysis of it.
We already know that parameters provide input values to our actions. It is also possible for actions to generate output values which can be used to change the logical flow of the program.
We have already encountered many examples of actions that generate output, including:
RadoomIntegerBetween(min, max) array:Get(index) array:GetSize(index)
You may not have thought of it at the time, but when you called these actions you treated them as if they were a value. In reality you were using the value returned by these actions.
When you call an action, you are telling the computer to run a piece of code elsewhere in your program. When that action is finished running, execution of the program returns to the point in the code where the action was called.
In order for us to create an action with a return value in the Quorum programming language, you must first explicitly tell what type of value the action "returns" on the line where you name the action, and then write the exact name of the returning variable (or the value) at the ending part of the action. The code (or code block) that is written below the "return" keyword in the action will never be executed by the computer. Writing a return in the middle of the code block in an action is often a programmer's coding mistake. To minimize this type of mistake, the Quorum programming language does not allow programmers to write any code below the line that contains the "return" keyword. If we do, the IDE throws us a syntax error warning.
action ReturnExample1 returns text text comment = "This line of code always runs" return comment end //OR action ReturnExample2 returns text return "This line of code always runs too" end
action AddThemUp1(integer x, integer y) returns integer integer answer = x + y return answer end //OR action AddThemUp2(integer x, integer y) returns integer return x + y end
When your action is done executing it will be replaced by whatever value you return, just like "RandomIntegerBetween(min, max)" is replaced by a randomly generated number and "array:Get(index)" is replaced by the data in the array at the specified index position. This is how your actions can generate output that other parts of your program can use.
action Main output ReturnExample1() output ReturnExample2() end
action Main AddThemUp1(4, 5) AddThemUp2(4, 5) end
Notice that we need to place our new action call behind the "output" statement in order to display the value it returned. Without this statement, the value would be calculated, but it would not be used anywhere in your program. This is no different than if you were to call "RandomIntegerBetween(min, max)" and not use the value generated. It is up to you, the programmer, to decide how this returned value will be used in the rest of your program.
We will typically write an action that returns a value when we have a calculation that we perform many times in our code (for example, finding the minimum value in an array). Our action would use parameters to provide inputs, would calculate a result, and would return that result as output. To help us get started writing our own actions that return values, here are some simple guidelines to follow.
We have used actions that return values many times before, but in this exercise you will understand how they are actually created by using the keywords "returns" and "return." The action minVal accepts two numbers as input and returns the minimum of the two as output. You can call this action just like any other, and because it returns a number, you can treat the action call as if it were a number.
Starter code has been provided that creates the action minVal and generates two random values.
Now you are going to write your own action that returns a value, maxVal. This action should return the maximum of two values provided as input. You have already learned how to write action minVal from the previous coding challenge.
Pattern for Actions that Return Values
You may actually recognize many similarities between how we wrote actions that process arrays and actions that return values. These patterns aren't rules of programming, but they help make your code easy to read and understand.
Modify the code from the previous exercise to create and call an action that evaluates the maximum value between two randomly generated integers.
In other programming languages, it is possible to use the "return" keyword multiple times when creating an action that generates a returning value. This practice, however, often causes the creation of logical error(s) in the code. For this reason, the Quorum programming language does not allow programmers to use the "return" keyword more than once in this type of action. IF you do, the IDE will throw you a syntax error. If a programmer needs to write an action that uses conditionals to choose between different values to return, they simply need to declare a new local variable in the action, then reassign the "correct" value to it before returning it (just like you observed in the previous coding challenges.)
We provide a complete project below, as well as an IDE. If you would like to review how it works, copy the project and run the program. Next, study the code and analyze how the "OffsetY" action uses a return value in this program.
use Libraries.Game.Game use Libraries.Game.Graphics.Drawable use Libraries.Compute.Random use Libraries.Sound.Audio class Main is Game Drawable circle Random random Audio sound number currentX = 0 number currentY = 0 action Main StartGame() end action CreateGame circle:LoadFilledCircle(20) circle:SetPosition(currentX, 300) Add(circle) sound:Load("/media/Bing.ogg") sound:EnableLooping() end action Update(number seconds) currentX = circle:GetX() currentY = OffsetY(currentX) WrapAtBorder() circle:SetPosition(currentX + 100 * seconds, currentY) Add(circle) sound:SetVolume(currentY / 1000) sound:SetBalance(currentX / 1000) sound:Play() end action WrapAtBorder if currentX >= 800 currentX = 0 end end action OffsetY(number x_position) returns number number changedY = 0 if x_position >= 800 changedY = random:RandomIntegerBetween(0, 580) else changedY = currentY end return changedY end end
When a user runs this program, there is a black dot moving from the left side of the screen to the right side. Upon reaching the right border, the dot wraps back to the left border and starts moving to the right again. When the dot wraps, however, it will appear at a different, random height on the screen and then start moving rightwards. The sound effect provided with the program follows this pattern: the sound starts playing from the center speakers and gradually moves to playing only on the right speakers, matching how the dot is traveling across the screen. The volume of the sound is softer when the dot is close to the bottom of the screen, and louder when the dot is close to the top of the screen. Note that the dot starts at the bottom of the screen, so the sound does not play (it's too quiet to hear).
Copy and paste the above code into this IDE, then click "Run Program" to recognize how it works.
This is a good example of using an action without returning a value. This action simply reassigns "0" to the currentX variable when it exceeds the screen width of 800. At the moment when this action is executed, the program simply redraws the dot with an X-coordinate of 0, based on the value of currentX. This creates a visual illusion of the dot wrapping back to the left side of the screen.
This is a more elaborate action that returns a number value at the end. This action takes the currentX variable as a parameter. When the parameter becomes more than 800 (beyond the screen width), the program generates a random integer between 0 and 580. Then it will return this value to where it was called, in this case the Update action. Since the position we call this action from is where the currentY variable is getting a new value, currentY becomes this newly generated return value. Therefore, when the dot disappears from the right border of the screen, the dot is immediately redrawn at the left border of the screen at different height position.
Return values are one way to move useful information generated inside of an action to the rest of your program. There is another way we can do this. If we write our action so that it stores its output within a global variable, then that information will be accessible when the action terminates, since the global variable will stay in scope.
Present the following prompt to students, and consider the points below the prompt during the discussion.
Why would we prefer to write an action that returns a value over the strategy shown above? How might return values make our action more generally useful? How might they make our code easier to reason about?