operator == method

  1. @override
bool operator ==(
  1. Object other
)
override

SCC32: value equality, delegated to the wrapped native.

Without this the wrapper compared by identity, so two separately constructed wrappers around equal natives were different keys. The interpreted a == b expression looked right only because visitBinaryExpression unwraps both operands before comparing — the wrapper itself was never consulted. So a script got true from == and a miss from every hash-based collection, with no error either way. List membership was wrong too ([Duration(seconds: 1)].contains(Duration( seconds: 1)) was false), which no amount of hashing would explain and which is why hashCode alone was not the fix.

Equality with the raw native is deliberate, and it is the same choice BridgedEnumValue already made for the same reason.

SCD98 removed the inconsistency this was written to survive, and this operator stays anyway. When this comment was written a constructor call yielded a wrapper while every bridged method return yielded a bare native, so DateTime(2021).difference(x) and Duration(seconds: 1) were the same value in two representations that routinely met in one collection. The constructor now yields the native too, so nothing the interpreter PRODUCES is a wrapper and that particular collision cannot arise. What remains is the boundary this type exists for: Environment.toBridgedInstance still hands a wrapper to bridge dispatch, and an embedder can put one into a collection itself. So the operator is no longer a workaround for an internal inconsistency — it is what it reads as, a courtesy to a wrapper that arrives from outside.

This is asymmetric, which is normally a hazard — raw == wrapper stays false because a native's == rejects a foreign type, and nothing here can change that. It is safe because Dart's hash lookup calls lookupKey == storedKey, making the lookup key the receiver: whenever the wrapper is the value being looked up, this operator runs and the comparison succeeds regardless of how the key was stored. The opposite direction — a raw native looking up a stored wrapper — would fall on the unfixable side, which is why hash keys are additionally normalized to the native at storage time (see _unwrapHashKey in the interpreter). Between the two, no stored key is ever a wrapper and every lookup resolves.

Implementation

@override
bool operator ==(Object other) {
  if (identical(this, other)) return true;
  if (other is BridgedInstance) {
    return nativeObject == other.nativeObject;
  }
  return nativeObject == other;
}