Note
|
I promised I’d removed some of the more deep-dive content from this year’s content to streamline the lab. This is one such activity. |
Scopes
Notice the brackets on the if statement. There is an important interaction with declaring variables you need
to be aware of. It is related to the concept of scope. For our purposes, we are going to treat 'scope'
as being between a set of curley brackets. A scope begins at the starting curley bracket {
and a scope
ends }
at the closing curley bracket (there are actually more complex notions of scope in other programming
languages, but this will do us just fine for now).
Variables only exist in the scope they were declared. Their lifetime is also often bounded by their scope.
Note
|
There are ways for variables (or their contents) to escape this scope, it usually involves poorly designed programs, language hacks, or languages with a different idea of 'scope' but we’ll file that under, "definately not first year, first session content". Its also far more common in other languages (like python, javascript or C++). |
In other words, the varaible exists from the point you declare it to the closing bracket that contains that declaration. I know that sounds complicated, but the idea is much easier when its demonstated.
Let me show you:
void Main(string[] args) {
int myNumber = 42; // (1)
if ( myNumber == 42 ) {
string myWord = "banana"; // (2)
// I'm just doing this to show it's allowed, it will have no effect as it's already 42
myNumber = 42;
}
Console.WriteLine("MyNumber is: {0:D}", myNumber); // (3)
}
-
is a variable declaration inside the function’s scope, it stops existing at the end bracket (
}
) of the function -
is a variable declaration inside the if statement’s scope, it stops existing at the end of the if statement.
-
is after the end bracket of the if statement, therefore myWord no longer exists, but before the closing bracket for the function, therefore myNumber still exists
Because, 'myWord' only exists in the scope of the if statement, we cannot use it outside the statement. Likewise, if we had another function, the variables declared in this function cannot be used outside it. This concept can take a little while to get your head around, but it makes reasoning about what our code is doing a lot simplier.
Variable assignment vs declaration
Ok, so let’s take a look at another situation. Lets assume (for a reason that’s not in any way related to the advanced section below this one) we have a situation where we want to set the value of a variable depending on some if some condition is true or false.
void Main(string[] args) {
int myNumber = 42; // (1)
if ( myNumber == 42 ) {
string myWord = "forty-two"; // (2)
} else {
string myWord = "not forty-two"; // (3)
}
// THIS CODE WILL NOT COMPILE.
Console.WriteLine("MyNumber is: {0:D}, this is: {1:S}", myNumber, myWord); // (4)
}
-
myNumber, as declared before
-
variable declared inside the if statement
-
varaible declared inside the else statement
-
attempt to use a non-existant variable called myWord
Q Take a moment to think about what i’ve said about scope to reason why this code is incorrect. Why is this the case?
Reveal Answer
The code above declares two variables in different scopes but with the same name. Because they are in different scopes this is allowed. However, because the variable’s scope ends at the curley bracket where it was declared, neither of these exist on line (4).
Therefore, there is no variable called myWord
in scope on line (4), and the compiler tells us off.
Q How could we fix this?
We already have all the tools we need at our disposal, I’ve included a chain of reasoning as to how you might arrive at this solution, but it’s a bit convoluted:
Reveal answer
-
We know for the variable to be in scope on (4), the 'closing bracket' that 'ends its scope' must be after (4).
-
We know variables declared in the function directly (as we did on (1) will exist on (4))
-
From my extra assignment in the 'hello world' example (line (2) in that code snippet), we know we can assign variables after they are created
-
Assignment inside if statements is allowed, I cautioned you about programming languages which could restrict this ealier in 'avoiding else', I also had that odd comment in the if statement example showing you it was possible.
-
The if statement’s scope includes the function that contains it (it’s not before the ending bracket for the function after all)
-
Lastly, we know that a variable can only be used after it is declared, therefore the variable declaration must occour before the if statement.
If we put all that together, we end up with the following:
void Main(string[] args) {
int myNumber = 42;
string myWord;
if ( myNumber == 42 ) {
myWord = "forty-two";
} else {
myWord = "not forty-two";
}
Console.WriteLine("MyNumber is: {0:D}, this is: {1:S}", myNumber, myWord);
}
You could also alter this to assign, "not forty-two" to myWord when it is declared, and remove the need for the else statement.
Plurals, formatting strings and code duplication
Note
|
I’m now going to give you a choice. I mentioned playing with formatting strings ealier. You can choose to do so, by doing this section. I recommend pairing up with another member of the cohort Note I labelled as advanced. If you’d rather just follow along with the guide, skip over this section. Be aware that the advanced sections in my materials are designed to provide insights, but may feature content we’ve not covered yet, and so don’t find it disheartening if you find it challenging! |
As mentioned in my 'code vs codes' note ealier, sometimes natural language(s) can break rules, words can also
change depending on context. In this case, the word light is lights when plural. Alter the code I gave you
ealier. Alter the assignment on the line I marked with a (2)
to assign the value 1
, and rerun the code.
What is the output?
Reveal Answer
There are 1 lights
Light vs Lights
The statement there are 1 lights
is not grammatically correct. There should be 1 light, not 1 lights.
Note
|
There is another issue with the statement, but for now 'light vs lights' is the only issue I want you to fix for this part (you’ll see why after you have completed it). Fixing both grammatical errors actually does not fulfil the requirements I will set out in the task box. |
There are many ways you could fix this:
-
You could wrap the whole output in an if statement, duplicating the
WriteLine
call for both cases -
You could use an if statement and a
string
variable to swap out the formatting string (this is also how you could implement basic support for outputs in other languages, like French). There is a potential issue with scope in this case. -
You could use a (string) variable to store either 'light' or 'lights', and insert it as another formatting item into the string. Again be careful with variable scope.
-
You could use a Ternary Conditional and a formatting item as one of the arguments to the formatting string, avoiding the need for another variable
-
Something else entirely
In pairs (or small groups) discuss and research which of these approaches makes the most sense.
Modify the code in such a way that:
-
The output when
myValue
is 1 is: There are 1 light. -
The output when
myValue
is not 1 is: There are n lights.
Where, n is the current value of the variable myValue.
Try your solution with the following cases:
MyValue Value | Expected Output |
---|---|
0 |
There are 0 lights |
1 |
There are 1 light |
4 |
There are 4 lights |
-120 |
There are -120 lights |
N.B. for this part, the output, 'There is 1 light' is considered an incorrect output.
Are vs Is
Many solutions often involve trade-offs. Some of the approaches I mentioned will make solving these next tasks easier and some will be more complicated. You can still solve it using all three of the above approaches, but it will involve more work.
The statement 'there are 1 light' is not correct, it would be better if it was, 'there is 1 light'.
You have a few ways to fix this, depending on the approach taken in part 1 (hence why I didn’t want you to fix both issues):
-
If you duplicated the statement entirely, you can get away with just modifying the bit that corrisponds to the
myValue == 1
case -
If you used a variable to store the formatting string, you will need to modify the formatting string for the
myValue == 1
case -
If you used another formatting item and a variable, you can use a second formatting item (and another variable) to deal with the 'is' and 'are' issue
-
If you used a ternary, you are in good company, before I spotted the 'are vs is' issue when writing this, that would have been my perferred solution. Your code will need to be slightly more complicated now. You can use two ternaries (one for choosing the singular or plural form, one for choosing 'is', or 'are').
-
You could mix solutions, using one of these approaches for part 1, and another for part 2
In pairs (or small groups) discuss and research which of these approaches makes the most sense.
Modify the code in such a way that:
-
The output when
myValue
is 1 is: There is 1 light. -
The output when
myValue
is not 1 is: There are n lights.
Where, n is the current value of the variable myValue.
Try your solution with the following cases:
MyValue Value | Expected Output |
---|---|
0 |
There are 0 lights |
1 |
There is 1 light |
4 |
There are 4 lights |
-120 |
There are -120 lights |
N.B. for this part, the output, 'There is 1 light' is considered an correct output, and 'There are 1 light' is considered incorrect output.
Nouns and English
English nouns are quite complicated, and there are many exceptions to just being able to add s to the end. Sorry if that was how you dealt with part 1 or 2. I’m about to ruin your day.
Let’s modify your code to work with some other nouns. Try doing these in order, as I make the progressivly more annoying.
Modify the code in such a way that it correctly displays output for the following cases:
Singular | Plural |
---|---|
Apple |
Apples |
Sheep |
Sheep |
Mouse |
Mice |
Cactus |
Cacti |
You do not need to make it work for all these cases at the same time. You can alter your solution for each one in turn. You could also comment out your solutions if you want to keep them.
I’ll show you a better way to keep track of changes between versions later (Git). You’ll also need that for GAM102.
Discuss with another pair, or in your group the following points:
-
What approach(es) did you take and why?
-
How well did your approach deal with these modifications?
-
Did you find any of these cases particularly challenging or annoying to deal with?
-
Knowing what you know now, would you have chosen a different approach?
Changing requirements
As programmers, we often need to deal with changing requrirements. Many of the approaches and methods of writing code are aimed at simplying the process of making modifications to our code - that and ensuring we’re dealing with the right level of abstraction. All of that complexity I skipped over ealier (namespaces, classes) are (arguably) a result of this mindset.
If I’d asked for a different set of changes, the 'best' approach might have been different, for example:
-
the output should now treat
myValue
as a time in seconds and represents the number of seconds it takes to boil an egg, and should therefore output, "the amount of time required to boil an egg is n seconds", -
Output to a text file rather than a terminal window, you would need to alter every call to
System.WriteLine
, solutions which duplicatedSystem.WriteLine
would mean needing to change the code in multiple places. -
What if I told you that you needed to be able to support a fictional language which has special cases for
1
but also treats even values differently than odd ones? You would need to add additional conditions to your if statements, or and using turnaries becomes a complete mess. -
What if the code needed to support other languages? Solutions which didn’t duplicate the whole formatting string might have a hard time dealing with the changes in sentence structure
Many of the problem solving techniques programmers have developed are about trying to make such changes easy to make. We’ll look at this idea more in the future.