views:

505

answers:

10

Is anyone willing to help me 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 exhibit the behaviour the user mistakenly expected?

+4  A: 

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
If they are a programmer they might know what "lazy evaluating" means. Otherwise this would be a bit confusing.
Ash
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
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.
Eduardo León
@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
+18  A: 

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;
Zed
+8  A: 

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
+16  A: 

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
"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
@silky: "m(++x);" is one statement.
Stephen C
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
@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
And now, ladies and gentleman, welcome Goto and the Loops!
Zed
_"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
I meant what I wrote :-)
Stephen C
Then what you meant is wrong. -1
sbi
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
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
@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
_"C++ is an imperative programming language not an equation solver."_ Now this I can fully agree with. Downvote removed. `:)`
sbi
@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
A: 

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
Don't anthropomorphize computers. They hate that. ;-)
Jeffrey Hantin
+1  A: 

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
+4  A: 

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
Explaining C++ to "not overly technical" person seems quite useless :)
n0rd
@n0rd, You're right I probably should say "an inexperienced programmer".
Ash
+1  A: 

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
A: 

Here is an example which explains it quite neatly; devx.com/tips. The simple answer is initialise everything before you read it, in the end the only thing this will cost is a couple of extra key strokes. It's not something which is really worth spending brain power on!

Chris Huang-Leaver
A: 

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