Is this:
if(x != y)
{
}
different from this:
if (x is not y)
{
}
Or are there no differences between the two conditions?
The not-equal-to operator ( != ) returns true if the operands don't have the same value; otherwise, it returns false .
operator in C. Logical NOT is denoted by exclamatory characters (!), it is used to check the opposite result of any given test condition. If any condition's result is non-zero (true), it returns 0 (false) and if any condition's result is 0(false) it returns 1 (true).
is and is not are the identity operators in Python. They are used to check if two values (or variables) are located on the same part of the memory. Two variables that are equal does not imply that they are identical.
In early C, the operator && did not exist, and because of that & was used for this purpose. One way to explain it is that you could imagine that & is the same thing as applying && on each individual bit in the operands. Also note that & has lower precedence than &&, even though intuition says that it should be the other way around.
All the operators listed exist in C++; the column "Included in C", states whether an operator is also present in C. Note that C does not support operator overloading . When not overloaded, for the operators &&, ||, and , (the comma operator ), there is a sequence point after the evaluation of the first operand.
The difference in coverage is detailed by each different category of clause: A, B, and C. Clause C is the most restrictive of the three, with A being the broadest. As stated above, Institute Cargo Clause A is the widest coverage you can purchase, also known as an ‘All Risks’ Cargo insurance policy.
The “ = ” is an assignment operator is used to assign the value on the right to the variable on the left. The ‘==’ operator checks whether the two given operands are equal or not. If so, it returns true.
Operator | != |
is not |
---|---|---|
Original purpose | Value inequality | Negated pattern matching |
Can perform value inequality | Yes | Yes |
Can perform negated pattern matching | No | Yes |
Can invoke implicit operator on left-hand operand |
Yes | No |
Can invoke implicit operator on right-hand operand(s) |
Yes | Yes1 |
Is its own operator | Yes | No2 |
Overloadable | Yes | No |
Since | C# 1.0 | C# 9.03 |
Value-type null-comparison branch elision4 | Yes | No[Citation needed]5 |
Impossible comparisons | Error | Warning |
Left operand | Any expression | Any expression |
Right operand(s) | Any expression | Only constant expressions6 |
Syntax | <any-expr> != <any-expr> |
<any-expr> is [not] <const-expr> [or|and <const-expr>]* and more |
Example | != |
is not |
---|---|---|
Not null | x != null |
x is not null |
Value inequality example | x != 'a' |
x is not 'a' |
Runtime type (mis)match | x.GetType() != typeof(Char) |
x is not Char 7
|
SQL x NOT IN ( 1, 2, 3 )
|
x != 1 && x != 2 && x != 3 |
x is not 1 or 2 or 3 |
To answer the OP's question directly and specifically:
if( x != y ) { }
// vs:
if( x is not y ) { }
If x
is an integral value-type (e.g. int
/ Int32
) and y
is a const-expression
(e.g. const int y = 123;
) then no, there is no difference, and both statements result in the same .NET MSIL bytecode being generated (both with and without compiler optimizations enabled):
If y
is a type-name (instead of a value name) then there is a difference: the first if
statement is invalid and won't compile, and the if( x is not y )
statement is a type pattern match instead of a constant pattern match.
Footnotes:
"Constant Pattern": "When the input value is not an open type, the constant expression is implicitly converted to the type of the matched expression".
x is not null
is more analogous to !(x == null)
than x != null
.
C# 7.0 introduced some limited forms of constant-pattern matching, which was further expanded by C# 8.0, but it wasn't until C# 9.0 that the not
negation operator (or is it a modifier?) was added.
Given a non-constrained generic method, like so:
void Foo<T>( T x )
{
if( x == null ) { DoSomething(); }
DoSomethingElse();
}
...when the JIT instantiates the above generic method (i.e.: monomorphization) when T
is a value-type (struct
) then the entire if( x == null ) { DoSomething(); }
statement (and its block contents) will be removed by the JIT compiler ("elision"), this is because a value-tupe can never be equal to null
. While you'd expect that to be handled by any optimizing compiler, I understand that the .NET JIT has specially hardcoded rules for that particular scenario.
==
and !=
operators, but not the is
operator, so while if( x == null ) { DoSomething(); }
would be elided, the statement if( x is null ) { DoSometing(); }
would not, and in fact you would get a compiler error unless T
was constrained to where T : class
. Since C# 8.0 this seems to now be allowed for unconstrained generic types.Surprisingly I couldn't find an authoritative source on this (as the published C# specs are now significantly outdated; and I don't want to go through the csc
source-code to find out either).
Note that a constant-expression does not mean a literal-expression: you can use named const
values, enum
members, and so on, even non-trivial raw expressions provided all sub-expressions are also constant-expressions.
static readonly
fields could be used though.Note that in the case of typeof(X) != y.GetType()
, this expression will return true
when X
is derived from y
's type (as they are different types), but x is not Y
is actually false
because x
is Y
(because x
is an instance of a subclass of Y
). When using Type
it's better to do something like typeof(X).IsSubclassOf(y.GetType())
, or the even looser y.GetType().IsAssignableFrom(typeof(X))
.
Char
is a struct and so cannot participate in a type-hierarchy, so doing !x.IsSubclassOf(typeof(Char))
would just be silly.An additional difference to the ones listed in the excellent accepted answer is that (since C# 7.0), is
between two NaN values is a pattern that matches, because x.Equals(y)
is true
when both x
and y
are NaN, and a NaN value does not have an integral type. Therefore, is not
between two NaN values returns that the pattern is not a match.
However, C# follows IEEE floating-point and C by specifying that a !=
comparison between two NaN values is true
and an ==
comparison between them is false
. This was mainly because the Intel 8087 floating-point co-processor back in 1980 had no other way to test for NaN.
Nan and null are properties that variables can contain that have no values. Equality checks require an actual value to determine equality. After all the question on whether Sally and Peter has the same amount of apples when nobody knows how many Apples either of them has is meaningless.
Sometimes you want to check if a variable has a property without a value. A basic equality check would not be sufficient for this. That is when is / is not operator is useful. It could be said != is a value check where is / is not a property check.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With