You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The workspace splits three ways on whether a self-reference (this
/ self) and a super-reference (super / base) are Halstead
operators or operands. Java, C# and Kotlin call them operators; every
other language that classifies them at all calls them operands. The
same source translated between two languages therefore scores different n1 / N1 / n2 / N2, and the derived volume / difficulty / effort
/ time / bugs and all three maintainability-index variants move with it.
Found while resolving #1361, which added the missing Cpp / Mozcpp This arm and had to pick a side. It picked operand, on the
majority plus a structural argument (see below); this issue is the
remaining disagreement, deliberately left unsettled there rather than
widened into a twelve-language rewrite.
Measured
Every row below was measured with bca ops --no-config at the pinned
grammars, not read off the source.
Four of the operand rows (Python, Groovy, ObjC, Lua) are operands by
grammar accident — those grammars spell the keyword as a plain identifier (kind_id 1), so no dispatch arm is involved and no
deliberate decision was ever made. PHP is a fourth: $this is a variable_name, while PHP's Zelf arm — which is an operator —
covers the unrelated self:: class reference, not the instance.
So the live disagreement is Java / C# / Kotlin (three deliberate
operator arms) against the JS family plus Ruby, Rust and C++ (seven
deliberate operand arms). Counting the grammar-accident rows too, the
split is eleven operand against three operator.
Which way is right
#1361's argument for operand, restated so this issue can be decided
without re-deriving it:
Structure. A member access is <receiver> <op> <field>. p.x
bills operands p / x around the . operator. Classifying the
receiver as an operator makes this.x a binary operator with one
operand, and scores the identical AST differently based only on how
the receiver is spelled. In Java today, this.x and p.x are (n1, n2)(2, 1) and (1, 2) respectively.
Role. A self-reference denotes a value and stands wherever a
variable stands (return this;, f(this), super.g()); the . / -> acting on it is already counted.
Provenance. The three operator arms each swept the keyword in
under a // Operator: … keywords heading — classification by lexical
class rather than by Halstead role. That is the same style that
produced Per-language Halstead operator/operand classification inconsistencies #695's accessor-keyword split, where get / set were
operands in the JS family and operators in C#. The JS-family operand
arm, by contrast, reasons about it explicitly: its MetaProperty
note calls this "one atomic operand".
Proposed resolution
Move This / Super out of the operator arm and into the operand arm
in java.rs, csharp.rs (This / Base) and kotlin.rs, leaving
PHP's Zelf / Parent alone — self:: / parent:: are class
references in scope-resolution position, a genuinely different
construct from $this.
Per grammar-dispatch section 1, enumerate the numeric-suffix aliases in
all three generated enums before writing the arms, and per section 5
confirm no wrapper already bills the same text (super_interfaces, base_list, super_expression).
Expected impact
n1 / N1 fall by one occurrence per self/super reference and n2 / N2 rise by the same, in Java, C# and Kotlin. Snapshot churn is
limited to whatever those languages hold in the integration corpora,
which per the project's own corpus notes is small next to the C-family
share.
Summary
The workspace splits three ways on whether a self-reference (
this/
self) and a super-reference (super/base) are Halsteadoperators or operands. Java, C# and Kotlin call them operators; every
other language that classifies them at all calls them operands. The
same source translated between two languages therefore scores different
n1/N1/n2/N2, and the derived volume / difficulty / effort/ time / bugs and all three maintainability-index variants move with it.
Found while resolving #1361, which added the missing
Cpp/MozcppThisarm and had to pick a side. It picked operand, on themajority plus a structural argument (see below); this issue is the
remaining disagreement, deliberately left unsettled there rather than
widened into a twelve-language rewrite.
Measured
Every row below was measured with
bca ops --no-configat the pinnedgrammars, not read off the source.
ThisSupersrc/getter/java.rsThisBasesrc/getter/csharp.rsThisSupersrc/getter/kotlin.rsThisSupersrc/getter.rs(shared macro)ThisSupersrc/getter.rs(shared macro)ThisSupersrc/getter.rs(shared macro)ThisSupersrc/getter.rs(shared macro)ZelfSupersrc/getter/ruby.rsZelfsrc/getter/rust.rsThissrc/getter/cpp.rsThissrc/getter/mozcpp.rs$this(variable_name)self(identifier)this(identifier)self(identifier)self(identifier)Four of the operand rows (Python, Groovy, ObjC, Lua) are operands by
grammar accident — those grammars spell the keyword as a plain
identifier(kind_id 1), so no dispatch arm is involved and nodeliberate decision was ever made. PHP is a fourth:
$thisis avariable_name, while PHP'sZelfarm — which is an operator —covers the unrelated
self::class reference, not the instance.So the live disagreement is Java / C# / Kotlin (three deliberate
operator arms) against the JS family plus Ruby, Rust and C++ (seven
deliberate operand arms). Counting the grammar-accident rows too, the
split is eleven operand against three operator.
Which way is right
#1361's argument for operand, restated so this issue can be decided
without re-deriving it:
<receiver> <op> <field>.p.xbills operands
p/xaround the.operator. Classifying thereceiver as an operator makes
this.xa binary operator with oneoperand, and scores the identical AST differently based only on how
the receiver is spelled. In Java today,
this.xandp.xare(n1, n2)(2, 1)and(1, 2)respectively.variable stands (
return this;,f(this),super.g()); the./->acting on it is already counted.under a
// Operator: … keywordsheading — classification by lexicalclass rather than by Halstead role. That is the same style that
produced Per-language Halstead operator/operand classification inconsistencies #695's accessor-keyword split, where
get/setwereoperands in the JS family and operators in C#. The JS-family operand
arm, by contrast, reasons about it explicitly: its
MetaPropertynote calls
this"one atomic operand".Proposed resolution
Move
This/Superout of the operator arm and into the operand armin
java.rs,csharp.rs(This/Base) andkotlin.rs, leavingPHP's
Zelf/Parentalone —self::/parent::are classreferences in scope-resolution position, a genuinely different
construct from
$this.Per grammar-dispatch section 1, enumerate the numeric-suffix aliases in
all three generated enums before writing the arms, and per section 5
confirm no wrapper already bills the same text (
super_interfaces,base_list,super_expression).Expected impact
n1/N1fall by one occurrence per self/super reference andn2/N2rise by the same, in Java, C# and Kotlin. Snapshot churn islimited to whatever those languages hold in the integration corpora,
which per the project's own corpus notes is small next to the C-family
share.