Operator set implemented incompletely

ID

vbnet.correctness.operator_set_incomplete

Severity

low

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

low

Resource

Type Design

Language

VB.NET

Description

Reports a type that overloads one operator of an inverse arithmetic pair without the other - + without -, or * without /, in either direction. A type that declares both members of the pair is not reported, in either declaration order.

Rationale

Arithmetic operators are read as a set. Once a type supports a + b, callers reasonably expect a - b to exist as well, and code that has to compute one from the other ends up reaching past the type - unwrapping it to its underlying value, doing the arithmetic on that, and rebuilding the instance. That workaround bypasses whatever the type validates or normalises when it is constructed, which is usually exactly what the type exists to guarantee. The asymmetry also makes the type unusable in generic numeric code, and it commonly means the missing operator was simply overlooked rather than deliberately withheld.

The following code illustrates the pattern detected by this rule:

    Public Value As Double

    ' FLAGGED: Operator set implemented incompletely
    Public Shared Operator +(ByVal a As Reading, ByVal b As Reading) As Reading
        Return New Reading With {.Value = a.Value + b.Value}
    End Operator
End Structure

Public Structure Drift
    Public Value As Double

    ' FLAGGED: Operator set implemented incompletely
    Public Shared Operator -(ByVal a As Drift, ByVal b As Drift) As Drift
        Return New Drift With {.Value = a.Value - b.Value}
    End Operator
End Structure

Public Structure Scale
    Public Factor As Double

    ' FLAGGED: Operator set implemented incompletely
    Public Shared Operator *(ByVal a As Scale, ByVal k As Double) As Scale
        Return New Scale With {.Factor = a.Factor * k}
    End Operator
End Structure

Public Class Rate

Remediation

Add the missing operator as a Public Shared Operator alongside the one that already exists, keeping the same operand and return types so the pair composes, and route it through the same constructor or factory the existing operator uses so both go through the same validation. If the inverse genuinely has no meaning for the type - a monotonic counter or an accumulator, say - expose the intended arithmetic through a named method instead and drop the operator, rather than leaving callers a half-set they have to work around.

Configuration

This detector does not need any configuration.