Immediate window behavior differences in C# and VB.NET - c#

I have noticed that the immediate window in VS 2010 behaves differently when debugging a C# project and a VB.NET project, although I haven't been able to find any specific documentation of this difference.
For C# projects, I can simply type in any expression, and it will be evaluated and displayed, i.e. typing in
foo.bar == "baz"
will output
false
In VB.NET, however, doing the same thing outputs nothing.
I have to put a question mark in front of the expression for it to work.
?foo.bar = "baz"
false
Edit for clarity and my bad example above:
All other expressions exhibit the same behavior, including simple math such as '1 + 2'. Sometimes the error message is different though, as 1 + 2 results in the error 'Labels that are numbers must be followed by colons.'
Is there a way to 'fix' this behavior and make the VB.NET immediate window behave more like the C# one? Having to type a ? in front of every statement can be a pain when using it frequently.

The semantics of the immediate windows are just different. In C#, any expression or statement you enter is evaluated, and the result of the evaluation is printed to the window. In VB.NET, you have to enter a complete statement; you can't enter a bare expression. In your example, as you discovered, you need to use the 'Print' statement (the alias for which is ?) if you want to print anything to the window.
One reason for this is that the semantics of the languages are different. As Bob Kaufman mentioned, = can be an assignment operator or an equality test. If the VB.NET window worked like the c# window, there would be no way to determine whether a = b meant "assign b to a" or "evaluate whether b is equal to a".
Assignments do not have a value in VB.NET; a = b = 4 means "evaluate whether b is equal to 4, and assign the result of that evaluation to a." This means that a will either be equal to true or false.
In C#, an assigment is also an expression with a value, so a = b = 4 means "assign the value 4 to b, and assign the value of the expression (b = 4) to a." This means that a will be equal to 4.

The immediate window parser expects a statement if you don't use the ? command. The command
foo.bar = "baz"
is legal in vb.net, it is an assignment statement, giving the bar field or property of the object foo the value "baz". It is however going to complain if bar is a method of the class. Similarly, "1+2" is not a valid statement in vb.net, the ? command helps the interpreter to understand that you meant to evaluate an expression. To turn the = operator from an assignment into a comparison operator, you have to make the parser understand that an expression is being evaluated. ? required. Same thing for "1+2", the vb.net statement parser accepts a number at the start of a statement as a statement label, fit for a GoTo.
The C# language follows the curly brace languages standard where any expression is also a valid statement. So "1+2" is interpreted as a valid statement without help from ? Which is also the reason it needs a separate symbol for the equality operator (==), a parser wouldn't otherwise know the difference between an assignment statement and an expression.

Related

Why does the code get compiled when I use !!= C#

I am trying to understand how does the code get compiled when I use (!!=)
Apparently the 2 snippets below do the same thing.
Why are both permissable?
if (4 !!= 5)
Console.WriteLine("vvvvvv");
the above does the same thing as:
if (4 != 5)
Console.WriteLine("vvvvvv");
The expression 4 !!= 5 is parsed as the null-forgiving operator applied to 4, and then != applied to that expression and 5. That is, (4!) != 5.
According to the draft spec, a null forgiving expression is a kind of primary expression:
primary_expression
: ...
| null_forgiving_expression
;
null_forgiving_expression
: primary_expression '!'
;
and that:
The postfix ! operator has no runtime effect - it evaluates to the result of the underlying expression. Its only role is to change the null state of the expression to "not null", and to limit warnings given on its use.
In other words, the ! after 4 does nothing and is very redundant. The constant 4 is never null after all :)
This only works in C# 8.0 and later. See null-forgiving.
I believe you are just stating that 4 could be null and telling the compiler that it should not show errors if 4 does happen to be null.
To complement other answers - in case you don't understand something about what is happening in terms of compilation you can use tools such decompilers - for example an online one - https://sharplab.io/. Among the others capabilities it provides ability to see the decompiled to IL(not very useful here), C# (basically desugared version of the code, for this one - see, also not very useful here) and also syntax tree (for this one - see), which can be useful in this particular case. I've used next code (so it can be compiled in release mode without optimizing constants out):
public class C {
public void M(int? i) {
if (i !!= 5)
Console.WriteLine("vvvvvv");
}
}
If you expand CompilationUnit ->
ClassDeclaration -> MethodDeclaration -> Body ->
IfStatement -> Condition -> Left you will see that it is actually SuppressNullableWarningExpression with operand being i:
With sharplab.io kindly highlighting the part of the code which is represented by selected syntax node. So as others described you can see that compiler parses your code as 4 followed by null-forgiving operator.

Prepare syntax tree (ast) to easily perform short circuit operations

What is the best way to prepare a syntax tree containing conditions to allow easy and fast short curcuit usage?
The rules of short circuit in general are very easy:
If one component in an and block returns false, the complete block will return false and execution can be exited
If one component in an or block returns true, the complete block will return true and execution can be exited
So for example this simple statement will be evaluated to the following syntax tree 1 = 0 and 1 = 1:
and
/ \
= =
/ \ / \
1 0 1 1
In this case it is easy. After executing the first part of the tree (branch),
the execution will be exited it only can return false. But if the tree gets more
complex, there must be a way to be more efficient. Or is this already the most
efficient way?
For example, how does the c# compiler evaluate the syntax tree in this cases?
EDIT
Should I write all conditions in a simple list, and branch to the end if true or false is not possible? So that i have no and and or parts at the end?
Thank you all a lot!
Your definition of short circuiting doesn't quite match that of C# and other languages. In most (presumably all) languages that have short circuiting the behavior depends on the value of the left operand only, that is:
left && right always evaluates left and only evaluates right if left was true.
left || right always evaluates left and only evaluates right if left was false.
So the rules of the language guarantee you that the right operand will never be tried first, even if the compiler may think that trying the right operand first would be more efficient. This way you know that list == null || list.IsEmpty() can't ever throw a null pointer exception.
So to answer your question, the compiler won't generate anything more efficient than "evaluate the left operand and then evaluate the right operand only if you have to" because anything else would break the rules of the language.
PS: In theory it would be possible for the compiler to reorder the operands if it can prove that they don't have any side-effects, but to the best of my knowledge that is not done. Either way that would not happen at the AST level.
PPS: The C# compiler does not evaluate the AST, it generates code from it. It's a compiler, not an interpreter.

Constants and compile time evaluation - Why change this behaviour

If you forward to approximately 13 minutes into this video by Eric Lippert he describes a change that was made to the C# compiler that renders the following code invalid (Apparently prior to and including .NET 2 this code would have compiled).
int y;
int x = 10;
if (x * 0 == 0)
y = 123;
Console.Write(y);
Now I understand that clearly any execution of the above code actually evaluates to
int y;
int x = 10;
y = 123;
Console.Write(y);
But what I dont understand is why it is considered "desirable" to make the following code in-compilable? IE: What are the risks with allowing such inferences to run their course?
I'm still finding this question a bit confusing but let me see if I can rephrase the question into a form that I can answer. First, let me re-state the background of the question:
In C# 2.0, this code:
int x = 123;
int y;
if (x * 0 == 0)
y = 345;
Console.WriteLine(y);
was treated as though you'd written
int x = 123;
int y;
if (true)
y = 345;
Console.WriteLine(y);
which in turn is treated as:
int x = 123;
int y;
y = 345;
Console.WriteLine(y);
Which is a legal program.
But in C# 3.0 we took the breaking change to prevent this. The compiler no longer treats the condition as being "always true" despite the fact that you and I both know that it is always true. We now make this an illegal program, because the compiler reasons that it does not know that the body of the "if" is always executed, and therefore does not know that the local variable y is always assigned before it is used.
Why is the C# 3.0 behaviour correct?
It is correct because the specification states that:
a constant expression must contain only constants. x * 0 == 0 is not a constant expression because it contains a non-constant term, x.
the consequence of an if is only known to be always reachable if the condition is a constant expression equal to true.
Therefore, the code given should not classify the consequence of the conditional statement to be always reachable, and therefore should not classify the local y as being definitely assigned.
Why is it desirable that a constant expression contain only constants?
We want the C# language to be clearly understandable by its users, and correctly implementable by compiler writers. Requiring that the compiler make all possible logical deductions about the values of expressions works against those goals. It should be simple to determine whether a given expression is a constant, and if so, what its value is. Put simply, the constant evaluation code should have to know how to perform arithmetic, but should not need to know facts about arithmetical manipulations. The constant evaluator knows how to multiply 2 * 1, but it does not need to know the fact that "1 is the multiplicative identity on integers".
Now, it is possible that a compiler writer might decide that there are areas in which they can be clever, and thereby generate more optimal code. Compiler writers are permitted to do so, but not in a way that changes whether code is legal or illegal. They are only allowed to make optimizations that make the output of the compiler better when given legal code.
How did the bug happen in C# 2.0?
What happened was the compiler was written to run the arithmetic optimizer too early. The optimizer is the bit that is supposed to be clever, and it should have run after the program was determined to be legal. It was running before the program was determined to be legal, and was therefore influencing the result.
This was a potential breaking change: though it brought the compiler into line with the specification, it also potentially turned working code into error code. What motivated the change?
LINQ features, and specifically expression trees. If you said something like:
(int x)=>x * 0 == 0
and converted that to an expression tree, do you expect that to generate the expression tree for
(int x)=>true
? Probably not! You probably expected it to produce the expression tree for "multiply x by zero and compare the result to zero". Expression trees should preserve the logical structure of the expression in the body.
When I wrote the expression tree code it was not clear yet whether the design committee was going to decide whether
()=>2 + 3
was going to generate the expression tree for "add two to three" or the expression tree for "five". We decided on the latter -- constants are folded before expression trees are generated, but arithmetic should not be run through the optimizer before expression trees are generated.
So, let's consider now the dependencies that we've just stated:
Arithmetic optimization has to happen before codegen.
Expression tree rewriting has to happen before arithmetic optimizations
Constant folding has to happen before expression tree rewriting
Constant folding has to happen before flow analysis
Flow analysis has to happen before expression tree rewriting (because we need to know if an expression tree uses an uninitialized local)
We've got to find an order to do all this work in that honours all those dependencies. The compiler in C# 2.0 did them in this order:
constant folding and arithmetic optimization at the same time
flow analysis
codegen
Where can expression tree rewriting go in there? Nowhere! And clearly this is buggy, because flow analysis is now taking into account facts deduced by the arithmetic optimizer. We decided to rework the compiler so that it did things in the order:
constant folding
flow analysis
expression tree rewriting
arithmetic optimization
codegen
Which obviously necessitates the breaking change.
Now, I did consider preserving the existing broken behaviour, by doing this:
constant folding
arithmetic optimization
flow analysis
arithmetic de-optimization
expression tree rewriting
arithmetic optimization again
codegen
Where the optimized arithmetic expression would contain a pointer back to its unoptimized form. We decided that this was too much complexity in order to preserve a bug. We decided that it would be better to instead fix the bug, take the breaking change, and make the compiler architecture more easily understood.
The specification states that the definite assignment of something that is only assigned inside an if block is undetermined. The spec says nothing about compiler magic that removes the unnecessary if block. In particular, it makes for a very confusing error message as you change the if condition, and suddenly get an error about y not being assigned "huh? I haven't changed when y is assigned!".
The compiler is free to perform any obvious code removal it wants to, but first it needs to follow the specification for the rules.
Specifically, section 5.3.3.5 (MS 4.0 spec):
5.3.3.5 If statements
For an if statement stmt of the form:
if ( expr ) then-stmt else else-stmt
v has the same definite assignment state at the beginning of expr as at the beginning of stmt.
If v is definitely assigned at the end of expr, then it is definitely assigned on the control flow transfer to then-stmt and to either else-stmt or to the end-point of stmt if there is no else clause.
If v has the state “definitely assigned after true expression” at the end of expr, then it is definitely assigned on the control flow transfer to then-stmt, and not definitely assigned on the control flow transfer to either else-stmt or to the end-point of stmt if there is no else clause.
If v has the state “definitely assigned after false expression” at the end of expr, then it is definitely assigned on the control flow transfer to else-stmt, and not definitely assigned on the control flow transfer to then-stmt. It is definitely assigned at the end-point of stmt if and only if it is definitely assigned at the end-point of then-stmt.
Otherwise, v is considered not definitely assigned on the control flow transfer to either the then-stmt or else-stmt, or to the end-point of stmt if there is no else
For an initially unassigned variable to be considered definitely assigned at a certain location, an assignment to the variable must occur in every possible execution path leading to that location.
technically, the execution path exists where the if condition is false; if y was also assigned in the else, then fine, but... the specification explicitly makes no demand of spotting the if condition is always true.

Is (--i == i++) an Undefined Behavior?

this question is related to my previous problem. The answer I got was "It is an Undefined behavior."
Please anyone explain:
What is an undefined behavior?
how can I know my code has an undefined behavior?
Example code:
int i = 5;
if (--i == i++)
Console.WriteLine("equal and i=" + i);
else
Console.WriteLine("not equal and i=" + i);
//output: equal and i=6
What is an Undefined-Behaviour?
It's quite simply any behaviour that is not specifically defined by the appropriate language specification. Some specs will list certain things as explicitly undefined, but really anything that's not described as being defined is undefined.
how can I know my code has an undefined behavior?
Hopefully your compiler will warn you - if that's not the case, you need to read the language specification and learn about all the funny corner cases and nooks & crannies that cause these sorts of problems.
Be careful out there!
It's undefined in C, but well-defined in C#:
From C# (ECMA-334) specification "Operator precedence and associativity" section (§14.2.1):
Except for the assignment operators and the null coalescing operator, all
binary operators are left-
associative, meaning that operations
are performed from left to right.
[Example: x + y + z is evaluated as (x + y) + z. end example]
So --i is evaluated first, changing i to 4 and evaluating to 4. Then i++ is evaluating, changing i to 5, but evaluating to 4.
Yes, that expression is undefined behavior as well (in C and C++). See http://en.wikipedia.org/wiki/Sequence_point for some information on the rules; you can also search for "sequence point" more generally (that is the set of rules that your code violates).
(This assumes C or C++.)
Carl's answer is exact in general.
In specific, the problem is what Jeremiah pointed out: sequence points.
To clarify, the chunk of code (--i == ++i) is a single "happening". It's a chunk of code that's evaluated all at once. There is no defined order of what happens first. The left side could be evaluated first, or the right side could, or maybe the equality is compared, then i is incremented, then decremented. Each of these behaviors could cause this expression to have different results. It's "undefined" what will happen here. You don't know what the answer will be.
Compare this to the statement i = i+1; Here, the right side is always evaluated first, then its result is stored into i. This is well-defined. There's no ambiguity.
Hope that helps a little.
In C the result is undefined, in C# it's defined.
In C, the comparison is interpreted as:
Do all of these, in any order:
- Decrease i, then get value of i into x
- Get value of i into y, then increase i
Then compare x and y.
In C# there are more operation boundaries, so the comparison is interpreted as:
Decrease i
then get value of i into x
then get value of i into y
then increase i
then compare x and y.
It's up to the compiler to choose in which order the operations are done within an operation boundary, so putting contradictory operations within the same boundary causes the result to be undefined.
Because the C standard states so. And your example clearly shows an undefined behabiour.
Depending on the order of evaluation, the comparison should be 4 == 5 or 5 == 6. And yet the condition returns True.
Your previous question was tagged [C], so I'm answering based on C, even though the code in your current question doesn't look like C.
The definition of undefined behavior in C99 says (§3.4.3):
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
Appendix J.2 of the C standard has a (long -- several pages) list of undefined behavior, though even that still isn't exhaustive. For the most part, undefined behavior means you broke the rules, so the way to know it is to know the rules.
Undefined behavior == the result cannot be guaranteed to always be the same whenever you run it in the exact same conditions, or the result cannot be guaranteed to always be the same whenever you use different compilers or runtimes to execute it.
In your code, since it is using a equal comparison operator which does not specify which side of the operands should be executed first, --i or i++ may end up running first, and your answer will depend on the actual implementation of the compiler. If --i is executed first, it will be 4 == 4, i=5; if i++ is implemented first, it will be 5 == 5, i=5.
The fact that the answer may turn out to be the same does not prevent the compiler from warning you that this is an undefined operation.
Now if this is a language that defines that the left hand side (or right hand side) should always be executed first, then the behavior will no longer be undefined.

Nothing != null - or does it?

Recently in a previous project I came across a peculiar difference between VB.NET and C#.
Consider the following C# expression which:
null <= 2
This expression evaluates to False which is what I would expect.
Then the corresponding VB.NET expression:
Nothing <= 2
I was surprised to learn that this expression actually evaluates to True
It seems like a fairly fundamental design decision between the two languages and it certainly caught me out.
Is anyone able to tell me why?
Are null and Nothing one and the same?
If so, why do they behave differently?
Nothing in VB evaluates to the default value for a given type. (See this link for details.)
For an integer comparison (which the compiler will assume from the right hand operand), Nothing will thus be 0. 0 <= 2 is true for more obvious reasons :-)

Categories