6

How might one craft a good explanation of why the following code is not correct, in that the author is attempting to write C++ code declaratively rather than procedurally?

const double NEWTONS_PER_POUND = 4.448;

int main()
{
   double pounds, newtons;
   pounds = newtons/NEWTONS_PER_POUND; /* pounds equals 'unassigned variable'/4.448 */
   newtons = 10.0;
   cout << pounds << endl;             /* a big number, not 10.0/4.448 */
   return 0;
}

The author expected cout to display a proper calculation, but instead gets a "crazy number."

I would explain this as "C++ is procedural, and therefore at the time of the declaration

pounds = newtons/NEWTONS_PER_POUND;

newtons has not been assigned a value.

Any better suggestions? Or an explanation why C++ isn't "smart" enough to carry out the behavior the user mistakenly expected?

ybakos
  • 8,152
  • 7
  • 46
  • 74
  • 3
    Many modern compilers will attempt to identify uninitialized variables and report them as compile-time errors. – KV Prajapati Sep 01 '09 at 06:57
  • 2
    Actually following the semantics of the language you are using (and learning them, if you don't know them) usually helps. Nobody can write this in C++ and expect it to "work" in any way. Maybe it would, in a fictional C++ language, but not in the real one. If he doesn't understand your explanation, well, he's simply too stubborn or willingly blind to reality. – Daniel Daranas Sep 01 '09 at 08:23
  • 1
    One more time, I hold that people must learn low-level languages FIRST... starting with assembly. In assembly, the inherently sequential way the computer works is EXPLICIT. – isekaijin Sep 01 '09 at 12:38
  • There are no confusing statements such as `b=c`. – isekaijin Sep 01 '09 at 12:39
  • b=c is not confusing. The value of c is assigned to b. – Daniel Daranas Sep 01 '09 at 18:23
  • I once met an academic who complained that the problem with imperative programming languages was that they implied a computer was a machine that executed instructions one after another, simply reading values from memory, changing them, and writing them back. The only reply I could think of was, "well... it *is*." – Crashworks Sep 02 '09 at 23:25
  • 2
    It is in a CPU. Then once you get your head into some VHDL, it isn't. – Zan Lynx Sep 03 '09 at 04:21

9 Answers9

21

Tell the author that

pounds = newtons/NEWTONS_PER_POUND;

commands the CPU to

  • take the value at the address referred to as "newtons"
  • take the value at the address referred to as "NEWTONS_PER_POUND"
  • divide them
  • store the result at the address referred to as "pounds"

what he is looking for is most probably a function in imperative terms:

double newtons_to_pounds(double newtons) {
  return newtons/NEWTONS_PER_POUND;
}

...

newtons = 10.0;
cout << newtons_to_pounds(newtons) << endl;    /* a big number, not 10.0/4.448 */
return 0;
Richard Corden
  • 21,389
  • 8
  • 58
  • 85
Zed
  • 57,028
  • 9
  • 76
  • 100
18

C++ is an imperative programming language not an equation solver.

C++ executes statements in the order that you write them. C++ does not initialize variables unless it is told to. C++ allows you to use a variable whose value has not been initialized, but when you do this the result is unspecified. Unspecified means than anything can happen, including bad things like producing "crazy numbers".

Here's the detailed explanation:

double pounds, newtons;
pounds = newtons/NEWTONS_PER_POUND;
newtons = 10.0;

The first statement declares two variables without initializing them. At this point, their values are unspecified.

The second statement reads the value of newtons (which could be anything) and divides it by NEWTONS_PER_POUND. The result (which could be anything) is assigned to pounds.

The third statement initializes newtons, but it is too late to affect the calculation we just performed.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • "execute statements in the order that you write them." that's not correct. m(++x);. i 'wrote' the calling of `m` first. but it will actually increment `x` first, and then call `m`. – Noon Silk Sep 01 '09 at 07:00
  • 3
    @silky: "m(++x);" is one statement. – Stephen C Sep 01 '09 at 07:03
  • When you write it, I hope you're fully aware of the order of precedence. So therefore you've written it in that order. Otherwise, why are you writing code when you don't know what it does? – Pod Sep 01 '09 at 09:03
  • @Pod: what are you talking about? Of course I understand operator precedence!! But it has nothing to do with the order in which >>>STATEMENTS<<< are executed. – Stephen C Sep 01 '09 at 09:39
  • 1
    _"C++ is a programming language not an equation solver."_ I guess what you meant to say was: "C++ is a procedural programming language, not a declarative one." There are declarative programming languages allowing the code in question to work, after all. – sbi Sep 01 '09 at 18:06
  • C++ IS a programming language and it is NOT an equation solver. What I said is incontravertibly correct ... just not what you wanted me to say. -10 sbi for trying to put words into my mouth !!! – Stephen C Sep 02 '09 at 09:35
  • What the guy wrote would be perfectly valid code outputting exactly what he predicted in quite a few programming languages. So there's no contradiction between a "programming language" and an "equation solver". You could just as well have said "C is a programming language and not some OO language". This, too, would be wrong, since OO languages are (well, they might be) programming languages, too. I first thought you just expressed it poorly, but since you really meant it that way, it is, IMO, wrong. As I understand, this is the canonical use case for downvoting. Now, why are you mad at me? – sbi Sep 02 '09 at 16:42
  • @sbi: How about this: "Sneaker" is a kind of "Shoe", not a kind of "Loafer". That statement is perfectly accurate. What is not explicitly stated in that sentence is that "Loafer" is *also* a kind of "Shoe". I'd be OK with you calling Stephen's answer "incomplete", but I don't think it's "wrong". – Daniel Pryden Sep 02 '09 at 23:27
  • _"C++ is an imperative programming language not an equation solver."_ Now this I can fully agree with. Downvote removed. `:)` – sbi Sep 03 '09 at 09:15
  • @Daniel: Yes, but he wrote "This is a kind of shoe, not a sneaker". Anyway, Stephen has changed the answer and I now fully agree with it. (Unfortunately SO prevents me from upvoting it. So whoever reads this: please add an upvote for me. `:^>`) – sbi Sep 03 '09 at 09:17
8

Well that shouldn’t be too hard to explain, regardless of the students’ background: just thell them that C++ evaluates programs one step at a time, statement after statement (notwithstanding compiler artifacts such as reordering …).

There’s absolutely nothing special to C++’ way of handling this, nor is it even limited to computer programming – rather, it’s an everyday way of dealing with an ordered list of instructions.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
4

It's not lazy evaluating newtons

As such the calculation is performed at the time of declaration, not at the time of request. He's after functional code, not what C++ will do.

Spence
  • 28,526
  • 15
  • 68
  • 103
  • If they are a programmer they might know what "lazy evaluating" means. Otherwise this would be a bit confusing. – Ash Sep 01 '09 at 07:31
  • 1
    Really? I always thought the explanation of lazy as opposed to eager was one of the easier things to explain to a non programmer. Lazy, does it when needed, eager, does it when told to. – Spence Sep 01 '09 at 07:34
  • In functional programming, you still have to respect the sequence of the program flow. I think the author's code is more in the vein of logical (constraint-based) programming. – isekaijin Sep 01 '09 at 12:41
  • @Spenced, I've actually explained something I built to a non-programmer as using "lazy evaluation", they became annoyed I was using technical jargon! "Lazy" by itself is obvious but lazy evaluation seems to require more explanation. – Ash Sep 04 '09 at 04:08
4

If the person is not overly technical you could try:

"The statements in this C++ program are like the steps required to make a cake. You must perform the steps one by one and they must be to be performed in a certain order for it to be a success."

Ash
  • 60,973
  • 31
  • 151
  • 169
1

Explain that pounds is assigned a value on the line with the assignment operator:

pounds = newtons/NEWTONS_PER_POUND;

If this were not the case, but that pounds was evaluated when it was used (as with the cout statement), then if the value of newtons changed, then the value of pounds would change as well. Since pounds is not any type of pointer, but is a simple integer, this is not possible.

Mike Hall
  • 1,151
  • 2
  • 10
  • 24
1

What about stepping through the code in a debugger?

IME there's nothing like this to understand the execution of a program written in a procedural language (i.e., modeled on how the CPU actually executes code).

sbi
  • 219,715
  • 46
  • 258
  • 445
0

You are trying to get the listener to undergo a paradigm shift - to change his/her entire approach to comprehending this code.

"pounds" is just a number. It's got no concept of how its created. You tell "pounds" how it's created, it won't remember. It will just remember what it is, not how it is created.

It may seem a bit strange to anthropomorphise a block of memory. :-)

Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
0

Take a slightly more complex example where a variable like newtons is reused and assigned values more than once. For instance:

double pounds, newtons;

newtons = 10.0;
pounds = newtons/NEWTONS_PER_POUND;
cout << pounds << endl;

newtons = 15.0;
pounds = newtons/NEWTONS_PER_POUND;
cout << pounds << endl;

return 0;

Show him both the code and the output. Then ask him to explain how and why the program produces a different number for each line. I'd think that should help push him in the direction of viewing the program as a procedure that runs from top to bottom.

TheUndeadFish
  • 8,058
  • 1
  • 23
  • 17