self-confidence of compiler

  • Thread starter Thread starter valentin tihomirov
  • Start date Start date
V

valentin tihomirov

fDeleted = false;
uint jobId;

foreach (Struct struct in structures) {
if (struct.type == JOB) {
jobId = struct.id;
if (struct.dataType == STATUS)
fDeteted = (struct.data & STATUS_DELETED) != 0;
}

if (fDeleted)
writeln(jobId + " has completed");

Note that the job id is initialized before the 'deleted' flag gets any
chance to set true. So it is not possible to use not initialized jobId.
Nevertheless, compler forces me to do the useless initialization. Do the
designers of 'clever' robots forsee any overcoming for the limitations they
impose?
 
Your code does not guarantee that jobId will ever be assigned.

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net
 
fDeleted = false;
uint jobId;
foreach (Struct struct in structures) {
if (struct.type == JOB) {
jobId = struct.id;
if (struct.dataType == STATUS)
fDeteted = (struct.data & STATUS_DELETED) != 0;
}
if (fDeleted)
writeln(jobId + " has completed");
Note that the job id is initialized before the 'deleted' flag gets any
chance to set true. So it is not possible to use not initialized
jobId. Nevertheless, compler forces me to do the useless
initialization. Do the designers of 'clever' robots forsee any
overcoming for the limitations they impose?

What if "structures" is empty and the code within the foreach never runs?

Hans Kesting
 
valentin tihomirov said:
fDeleted = false;
uint jobId;

foreach (Struct struct in structures) {
if (struct.type == JOB) {
jobId = struct.id;
if (struct.dataType == STATUS)
fDeteted = (struct.data & STATUS_DELETED) != 0;
}

if (fDeleted)
writeln(jobId + " has completed");

Note that the job id is initialized before the 'deleted' flag gets any
chance to set true. So it is not possible to use not initialized jobId.
Nevertheless, compler forces me to do the useless initialization. Do the
designers of 'clever' robots forsee any overcoming for the limitations
they impose?
Hi Valentin,

I'm not sure, what exactly is your concern here.
Surely, this is one of the seldom cases, where a variable can't be used
unassigned, but the compiler supposes it can. This doesn't seem to be a
secial problem of C#, but for any language, that prohibits the use of
unassigned variables. (Though maybe C# is the only one until now, I'm not
sure).

Why don't you initialize it to zero? performence considerations?

If you want a language, that allows the use of unassigned variables, you
will have to use another language.

Christof

PS You could try to use

unsafe {uint* p = &jobId;}

just before the loop. Probably the compiler will optimize this assignment
away.
 
Kevin Spencer said:
Your code does not guarantee that jobId will ever be assigned.

Yes, but it guarantees, that jobId is not used unassigned (if it doesn't
occur further down in the code).

BTW The code surely isn't tested, as it was posted. The compiler wouldn't
allow the use of struct as a identifier.

Christof[/QUOTE]
 
This doesn't seem to be a secial problem of C#, but for any language, that
prohibits the use of unassigned variables. (Though maybe C# is the only
one until now, I'm not sure).

I just wanted to know about language designer discussions on the topic. I
like freedom and doing reasonable things.


If you want a language, that allows the use of unassigned variables, you
will have to use another language.


Where do you see that?

I DO NOT USE ANY UNINITIALIZED VARIABLES!!!

I have told that explicitly in the OP. I thought that people think a bit
wider than compiler and can understand that.

Are people formatted by Micro Soft?

In the beginning, you tell that I do not use uninitialized vars. Then, you
tell that this is not a problem of a language. You conclude that the ones
who do not want to use uninitialized vars (all the adequate people) need a
lang which allows using unitialized data! What a starling train of thought
to upside things down!
 
valentin tihomirov said:
I just wanted to know about language designer discussions on the topic. I
like freedom and doing reasonable things.

I have told that explicitly in the OP. I thought that people think a bit
wider than compiler and can understand that.

In the beginning, you tell that I do not use uninitialized vars. Then, you
tell that this is not a problem of a language. You conclude that the ones
who do not want to use uninitialized vars (all the adequate people) need a
lang which allows using unitialized data! What a starling train of thought
to upside things down!

The problem is not, that you use an unassigned variable; the problem is that
the compiler can't recognize it.

The designers of C# decided (for good reasen) not to allow any use of an
unassigned variable. After that, they had to decide, by wich rules they test
it.
It is an infeasable problem to automatically detect all cases of use of
unassigned variables and all cases of variables wich will never be used
unassigned. So they had to make a cut somewhere.
That's why I said, this is a problem for any language, that prohibits the
use of unassigned variables. There always will be cases, where a variable is
defnitly assigned on any access, wich the language resp. the compiler will
detect as probably use of unassigned variable.

From another perspective: Think of a language the (by specification) assigns
every local variable with the default value of the type (like in VB.NET). An
optimizing compiler could try to eliminate any implicit initilization, where
it detects, that the implicit start value will never be used.
In this case, with code analogous to yours the compiler would still
implicitly initialize the variable, because it can't detect, that the
initial value will never be used.

Now, C# only enforces you, to explicitly initialize variable, wich the above
mentioned compiler would initialize implicitly.

I hope you understand this better.

Christof
 
valentin said:
I just wanted to know about language designer discussions on the topic. I
like freedom and doing reasonable things.





Where do you see that?

I DO NOT USE ANY UNINITIALIZED VARIABLES!!!

I have told that explicitly in the OP. I thought that people think a bit
wider than compiler and can understand that.

Are you saying that you want the compiler to detect (in the general
case) whether a variable will be uninitialized? Spend a minute thinking
about why creating such a compiler isn't possible (hint: halting problem).

Alun Harford
 
Valentin,

While yes the jobId will never be accessed, it is beyond the compiler to
figure it out.

What you are looking for is static analysis of the code, something way
beyond (and usually very computationally intensive) what a compiler is
expected to do.

Short answer, you are right, it shouldn't give you grief about this,
unfortunately, the compiler would have to expend a severe amount of
processing power and time to figure this out.
 
Nicholas Paldino said:
While yes the jobId will never be accessed, it is beyond the compiler to
figure it out.

What you are looking for is static analysis of the code, something way
beyond (and usually very computationally intensive) what a compiler is
expected to do.

Short answer, you are right, it shouldn't give you grief about this,
unfortunately, the compiler would have to expend a severe amount of
processing power and time to figure this out.

Perhaps more importantly than the processing power (at least in my
view) - to specify the *exact* behaviour here, i.e. what the compiler
must be able to work out - would make the C# language specification
huge compared with its current form.

The rules for definite assignment are currently incredibly tedious, but
at least they're reasonably clear. Putting in a lot of static analysis
requirements would make it a lot harder to understand what we *should*
be able to expect, and to verify that a compiler did the right thing.
 
I just wanted to know about language designer discussions on the topic. I
like freedom and doing reasonable things.

OK... you like the freedom to make your own decisions. C#, however, is
a language for the masses, and tries to help programmers who may not
be as smart as you are, so that they don't make simple mistakes.

Yes, you have carefully constructed your code so that for all paths of
execution, no unassigned variable is ever used. However, you've done
it in such a clever way that the simple static analysis built into the
compiler can't tell that this is so.

A lesser programmer would try to do the same thing that you did and
screw it up. The compiler is trying to help that guy. Unfortunately,
this cramps your style. The fact is that there is no middle ground
here: either the compiler allows you to do what you want without
complaint, and lets (I would say) the majority of programmers make
elementary errors which cost time and money to find and fix, or it
insists on checking for uninitialized variables (among other things)
and puts some constraints on people like you and me. I don't see how
it would be possible to accommodate both types of programmers.

If you want a language that lets you do whatever you like while
imposing few, if any constraints, use C++. However, I should point out
that all of the freedom C++ gives you ends up biting large numbers of
people. That's why C++ didn't take the business world by storm (for
example): the language gives one so much freedom that it's dead easy
to write subtly incorrect code.

So, C# does a bit too much hand-holding. C++, IMHO, does far too
little. No matter where you put the balance point, somebody is going
to be unhappy with it.
 
OK... you like the freedom to make your own decisions. C#, however, is
a language for the masses, and tries to help programmers who may not
be as smart as you are, so that they don't make simple mistakes.
[...]
So, C# does a bit too much hand-holding. C++, IMHO, does far too
little. No matter where you put the balance point, somebody is going
to be unhappy with it.

IMHO, that's a poor argument in this situation. As I have pointed out in
the past, the current behavior actually *reduces* the effectiveness of
hand-holding. It forces the programmer to initialize a variable with a
value that may or may not be valid, and in a way that will hide any true
"this variable is used before it's initialized" bugs (at least at compile
time).

I defer to the claims that it would be impractical for the compiler to
correctly handle all cases, as well as to the claims that the language
specification specifically calls out the current behavior. While I'm not
entirely in agreement with those claims, they are more subjective and
harder to debate. But I don't find it supportable at all to claim that
the current behavior always ensures more bug-free code, or is even an
example of improved "hand-holding".

Pete
 
OK... you like the freedom to make your own decisions. C#, however, is
a language for the masses, and tries to help programmers who may not
be as smart as you are, so that they don't make simple mistakes.
[...]
So, C# does a bit too much hand-holding. C++, IMHO, does far too
little. No matter where you put the balance point, somebody is going
to be unhappy with it.

IMHO, that's a poor argument in this situation. As I have pointed out in
the past, the current behavior actually *reduces* the effectiveness of
hand-holding. It forces the programmer to initialize a variable with a
value that may or may not be valid, and in a way that will hide any true
"this variable is used before it's initialized" bugs (at least at compile
time).

I defer to the claims that it would be impractical for the compiler to
correctly handle all cases, as well as to the claims that the language
specification specifically calls out the current behavior. While I'm not
entirely in agreement with those claims, they are more subjective and
harder to debate. But I don't find it supportable at all to claim that
the current behavior always ensures more bug-free code, or is even an
example of improved "hand-holding".

Well, all I can offer is my own experience. Even the much-maligned
"uninitialized variable" warning has helped me catch a few errors that
I would otherwise have let slip until I started testing, where they
would have been harder to catch.

However, you're right in one sense: this is probably like the Java
"checked exception" debate: it's too easy to simply do the wrong thing
in order to make the compiler shut up, rather than reorganizing the
code so that the warning is still useful but the code is now something
acceptable to the compiler. By this I mean the difference between
adding an "else" case to initialize the variable, rather than simply
setting it to zero upon declaration. That sort of thing.

As well, from my own experience, C++ newbies produce some of the
buggiest code I've ever seen. The language is so powerful, and
provides so little hand-holding that it's dead easy to make fatal
mistakes. With great power comes great responsibility, as it were.
 
Well, all I can offer is my own experience. Even the much-maligned
"uninitialized variable" warning has helped me catch a few errors that
I would otherwise have let slip until I started testing, where they
would have been harder to catch.

I apologize if I gave the impression that I was somehow not in favor of
having an "uninitialized variable" compiler error. That's not the case.
In fact, it's exactly because I think it's such a useful compile-time
error that it frustrates me when the compiler doesn't even pick up on
relatively simple cases where the variable *is* always initialized and I
have to do something arbitrary to make the compiler be quiet.

To be sure, I *like* having the compiler looking for uninitialized
variables. I just don't like it when the compiler is mistaken and
generates a false positive.
However, you're right in one sense: this is probably like the Java
"checked exception" debate: it's too easy to simply do the wrong thing
in order to make the compiler shut up, rather than reorganizing the
code so that the warning is still useful but the code is now something
acceptable to the compiler. By this I mean the difference between
adding an "else" case to initialize the variable, rather than simply
setting it to zero upon declaration. That sort of thing.

Well, that's part of my complaint. There are relatively simple examples
of the compiler complaining that involve only multiple paths, all of which
initialize a variable. Reorganizing the code doesn't really help. Either
the error remains, or the code is now reorganized in a less-desirable,
less-maintainable, less-clear way.

We're not talking about deeply nested, strangely-arranged loops, if()
statements, etc. here. We're talking about code that has just two
branches, both of which initialize the variable, and yet the compiler
complains.
As well, from my own experience, C++ newbies produce some of the
buggiest code I've ever seen. The language is so powerful, and
provides so little hand-holding that it's dead easy to make fatal
mistakes. With great power comes great responsibility, as it were.

I think C# represents great strides in improving the "idiot-proofness" of
the language. Again, this is one of the reasons this particular issue
bugs me. The compiler error as implemented not only fails to idiot-proof
the code, it tends to lead to code that is even more resistant to
idiot-proofing than usual.

Granted, there's always a better idiot. :) But I think the goals of C#
are commendable, and that's why I'm annoyed that it falls down in this one
particular situation.

Pete
 
Peter Duniho said:
Well, that's part of my complaint. There are relatively simple examples
of the compiler complaining that involve only multiple paths, all of which
initialize a variable. Reorganizing the code doesn't really help. Either
the error remains, or the code is now reorganized in a less-desirable,
less-maintainable, less-clear way.

We're not talking about deeply nested, strangely-arranged loops, if()
statements, etc. here. We're talking about code that has just two
branches, both of which initialize the variable, and yet the compiler
complains.

Could you give an example? Here's one that *does* work:

using System;

class Program
{
static void Main(string[] args)
{
string x;

if (args.Length==0)
{
x = "None";
}
else
{
x = "Some";
}
Console.WriteLine (x);
}
}

Most examples which don't work (that I've seen) either involve for
loops or inter-dependency of two variables (if x is true then y is
definitely initialized).

I'm not doubting that you've run into more primitive issues, I'm just
interested in what they are :)
 
The rule: "Only initialized variables are allowed to be used" seems natural
and ultimately simple. The rules describing where you cut the analisys
should be extremely complex, I beleive.
 
Short answer, you are right, it shouldn't give you grief about this,
unfortunately, the compiler would have to expend a severe amount of
processing power and time to figure this out.

Does "severe" charactarize the halting problem? If it is true that the
problem is akin to the halting problem then infinite processing power is
needed, I suspect.
 
valentin tihomirov said:
Does "severe" charactarize the halting problem? If it is true that the
problem is akin to the halting problem then infinite processing power is
needed, I suspect.

If the compiler should catch *all* cases of variables, that aren't accessed
uninitialized it would use up to infinite processing power and infinite
quantity of analyzing code.
 
IMHO, that's a poor argument in this situation. As I have pointed out in
the past, the current behavior actually *reduces* the effectiveness of
hand-holding. It forces the programmer to initialize a variable with a
value that may or may not be valid, and in a way that will hide any true
"this variable is used before it's initialized" bugs (at least at compile
time).

Thank you for this remarkable point. The garbage-initialization effectively
turns the protection off. Intuitively, I felt strange when recommended to
stop compiler protection for the reason the compiler is so good to protect
me. I become irritated when asked to produce absurd things, even as small as
garbage-initializer. Everybody should keep in mind that absolutely every
action consumes energy and other resourses.
 
Back
Top