Introduction to Programming: Comment on Test 1

I thought it would be worthwhile, now the test has been marked, to make some comments on commonly occurring errors and problems in the answers to the tests.

The test was marked out of 80, and the 20 marks for each question were divided equally among its parts (except 2e had 5 marks with 3 for the rest of question 2).

Question 1

Part a

It was important here to note that the standard Java compiler does not translate Java code into the machine code which a computer obeys directly. Rather, it translates it into an intermediate form called Java byte code which is similar to machine code but is run by another program (called an interpreter) going through it and making the machine obey it.

The reason for this is that if a language compiles directly to machine code there has to be a separate compiler for every type of machine, and the compiled version of the program for one type of machine won't run on another type of machine. In Java there has to be a separate Java byte code interpreter for each type of machine, but as Java byte code is always the same for any machine, the compiled version of Java can be run on any machine that has a Java byte code interpreter. This gives Java programs their "run anywhere" property.

Part b

It is important to remember that aliasing only occurs with object values. Many people gave examples which suggested they believed it also occurred with primitive values (i.e. numbers of various sorts). If we have two int variables, a and b, then executing a=b will cause the value of a to be copied to b, but there is no aliasing: after that there are no links of any sort between b and a, so changing the value one of them stores will not affect the other.

Aliasing is only going to matter with mutable objects (that is objects whose field values can be changed either because they are not declared as private or they have methods that can chage them). In that case, after executing a=b the two variables a and b do refer to the same object. It will be the object which b referred to before the assignment was executed. Then, making a change to the object by calling a method on either a or b, or assigning a new value to a non-private field of a or b will change the object both refer to as it is literally the same object. Note, if either a or b is later assigned to another object that does not change what the other of them refers to. So if we later do b=c, then b will refer to the object which c referred to previously (and c will still refer to it). But a will stay referring to the object which b used to refer to.

Note it is possible for two separate objects to have data of equal values stored in their own fields. This is not aliasing. Aliasing refers to two or more names for the same object, not two or more identical but separate objects.

Part c

There are only two short-circuit operators, && and ||, so it was strange that a lot of people wrote an answer here which was too general, written as if there were large numbers of different short circuit operators with different numbers of operands. Actually, you could say there is a third short-circuit operator, the conditional operator ?:, since with exp1?exp2:exp3, the expression exp2 is only evaluated if exp1 evaluates to true and exp3 is only evaluated if exp1 evaluates to false.

So what was expected was a precise description of how && works, that is that in an expression of the form exp1&&exp2, the subexpression exp2 is only evaluated if exp1 evaluates to true. This will only have an effect if exp2 has a side-effect (i.e. evaluating it can change the state of something) or evaluating it can cause an exception. So exp2 cannot just be a variable (some people wrongly referred to it as that).

However, the question did not ask for an expression which would demonstrate that the operator has a short-circuit effect. Some people chose to answer the question by giving such an expression but without actually explaining what is meant by short-circuiting with respect to the && operator. There were no marks for that, as it didn't answer the question.

Part d

A lot of people confused scope with access. The question was not about where you could access fields and methods of an object, so it was not about public and private. It was about variables declared within a method, so they exist only as long as the method is being executed in order to hold values temporarily needed by that method. In Java you can declare a variable not just within a method but within a block inside a loop, if statement or try-catch statement. In that case the variable only exists for as long as the block is executed. A block is the set of statements enclosed by { and }.

Question 2

Part a

The major mistake made here was to forget that the division operator / has higher precedence than the subtraction operator -. So the expression a-b/c should be interpreted as a-(b/c) and not as (a-b)/c. Some people who got that bit right forgot that division of two integers in Java gives an integer. So b/c where b stores 10 and c stores 3 results in 3 and not 3.3333333333333. It certainly does not result in 3 followed by a symbol which is a 1 on top of a horizontal bar on top of a 3 (I'm not sure I can do that symbol in HTML). Remember when you are asked to write what would be printed, you are expected to write exactly what would be printed, and it ought to be obvious that a one third symbol would not be.

Part b

The main thing to remember here is that b*=a+1 multiplies b by a+1. It does not multiply b by a and then add 1 to the result.

Part c

Here the main point is that ++c means "add 1 to the value of c then use it". So the value that is passed to be printed out is one greater than the previous value of c. But remember (though it wasn't tested in this part of the question) that c keeps its new value, so if there were another line after the System.out.println(++c); line, c would have the value 13 in that line.

Part d

The expression exp1?exp2:exp3, evaluates to the value of expression exp2 if exp1 evaluates to true and to the value of exp3 if exp1 evaluates to false. People who didn't know this, presumably because they weren't at the lecture where it was talked about, were, obviously, stuck on this question.

The ?: is a little obscure - you don't see it that often, you never really have to use it, and it's often mentioned as an afterthought in textbooks. But if you're familiar with it, you won't be confused if you come across some code where someone has decided to use it.

Part e

Here the main point is that a-- means "use the value of a then subtract 1 from it". So when a holds the value 9, the statement b=a-- means "use the value of a (i.e. 9) in the assignment, then subtract 1 from it". So b ends up as 9 and a ends up as 8. The ++ and -- operators have a permanent effect, so in this case a stays with the value of 8 until it is assigned a new value in the statement a=b*2.

Also in this part it should again be remembered that what was asked for was exactly what would be printed. The println call prints the three number with a spaces in between them, not commas. A few people still have not grasped that + when a string is involved means "join the string representations" and not "arithmetic add", and of course " " is a string, the string consisting of one space character.

Part f

This part was a check on whether you could remember type casting with numbers. Type casting has higher precedence than arithmetic operators, so (double)a/b is ((double)a)/b and not (double)(a/b). In other words, the double equivalent of the value of a is divided by the value of b. As a has the value 8, its double equivalent is 8.0 and dividing by 3 (the value of b) gives 2.6666667, or rather the closest that can be got to two and two thirds represented in the way Java represents fractional number. If (double)a/b were interpreted the other way round, you would have integer division of 8 by 3, resulting in 2 and then the conversion to a double resulting in d being set to 2.0.

But note that in a similar way, (int)d*2 is interpreted as ((int)d)*2 and not as (int)(d*2). In other words, the integer conversion of d is found first and that is multiplied by 2. As d has value 2.6666667 or thereabouts, the integer conversion gives the value 2 and that is multiplied by 2 in c=(int)d*2 to give c the value 4. It's not the case that d is multiplied by 2 first, giving 5.3333333 and that is converted to an integer.

Question 3

Part a

A lot of people gave answers involving forms like a<b<c. That is not valid Java, and there was no excuse for not knowing that as it was explained why not in a lecture. Computer languages are not like human languages where we can deduce a meaning if a sentence isn't quite grammatical. If the grammar is wrong when you write something in a programming language, it won't compile and that's it. It may be obvious to us that a<b<c is meant to mean "a is less than b and b is less than c" but it isn't to Java. Java doesn't have that form so if you tried to write a program using it, you would get a compiler error.

The reason it is not valid Java is that as < is a binary operator (i.e. takes two arguments, one to its left, the other to its right), a<b<c must be interpreted as either (a<b)<c or a<(b<c). But neither of these makes sense because both would involve comparing a boolean (i.e. true or false, the result of the < within the brackets) with an integer, which doesn't make sense.

A more subtle error in this question is that it didn't actually state that a was less than c, though a lot of people assumed it. As it wasn't stated, you had also to allow for the case that c was the lowest, b the middle and c the highest, and print Yes in that case.

By the way, when the question asked for code that printed Yes it meant that, and not YES. It is important to be precise when writing programs, and if you are told to write a program to do something make sure it does exactly that. You don't know what the code you're writing is for, it may be used to provide input for another program that tests for Yes and not YES. The very earliest computers made no distinction between small and capital letters but that was back in the Stone Age when computer memory was so expensive that it made sense to save space by minimising the set of characters usable, and anyway computers just calculated and printed numbers. Most of you weren't even born when that was the case, so there is no excuse for ignoring case sensitivity now.

That also applies to writing Java reserved words (if, while etc.) - they use small letters and it's a mistake to use capital letters, Java won't interpret If as an if and so on. Capital letters are used in Java in words like String, but that's a predefined object-type, and charAt but that's a predefined method, neither are reserved words which are things that can't be analysed in any other way than as symbols of Java. Of course, it's equally wrong to use string for String and so on.

Another point on this question is that the question told you that you have three int variables a, b and c, which have been given values. So it is assumed you are writing a piece of code to put below an existing piece of code which already has a line int a,b,c; plus further code to give values to a, b and c (or some other code which has the same effect). It is therefore wrong to write as part of your answer int a,b,c;. The effect of that is to declare three new variables called a, b and c. Depending on circumstances (to do with scope, as mentioned in question 1d), this would either be an error or would mean the rest of your code refers to these three new variables which have no connection to the a, b and c of the question.

A final point is that a lot of people seemed to be making up notation that doesn't exist in Java. In some cases, from my knowledge of other programming languages, they're using something from Pascal or Basic, for example using the word and as in Pascal, rather than Java's &&. This indicates the danger of thinking you know how to program from previous experience. Since all you need for the test was explained in the lectures, and can also be found in the web notes and in your textbooks, using notation from a language you studied previously suggests you haven't been working hard enough at studying Java. Plenty of those making mistakes which suggest pre-university familiarity with another language haven't got very far on other aspects of the test. This indicates that pre-university programming experience may not be as helpful as those without it sometimes imagine. Sometimes it's a case of not realising how trivial the pre-university programming was, other times the pre-university experience actually makes it harder to start thinking about programming in the object-oriented style of Java.

A few people simply made up notation of their own, for example, b!<a for "b not less than a". Maybe this seems as if it ought to work, since != is Java's symbol for "not equal". However, it doesn't work - the symbol b!<a is not in any Java textbook or web site, and the test was open book so you could check that. Also the mathematical "less than or equal" and "greater than or equal" signs (I can just about render them in HTML as < and >) are not valid Java operators. That ought to be obvious, since how would you be able to type them into a Java program without a key on the computer keyboard for them? When you are asked to write a Java program, do be accurate, and that involves little things like using the correct <= and >= for "less than or equal" and "greater than or equal".

Part b

O.K., now we're onto the big one, and I never expected this would cause the problems it did. "Call a method on a variable with an argument" is something we have been doing right from week 3 with the Ship examples. When in ShipMain4.java we had the statement argo.setCourse(90) we were calling method setCourse on variable argo with argument 90.

When it's stated that a method has signature boolean hit(int force) it means when the method is called it must be attached to an object. If the method was declared as static its call should be attached to the name of its class, but hit wasn't declared as static. Attaching a method to an object means you have a reference to an object, followed by a dot, followed by the call. Usually the reference is a variable which has been set to refer to an object.

You were told that punchbag was a variable on which that method could be called. You didn't need to know anything else about the method other than that fact and its signature. That fact meant you could write punchbag.hit(arguments). As the return type of hit was given as boolean the expression punchbag.hit(arguments) evaluates to a boolean value, i.e. either true or false. So what happens is that anywhere where punchbag.hit(arguments) occurs in your code, when the computer evalutes that code, it will go away, execute the code in the hit method, which will eventually return true or false. You don't need to know, and weren't told in the question how it does it. All you need to know is what you are told by that return type, that where you wrote punchbag.hit(arguments) it's writing something that will actually become true or false when the code is evaluated, only you don't know which until that happens.

Now, in punchbag.hit(arguments), what arguments must be is given by what appears between the opening and closing bracket in the signature. There is one int argument given there called force. It doesn't matter what the argument is called, because that's only really relevant to the code for the method, which you weren't given. What it means is that in your call to hit, you must make arguments one thing which evaluates to an integer value. The question tells you that you have one such thing, a variable of type int called b, and it tells you to use it as an argument. So your call to hit on punchbag with argument b cannot be anything except:

punchbag.hit(b)
What actually happens when punchbag.hit(b) is executed is that the code for the method hit is executed with force, the name given to its int parameter, replaced by b, the call argument.

The next issue is how to keep making that call until the number of times in variable c or until it returns false. We can do something a certain number of times by setting another variable to 0 and increasing it by 1 each time until it reaches the value. The question stated that we could use the variable a to store temporary values. We can exit a loop before its condition is met by using break, and this is technique is used in the following solution:

a=0;
while(a<c)
   {
    if(!punchbag.hit(b))
       break;
    a++;
   }
When you test the value of punchbag.hit(b) in the condition of the if statement here it does actually call the method, so it is called each time round the loop. The symbol ! is Java's "not" operator, which must be applied to a boolean expression. So if punchbag.hit(b) returns false then !punchbag.hit(b) is equivalent to !false which is true, so break is then obeyed which causes execution to leave the loop. Otherwise, a is increased by one and we go to the top of the loop and test whether it is still less than c, exiting the loop if it isn't, obeying the loop again if it is.

Note the importance of good layout here. While the Java compiler doesn't require it, it's essential to make your program easier for the human reader to pick up. I prefer the closing } to be directly below the opening { and both to be at the beginning of the line, but many authors recommend a style where the opening { is on the same line as the while and the closing } is directly below the w, giving:

a=0;
while(a<c) {
   if(!punchbag.hit(b))
      break;
   a++;
}
I think that's makes it a little less clear what the structure is at a glance, but it's still perfectly acceptable. What is unacceptable is what many people wrote, something like:
a=0;
while(a<c) {
   if(!punchbag.hit(b))
      break;
   a++;    }
That's a sort of combination of the worse aspects of the previous layouts, and makes the structure of your code harder to see at a glance. I have never ever seen a textbook which recommends that code be laid out like that, so it's a mystery why so many students write code like that in tests and exams.

What's even worse than that is the complete lack of indentation:

a=0;
while(a<c) {
if(!punchbag.hit(b))
break;
a++;    }
You can't tell from this which statement is inside the while loop and which is not, and which is inside the if statement inside the while loop. There is no excuse for this - the structured programming revolution in which programs were seen as nested structures rather than as lists of statements with control jumping about them took place in the 1960s. As part of thinking in a structured programming way, you should think of your while statement as taking the form:
while(test)
   {
    stuff
   }
that is, before you even think about what's inside it you know the opening { has a matching }, and the whole thing is one block where you keep testing test then doing stuff until test evaluates to false. You should think of this as a single statement which may have some statements inside it as part of it. What you should NEVER EVER think of your programs as is as a list of statements into which you insert {s and }s until the thing works, that is failing to appreciate the way some statements form parts of other compound statements.

Break statements are considered not really in accord with the principles of structured programming. When you have a loop like ours of the form

while(a<c)
   {
    stuff
   }
you will expect that loop to exit when a<c is false, that is for a to have a value which is equal to or greater than c. It might come as a surprise, maybe because your program went wrong because it was based on that expectation, to find sometimes the loop exits with a less than c because hidden inside stuff is a break statement. That wasn't too much problem in our small example, but suppose stuff was some fairly complex code.

The break wasn't necessary in our example. Here's an alternative way of answering it:

a=0;
while(a<c&&punchbag.hit(b))
   {
    a++;
   }
Since the body of the while statement has only one statement in it, you don't need the brackets, so this could be written:
a=0;
while(a<c&&punchbag.hit(b))
   a++;
Note that whatever comes after this in the code is not within the while loop. A while loop officially takes the form while(test) statement, that is the while(test) part is followed by a single statement. The { and } have the effect of gathering together a list of statements and making them into a single statement.

Our example quite nicely illustrates the short-circuit effect of &&. When it makes the test a<c&&punchbag.hit(b) in the while loop, if a is equal to c then a<c is false and we don't evaluate punchbag.hit(b). That is just as well, because if we did, we would be calling hit with argument b on punchbag one more time than we were asked to.

Since the test was set before we had discussed for statements, you wouldn't have been expected to have answered it using a for statement. However, it could be done that way, and that wouldn't have been wrong. A for statement is just like a while statement, except it has an extra part before the test and separated from it by a ; where you can initialise a variable to a value (or even declare and initialise a new variable), and an extra part after the test, again separated with a ;, which is a statement executed after executing all those in the body. The following for statement will answer the question:

for(a=0; a<c&&punchbag.hit(b); a++);
That's it: there's no body to this for statement because all that is needed is in the top part. That is indicated (rather subtly) by the way it is followed by ;. A for statement takes the form for(initialise;test;update) statement. Note there is no ; after the ). So if a ; is found after the ), it is taken to be that for statement's statement part. Anything else coming after it is not part of the for statement. That is why it is an error to put a ; after the ) in a for statement: it completely alters the meaning of your code.

Question 4

Everyone ought to have been able to produce something at least coherent for this question. It uses the same example (slightly shortened by not mentioning a couple of the methods) that was given out three weeks before the test, here which was subsequently given as lab work. Lab work is an essential part of the course, you are expected to do it, it is the way to really learn the concepts that are covered in the lectures. Anyone who had made an attempt at that lab work ought not to have problems knowing how to call the methods in this question.

General problems with this question include failing to note that the question asked for a fragment of Java code. That means enough lines of Java code to do what the question asks and no more. It certainly does not mean writing:

class Something
{
 public static void main(String[] args)
 {
 Some stuff
 }
}
That extra packaging is needed if you are writing a complete program in order for it to run under Java, but you are rarely going to be asked to write a complete program in a test or exam. You would more commonly be asked to write a complete method, which would include the method signature. But if you are asked to write a code fragment, it's just a few lines without any extra packaging.

Many of the same sort of problems as mentioned with question 3 occurred again here: failure to appreciate that { and } always come as a pair, failure to use indentation properly, inventing new notation which isn't part of Java or is part of another language. Some people made use of the two methods which were in the original example given as a class exercise, but not mentioned in the test. If you are given a piece of code merely as an example in class, you should not assume the marker of a test or exam is even aware of it. If a question gives some example code, make use of that, any extra code you have written for yourself as part of the answer, and anything which is built-in to Java. But don't assume the existence of anything not given to you.

It was surprising to see how many people clearly did not understand how to call a method on an object, despite the fact that we had been doing that for weeks in the labs and lectures. So, let us go over it. The three methods given for a Machine object can only be called attached to a Machine object. The method getTemp has signature:

int getTemp()
which means it must be called with no arguments and returns an int. So it can only be called in the form m.getTemp() where m is any expression that refers to a Machine object. Most commonly m will be a variable of type Machine but it could also be a call to another method which returns a Machine object. Actually there is an exception to this, which wasn't relevant to this question: getTemp could be called within the code for a method of type Machine without being attached to a Machine object, in that case it would be assumed to be attached to the object to which the call the method whose code it is within is attached to.

As getTemp returns an int, the call m.getTemp() can occur anywhere where an int can occur, that is within an arithmetic expression or as an argument to a method in a place where an int is asked for in the method's signature. The () in the signature indicate that a call to getTemp takes no arguments. However, it is still necessary to put the () in the method call.

The method pushButton() with signature:

Grommet pushButton()
is very similar to getTemp except, as the signature indicates, it returns a Grommet rather than an int, so a call to it, which will take the form m.pushButton(), where m is any expression that refers to a Machine object, and can be used in any place where a reference to a Grommet object can be used.

The method addFuel is rather different. Its signature:

void addFuel(int amount)
indicates it has no return type. The word void means that. This means you cannot use a call to it in the place of any value, but only as a statement on its own, taking the form m.addFuel(n);. Here while m is any reference to a Machine object, i is any int value, so it could be an actual number, a variable of type int, an arithmetic expression which has an int value, or a method call with return type int. You must give any call to addFuel exactly one int argument, that is what the (int amount) in the signature means. However, it does not mean you write the word int in front of the argument you give to a call to addFuel.

The method getQuality is a Grommet method, which means a call to it must be attached to a reference to a Grommet object. That reference could be a variable of type Grommet, but it could also be a call to pushButton (which must in turn be attached to a reference to a Machine object), as that returns a Grommet object. The signature for getQuality is:

int getQuality()
which means it takes no arguments and returns an int just like getTemp.

Part a

This part tested whether you knew how to read an int and pass it as an argument to a method requiring an int argument. You need to be aware of the fact that to do any reading in Java you need a BufferedReader object. Actually there are other ways, but Java input/output is complex, so assume that for simplicity. Some of the notes refer to a class called Text which was provided by Judy Bishop to accompany her textbook. However, as that is not part of official Java you should not assume it is available unless you are told so in a question. This is how you have been told to create a BufferedReader object referred to by in which reads from the command window:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
There is nothing special about the name in, it could have been called anything, but in is usual. You cannot assume a BufferedReader variable called in exists unless you are told it does in the question, which you were not in this case.

You have been told that a BufferedReader object has a method called readLine which reads a whole line of text. It also has a method which reads a single character, but it does not have a method which reads a single integer. So to read an integer we have to read a line and then convert that line to an integer (if there was more than the single integer on the line, we would need to use a StringTokenizer to break it up, but we won't consider that here).

The static method parseInt in built-in class Integer takes a String as its argument and returns the equivalent int value. Because it is static you must attach the call to the name Integer rather than to an Integer object (note the type Integer is an entirely separate thing, which we have not covered yet, to the type int). The following declares a String variable called str and an int variable called amount then sets the String variable to the result of reading a line and the int variable to the result of converting that line to an int:

String str;
int amount;
str = in.readLine();
amount = Integer.parseInt(str);
Java allows you to combine creating a variable with giving it a value, which enables us to write the following instead of the above:
String str = in.readLine();
int amount = Integer.parseInt(str);
The variable str here is used only for this one purpose of passing a String value from the readLine call to become the argument of the parseInt call. So really there is no need to have a separate named variable, we could just put the readLine call directly as the argument to the parseInt call, making:
int amount = Integer.parseInt(in.readLine());

Note that method arguments in Java are always fully evaluated before they are passed to the code for the method. So in the above example, in.readLine() is evaluated first to a String value, and that value is passed in to the code for parseInt to take the place of the String parameter to that code.

Starting a machine is simulated by creating a Machine object. You are told that a Machine object can be created with a zero-argument constructor, thus new Machine() refers to a newly created Machine object. But there is no point in creating a new object unless we either give it a name to allow us to refer to it later, which we do so by assigning a value to refer to it, or we pass it as an argument to something else. Below shows the declaration of a variable called m of type Machine which is combined with setting it to refer to a new Machine object:

Machine m = new Machine();

Now all we need do is pass the integer amount read as the argument to the call of the method addFuel on the new Machine object. This is done by:

m.addFuel(amount);
That is all that is needed, nothing in the question asked for any more calls to be made, and it's a mistake to add something to an answer which was neither asked for nor is needed to make something else work which was asked for. Quite a few people who answered this question made further method calls which might have lost them marks.

Note that although in the answer given here the argument to the method addFuel is a variable of the name amount, which is the same name as the parameter name in the signature given for addCount, that was not a necessity. An int variable of any name could have been used as the argument, or a method call or arithmetic expression which has an int value. In fact it was not necessary to have a separate int variable at all, as all it was used for was this once-only passing of an int value. So we could have further combined statements with the call to read an int value as the argument to addFuel making:

m.addFuel(Integer.parseInt(in.readLine()));

Part b

Here the question states that a machine is to be created and made to produce grommets until its temperature drops below 20. Any question which involves doing something repeatedly until a condition is met must involve a loop. It was surprising to see quite a few people answer this question with a code fragment that involved an if rather than a while. The form if(test)stat means that stat is obeyed at most once, in the case where test evaluates to true when execution reaches it. But the form while(test)stat means if test still evaluates to true after the execution of stat then stat is executed again, and repeatedly until after executing it test does not evaluate to true.

We have already seen that Machine m = new Machine(); is a statement that creates a new Machine object and sets the variable m to refer to it. Then the temperature of that Machine object is obtained by m.getTemp(). Using this, a while loop which tests whether the temperature of the machine is not less than 20 each time round the loop takes the form:

while(m.getTemp()>=20)
   {
    stuff
   }
Note the Java symbol for "greater than or equals", which is the same as "not less than". It is >=. There should be no call to getTemp inside stuff, the call is made when the while loop's test is evaluated. A lot of people seemed to assume that if you made a call m.getTemp() somewhere inside stuff, then somehow a variable called temp or getTemp is set to the result and may be used in the test. This is, of course, nonsense.

A call of the method pushButton on a Machine object returns a Grommet object but also changes the internal state of the Machine object so that next time getTemp is called on it, a different value will be returned. That is why the following loop:

while(m.getTemp()>=20)
   {
    Grommet g = m.pushButton();
   }
will halt, because the internal state of the object referred to by m will change and eventually reach the point where m.getTemp()>=20 will evalute to false and the loop will be exited. It is always necessary to have something in a loop which changes something in the loop's test so that the test will at some time evaluate to false. I was surprised at how many people failed to realise this elementary point and gave answers involving loops that would quite obviously never terminate.

This loop could have been written:

while(m.getTemp()>=20)
   {
    m.pushButton();
   }
The pushButton method is unusual in that it both returns a value and changes the state of the object that it's called on. So you can call it on its own and not even acknowledge that it returns a value, which is what is done when m.pushButton(); is used as a statement on its own. However, it's good programming practice to acknowledge when a method returns a value and use a call on its own only when the call is to a method with return type void. That is why the recommended answer here assigns the result of calling pushButton to a Grommet variable g even though this variable is never used.

The loop given above doesn't do any counting, but that is easily corrected by adding a variable which is assigned initially to zero and increased by 1 each time round the loop. Note that although the answers given for the test did not use for loops, it would be natural to make the code a little more compact by using one, giving the answer:

Machine m = new Machine();
int count;
Grommet g;
for(count=0; m.getTemp()>=20; count++)
   g=m.pushButton();
System.out.println(count+" grommets produced");
Note there are no { and } because the loop has only the statement g=m.pushButton(); within it. The next statement which prints the final message is not within the loop. The lack of { and } tells the Java compiler only to include g=m.pushButton(); within the loop. The fact that we also indent the line a few spaces means nothing to Java, but makes the structure clear to human readers of the code. If there is only one statement in a loop, it can't be a declaration, which is why the Grommet variable g is declared before the loop (I wouldn't expect you to know a minor detail like that - I didn't know myself until this question raised the possibility, and I checked to see for myself by attempting to compile a version which had Grommet g = m.pushButton(); as the loop body, and got an error message).

Some people, aware that you can declare variables in the initialisation part of a for loop might have thought the for loop could have been written

for(int count=0; m.getTemp()>=20; count++)
   g=m.pushButton();
and then you wouldn't have the earlier declaration statement int count;. This would have been wrong, however, as that would mean that count had scope only inside the for loop, and so you wouldn't be able to refer to it after the loop as is needed to print the final mesage.

I was surprised that quite a few people answering this question seemed to think a call to the Grommet method getQuality would return the number of grommets produced. Since the question (and the very name of the method!) suggests clearly that this method gives the quality of a grommet, I am at a loss to understand why so many people made a mistake that surely common sense rather than any familiarity with Java would have dictated was stupid.

Part c

This question again requires a loop in which a call to pushButton is made, but in this case a loop with two counts kept, one of the number of times the loop has been executed, and the other of the number of times the grommet produced has a higher quality than that of g.

Note that what is required is a code fragment which assumes that the variable g has already been declared and given a value. You don't know how it was given a value, but the idea is that you are writing some code that will be slotted in after the code that gives g a value. So it is a bad mistake to declare a new variable g and/or give g a new value, as many did. Many people did not seem to understand that the way to compare the qualities of two grommet object is to call the getQuality method on each of them, and compare the values returned. Also in this case, unlike the previous two parts, you are told a Machine variable called m already exists and should be used so it's equally wrong to declare and/or give a value to variable m.

Actually, the answer previously circulated calls getQuality on g every time round the loop, even though g and its quality aren't changed. So a slightly more efficient way of handling it would be to make a call once to getQuality on g and store it in a variable. It takes less time for the Java execution mechanism to look at the value of a variable than it does to call a method. That would give the following answer:

int count=0, qcount=0;
int gQual=g.getQuality();
while(count<100)
   {
    Grommet g1=m.pushButton();
    count++;
    if(g1.getQuality()>gQual)
       qcount++;
   }
System.out.println(qcount+" high quality grommets produced");
While minor efficiency matters like this are not too important, and you will not lose marks if your code isn't quite as efficient as it could be, it's a good idea to be aware of such issues.

Note, again, the importance of good layout as shown here. The lines Grommet g1=m.pushButton(); and count++; are inside the while loop and are indented (written after several spaces to their left) so that is clearer to someone who looks at the program. The next two lines are a single if statement, again inside the while loop so indented, but the line qcount++; is inside the if statement which is inside the while loop, so it is indented a bit more to make clear it is a statement inside a statement inside a statement. It is important to think of a loop, such as the while loop here as a single statement, inside of which are substatements, so the above example consists of four top-level statements: the one on the first line which declares and initialises the two variables count and qcount, the one on the second line which declares and initialises (to the value obtained by calling method getQuality on variable m) the variable gQual, the while statement taking the next seven lines, and the final statement being the call to the method println on System.out.

As with part b, a more compact piece of code could be obtained by using a for loop. In that case, the variable count could be declared inside the for part as it is used only within the loop, but qcount has to be declared before it as it is used after the loop has finished. This would give us:

int qcount=0;
int gQual=g.getQuality();
for(int count=0; count<100; count++)
   {
    Grommet g1=m.pushButton();
    if(g1.getQuality()>gQual)
       qcount++;
   }
System.out.println(qcount+" high quality grommets produced");
For even more compact code, it could be noted that the variable g1 is used only to convey a value from the call to pushButton on m in order for getQuality to be called on it in the if statement test. Instead of using a separate variable g1 the call to getQuality could be attached directly to the call to pushButton giving:
int qcount=0;
int gQual=g.getQuality();
for(int count=0; count<100; count++)
   if(m.pushbutton().getQuality()>gQual)
      qcount++;
System.out.println(qcount+" high quality grommets produced");
This has exactly the same effect as the previous code fragment, but the Grommet object produced by the call to pushButton is anonymous as it was never given a name. Note that the { and } are omitted. This is because the for loop now has only one statement - the if statement inside it (and inside the if statement is the statement qcount++;), and { and } are not needed if they only enclose a single statement. It wouldn't have been an error to leave them in, and some authors (for example Barnes) recommend always using them even when they do only enclose a single statement.

Matthew Huntbach
22nd December 2000