2017-03-08 1 views
4

Étant donné une bibliothèque Java contenant la classe suivante (condensée):méthodes Java sont surchargés automatiquement à tort dans Kotlin

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; 
    } 

    /* ... */ 
} 

Depuis Kotlin convertit automagiquement noms de méthode appropriés dans les opérateurs surchargées, je peux écrire

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) 

... avec le résultat tout à fait inattendu que v0 obtient mutées par l'opération de division infix. Et, en outre, que la référence stockée dans res points le même objet que v0 Sortie:

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) 

Depuis la bibliothèque fournit également une surcharge pour écrire le résultat dans un autre vecteur, je me demandais si je ne peux dire ' kotlin de ne pas utiliser la méthode Vector2f.div(Vector2f) fournie.

J'ai déjà essayé de fournir une méthode d'extension à Vector2f mais qui obtient ombré par le vrai membre:

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! 
+1

Si vous êtes intéressé, [ici] (https://github.com/elect86/glm) un port glm – elect

+0

@elect en utilisant votre port est la meilleure solution, pourquoi ne postez-vous pas comme une réponse? – voddan

+0

Peur d'apparaître trop insistant/invasive, mais puisque vous l'avez suggéré, je vais essayer .. – elect

Répondre

1

Idéalement, vous souhaitez changer la classe Java pour faire ses fonctions d'opérateur adhèrent aux conventions mieux. Si vous ne pouvez pas modifier cette classe d'origine, vous aurez toujours l'opérateur / disponible pour utiliser à partir Kotlin lorsque vous l'utilisez. Étant donné qu'il se trouve dans la classe d'origine, vous ne pourrez pas le remplacer par une fonction d'extension, l'original aura toujours la priorité, indépendamment de l'endroit où l'extension est déclarée ou importée.

Vous devrez soit vivre avec la syntaxe étant disponible, ou si vous ne pouvez vraiment pas avoir cela, vous pouvez créer une classe wrapper autour de Vector2f qui n'a pas une fonction de ce nom accessible au public.

+0

C'est un peu triste, car la bibliothèque est vraiment bonne. Mais en utilisant une surcharge de l'opérateur qui vous surprend totalement est tout simplement mauvais :( – baeda

+0

'@ @ kotlin.internal.HidesMembers' résoudrait le problème, mais vous savez, si vous travaillez pour JetBrains .. – voddan

3

Je travaille sur le port de GLM here

Pour exemple, le code correspondant est here

operator fun div(b: Float) = div(Vec2(), this, b, b) 
operator fun div(b: Vec2) = div(Vec2(), this, b.x, b.y) 

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, b.x, b.y) 

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, b.x, b.y) 

La logique est derrière tout à fait simple, le référencement de votre échantillon, le plus court/code le plus simple:

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

val res = v0/v1 

toujours crée une nouvelle instance. Cela fait suite en quelque sorte les lignes directrices qui ont également été écrites sur le Kotlin docs. Et qui sont toujours là pour la section inc() et dec() (elle a été modifiée entre-temps).

est également moins sujettes erreur forme possible (expérience personnelle ..)

Pour la performance des scénarios critiques, lorsque vous ne voulez pas affecter une nouvelle instance, le compromis est de renoncer à la surcharge d'opérateur et en utilisant la forme fonctionnelle:

v0.div(v1, res) 

qui signifie, diviser v0 par v1 et mettre le résultat dans res.

Si vous souhaitez que l'objet récepteur à muter et à accueillir directement le résultat:

v0 div_ v1 

l'idée sous-jacente est d'exploiter la similitude derrière le trait de soulignement _ et le signe égal = et interpréter div_ comme /=

+0

Je upvoted pour l'effort et je suis sûr Je regarde dans votre port GLM au lieu d'utiliser celui que j'ai en ce moment car il ne fournit pas la réponse à la question ('puis-je faire kotlin accepter ma surcharge d'opérateur au lieu de la génération automatique') vraiment, je ne peux pas accepter c'est vrai j'ai peur! – baeda

+1

Ouais, ne vous inquiétez pas, je l'obtiens totalement, merci pour l'upvoting :) J'espère que ce sera utile pour les gens qui auront des problèmes similaires à votre – elect