5.6.9.5 Relational Operators
Note
This section describes the implementation of MS-VBAL §5.6.9.5 Relational Operators.
Runtime Semantics
Relational operators are simple data operators: they validate their operands through
OperatorRuntimeSemantics.LetCoerceNonNullOperand
(RD-VBAL §5.6.9.2 Simple Data Operators).
Relational operators compare in the effective type, and yield a VBBooleanValue.
| Effective type | Compared in |
|---|---|
| Integral | The effective type's own representation: for example Long as a 32-bit int, and LongLong as a 64-bit long. |
Boolean |
A 64-bit integer (long). |
Fixed-point (Currency, Decimal) |
decimal |
String |
The data of the strings, in the module's comparison mode. See String comparison. |
| Condition | Run-time error |
|---|---|
An operand is NaN. |
6 — Overflow |
Run-time error 6 is VBRuntimeErrorId.Overflow.
👉 The range checks of a For loop use the relational operators
RDCore.Runtime.Semantics.Operators.Relational.BinaryGtRelationalOperatorRuntimeSemantics and
BinaryLtRelationalOperatorRuntimeSemantics, not a raw numeric comparison
(RD-VBAL §5.4.2.3 For Statement).
Variant String/Numeric comparison
RD-VBA implements the Variant String/Numeric comparison exception of MS-VBAL §5.6.9.5 as run-time behaviour.
The exception applies when both relational operands are Variant, one originally holding a String value and the
other a numeric value:
- The numeric operand is always considered less than the
Stringoperand, regardless of their actual values. - RD-VBA never attempts to coerce the
Stringoperand to a number. Depending on its content, that coercion would fail, or succeed incorrectly.
BinaryRelationalOperatorRuntimeSemantics handles the exception as a short-circuit:
- It detects the
VariantString/Numeric case before normal effective-type determination and coercion run. - It reduces the case to a synthetic
Integerrank for each operand (table below). - The relational operator's ordinary
Integerevaluation branch compares the synthetic ranks.
| Operand | Synthetic Integer rank |
|---|---|
The numeric-holding Variant |
0 |
The String-holding Variant |
1 |
The short-circuit runs before normal coercion because normal coercion would otherwise try, and fail, to coerce the
String to a number. Because the case is reduced to synthetic ranks, the Variant String/Numeric case needs no
separate evaluation path.
The comparison is legitimate, and almost never meant: the analysis states it as a fact of the operation
(ComparisonOperatorSemanticFlags.IsVariantStringNumericException), and RDCore.Diagnostics reports it as
RDC11011, a warning.
Variant compared with a String
RD-VBA compares a Variant holding a number, a Date or a Boolean with a String operand that is not a Variant (a
variable declared As String, or a string literal) as text, as MS-VBA does:
- The effective value type is
String. - The
Variant's value is Let-coerced toString, and the twoStringvalues are compared (String comparison). - No error is raised, whatever the
Stringholds.
🎯 This departs from MS-VBAL §5.6.9.5. Its effective-value-type table gives a numeric operand and a String operand
the numeric type, so the String is Let-coerced to a number, which raises run-time error 13 (Type mismatch) when it is
not one. Its one exception covers two Variant operands only (above).
MS-VBA compares the text instead, as Microsoft Learn documents it: "One expression is a String and the other is any Variant except a Null: perform a string comparison". These results were measured in Excel:
Variant holds |
String |
Comparison | MS-VBA | MS-VBAL §5.6.9.5 |
|---|---|---|---|---|
0@ (Currency) |
"." |
= |
False |
Type mismatch (13) |
5@ |
"." |
> |
True, as "5" comes after "." |
Type mismatch (13) |
10@ |
"9" |
> |
False, as "10" comes before "9" |
True |
1.5 |
"1.5" |
= |
True |
True |
10 |
"" |
> |
True |
Type mismatch (13) |
#1/2/2020# |
"x" |
= |
False |
Type mismatch (13) |
True |
"x" |
= |
False |
Type mismatch (13) |
When neither operand is a Variant (a Currency and a String variable, say), the table applies, and MS-VBA raises the
type mismatch too. A Variant holding an Error keeps the table's behaviour, which nothing has measured otherwise.
RD-VBA runs the code as MS-VBA does. The analysis states the departure as a fact of the operation
(ComparisonOperatorSemanticFlags.IsVariantComparedWithStringAsText), and RDCore.Diagnostics reports it as
RDC11013, a warning that stands in for the type mismatch the specification raises.
A Variant String compared with a number
The other way around: one operand is a Variant holding a String, and the other a number, a Date or a Boolean that
is not a Variant (a variable declared with the type, a literal). RD-VBA compares them as MS-VBA does:
- When the
StringLet-coerces to the effective value type the table gives, the table applies:"3" < 5isTrue, and so are"&H3" < 5,"(3)" < 0and"$3" < 5. A date's text compared with aDateis read as aDate(below), and"True" = TrueisTrue. - When the coercion is a type mismatch, nothing is raised, and the
Stringranks above the other operand, whatever its value, as it does when both operands areVariantvalues (above):"abc" > 5isTrue,"abc" = 5isFalse, and5 < "abc"isTrue. - Any other error of the coercion is raised: a number's text too large for the type overflows (6).
🎯 This departs from MS-VBAL §5.6.9.5. Its table makes the String's coercion to the effective type a type mismatch
(13), and so does Microsoft Learn's
Comparison operators
page, for a Variant string that can't be converted to a number. These results were measured in Excel (oracle\s48 H,
I, K, L):
Variant holds |
Other operand | Comparison | MS-VBA | MS-VBAL §5.6.9.5 |
|---|---|---|---|---|
"abc" |
5 |
<, >, = |
False, True, False |
Type mismatch (13) |
"" |
5 |
< |
False |
Type mismatch (13) |
"1/2/1900" |
5, 34 |
< |
False, False (the text of a date is no number) |
Type mismatch (13) |
"1/2/1900" |
a Date of 5 |
< |
True, as 1/2/1900 is day 3 |
True |
"abc" |
a Date, a Boolean, a Currency, a Byte |
> |
True |
Type mismatch (13) |
"3" |
5, an Integer, a Date, a Boolean, a Currency |
< |
True |
True |
A String declared as one is not a Variant: s < 5, with s holding "abc", raises the type mismatch in MS-VBA as
the table says, and in RD-VBA. The analysis states the departure as a fact of the operation
(ComparisonOperatorSemanticFlags.IsVariantStringThatIsNoValueRanked), and RDCore.Diagnostics reports it as
RDC11020, a warning that stands in for the type mismatch the specification raises.
A String compared with a Date
The table gives a String and a Date the effective type Date. The operands of a Date effective type are compared by
their serial, a Double. A String operand is first Let-coerced to Date, which reads the text of a date as one, and is
then compared by its serial: "1/2/1900" compared with a Date of 5 compares day 3 with day 5 (oracle\s48 K04).
String comparison
Each of the six operators compares two String operands as
StringComparisonRules.Compare orders them, against 0.
Compare is the one place a String order is defined, and Select Case compares through the same operators. It
compares in the comparison mode of the module (RD-VBAL §5.2.1.1 Option Compare Directive),
and sees every byte of a string's data, a trailing byte included
(RD-VBAL §2.4.1.2 VBStringType).
| Mode | Two Strings compare by |
|---|---|
| Binary | Their data: the code units, in order, then a trailing byte. A string whose code units begin another's, followed by more, is greater. Between the same code units, no trailing byte is less than any, and two trailing bytes compare by value. |
| Text | Their characters regardless of case, according to the environment's regional settings. A trailing byte is not text: it only breaks a tie between two strings that are equal regardless of case, the same way. |
🎯 MS-VBAL §5.6.9.5 compares "each byte of the implementation-specific representation of the string data". Binary
mode compares the code units of that data rather than its bytes one by one. The two find the same strings equal, and
order alike any two strings whose characters are all below U+0100. Where they differ, RD-VBA's representation is
little-endian: "Ł" (41 01) is greater than "B" (42 00) by code unit, and would be less byte by byte.
Like matches characters against a pattern of characters, and a trailing byte is not one
(RD-VBAL §5.6.9.6 Like Operator).
5.6.9.5.1 = Operator
This section corresponds to MS-VBAL §5.6.9.5.1 = Operator.
Note
Reserved. This section has no content yet.
5.6.9.5.2 <> Operator
This section corresponds to MS-VBAL §5.6.9.5.2 <> Operator.
Note
Reserved. This section has no content yet.
5.6.9.5.3 < Operator
This section corresponds to MS-VBAL §5.6.9.5.3 < Operator.
Note
Reserved. This section has no content yet.
5.6.9.5.4 > Operator
This section corresponds to MS-VBAL §5.6.9.5.4 > Operator.
Note
Reserved. This section has no content yet.
5.6.9.5.5 <= Operator
This section corresponds to MS-VBAL §5.6.9.5.5 <= Operator.
Note
Reserved. This section has no content yet.
5.6.9.5.6 >= Operator
This section corresponds to MS-VBAL §5.6.9.5.6 >= Operator.
Note
Reserved. This section has no content yet.
⏮️ RD-VBAL §5.6.9.4 & Operator | ⏭️ RD-VBAL §5.6.9.6 Like Operator