---
title: Compare versions numerically
summary: Evaluate equality and ordering by normalizing each version segment to its numeric value.
status: draft
owner: SAIF Team
last_reviewed: 2026-07-30
library: SAIF.Framework.Version
reference_type: package
operation_id: OP-VER-003
trigger: Caller invokes CompareTo or operators =, <>, <, >
---

# Compare versions numerically

This operation defines equality and ordering for `Version` instances. Rather than comparing the raw segment strings, it converts each of `Major`, `Minor`, `Build`, and `Revision` to an integer and compares those integers in `Major` → `Minor` → `Build` → `Revision` precedence. The same normalization and precedence rules back all four comparison operators and the `IComparable` implementation.

| Field | Value |
| --- | --- |
| **Operation ID** | `OP-VER-003` |
| **Trigger** | Caller invokes `CompareTo` or operators `=`, `<>`, `<`, `>` |
| **Inputs** | Two `Version` instances, or `obj As Object` for `CompareTo` |
| **Outputs** | Boolean operator result or integer `CompareTo` result |
| **Primary components** | `Version.CompareTo`, `Version.=`, `Version.<>`, `Version.<`, `Version.>`, `Extensions.ToInt` |
| **Entry point** | `SAIF.Framework.Version\Version.vb` |

## Steps

1. If the caller used `CompareTo(obj)`, cast `obj` to `SAIF.Framework.Version.Version` before any operator logic runs.
   - On failure: if `obj` is `Nothing` or not a `Version`, the cast throws and the exception bubbles unchanged to the caller.
2. Normalize every segment that will be compared by passing its string value through `ToInt` ([BR-001](../business-rules.md#br-001-non-numeric-leading-characters-in-a-version-segment-are-coerced-to-0), [BR-006](../business-rules.md#br-006-equality-and-ordering-are-defined-purely-by-the-four-numeric-components-not-by-string-equality)).
   - `ToInt` extracts only the leading run of digits, via `Regex.Match(value, "\d*")`.
   - On failure: if the extracted text still fails integer conversion, an empty `Catch` block swallows the error and the normalized value becomes `0` ([BR-001](../business-rules.md#br-001-non-numeric-leading-characters-in-a-version-segment-are-coerced-to-0)).
3. For the `=` operator, compare the normalized `Major`, `Minor`, `Build`, and `Revision` pairs and return `True` only when all four match ([BR-006](../business-rules.md#br-006-equality-and-ordering-are-defined-purely-by-the-four-numeric-components-not-by-string-equality)).
4. For the `<>` operator, run the same four-part equality test and return its logical negation.
5. For the `<` and `>` operators, walk the normalized segments in `Major` → `Minor` → `Build` → `Revision` order and stop as soon as one segment determines the relation ([BR-006](../business-rules.md#br-006-equality-and-ordering-are-defined-purely-by-the-four-numeric-components-not-by-string-equality)).
   - If an earlier segment already establishes the relation: return immediately without inspecting later segments.
   - If every compared segment is equal: return `False` — neither operator considers two equal versions to be less-than or greater-than each other.
6. Before the minor-segment comparison, both the `<` and `>` operators evaluate a guard condition intended to confirm the majors are equal. As written, the condition compares `v2.Major.ToInt` against itself (`v2.Major.ToInt = v2.Major.ToInt`) rather than against `v1.Major.ToInt` ([BR-007](../business-rules.md#br-007-tautological-major-equality-check-in-the--and--operators)).
   - This guard is always `True`, so it never actually re-verifies major equality at this point.
   - Execution still proceeds correctly in practice: the preceding major-based less-than/greater-than checks already gate entry into this branch, so the tautology does not currently change any returned result — but it should be corrected to compare `v1` against `v2`.
7. When invoked via `CompareTo`, translate the operator outcomes into the standard contract: return `0` if `v2 = Me`, `1` if `v2 < Me`, and `-1` if `v2 > Me` ([BR-006](../business-rules.md#br-006-equality-and-ordering-are-defined-purely-by-the-four-numeric-components-not-by-string-equality)).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Caller requests comparison]) --> Cast{Invoked via CompareTo?}
	Cast -->|Yes| CastObj[Cast obj to Version]
	Cast -->|No| Normalize[Normalize segment values via ToInt]
	CastObj --> Normalize
	Normalize --> Eq{Equality operator, or all segments equal?}
	Eq -->|Yes| EndEq([Return true, or CompareTo 0])
	Eq -->|No| Order[Compare Major then Minor then Build then Revision]
	Order --> Result{Relation established by an earlier segment?}
	Result -->|Yes| EndOrder([Return ordering result, or mapped CompareTo value])
	Result -->|No| EndFalse([Return false — no relation established])
```

## Failure and edge-case behavior

- `CompareTo` relies on a direct cast of its `Object` parameter and performs no type check beyond that cast; an incompatible or `Nothing` argument raises an unhandled exception.
- Segment normalization discards any non-numeric suffix and coerces conversion failures to `0`, so malformed segments never cause a comparison to fail — they simply compare as `0` ([BR-001](../business-rules.md#br-001-non-numeric-leading-characters-in-a-version-segment-are-coerced-to-0)).
- The `<` and `>` operators contain the tautological major-equality guard described in [BR-007](../business-rules.md#br-007-tautological-major-equality-check-in-the--and--operators); it is a likely copy-paste defect that does not currently affect comparison outcomes.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `SAIF.Framework.Version\Version.vb`
