Block passing

Here’s a short bit of code from a larger application that is giving me
a NullPointerException in convertRubyToJavaInt. I can’t figure out why
it is doing that. The problem disappears if you comment out the block
that is being passed to the JButton initialize method. That’s on the
line that sets ok_button. Any idea what is going on here?

include Java
import javax.swing.JButton
import javax.swing.JFrame

class JButton
def initialize(name, &block)
super(name)
# Not using the block yet, but will later.
end
end

class GUI < JFrame
def initialize
super(‘Title’)
ok_button = JButton.new(‘OK’) { puts ‘pressed OK’ }
content_pane.add(ok_button)
pack
self.default_close_operation = JFrame::EXIT_ON_CLOSE
end
end

GUI.new.visible = true


Mark V.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Wed, Oct 7, 2009 at 1:37 PM, Mark V. [email protected] wrote:

Here’s a short bit of code from a larger application that is giving me a
NullPointerException in convertRubyToJavaInt. I can’t figure out why it is
doing that. The problem disappears if you comment out the block that is
being passed to the JButton initialize method. That’s on the line that sets
ok_button. Any idea what is going on here?

Can you show the full NPE trace? And try against 1.4RC1, some of this
has been cleaned up.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Quoting C. Oliver N. [email protected]:

On Wed, Oct 7, 2009 at 1:37 PM, Mark V. [email protected] wrote:

Here’s a short bit of code from a larger application that is giving me a
NullPointerException in convertRubyToJavaInt. I can’t figure out why it is
doing that. The problem disappears if you comment out the block that is
being passed to the JButton initialize method. That’s on the line that sets
ok_button. Any idea what is going on here?

Can you show the full NPE trace? And try against 1.4RC1, some of this
has been cleaned up.

Sure! See below. Note how “pressed OK” is output. That seems wrong
because
it’s in a block that I pass to the JButton initialize method, but don’t
execute. The code is identical to that in my previous email.

Swing$ jruby gui.rb
pressed OK
org/jruby/javasupport/JavaUtil.java:922:in convertRubyToJavaInt': java.lang.NullPointerException: null (NativeException) from org/jruby/gen/org/jruby/gen/InterfaceImpl271097958.gen:13:in getIconWidth’
from javax/swing/SwingUtilities.java:890:in layoutCompoundLabelImpl' from javax/swing/SwingUtilities.java:817:in layoutCompoundLabel’
from javax/swing/plaf/basic/BasicGraphicsUtils.java:262:in
getPreferredButtonSize' from apple/laf/CUIAquaButton.java:450:in getPreferredSize’
from javax/swing/JComponent.java:1624:in getPreferredSize' from java/awt/BorderLayout.java:690:in preferredLayoutSize’
from java/awt/Container.java:1558:in preferredSize' ... 10 levels... from gui.rb:15:in initialize’
from gui.rb:22:in `new_proxy’
from gui.rb:22
Swing$ jruby -v
jruby 1.4.0RC1 (ruby 1.8.7 patchlevel 174) (2009-09-30 80c263b) (Java
HotSpot™ Client VM 1.5.0_19) [i386-java]


R. Mark V.
Object Computing, Inc.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Oct 9, 2009, at 4:26 AM, Vladimir S. wrote:

that sets
ok_button. Any idea what is going on here?

Sure, the way you construct the OK button is not 100% correct. You
provide a block to the constructor, but JButton’s two-arg constructor
is JButton(text, icon). So, essentially, instead of icon you supply
a block, and when the Frame tries to layout itself, it asks the “icon”
to report its width via getIconWidth(), and that block gets confused.
:slight_smile:

Interesting. However, this code worked with an earlier version of
JRuby. I wonder what changed. That JButton constructor isn’t new.

The fix is simple, instead of:
ok_button = JButton.new(‘OK’) { puts ‘pressed OK’ }

do

ok_button = JButton.new(‘OK’)
ok_button.add_action_listener { puts ‘pressed OK!’ }

This should work.

Thanks! That does work, but I thought it was more elegant to be able
to pass to the constructor the block of code I want to execute when
the button is pressed.


Mark V.


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Mark,

On Wed, Oct 7, 2009 at 9:37 PM, Mark V. [email protected] wrote:

Here’s a short bit of code from a larger application that is giving me a
NullPointerException in convertRubyToJavaInt. I can’t figure out why it is
doing that. The problem disappears if you comment out the block that is
being passed to the JButton initialize method. That’s on the line that sets
ok_button. Any idea what is going on here?

Sure, the way you construct the OK button is not 100% correct. You
provide a block to the constructor, but JButton’s two-arg constructor
is JButton(text, icon). So, essentially, instead of icon you supply
a block, and when the Frame tries to layout itself, it asks the “icon”
to report its width via getIconWidth(), and that block gets confused.
:slight_smile:

The fix is simple, instead of:
ok_button = JButton.new(‘OK’) { puts ‘pressed OK’ }

do

ok_button = JButton.new(‘OK’)
ok_button.add_action_listener { puts ‘pressed OK!’ }

This should work.

Thanks,
–Vladimir


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Oct 9, 2009 at 7:10 AM, Vladimir S. [email protected]
wrote:

So it seems that it worked before due to bugs in JRuby.

Ahh…interesting. Well if we fixed that NPE it might start “working”
again, but obviously it’s not the expected result. Which commit was
it?

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Hi Mark,

On Fri, Oct 9, 2009 at 2:47 PM, Mark V. [email protected] wrote:

Interesting. However, this code worked with an earlier version of JRuby. I
wonder what changed.

Indeed, it stopped working since July 2008, after one of Charlie’s
commits that fixed various java-integration bugs.
Before that, the code worked somewhat, but was printing ‘pressed OK’
when container tried to obtain the size of the button. :slight_smile:

So it seems that it worked before due to bugs in JRuby.

Thanks! That does work, but I thought it was more elegant to be able to pass
to the constructor the block of code I want to execute when the button is
pressed.

Well, yeah, for this particular case, yes, but hard to figure out what
to do in general case, not to mention that there could be multiple
listeners and different users would like to do different things.

Thanks,
–Vladimir


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Oct 9, 2009 at 6:47 AM, Mark V. [email protected] wrote:

On Oct 9, 2009, at 4:26 AM, Vladimir S. wrote:

Sure, the way you construct the OK button is not 100% correct. You
provide a block to the constructor, but JButton’s two-arg constructor
is JButton(text, icon). So, essentially, instead of icon you supply
a block, and when the Frame tries to layout itself, it asks the “icon”
to report its width via getIconWidth(), and that block gets confused.
:slight_smile:

We do need to fix this so it doesn’t NPE…that should not happen. At
worse it should provide a type error of some kind.

Interesting. However, this code worked with an earlier version of JRuby. I
wonder what changed. That JButton constructor isn’t new.

I’m not sure this ever worked…it doesn’t seem possible. How early
was that other version? The issue here is that we’re trying to force
the block to act like it’s an Icon, when of course that’s a little
absurd. Passing a block to JButton.new never would have worked in the
past, unless some other library added a block version of “new” that
wired up the action listener for you.

ok_button = JButton.new(‘OK’)
ok_button.add_action_listener { puts ‘pressed OK!’ }

Thanks! That does work, but I thought it was more elegant to be able to pass
to the constructor the block of code I want to execute when the button is
pressed.

JRuby handles blocks passed to Java by trying to implement an
interface for the last argument. That’s all it has ever done, and
before this time last year it pretty much just ignored it.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Oct 9, 2009 at 9:37 PM, Charles Oliver N.
[email protected] wrote:

Ahh…interesting. Well if we fixed that NPE it might start “working”
again, but obviously it’s not the expected result. Which commit was
it?

git bisect points to: c306f7f4b19162a83c1fa8f3b983e7e6c70083d9:
“Wire in closure-conversion logic for constructors, add specs for it,
and add more specs (and fix bugs discovered)”

Thanks,
–Vladimir


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Oct 9, 2009 at 2:37 PM, Charles Oliver N.
[email protected] wrote:

when container tried to obtain the size of the button. :slight_smile:

So it seems that it worked before due to bugs in JRuby.

Ahh…interesting. Well if we fixed that NPE it might start “working”
again, but obviously it’s not the expected result. Which commit was
it?

Another possible breaker is Rubeus…It actively made a whole
framework around suppluing blocks to all Swing component constructors
(I am not sure how it is implemented yet to know):

http://code.google.com/p/rubeus/source/browse/trunk/examples/nyanco_viewer/nyanco_viewer_rubeus.rb

-Tom


blog: http://blog.enebo.com twitter: tom_enebo
mail: [email protected]


To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Mon, Oct 12, 2009 at 9:45 AM, Thomas E Enebo [email protected]
wrote:

Another possible breaker is Rubeus…It actively made a whole
framework around suppluing blocks to all Swing component constructors
(I am not sure how it is implemented yet to know):

I’m pretty sure they monkey-patched “new” on those Java classes to
take blocks and run them, so they’d probably be fine.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Fri, Oct 9, 2009 at 2:19 PM, Vladimir S. [email protected]
wrote:

git bisect points to: c306f7f4b19162a83c1fa8f3b983e7e6c70083d9:
“Wire in closure-conversion logic for constructors, add specs for it,
and add more specs (and fix bugs discovered)”

Filed http://jira.codehaus.org/browse/JRUBY-4087 for it. Marked as
minor since the block-to-Icon is unexpected and wouldn’t be useful
even if this was working.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Oct 9, 2009, at 2:27 PM, Charles Oliver N. wrote:

confused.
was that other version? The issue here is that we’re trying to force
to the constructor the block of code I want to execute when the
button is
pressed.

JRuby handles blocks passed to Java by trying to implement an
interface for the last argument. That’s all it has ever done, and
before this time last year it pretty much just ignored it.

I gave a talk on JRuby to the St. Louis Java User Group in May 2007.
This was before the 1.0 release of JRuby, but I don’t know exactly
which version I was using. Here is some code I demoed in that talk
that worked at the time. Note how I’m passing a block to the JButton
constructor.

include Java

BorderLayout = java.awt.BorderLayout
JButton = javax.swing.JButton
JFrame = javax.swing.JFrame
JLabel = javax.swing.JLabel
JOptionPane = javax.swing.JOptionPane
JPanel = javax.swing.JPanel
JTextField = javax.swing.JTextField

class BlockActionListener < java.awt.event.ActionListener

super call is needed for now - see JRUBY-66 in JIRA

def initialize(&block); super; @block = block; end
def actionPerformed(e); @block.call(e); end
end

class JButton
def initialize(name, &block)
super(name)
addActionListener(BlockActionListener.new(&block))
end
end

class HelloFrame < JFrame
def initialize
super(“Hello Swing!”)
populate
pack
self.resizable = false
self.defaultCloseOperation = JFrame::EXIT_ON_CLOSE
end

def populate
name_panel = JPanel.new
name_panel.add JLabel.new(“Name:”)
name_field = JTextField.new(20)
name_panel.add name_field
button_panel = JPanel.new

 greet_button = JButton.new("Greet") do
   name = name_field.text
   msg = %(<html>Hello <span style="color:red">#{name}</span>!</

html>)
JOptionPane.showMessageDialog self, msg
end
button_panel.add greet_button

 clear_button = JButton.new("Clear") { name_field.text = "" }
 button_panel.add clear_button

 contentPane.add name_panel, BorderLayout::CENTER
 contentPane.add button_panel, BorderLayout::SOUTH

end
end # of HelloFrame class

HelloFrame.new.visible = true


Mark V.