Los methods Java se sobrecargan automáticamente en kotlin

Dada una biblioteca Java que contiene la siguiente class (condensada):

public class Vector2f { public float x; public float y; public Vector2f div(Vector2f other) { x /= other.x; y /= other.y; return this; } public Vector2f div(Vector2f other, Vector2f dest) { dest.x = x / other.x; dest.y = y / other.y; return dest; } /* ... */ } 

Como Kotlin convierte automáticamente nombres de methods adecuados en operadores sobrecargados, puedo escribir

 val v0 = Vector2f(12f, 12f) val v1 = Vector2f(2f, 2f) val res = v0 / v1 println(v0) println(v1) println(res) res.x = 44f println() println(v0) println(v1) println(res) 

… con el resultado completamente inesperado de que v0 se mutó por la operación de split infija. Y, además, que la reference almacenada en res apunta al mismo object que v0 Output:

 Vector2f(6.0, 6.0) Vector2f(2.0, 2.0) Vector2f(6.0, 6.0) Vector2f(44.0, 6.0) Vector2f(2.0, 2.0) Vector2f(44.0, 6.0) 

Como la biblioteca también proporciona una sobrecarga para escribir el resultado en otro vector, me preguntaba si puedo 'decirle' a kotlin que no use el Vector2f.div(Vector2f) proporcionado Vector2f.div(Vector2f) .

Ya he intentado proporcionar un método de extensión a Vector2f pero el miembro real lo Vector2f :

 operator fun Vector2f.div(other: Vector2f): Vector2f = this.div(other, Vector2f()) ^~~ extension is shadowed by a member: public open operator fun div(other: Vector2f!): Vector2f! 

Idealmente, cambiaría la class Java para hacer que sus funciones de operador se adhieran mejor a las convenciones. Si no puede modificar esa class original, siempre tendrá el operador / disponible para usar desde Kotlin cuando lo esté utilizando.

Dado que está dentro de la class original, no podrá sobrescribirlo con una function de extensión, el original siempre tendrá prioridad sobre él, independientemente de dónde se declare la extensión o cómo se importe.

Tendrás que vivir con la syntax disponible, o si realmente no puedes tenerla, podrías crear una class contenedora alnetworkingedor de Vector2f que no tenga una function de ese nombre públicamente disponible.

Estoy trabajando en el puerto glm aquí

Para su ejemplo, el código relevante está aquí

 operator fun div(b: Float) = div(Vec2(), this, b, b) operator fun div(b: Vec2) = div(Vec2(), this, bx, by) fun div(bX: Float, bY: Float, res: Vec2 = Vec2()) = div(res, this, bX, bY) fun div(b: Float, res: Vec2 = Vec2()) = div(res, this, b, b) fun div(b: Vec2, res: Vec2 = Vec2()) = div(res, this, bx, by) fun div_(bX: Float, bY: Float) = div(this, this, bX, bY) infix fun div_(b: Float) = div(this, this, b, b) infix fun div_(b: Vec2) = div(this, this, bx, by) 

La lógica detrás es bastante simple, haciendo reference a su muestra, el código más corto / más simple:

 val v0 = Vec2(12f) val v1 = Vec2(2f) val res = v0 / v1 

siempre crea una nueva instancia. Esto de alguna manera sigue las pautas que también se escribieron en los documentos de Kotlin . Y eso todavía está allí para la sección inc() y dec() (se ha modificado mientras tanto).

También es la forma less propensa a errores posible (experiencia personal …)

Para escenarios críticos de performance, cuando no desea asignar una nueva instancia, el compromiso es renunciar a la sobrecarga del operador y usar la forma funcional:

 v0.div(v1, res) 

eso significa, divida v0 por v1 y coloque el resultado en res .

En caso de que quiera que el object receptor mute y acomode directamente el resultado:

 v0 div_ v1 

la idea detrás de esto es explotar la similitud detrás del guión bajo _ y el signo igual = e interpretar div_ as /=