Une discussion est en cours dans le canal #clojure sur Freenode à ce sujet. Chris Houser (qui allait poster une réponse, mais a finalement décidé qu'il était trop occupé pour le faire) a posté a Gist qui montre ce qui se passe avec une méthode surchargée boolean
vs Object
; il s'avère que dans certains scénarios, en plus d'un cast (boolean ...)
, un indice de type est requis. La discussion a été très instructive, avec quelques coins sombres du processus de compilation de Clojure devenant joliment éclairés. (Voir les liens vers le journal IRC ci-dessous.)
Fondamentalement, si un objet est créé directement dans le formulaire d'appel de méthode - (.foo (Foo.) ...)
, dites - ce type d'indice n'est pas nécessaire; il n'est pas non plus nécessaire si l'objet a été construit comme une valeur pour un local dans un formulaire let
(voir la mise à jour 2 ci-dessous et ma version du Gist). Si l'objet est obtenu par la recherche Var, cependant, un indice de type est requis - qui peut être fourni soit sur le Var lui-même ou, sur le site d'appel, sur le symbole utilisé pour faire référence à la Var.
Le code Java à partir du Gist:
Et le code Clojure:
(.foo (mypkg.Ugly.) 5)
;=> "obj: 5"
(.foo (mypkg.Ugly.) true)
;=> "obj: true"
(.foo (mypkg.Ugly.) (boolean true))
;=> "bool: true"
(def u (mypkg.Ugly.))
(.foo u (boolean true))
;=> "obj: true"
(.foo #^mypkg.Ugly u (boolean true))
;=> "bool: true"
Notez comment le compilateur Clojure a besoin d'un indice de type sur u
pour être en mesure de compiler un appel de méthode directe . Sinon, le code basé sur la réflexion semble être généré, ce qui semble perdre de vue le fait que l'argument est censé être primitif en cours de route. Mes ajouts suivent (et voici my fork of the above Gist).
;; renamed mypkg.Ugly to foo.TestInterop2 when doing my tests
user> (let [t (foo.TestInterop2.)]
(.foo t (boolean true)))
"bool: true"
;;; type-hinting the Var
user> (def #^foo.TestInterop2 x (foo.TestInterop2.))
#'user/x
user> (.foo x (boolean true))
"bool: true"
Le sujet a été abordé at this point. Chouser posté le Gist half an hour later, avec la discussion devient de plus en plus intéressant après cela.
Cela explique pourquoi il fonctionnait toujours dans les programmes de test et non dans le vrai programme. J'ai mis l'indice de type sur l'appel, et ça fonctionne maintenant très bien. Merci beaucoup. J'ai eu une chance de créer une macro pour cela, puisque vous pouvez obtenir la classe à partir de la variable, mais il semble que les indications de type ne soient pas macro-isées. –
Heureux d'entendre ça! Oh, et en fait, il est possible de gérer les indications de type dans les macros - et parfois une macro bien conçue peut produire du code joliment suggéré avec un minimum de frappe supplémentaire. Vous pourriez poser une question distincte à ce sujet si vous voulez de l'aide pour en écrire un. –
Je n'ai pas réussi à faire fonctionner ça avec mon code, même si ma situation est un peu différente. Les méthodes Java que j'essaie d'appeler sont JavaFX 'Application.launch'. Je souhaite la méthode statique 'launch' avec l'argument' Class étend Application> 'et ne peut pas donner un indice de type à mon appel (j'ai essayé plusieurs approches) qui provoque l'appel de la méthode' launch' correcte et j'obtiens des erreurs "La classe ne peut pas être convertie en chaîne". – Jason