Skip to content

Fix operator stub signatures: drop self param, detect reverse operators#17

Open
eevleevs wants to merge 1 commit into
MHDante:mainfrom
eevleevs:fix/operator-stub-signatures
Open

Fix operator stub signatures: drop self param, detect reverse operators#17
eevleevs wants to merge 1 commit into
MHDante:mainfrom
eevleevs:fix/operator-stub-signatures

Conversation

@eevleevs

@eevleevs eevleevs commented Jul 5, 2026

Copy link
Copy Markdown

Problem

.NET operators are static methods (e.g. \op_Addition(Point p1, Point p2)). The generator was prepending \self\ on top of both parameters, producing 3-param signatures:

\\python

Before (wrong):

def add(self, p1: Point, p2: Point) -> Point: ...
\\

Python's dunder protocol shifts the first operand into \self, so the correct signature has only 2 params:

\\python

After (correct):

def add(self, p2: Point) -> Point: ...
\\

This caused two type-checker errors when subclassing .NET types:

  1. Invalid override — the subclass's 2-param _add_(self, other)\ is incompatible with the parent's 3-param signature (LSP violation)
  2. Missing argument — calling \super().add(other)\ is missing the \p2\ parameter

Fix

  1. Drop the redundant parameter — For operators, the first .NET parameter becomes \self\ and is removed from the parameter list (\skipIndex\ in \GetParameters)

  2. Detect reverse operators — When the first parameter type doesn't match the declaring type (e.g. \op_Multiply(float, Vector)\ on the \Vector\ class), the method maps to the reverse dunder (_rmul_\ instead of _mul_). The second parameter becomes \self\ and is dropped instead.

  3. Comparison operators (_eq_, _ne_, _gt_, _lt_, _ge_, _le_) have no reverse variants in Python — they always use the same name regardless of operand order.

Verification

Regenerated stubs for Tekla Structures DLLs and confirmed correct output:

\\python

Point operators (symmetric):

def add(self, p2: Point) -> Point: ...
def sub(self, p2: Point) -> Point: ...
def eq(self, p2: Point) -> bool: ...

Vector operators (asymmetric):

def mul(self, Multiplier: float) -> Vector: ... # op_Multiply(Vector, float)
def rmul(self, Multiplier: float) -> Vector: ... # op_Multiply(float, Vector) → reverse!
\\

Type checker (\ y) passes cleanly on subclasses that override these operators.

.NET operators are static methods (e.g. op_Addition(Point, Point)) with
two parameters. The generator was prepending self on top of both
parameters, producing 3-param signatures like __add__(self, p1, p2)
instead of the correct 2-param __add__(self, p2).

This fix:
- Drops the first parameter for forward operators (it becomes self)
- Drops the second parameter for reverse operators (e.g. op_Multiply(float, Vector)
  maps to __rmul__ instead of __mul__)
- Adds isReverse detection by comparing parameter types to the declaring type
- Comparison operators (__eq__, __ne__, __gt__, etc.) have no reverse variants

Fixes the Liskov Substitution Principle violation when subclassing .NET
types with operator overrides in Python.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant