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.
Related
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.
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.
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.
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 :-)
What is the best was to evaluate an expression like the following:
(A And B) Or (A And C) Or (Not B And C)
or
(A && B) || (A && C) || (!B && C)
At runtime, I was planning on converting the above expressions to the following:
(True And False) Or (True And False) Or (Not False And True)
or
(True && False) || (True && False) || (! False && True)
Conditions:
1) The logical expression is not known until runtime.
2) The number variable and their values are not known until runtime.
3) Variable values are never null.
I know I could create a simple assemble with a class and a method that I generate at runtime based on the inputs, but is there a better way.
I have done this before. Use a string builder to write the code, then call the compiler. After that, you load the assembly and call the method.
Suggestions?
Thanks.
If you're using .NET3.5 then you can parse the text and create an abstract sytax tree using the Expression classes. Then create a suitable LambdaExpression instance and compile it into a delegate, which you can then execute.
Constructing a parser and syntax tree builder for this kind of fairly simple grammer is quite an interesting exercise, and will execute somewhat faster than invoking the compiler (and it's neater in my view as well).
If you're not using .NET3.5, then it's also not complicated to implement an interpreted abstract syntax tree yourself.
Be warned: the two final conditions you're talking about are not necessarily equivalent. The && operators in C# will use short-circuit evalution, while the logical And operator in VB does not. If you want to be sure the statements are equivalent, translate a user And to AndAlso and a user Or to OrElse.
For simple expresssions you probably won't notice a difference. But if the conditions can have side effects or if the performance difference between the two is a concern, this can be important.
You can use https://github.com/mrazekv/logicalparser
Its simply library to write logical expression (evaulated with precenednce table, allows to OR, NOT, AND operator and >, >=, <=, < on integer variables and = on string variables)
You can do this easily with:
a parser generator (like ANTLR, mentioned above) that takes boolean expressions as input and produces an infix list and
code to evaluate a Reverse Polish Notation stack.
The grammar looks something like this:
program: exprList ;
exprList: expr { Append($1); }
| expr OR exprList { Append(OR); }
| expr AND exprList { Append(AND); }
| NOT exprList { Append(NOT); }
| ( exprList ) { /* Do nothing */ }
;
expr: var { Append($1); }
| TRUE { Append(True); }
| FALSE { Append(False); }
;
To evaluate, you do this:
for each item in list
if item is symbol or truth value, push onto RPN stack
else if item is AND, push (pop() AND pop())
else if item is OR, push (pop() OR pop())
else if item is NOT, push (NOT pop())
result = pop()
For symbols, you have to substitute the truth value at runtime.
You can write a simple interpreter/parser. Use something like ANTLR and reuse existing grammars.
If you are using .NET 3.5, you can create a Lambda Expression. Then you can create a delegate from it and call as standard delegate/method.
On the internet is a lot of samples about Lambda Expressions.
One solution would be to assemble the expression as a string, and then send it SQL Server, or whatever your database is for evaluation. Replace the actual variables with 1=1 or 0=1 for True and False respectively, and you would end up with a query like this:
SELECT 1 WHERE (1=1 And 0=1) Or (1=1 And 1=1) Or (Not 0=1 And 1=1)
Then when you run the query, you get a 1 back when the result is true. May not be the most elegant solution, but it will work. A lot of people will probably advise against this, but I'm just going to throw it out there as a possible solution anyway.
This will not be the best answer, but I myself had this problem some time ago.
Here is my old code:
VB.Net - no warranty at all!
https://cloud.downfight.de/index.php/s/w92i9Qq1Ia216XB
Dim BoolTermParseObjekt As New BoolTermParse
MsgBox(BoolTermParseObjekt.parseTerm("1 und (((0 oder 1 und (0 oder 4))) oder 2)").ToString)
This code eats a String with multiple '(', ')', 'and', 'or' plus 'other things' and breaks down the logic to a boolean by replacing the things with boolean values.
therefore:
Whatever 'other things' I wanted to evaluate I had to put in Function resolveTerm()
at the comment "'funktionen ausführen und zurückgeben, einzelwert!"
in page 2.
There the only evaluation rightnow is "If number is > 1"
Greetings
Take a look at my library, Proviant. It's a .NET Standard library using the Shunting Yard algorithm to evaluate boolean expressions.
It could also generate a truth-table for your expressions.
You could also implement your own grammar.