Please confirm this is a MSFT bug

  • Thread starter Thread starter Jake Forson
  • Start date Start date
OK. I never said your example does this. What I am saying is that there
*are* separate, more complex, real-world examples (such as the one I
presented). My key point is that it is highly desirable that the language
and compiler can handle these situations according to a *single*
*consistent* set of rules.


Again, from the compiler's perspective they don't *need* to; it is just a
damned good idea. The compiler enforces rules, not ideals. As such the
compiler *cannot* (ever) guard against threading foobars. It's hard enough
for the original developer to identify this!

But... at the end of the day, this whole discussion is a non-issue. It
gets raised on this list (and others) every week or so, and each time the
weight of opinion is with the compiler and the language spec. I will
happily conceed that spec conformance makes a far better reason "why", but
IMO the non-trivial examples like the above help provide counter-cases
against what you are proposing - *particularly* with a view to consistency
between use-cases. It *is* a realistic example; if I could be bothered I
would knock some code together to illustrate. But I can't be ;-p

Ok, I think we still misunderstand eachother (to some extent) but I
appreciate your input. Thanks again.
 
Jake Forson said:
Before I notify MSFT, can someone confirm this is in fact a compiler bug (it
seems pretty obvious but I'm fairly new to C#). The following code
(erroneously) generates compiler error CS0177 (The out parameter 'Whatever'
must be assigned to before control leaves the current method).

public void SomeFunc(out string Whatever)
{
bool Continue = ShouldWeContinue();
if (Continue)
{
Whatever = "Continue";
}

if (!Continue)
{
Whatever = "Didn't continue";
}
}

The problem is: where do you draw the line about what the compiler
infers from the code? We've got nice predictable rules now that are
solely based on the control-flow primitives and are not based on the
types of values in expressions. I think that's enough, and going down
the route you're suggesting (which is by design and not a bug, BTW)
would create more confusion than it's worth.

-- Barry
 
Jake said:
Ok, I think we still misunderstand eachother (to some extent) but I
appreciate your input. Thanks again.

Marc's point can be summed up as follows:

If the variable you're testing is local to the method then yes, it
would be possible to determine that the two statements were mutually
exclusive if the compiler were to do that much analysis.

However, if the variable you're testing is a field, part of the
object's state, there is no guarantee that it does not change its value
between the two if statements, and therefore the compiler should
complain that it doesn't know for sure that you have assigned a value
to the "out" parameter.

Nonetheless, I suspect that the real answer is that it's not worth all
of the extra effort and extra code to have the compiler do the level of
analysis needed to determine whether various conditions cover all
possibilities.
 
Jake Forson said:
Thanks for the info. While the KISS principle may apply here (on that we
agree), I'm at odds with your other points. It's certainly easier to parse
code without worrying about trapping this type of scenario and even
beneficial if it imrpoves compiler performance and robustness, but it's
still legal IMO (or should be). I doubt the C# standard says otherwise (I'd
be surprised to find out).

The C# standards are very clear on definite assignment, and they don't
contain any rules about the compiler performing any logic to determine
that one of two paths through code must be taken.
 
Jake said:
With all due respect, I'm not spamming this group. Nor do I wish to pursue
this issue ad nauseam. I'm trying to get to the bottom of it. I'm not a
programming novice (20+ years working in C/C++) and I know things aren't
always so cut-and-dry. People make their cases without knowing what the real
rules are and often quote from the standard without understanding it (not
necessarily in your case but in general - there's a lot of technical
legalese to wade through and it's easy to get things wrong). In any case,
now that I have the standard I can check for myself. Don't confuse someone
who's legimately defending a point however with someone who's being hostile
or argumentative (just because it seems that way to you).

Jake, you said multiple times in this thread that it's the spec that
matters, not the language. Yet you never checked the spec, just
assumed that the compiler must be in error. That's why you're getting
this heat.

The standard's online (and on the first page of a Google "c# spec"
search. They'll even send you hard copies for free). It's not that
hard to read - why didn't you check it before (repeatedly) calling the
compiler non-compliant against that spec?
 
I disagree that this is the situation. Your real-world example is definitely
a very good example of why the compiler should catch this as it has done,
but I really don't believe that it's that smart.

I think it boils down to something like this ..

object DoSomething(ref out object obj) {
bool cond = true;
if (cond) { // compiler sees a condition
obj = true;
} // no else statement; set value to obj ignored

if (false) { // compiler sees a condition
obj = false;
} // no else statement; set value to obj ignored
}

object DoSomething(ref out object obj) {
bool cond = true;
if (cond) { // compiler sees a condition
obj = true; // check; double-check in else statement required
} else {
obj = false; // double-check; set value to obj recognized
}
}

Jon
 
Same principle applies to ..

enum enm {
a, b
}
bool DoSomethingElse(enm someEnum) {
switch (someEnum) { // someEnum can only be enm.a or enm.b
case enm.a:
return true;
case enm.b:
return false;
}
}

This will not compile. However, this will.

enum enm {
a, b
}
bool DoSomethingElse(enm someEnum) {
switch (someEnum) { // someEnum can only be enm.a or enm.b
case enm.a:
return true;
case enm.b:
default: <<<<< compiler will always set something
return false;
}
}
 
Jon Davis said:
Same principle applies to ..

enum enm {
a, b
}

The principle is actually quite different for enumerations. A bool
expression will always either evaluate to true or false, since (under
the CLI) it's based on integers being zero or non-zero.
bool DoSomethingElse(enm someEnum) {
switch (someEnum) { // someEnum can only be enm.a or enm.b

This statement is where it falls apart. The enumeration value "(enm) 3"
will fit into a variable of type enm without error, so it isn't true
that someEnum can only be enm.a or enm.b.

-- Barry
 
Barry Kelly said:
This statement is where it falls apart. The enumeration value "(enm) 3"
will fit into a variable of type enm without error, so it isn't true
that someEnum can only be enm.a or enm.b.

Fine, ignore the commented portion, I was just trying to paint a scenario. I
was demonstrating the switch requiring a default value, not the enum, a
point that is retained regardless of (enm)3.

Try pasting the sample into VS or SnippetCompiler and you'll see the same
error.

'MyClass.DoSomethingElse(MyClass.enm)': not all code paths return a value

Jon
 
Jon Davis said:
Fine, ignore the commented portion, I was just trying to paint a scenario. I
was demonstrating the switch requiring a default value, not the enum, a
point that is retained regardless of (enm)3.

Try pasting the sample into VS or SnippetCompiler and you'll see the same
error.

'MyClass.DoSomethingElse(MyClass.enm)': not all code paths return a value

And it's absolutely right - if you pass in (enm)3 as the parameter,
then without the default case, your code would reach the end of the
method without returning anything. It's absolutely correct for the
compiler to complain about that.

It's not that switch requires a default, it's a matter of the
reachability of the end of the switch statement.

Now, the C# spec states:

<quote>
The end point of a switch statement is reachable if at least one of the
following is true:

* The switch statement contains a reachable break statement that
exits the switch statement.
* The switch statement is reachable, the switch expression is a
non-constant value, and no default label is present.
* The switch statement is reachable, the switch expression is a
constant value that doesn=3Ft match any case label, and no default label
is present.
</quote>

This is only actually conservative if the switch expression is a non-
constant value and you specify *every* value in the appropriate type as
a case label. For instance, if you were switching on a byte and all 256
possible values were specified and all of them returned, you'd still
have to have a default case. I can't remember ever seeing such a
situation, personally - so simplicity on the part of spec is
reasonable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top