Going to combine a few messages in one here:
On Mon, 2009-04-27 at 13:09 +0900, Gennady B. wrote:
In Ruby, “super()” is different from just “super”. The former will
invoke a superclass’ constructor with no parameters, while the latter
will call it with the same number of parameters as was in “new” call.
Thanks. That’s exactly the behavior I wanted. I wanted to call the
empty constructor explicitly.
On Mon, 2009-04-27 at 13:25 +0900, Nick S. wrote:
Your initialize method requires at least a “count” parameter, but
you’re not passing any. Do you mean to default it to something?
foo = Foo.new(42)
should work.
Good catch, Nick. Test case error. I was incrementally trying to build
up to the exact scenario that got the same error as my actual code.
Unfortunately, I stopped when I got the error, rather than actually
believing the compiler.
The original code didn’t have this problem.
On Mon, 2009-04-27 at 10:29 +0900, Charles Oliver N. wrote:
extend, extend with the same constructor style and just call “super”
We want to improve how this works, but the extension code needs a
rewrite before that can happen. Contributing broken specs for cases like
this that ought to “just work” would help us too.
Thanks for the info here, Charlie. Unfortunately, I was barking up the
wrong tree due to the message I got from jruby. I haven’t been able to
duplicate it in a simple case, but the code that caused the problem was
actually this:
28 class Button < JButton
29 def initialize(*args, &block)
30 super()
31 if args.length > 0 && args[0].is_a?(Action)
32 # action = args[0]
33 self.action_command = action.action_id
34 if action.status_text.nil?
35 self.tool_tip_text = action.label
36 else
37 self.tool_tip_text = action.status_text
38 end
39 self.text = action.label
Originally, I didn’t have the reference in line 32 because I’d copied
this code from another method where I was using aggregation instead of
inheritance, which produced the following error:
excalibur$ jruby actiontest.rb
…[path elided]/button_peer.rb:33:in initialize': wrong # of arguments(0 for 2) (ArgumentError) from actiontest.rb:46:in
initialize’
from actiontest.rb:58
The call in actiontest.rb looks like this:
45 back = BackAction.new
46 b1 = Button.new(back)
Since I hadn’t done the subclassing before, and the error was
complaining about the constructor call, that’s where I started looking.
I couldn’t figure out why the line number in the original error refers
to the first time the JButton instance was used, however.
Since Nick pointed out that the empty call to JButton() actually works
via ‘super()’, I went back to ensure that I wasn’t making the same
mistake in the original code. This morning, I noticed that I had
inadvertently lost the reference to the named action variable in the
refactoring. After adding line #32, everything works swimmingly.
This is actually the kind of thing I was talking about when I said I was
having to translate JRuby error messages.
Another case was when I was trying to give a derived AbstractAction
sub-class, e.g.:
27 class ToggleAction < AbstractAction
28 def initialize(action)
29 super(“Toggle Action State”)
30 @action = action
31 end
32
33 def actionPerformed(event)
34 puts “perf”
35 @action.enabled = !@action.enabled
36 end
37 end
Originally, since JRuby does method translation for action_performed to
actionPerformed, I’d implemented the class like this:
27 class ToggleAction < AbstractAction
28 def initialize(action)
29 super(“Toggle Action State”)
30 @action = action
31 end
32
33 def action_performed(event)
34 puts “perf”
35 @action.enabled = !@action.enabled
36 end
37 end
This gives the usefully obtuse (but totally accurate stack trace):
excalibur$ jruby actiontest.rb
Exception in thread “AWT-EventQueue-0” java.lang.AbstractMethodError:
org.jruby.proxy.javax.swing.AbstractAction$Proxy2.actionPerformed(Ljava/awt/event/ActionEvent;)V
at
javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at
javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at
javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at
javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at
javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6134)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
at java.awt.Component.processEvent(Component.java:5899)
at java.awt.Container.processEvent(Container.java:2023)
at java.awt.Component.dispatchEventImpl(Component.java:4501)
at java.awt.Container.dispatchEventImpl(Container.java:2081)
at java.awt.Component.dispatchEvent(Component.java:4331)
at
java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301)
at
java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895)
at java.awt.Container.dispatchEventImpl(Container.java:2067)
at java.awt.Window.dispatchEventImpl(Window.java:2458)
at java.awt.Component.dispatchEvent(Component.java:4331)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Admittedly, this one didn’t take me as long to figure out the root
cause, but it still wasn’t very helpful in identifying the actual cause.
Given that the behavior of “name mapping” isn’t 100% consistent (that it
does it during calls, but not during definition), it might actually
cause problems for more people than just me.
I know that JRuby isn’t the only implementation that does this (so does
IronRuby), but it might be something to put on the “todo” list to at
least provide some kind of warning or more automatic fixup.
While convenient, and certainly “more ruby-like”, I’m not really sure
that doing all of the automagic method translation stuff is actually all
that necessary, and, since it’s difficult to do for all cases without
adding even more overhead, maybe might just be simpler to avoid.
I’m sure most people would disagree with me, but really, how much more
of a PITA is it to do ‘rubyobj.addActionListener xyzzy’ than
‘rubyobj.add_action_listener xyzzy’? At least you’ve some visual clue
that you’re calling ‘native’ code here, and you don’t have to worry
about knowing when the interpreter’s going to “do what you mean” vs. “do
what you actually said”.
Overloaded methods are another kettle of fish…
Anyway, the problem’s solved now thanks to your collective help.
Aggregation isn’t an option in this particular case (even though that’s
my default approach), because what I need is a UI peer class that does
some translation between an abstract toolkit’s concepts of buttons,
actions, etc. and their “native” counterparts. All the peers need to be
‘native’ so that they can be passed around to the appropriate classes
where necessary in a consistent way vs. being ignored 99% of the time by
the rest of the application code.
Glad it did turn out to be just me, but a more accurate error message
would be nice.
Actually, as I was going to write the rest, I just figured out why I hit
the problem. Action is an accessor of JButton. Since I used the same
name, silent collision, the compiler’s happy, but it’s obviously still
somewhat confused. Not really sure what message I’d expect, but I still
think the current message is misleading.
At least now I understand what the issue was.
Cheers,
ast