Easily add a Java Listener

35 views
Skip to first unread message

rb

unread,
Aug 31, 2009, 2:41:47 PM8/31/09
to Clojure
Hi,

After using Jwt from Clojure, I did it with Jruby and discovered that
Jruby has what they call Closure Conversion (http://kenai.com/projects/
jruby/pages/CallingJavaFromJRuby#Closure_conversion ) where a Ruby
block or closure is converted to an appropriate Java interface. From
the wiki: "When calling a method that expects an interface, JRuby
checks if a block is passed and automatically converts the block to an
object implementing the interface".

I found this to be unbelievably easy to use and efficient (for the
developer) as the listener is added this way:
button.clicked.add_listener(self) do
greeting_.setText(nameEdit_.getText)
end

There's no need for the developer to implement any interface or manage
any proxy object.
I wondered if something similar is possible in Clojure. If not, would
this be considered a valuable addition to Clojure?

Thanks

Raphaël



Stuart Sierra

unread,
Aug 31, 2009, 5:54:06 PM8/31/09
to Clojure
That's a clever trick. How does the block know which interface method
was invoked?
-SS

Kevin Downey

unread,
Aug 31, 2009, 6:03:01 PM8/31/09
to clo...@googlegroups.com
I think this would necessitate an added layer of indirection and
reflection, which would mean taking a performance hit.
--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

Christophe Grand

unread,
Aug 31, 2009, 6:59:49 PM8/31/09
to clo...@googlegroups.com
Rhino provides a similar facility
https://developer.mozilla.org/en/Scripting_Java#JavaScript_Functions_as_Java_Interfaces
but AFAIK it uses reflection.
--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)

Luc Prefontaine

unread,
Aug 31, 2009, 9:26:13 PM8/31/09
to clo...@googlegroups.com
Hi guys,

Am I missing something here?

We define SWING listeners with proxies and find that it's already short in terms of code lines:

(.addMouseListener
  (proxy [MouseAdapter] []
    (mouseClicked [event]
        (if (= 2 (.getClickCount event))
(display-details (.locationToIndex (.getPoint event)))
        )
    )
  )
)

Does the removal of the proxy call warrants significant efforts to implement a "transparent" way of calling Java code ?
For us most of the programming time is spent in looking at the Javadoc of the Java code to find which interface to use and how, not typing the proxy call
itself.
Hope you do not hit too many member functions with the same name and number of arguments but with different classes/interfaces :)))
You would then now a way to solve the ambiguity...

Again did I miss something ?

Luc
Luc Préfontaine

Armageddon was yesterday, today we have a real problem...

Timothy Pratley

unread,
Aug 31, 2009, 10:34:50 PM8/31/09
to Clojure
If I understand correctly it could be implemented with the following
change to Reflector.java:
static Object boxArg(Class paramType, Object arg){
if(paramType.isInterface() && arg instanceof IFn)
return makeAProxy( findMethodMatch( paramType, arg ),
arg );

Which would then allow us to instead of using proxy:
> (.addMouseListener
>   (proxy [MouseAdapter] []
>     (mouseClicked [event]
>         (if (= 2 (.getClickCount event))
>                 (display-details (.locationToIndex (.getPoint event)))))))

Write it using a function which will discover what interface/method to
create a proxy for:
(.addMouseListener
#(if (= 2 (.getClickCount %))
(display-details (-> % .getPoint .locationToIndex)))
something)

The alternative solution for doing that if we are willing to create a
macro or helper function:
(defmacro add-action-listener
"Attaches an ActionListener to a Component"
[#^java.awt.Component obj, evt & body]
`(.addActionListener
~obj (proxy [java.awt.event.ActionListener] []
(actionPerformed [~evt] ~@body))))

(add-action-listener something evt
(if (= 2 (.getClickCount evt))
(display-details (-> evt .getPoint .locationToIndex))))

The only difference being of course that you'd need a separate helper
for all the different interfaces want to proxy, and would have to
explicitly choose which interface the function implements. I don't
have enough experience to know of how many anonymous single function
interface proxies are useful.


Regards,
Tim.

Luc Prefontaine

unread,
Aug 31, 2009, 11:32:02 PM8/31/09
to clo...@googlegroups.com
It could be handy to have this shortcut implemented as you suggest.
Solving ambiguities may be done through an explicit proxy or with some meta data to point to the proper
method match.

Luc
Reply all
Reply to author
Forward
0 new messages