Comparison Operators¶
| Operator | Description |
|---|---|
== |
Equality |
!= |
Inequality |
< |
Less than |
> |
Greater than |
<= |
Less than or equal |
>= |
Greater than or equal |
Operand types¶
A comparison's result is always bool, but its operands go through the same binary numeric
promotion as +, - and * — C# §12.4.7, tabulated in
Numeric Type Promotion. A pair the table refuses
is refused here too: the comparison operators do not have a wider set of admissible pairs than the
arithmetic ones.
| Left | Right | Comparison | Notes |
|---|---|---|---|
uint32 |
int16 |
bool |
Both promote to int64, then compare |
uint64 |
uint32 |
bool |
Both promote to uint64 |
uint64 |
1 |
bool |
Constant operand converts first (§10.2.11) |
int |
float |
bool |
Integer promotes to float64 |
decimal |
int |
bool |
Integer promotes to decimal |
float32 |
float64 |
bool |
Lower precision promotes |
uint64 |
any signed | ❌ SPY0222 | No common type; cast one operand |
decimal |
float64 |
❌ SPY0222 | No common type; convert one operand |
a: uint32 = 5
b: int16 = 4
r: bool = a > b # True — both promote to int64
c: uint64 = 5
d: uint32 = 4
s: bool = c > d # True — both promote to uint64
t: bool = c < 1 # False — the constant 1 converts to uint64 first
Pairs with no common type¶
uint64 against any signed type has no common type in C# (§12.4.7 offers long and ulong, and
neither holds both ranges), so the comparison is refused:
e: uint64 = 5
f: int32 = 4
# g: bool = e < f # ERROR (SPY0222): Type 'uint64' does not support
# # operator '<' with operand of type 'int32'
h: bool = int64(e) < int64(f) # False — compare as int64
i: bool = e < uint64(f) # False — or compare as uint64
Pick the cast that matches the range you actually need: int64(e) loses values above 2⁶³−1,
uint64(f) loses negative values.
decimal against float64 is refused for the same structural reason — C# has no implicit
conversion in either direction, because decimal has more precision and double more range:
d1: decimal = 1
f1: float64 = 2.0
# j: bool = d1 < f1 # ERROR (SPY0222): Type 'decimal' does not support
# # operator '<' with operand of type 'float64'
k: bool = d1 < decimal(f1) # True — compare as decimal
l: bool = float(d1) < f1 # True — or compare as float64
This is an Axiom-1 deviation. CPython compares the two happily (Decimal(1) < 2.0 is True),
because it converts the float to an exact decimal for the comparison. Sharpy follows .NET, where
the pair does not bind. Catalogued in docs/deviations.yaml as decimal-float-comparison-refused;
the remedy is to name the type you want to compare in.
Comparing against None¶
x == None is refused for a value-typed operand — the supported spelling is x is None, and the
diagnostic says so:
x: int = 1
# if x == None: # ERROR (SPY0222): Type 'int32' does not support operator
# # '==' with operand of type 'None'. Did you mean 'is None'?
y: int | None = None
# if y == None: # ERROR (SPY0222): Type 'int32 | None' does not support operator
# # '==' with operand of type 'None'. Did you mean 'is None'?
A reference-typed operand compares against None directly — the comparison lowers to a null
check, which is what the author meant:
is None works for both and is the spelling that narrows (see
Type Narrowing), so prefer it everywhere.
Implementation - ✅ Native - Direct mapping.