|
Replies:
56
-
Last Post:
Sep 15, 2006 3:46 AM
by: Kleopatra
|
|
|
|
|
|
|
Closures and Swing
Posted:
Aug 28, 2006 6:37 AM
|
|
|
It's occurred to me several times that Swing is one of the areas that can really benefit from using the proposed closure syntax. I'm probably murdering the syntax, but it seems that we could use closures to completely hide the listener interfaces, and make configuring swing components a lot more like the code that is used to configure GUI components in the web tier.
public class JXButton extends JButton {
public void onAction(void(ActionEvent) fn) {
...
}
}
usage might look something like
JXButton btn = new JXButton("Click Me");
btn.onAction( {btn.setText("Thank You")} );
One way to implement this would be to write a proxy that uses a hash to map the specific listener method being invoked to the closure/function that's been configured as the implementation.
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 28, 2006 9:25 AM
in response to: david_hall
|
|
|
Do you really need closures for this? Can't you just use the existing EventHandler class for this simple scenario?
Just do this:
JXButton btn = new JXButton("Click Me");
btn.addActionListener((ActionListener)EventHandler.create(ActionListener.class, btn, "Thank You"));
Erik
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 28, 2006 9:53 AM
in response to: evickroy
|
|
|
Less code is better. In fact I'd like that the standard JDK would add this in addtion to a series of 1 method interfaces that are there. And create add map to list etc. Sure the code that uses those features wouldn't work in pre 1.7 VM. I don't care. I wish java someday followed a total cut with the past , redesigning the API (Enumerations, one method interfaces, etc).
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 28, 2006 10:27 AM
in response to: evickroy
|
|
|
> Do you really need closures for this? Can't you just > use the existing EventHandler class for this simple > scenario? > > Just do this: > > JXButton btn = new JXButton("Click Me");
> btn.addActionListener((ActionListener)EventHandler.cre
> ate(ActionListener.class, btn, "Thank You"));
>
> > Erik
EventManager doesn't hide the listeners at all: it still keeps the focus on which listeners a component can have registered instead of which events a component can fire. The listener interfaces should be an implementation detail: hiding them all would significantly reduce the number of API's that a new developer has to learn, and make the remaining API's more like things he may have already worked with. In this case, I think it'll be very helpful if we can make swing coding look a lot more like web tier coding.
EventHandler really doesn't scale up very well -- it works OK for very simple things, but most of the problem is well beyond setting one beans properties to simple values. It's fairly common that the event handler involves some significant code. If you just need a single conditional test, you've gone beyond what EventHandler can support.
Using closures handles this case concisely; they can handle Hans' "trampoline methods" (from a blog entry he wrote a couple of years ago http://java.sun.com/products/jfc/tsc/articles/generic-listener/index.html) with similarly concise syntax; and they can easily handle the 'fairly simple but more than just single property setting' code that is the most common case in my experience.
Additionally, even in our two examples, closures support a much more concise syntax: the listener class is just overhead, and eliminating two references to it would be an improvement.
PS:
Really, I just tossed the example off the top of my head -- it's short enough to get the point across and to not bog down on details. Perhaps it was too short?
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 28, 2006 1:10 PM
in response to: david_hall
|
|
|
> > public class JXButton extends JButton {
> public void onAction(void(ActionEvent) fn) {
> ...
> }
> }
>
> usage might look something like > > JXButton btn = new JXButton("Click Me");
> btn.onAction( {btn.setText("Thank You")} );
>
I don't think there's any need to add a new method (other than to ditch the unused argument):
button.addActionListener((ActionEvent event) {
button.setText("Thank You");
});
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 29, 2006 4:09 PM
in response to: tackline
|
|
|
Hello,
I understand that there is a wider debate going on but for the very example given, my opinion is that using Actions is the preferred way. As far as I know, closures or delegates cannot address the use case of Actions.
Generally speaking, I tend to let my IDE (in my case, IntelliJ IDEA) do the work so I've never felt that creating an anonymous listener class could be some kind of a difficult task.
Pierre.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 5:48 AM
in response to: weebib
|
|
|
Pierre,
You make a great point about Actions. Currently, Actions are underused, but there is movement on many fronts. This includes the JRE, JSR-296, SwingLabs, and some independent projects.
Standards for building the GUI independently of Actions is another Swing weakness. Is the code that you're producing in IDEA effectively tied to that IDE? NetBeans has a good GUI builder, but it ties you to NetBeans and doesn't do a good job of isolating the GUI from Actions.
- Curt
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 12:21 PM
in response to: coxcu
|
|
|
It doesn't tie you to NetBeans, only to the layout it uses which is available as a separate download.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 12:55 PM
in response to: kirillcool
|
|
|
Sort of. You don't need Matisse to run or debug the code, but you need Matisse to maintain the code. Would you rather maintain the following GUI code using only a simple text editor, or hit your hand with a hammer?
http://jflubber.googlecode.com/svn/trunk/jFlubber/src/org/bldc/jflubber/JFlubberMainFrm.java /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents private void initComponents() { timeLabel = new javax.swing.JLabel(); startButton = new javax.swing.JButton(); stopButton = new javax.swing.JButton(); flubButton = new javax.swing.JButton(); saveButton = new javax.swing.JButton(); clearButton = new javax.swing.JButton(); jScrollPane1 = new javax.swing.JScrollPane(); flubPointsTextArea = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); timeLabel.setFont(new java.awt.Font("Dialog", 1, 18)); timeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); timeLabel.setText("0:00");
startButton.setText("Start"); startButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { startButtonMouseReleased(evt); } });
stopButton.setText("Stop"); stopButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { stopButtonMouseReleased(evt); } });
flubButton.setFont(new java.awt.Font("Dialog", 1, 18)); flubButton.setText("Flub"); flubButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { flubButtonMouseReleased(evt); } });
saveButton.setText("Save"); saveButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { saveButtonMouseReleased(evt); } });
clearButton.setText("Clear"); clearButton.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseReleased(java.awt.event.MouseEvent evt) { clearButtonMouseReleased(evt); } });
flubPointsTextArea.setColumns(20); flubPointsTextArea.setRows(5); jScrollPane1.setViewportView(flubPointsTextArea);
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) .add(flubButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) .add(timeLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() .add(startButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(stopButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE)) .add(layout.createSequentialGroup() .add(saveButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(clearButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(timeLabel) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(stopButton) .add(startButton)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(flubButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 60, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 248, Short.MAX_VALUE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(saveButton) .add(clearButton)) .addContainerGap()) ); pack(); }// </editor-fold>//GEN-END:initComponents
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 11:31 PM
in response to: coxcu
|
|
|
> Sort of. You don't need Matisse to run or debug the > code, but you need Matisse to maintain the code. > Would you rather maintain the following GUI code > e using only a simple text editor, or hit your hand > with a hammer? >
I wouldn't create any code that can only be maintained by a single specific tool.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 29, 2006 11:42 PM
in response to: tackline
|
|
|
> button.addActionListener((ActionEvent event) {
> button.setText("Thank You");
> });
> [Message sent by forum member 'tackline' (tackline)]
This is interesting, but this is not the forum for discussing how closures might impact SwingLabs projects. Maybe you'd like to join one of the open discussions, say on JavaLobby?
Regards Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 4:04 AM
in response to: Patrick Wright
|
|
|
In a sense Patrick you are right, but I guess anyone visiting this forum will have a strong interest in the broader Swing issue of code clutter due to event listeners.
Adding more syntactic sugar to Java in the form of closures is not going to resolve the deeper problem - that so much event handling code seems required to define useful functionality for a GUI. This in turn results from the difficulty of encapsulating the general use case of button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
doSomethingThenUpdateEntireGUI();
}
});
[Advertisement] Such an encapsulation is basically what is offered by http://superficial.sourceforge.net. Superficial avoids the need for hand-coded event handling by defining a generalised 'retargeting' sequence that rebinds all GUI widgets to the appropriate data objects.
Hoewever let's not forget that existing Java syntactic sugar makes a huge difference to its usability. Both the Facets implementation of Superficial and typical client code http://superficial.sourceforge.net/democode.html depend so heavily on (anonymous) inner classes that it would hard to implement or use in a language that didn't have them.
Regards, David Wright
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 5:41 AM
in response to: Patrick Wright
|
|
|
> This is interesting, but this is not the forum for discussing how > closures might impact SwingLabs projects. Maybe you'd like to join one > of the open discussions, say on JavaLobby?
On the contrary: if we're going to discuss how anything affects the swinglabs projects and particularly ideas that might be incorporated into swing, it seems like this is the place to do it. I know I'm thinking way out ahead, but this forum has exactly the set of people who I think would be most interested in discussing the issue and who are in the position to take the ideas discussed and apply them to swinglabs (and swing). We also don't have the traffic of JavaLobby/TSS/JRoller, so discussions around here tend not to degenerate like those do.
WRT tackline's proposal:
The difference between what he wrote and my original is not great. His proposal would change the implementation of the existing API's to something very like the way that I'd implement the "onAction" method that I proposed at the start of the thread.
That approach is a little better for those of us that have already learned swing programming. I think that the starting proposal is a little better for new developers, and is better overall, because it does a better job of hiding the listener abstraction. Tackline hides the plumbing, but preserves the name at the API level.
Realistically, he may be right since we would never be able to remove the existing method names. Would it be worth adding the new API's to swing components? Would it make sense at the JX or JN level to provide the API's that might be more approachable for new developers?
The listeners don't go away in either case: it's just a matter of how completely they can be ignored.
dave
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 5:49 AM
in response to: david_hall
|
|
|
Actually this isn't a matter of code clutter, its a matter of the functional programming crowd trying to push their ideas into Java see this: http://www.javalobby.org/java/forums/t77733.html?start=100#92037882
Anonymous inner classes aren't verbose, they just show us what is happening... Closures are verbose and a language change that will be very hard to swallow for most developers. Now functional programming ideas can coexist with object oriented concepts (most modern scripting languages take this approach) but we made a choice with Java and people should see closures for what they are "glorified function pointers".
-- Shai Almog vPrise http://www.vprise.com/ [att1.html]
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 8:36 AM
in response to: Shai Almog
|
|
|
> but we made a choice with Java and people should see closures > for what they are "glorified function pointers".
I LOVE glorified function pointers. They're so powerful.
Java is the platform where everything is glorious! - objects are glorified structs - the JVM is a glorified interpretter - the standard Java class library is a glorified programming platform - write-once, run anywhere is glorified platform emulator
... and my personal favourite: - loops and if statements are just "glorified gotos"!
Cheers, Jesse
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 9:36 AM
in response to: jessewilson
|
|
|
> - loops and if statements are just "glorified gotos"! >
Nice analogy 
Yes thats pretty much true, but unlike closures the constructs you listed that are essential for most languages, are well defined/known and have existed since Java came out... So most people have a basic idea of what these things are, I don't have to explain for loops.
When someone hears "closures" they think something special, lots of RoR developers when confronted about why a Rails like environment can't be built in Java (there actually are several such frameworks such as Rome) automatically cast the magic word: "Closures". People are hiding behind technical terms trying to add a feature that essentially boils down to a function pointer with weird syntax and a cool sounding name!
Closures are mostly redundant with some special cases that the closure crowd keeps highlighting while completely ignoring the more common things that most people will notice. It will actually make Swing far more complicated than it is today see my post:
http://jroller.com/page/vprise?anchor=closures_are_functional_programming
And read the bullet points.
-- Shai Almog vPrise http://www.vprise.com/ [att1.html]
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 10:57 AM
in response to: Shai Almog
|
|
|
Shai,
I think you overstate the negative impact that closures would have on Swing. With that said, the examples I have seen so far make the code less readable. Perhaps this is just because I'm still getting used to the syntax. Given the sponsorship of closures, I would be shocked if closures don't get added to Java.
Can someone explain why closures would be preferred over method references? If the compiler would generate the bridge classes for single-method interfaces, then method references could be very concise and typesafe. Is there a concrete proposal for method references comparable to the one for closures? As I understand it, they are both being considered for Dolphin.
See page 61 of "Mastering Mustang, Developing Dolphin" http://developers.sun.com/learning/javaoneonline/2006/coreplatform/TS-3439.pdf
Language Changes â—� Property support â—� Language for getFoo()/setFoo() pattern â—� Method References â—� addActionListener(reference updateList) â—� Block Closures â—� Readable statements-within-statements â—� Native XML Support â—� elt.add( <present> <who>currentSpeaker</who> <day>Calendar.TUESDAY</day>
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 11:35 AM
in response to: coxcu
|
|
|
> > I think you overstate the negative impact that closures would have on > Swing.
I don't think so  So lets see: if we look at java.awt.event it has 17 listener interfaces (not including AWTEventListener) javax.swing.event has 21 listener interfaces (if I'm not mistaken). Many of these aren't all that relevant since you can't really go into the Model classes and fix them to create a new add*Listener method so there will be inconsistency of where listeners are implemented. Now lets use guesstimates since I don't really have the energy to count everything (feel free to go over all the methods and post the right numbers). Assuming that all the AWT listeners are relevant and say 11 of the Swing listeners are also relevant we would have 28 interfaces in which I assume we will have an average of 2.5 methods to implement that means top level Swing components will have 56 additional methods that replicate existing functionality in an inconsistent way!
And people complain Swing is complicated and big, right now I'm working with a huge company that just flat out refuses to use Swing because of complexity... Its an uphill battle that I am fighting but argh its hard to argue some of their points (I can't get into details but trust me it would be HUGE).
So lets recap: Approximately 56 new methods that replicate existing functionality. Inconsistency since models can't be modified! Or worse adding additional interfaces e.g. TableModel2! Or worse breaking compatibility JDBC style by adding interface methods! Complex JavaDoc and declaration syntax such as this *simple* example from Patrick Gotthardt just imagine a complex example and how this will look in the JavaDoc: public <T> void each(Collection<T> c, void(T) handle)
I just hope that with my posts I raised enough awareness for these issue so people will say that Java 5 was enough and we don't need further changes. There is pressure to "innovate" and "compete" within Sun that negates the historical conservative roots of Java and is alienating a large body of its long time users.
-- Shai Almog vPrise http://www.vprise.com/ [att1.html]
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 12:45 PM
in response to: Shai Almog
|
|
|
Shai,
That might be one way of supporting closures, but I doubt the Swing team will go down that road. Given Sun's new openness for Java and Swing, the community should have ample oppurtunity to complain.
Swing is complicated and big. Anyone who tells you otherwise is selling something. The decision to leverage AWT so heavily was probably good for the short term, but bad for the long term. One of the reasons JComponent fares so poorly against its counterparts from other toolkits, in terms of API size, is because of all the cruft it inherits. Consider the following:
Widget (5 pages) http://buoy.sourceforge.net/docs/buoy/widget/Widget.html
JComponent (40 pages) http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JComponent.html
Incidentally, a typesafe language construct for method references would be great for Buoy. One of the big reasons I haven't done much with Buoy is that I'm such a big typesafety nut.
- Curt
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 12:54 PM
in response to: coxcu
|
|
|
> That might be one way of supporting closures, but I doubt the Swing team > will go down that road. Given Sun's new openness for Java and Swing, the > community should have ample oppurtunity to complain.
I hope they won't but look at all the examples people are giving for how Swing will improve with closures... Most experienced Swing developers don't use action listeners we use Actions so there goes that advantage, so how will Swing benefit from closures? That's the topic of this thread... It won't.
Swing is complicated and big.
I wasn't arguing that  I was making a point that its already complicated and big and there is no point in adding to that.
-- Shai Almog vPrise http://www.vprise.com/ [att1.html]
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 13, 2006 10:11 PM
in response to: Shai Almog
|
|
|
> [snip] Most experienced > Swing developers don't > use action listeners we use Actions
Why? Other people have said the same thing.
I quote from the Action javadoc: "Note that Action implementations tend to be more expensive in terms of storage than a typical ActionListener, which does not offer the benefits of centralized control of functionality and broadcast of property changes. For this reason, you should take care to only use Actions where their benefits are desired, and use simple ActionListeners elsewhere."
It seems to me Actions should only be used where you have two or more components that invoke the same action, e.g. a menu entry and a toolbar button. (Although I recognise their advantage in JXDialog)
It appears this is not the case Could someone please explain.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 14, 2006 6:19 AM
in response to: rturnbull
|
|
|
"Most experienced Swing developers don't use action listeners we use Actions"
In my experience, this is false. I was an experienced Swing developer long before I realized the value of favoring Actions. Browsing JavaOne online, I found a nice presentation that explained the value of designing an application around commands and actions. Unfortunately, that presentation is no longer on-line. Perhaps someone can post a link to it here.
My biggest problems with actions as they exist now are: 1) lack of documentation explaining when to use them 2) lack of typesafe attributes 3) no standard support for building actions from resources 4) an action manager would probably be nice, too
SAM - Swing Action Manager https://sam.dev.java.net/
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 14, 2006 9:40 AM
in response to: coxcu
|
|
|
> "Most experienced Swing developers don't use action > listeners we use Actions" > > In my experience, this is false. I was an > experienced Swing developer long before I realized > the value of favoring Actions.
This was also my experience.
> 2) lack of typesafe attributes
Amen! Our AbstractActionExt class in SwingX adds typesafety (sort of. You could still put the wrong type in the underlying map and get a class cast exception at runtime).
> 3) no standard support for building actions from > resources
Score one for JSR 296 (which tackles this head on).
Richard
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 14, 2006 7:37 PM
in response to: coxcu
|
|
|
> "Most experienced Swing developers don't use action > listeners we use Actions" > > In my experience, this is false. I was an > experienced Swing developer long before I realized > the value of favoring Actions. Browsing JavaOne > online, I found a nice presentation that explained > the value of designing an application around commands > and actions. Unfortunately, that presentation is no > longer on-line. Perhaps someone can post a link to > it here. >
Both replies to my post agreed the statement was incorrect.
However they focused on the "Most experienced Swing developer" part of the statement, rather than the "don't use action listeners we use Actions" part, which was the part I was interested in. They seemed to imply that most developers have not yet "realized the value of favoring Actions"
I still don't know why. Perhaps the missing presentation would answer my question
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 15, 2006 3:46 AM
in response to: rturnbull
|
|
|
Ray,
jdnc-interest@javadesktop.org wrote: >>[snip] Most experienced >>Swing developers don't >>use action listeners we use Actions > > > Why? > Other people have said the same thing. >
As I'm the one _preaching_ to use Actions instead of ActionListeners, I definitely will try to answer your question - next week, sorry for the delay.
Jeanette
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 9:12 PM
in response to: Shai Almog
|
|
|
(Picking up on one of Shai's earlier posts)
> java.awt.event it has 17 listener interfaces (not > including AWTEventListener) > javax.swing.event has 21 listener interfaces (if > I'm not mistaken). ... > Assuming that all the AWT listeners are relevant and > say 11 of the Swing > listeners are also relevant we would have 28 > interfaces in which I assume we > will have an average of 2.5 methods to implement that > means top level Swing > components will have 56 additional methods that > replicate existing > functionality in an inconsistent way!
As far as working just with the components goes, it doesn't have to be that complicated. Most of the eventListeners are of the form
public interface FooListener extends EventListener {
public void handleFoo(FooEvent evt);
}
The only thing that's different in all of the implementations is the name of the handler method. They could all be expressed as implementations of:
interface EventListener<E extends Event> {
public void handleEvent(E event);
}
... if we could go back and change the names (which, of course, we can't). However, suppose once we had closures, we added:
public void <E extends Event> onEvent(Class<E> eventType, void(E evt) handler) {
}
... to JComponent or Component. This would let us recast all of the listener registrations as
public void addFooListener(FooListener listener) {
onEvent(Foo.class, void(E evt){ listener.doFoo(evt) });
}
... meaning that instead of the dozens of methods you object to, I think we can get away with a just a couple. This lets us de-emphasize the listener interfaces without breaking code.
> Many of these aren't all that > relevant since you can't > really go into the Model classes and fix them to > create a new add*Listener > method so there will be inconsistency of where > listeners are implemented.
This is a great point, and I really can't answer it right now, other than start throwing cavaets around (like above, where I wrote "As far as working just with the components goes")
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 12:04 PM
in response to: coxcu
|
|
|
> Can someone explain why closures would be preferred > over method references? If the compiler would
Why, because Ruby has them... That seems to be the sole reason to add everything and the kitchen sink to Java these days whether it's a change for the better or not (and closures (which indeed are just function pointers with a fancy new name) are certainly NOT a change for the better).
> Language Changes > â—� Property support > â—� Language for getFoo()/setFoo() pattern wow, make things look more like C# to woo some C# programmers.
> â—� Method References function pointers by yet another name.
> â—� Block Closures function pointers by another name. Ruby has them so Java MUST have them too.
> â—� Readable statements-within-statements I can read things quite well as they are. Changing the language to make the syntax more obscure in the name of adding new "features" will change that.
> â—� Native XML Support So at last we'll be able to code a Java class as
<class language="java" package="com.mycompany.java">
<method return-type="void" static="true" access="public" name="main">
<argument-list>
<argument name="args" type="java.lang.String" array-type="true"/>
<argument-list>
<method-body>
<![PCDATA[System.out.println("Hello World!");]]>
</method-body>
</method>
</class>
I'd rather not.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 8:10 PM
in response to: Shai Almog
|
|
|
>> Anonymous inner classes aren't verbose, they just show us what is >> happening... Closures are verbose and a language change that will be very >> hard to swallow for most developers.
I've seen variations of this same statement in every discussion that I've followed. What I have yet to see, however, is any example where the closure syntax is actually more verbose at the point of use than the equivalent anonymous class. In every case I've seen, at the point of use, a closure will declare the types and names of its arguments while an anonymous class method signature has exactly the same information, but it's wrapped up in more packaging.
The essential part of the code is the body of the closure/interface implementation. That's the part that carries the intent of the author, and is the part that maintenance programmers need to see and understand. Everything else is just a wrapper. I just think that a shorter, more declarative wrapper makes some sense.
>> people should see closures for what they are "glorified function pointers".
Perhaps that's all they are: we haven't seen an implementation yet. We don't know how the Closure itself will be made available in the API -- it could very well be a first class object similar to String. There could very well be a lot that we can do with a java.lang.Closure that makes them much more than 'glorified function pointers'. But, even if they're not, I'll be happy to have them.
I don't like boilerplate. Having my editer generate boilerplate for me doesn't make me dislike boilerplate any less. I'd rather be able to pass a line or two of code around without having to create extra stuff.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 12:53 AM
in response to: david_hall
|
|
|
> I've seen variations of this same statement in every discussion that I've > followed. What I have yet to see, however, is any example where the closure > syntax is actually more verbose at the point of use than the equivalent > anonymous class.
If I'm not mistaken thats my quote  I didn't say closures would ever be more verbose than the current syntax for annonymous inner classes (although theoretically I did describe something on the JL that is possible). So I can't show such an example, I have shown an example where the complexity is IMO quite high and reuses Java syntax in such a way that it would now have additional meanings. IMO while this saves lines of code it is more complex and thus negates most of the advantage saved by the less lines of code. That is obviously a matter of opinion.
In every case I've seen, at the point of use, a closure will declare the > types and names of its arguments while an anonymous class method signature > has exactly the same information, but it's wrapped up in more packaging.
Anonymous inner classes are a shorthand for class declarations, so they have very low impact... They have no ripple effect of complexity through the language since you don't have to add methods to support them or additional declarations. Closure usage is arguably simple but it introduces brand new constructs and concepts into the language that people have to understand... Closures hide some syntax from the user of the method while creating a unique syntax for the method implementer, it would require an overhaul of every API in Java to support this for advantages that are really trivial and unnecessary in most cases.
Neal Gafter responded to my post yesterday with a link to his blog ( http://gafter.blogspot.com/2006/08/use-cases-for-closures.html ) he made some interesting points there specifically in his response to Mikael Grev. But if it takes such a huge blog to show a very small edge case of where closures have a minor advantage over inner classes then I doubt its worth it. When making such a significant change (this is VERY significant since it will require changing countless API's in util, Swing, AWT and probably more) you should consider its risks more in depth.
The essential part of the code is the body of the closure/interface > implementation.
I would argue this point. It would be like saying that a maintainer won't have to look at the JavaDoc for the method that accepts a closure... How will that JavaDoc look? It would be like saying that only API developers will ever make use of closures. It would be like saying that the number of duplicate API's won't affect project maintainance and development.
That's the part that carries the intent of the author, and is the part that > maintenance programmers need to see and understand. Everything else is just > a wrapper. I just think that a shorter, more declarative wrapper makes some > sense.
If all closures do is support a shorthand declaration then just follow my silly suggestion for "super anonymous inner classes" http://www.javalobby.org/java/forums/t77733.html?start=100#92037882 This suggestion is feasible and won't introduce any of the complexities associated with closure language changes (hell you could probably compile something like this with target 1.1) since its simply a javac change. Yes its a "hack" but so is the suggested closure implementation in Java... This will have far less wide impact on the language, I'm against this since I don't like the compiler making "decisions" on my behalf... Thats what brought us C++, but its not as bad as a complete modification of a huge language.
>> people should see closures for what they are "glorified function > pointers". > > Perhaps that's all they are: we haven't seen an implementation yet. We > don't know how the Closure itself will be made available in the API -- it > could very well be a first class object similar to String. There could very > well be a lot that we can do with a java.lang.Closure that makes them much > more than 'glorified function pointers'. But, even if they're not, I'll be > happy to have them.
People have raised points like Currying as an advantage, but they still fail to provide practical use cases where currying helps just some theoretical use cases that aren't practical. Can you think of a single API in Swing or anywhere that would make use of such a feature? I asked the commenters on my blog this question and not a single example came in response.
I don't like boilerplate. Having my editer generate boilerplate for me > doesn't make me dislike boilerplate any less. I'd rather be able to pass a > line or two of code around without having to create extra stuff. >
I agree, direct quote from my blog: " BTW if you think "my IDE can..." then there is really nothing to talk about, the best IDE takes seconds to convey any information (tune it for less and they all stall on large code) also once you start doing that whats the point of syntax? IDE's just don't cover the slack left by a programming language or platform, a good example would be older EJB versions where IDE's failed to pick up the slack and simplify that."
The IDE claim is used incorrectly by both sides, the anonymouse inner class fans say the IDE can generate code... The closure fans say the IDE can direct you to the source of anything just by pointing your mouse at something.
-- Shai Almog vPrise http://www.vprise.com/ [att1.html]
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 2:05 AM
in response to: Shai Almog
|
|
|
Hi Shai
I think there are two really separate questions here. One question is, should closures be added to Java? The second (on this thread) is, if closures were added, should Swing APIs take advantage of them, and how?
I think the first question, do we need closures, is well worth the debate and I'm enjoying all the discussion about it. But adding that to this thread isn't helpful. Or at least, we then need two threads. What I think this thread is about is how Swing could benefit from using closures. And I think that approaching it in a positive way--look how we can simplify development using Swing--is more helpful.
That's not to deny any of your feedback, opinions, etc. Your points are well-made and certainly the whole proposal of closures is generating a lot of strong emotion in the community.
I think we should discuss the ways in which closures could be used, and whether the advantage is (only) in reducing tokens we have to type, or whether there are some use-cases, such as people have shown for collections, where we actually get some real leverage.
So, Shai: suppose you were working with KindOfJava as a programming language, which was just like Java 5 but had closures. You'd still use Java 5 at your day job, but KindOfJava would also be available (like scripting/dynamic JVM languages are now). How might you use closures to make your Swing programming easier?
Cheers Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 3:13 AM
in response to: Patrick Wright
|
|
|
Hi,
Just some comments:
* Functors for Swing
Has anybody a copy of TS-3802 "Applying Generics and Functors to Desktop Java Technology Programming" from JavaONE 2004? It's not available anymore now... 
That session made good points about using functors for Swing. I assume all that should be easier now with "closures" (note that current closures are not able to keep state between invocations, so I don't consider them proper "closures").
* Threading
Another area where closures could make life easier for Swing developers is in the threading arena. Something like
SwingUtilities.invokeLater( { // Whatever code here } );
is probably easier to read than our current "new Runnable()" stuff. Closures may access non-final vars, so that stuff should be easier too.
I do still prefer SwingWorker, though 
Cheers, Antonio
Patrick Wright wrote: > [ stuff removed for brevity] > > So, Shai: suppose you were working with KindOfJava as a programming > language, which was just like Java 5 but had closures. You'd still use > Java 5 at your day job, but KindOfJava would also be available (like > scripting/dynamic JVM languages are now). How might you use closures > to make your Swing programming easier? > > Cheers > Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 5:37 AM
in response to: Antonio
|
|
|
Antonio
I'm the OP of this thread, as well as the presenter of the session you're citing. I'm not sure if I can post the slides or not, since Sun was (at the time) using that material as a benefit for those who paid for JavaOne attendance. I'll certainly post them to the JGA website if it turns out that I can.
Most of the regulars here know that that's my session, so I couldn't've gotten away with citing it 
I've brought up most of the salient points before, tho.
Dave
|
|
|
|
|
|
|
|
Why are only two years available?
Posted:
Aug 31, 2006 5:57 AM
in response to: david_hall
|
|
|
Sorry for being a bit tangental, but it has always frustrated me that there are only two years available at JavaOne online. http://developers.sun.com/learning/javaoneonline/
Does anyone know why they are limited to two years?
- Curt
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 6:04 AM
in response to: david_hall
|
|
|
Hi Dave,
jdnc-interest@javadesktop.org wrote: > Antonio > > I'm the OP of this thread, as well as the presenter of the session you're citing. I'm not sure if I can post the slides or not, since Sun was (at the time) using that material as a benefit for those who paid for JavaOne attendance. I'll certainly post them to the JGA website if it turns out that I can. > Oh, I didn't know that it was you!
I assume there's no problem in posting them, since Sun (or was it JavaOne) posted them for free after JavaOne, as far as I can tell. Anyway it's a good idea you checking it, just in case. > Most of the regulars here know that that's my session, so I couldn't've gotten away with citing it  >

I've tracked you by Googling until the JGA web site (and was about contacting you directly). Quite impressive job you've been doing there, guy. Congrats.
Cheers, Antonio
> I've brought up most of the salient points before, tho. > > Dave > [Message sent by forum member 'david_hall' (david_hall)] > > http://forums.java.net/jive/thread.jspa?messageID=148982 > > --------------------------------------------------------------------- > To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net > For additional commands, e-mail: jdnc-help@jdnc.dev.java.net > > >
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 3, 2006 11:44 AM
in response to: Antonio
|
|
|
Recently i've been making a factory for reading documents. IO is exception-land, and i'm here giving my support for a idea that was on this thread, of something like:
FileInputStream stream; byte [] b = new byte[20]; using(stream, { stream = new FileInputStream(someFile); stream.read(b); } );
using(Closable c, void() f) throws IOException { try{ f(); }finally{ try{ c.close(); }catch(NullPointerException e){e.printStacktrace();} } }
Would be usefull. It would be even better if it was like C# and the proposed syntatic sugar was implemented: using(stream = new FileInputStream){ //code of closure here without } You could probably do things like: dontCare(void() f){ try{ f(); }catch(Exception e){log(e);} }
dontCare{ using(FileInputStream s = new FileInputStream()){ do something } }
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 3:20 AM
in response to: Patrick Wright
|
|
|
Hi Patrick,
Hi Shai > > I think there are two really separate questions here. One question is, > should closures be added to Java? The second (on this thread) is, if > closures were added, should Swing APIs take advantage of them, and > how?
I think the first question was raised by myself in the JavaLobby thread, I think this thread should really discuss the second which IMO has also implications for the first... After all, if you read most of the comments in the JL thread the examples tend to circle around Swing/AWT and Collections so the closure crowd do actually expect integration and I wouldn't expect otherwise. Especially after Java 5 where Sun went over the entire API and modified existing code to generics and varargs causing my code to emit warnings and in some rather common cases not compile (which is not a terrible thing e.g. java.util.List/java.awt.List but on a much bigger scale and very inconvenient).
I think the first question, do we need closures, is well worth the > debate and I'm enjoying all the discussion about it. But adding that > to this thread isn't helpful.
Agreed, I tried to focus on how they are unpractical to Swing in my first response but it did get carried away  After all this is not a clean cut separation.
Or at least, we then need two threads.
-1 on that  The JavaLobby thread already has 169 comments and counting... Mostly silly back and forth but I think all the relevant points were made.
What I think this thread is about is how Swing could benefit from > using closures. And I think that approaching it in a positive > way--look how we can simplify development using Swing--is more > helpful.
OK, that's valid but then I wouldn't be able to say anything  If anyone has any idea about how Swing/SwingLabs can be simplified using closures I'll debate the negative side of that. Several brilliant people I know want closures but I still stand unconvinced so I think one should highlight the pitfalls and weaknesses of these ideas. Now you might say that my claiming that X can be done just as easily with an inner class isn't a valid drawback of closures... But really it is because then Swing becomes inconsistent using classes at one point and closures in another.
So, Shai: suppose you were working with KindOfJava as a programming > language, which was just like Java 5 but had closures. You'd still use > Java 5 at your day job, but KindOfJava would also be available (like > scripting/dynamic JVM languages are now). How might you use closures > to make your Swing programming easier? >
That's not a valid argument, up to here we agreed but you are now splitting the discussion into another question: In theory if we were living in a clean world should closures be used and how?
The current question relates to Swing as it is now designed around Java as it is now. A theoretical problem is irrelevant without existing code and when people don't even agree on basic concepts of language design (its a matter of opinion)... Rather than debate theories I think people can debate facts while separating them from opinion, that's hard to do with closures but relatively easy to do with Swing and closures.
Feel free to find an example where closures are more productive, I asked people multiple times to give me such "real world" examples and no one ever did. There just aren't any, I wouldn't be happy if I was proven wrong but I think I'm big enough to admit a mistake. Currying might contain some interesting use cases but I was racking my brain trying to find one case where it does provide real world advantages... Couldn't think of it either, trust me I gave it a lot of thought before starting a huge argument with practically everyone on that thread including some brilliant people. I think there is a party line and even great brilliant people might be wrong on some things.
-- Shai Almog vPrise http://www.vprise.com/ [att1.html]
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 4:33 AM
in response to: Patrick Wright
|
|
|
Hi Patrick,
> > I think the first question, do we need closures, is well worth the > debate and I'm enjoying all the discussion about it. But adding that > to this thread isn't helpful.
moving the closure of that part <g> (I'm walking on thin ice - my dictionary might not be good enough for cracking a joke).
Actually, I remember the last time I thought I wanted function pointers was nearly twenty years ago - when trying to implement "sophisticated" visualization of data output from all my fancy lab stuff, (in Turbo Basic): I couldn't believe that there was no possibility to replace a Gauß with a Lorentz distribution by simply changing a method pointer ... with the advent of Objects that desire vanished.
It's anecdotal, but marks my current position about closures: slightly astonished and very remote interest about all the noise they are creating. So beware, I know exactly nothing about any details, implications, pros and cons on the general level.
> What I think this thread is about is how Swing could benefit from > using closures. And I think that approaching it in a positive > way--look how we can simplify development using Swing--is more > helpful. >
That's a good suggestion, IMO.
Back to Dave's original example (arrgghhh.. forgot that I missed the first post due to the unsynched mailinglist, so I take the quote from one of the answers):
public class JXButton extends JButton {
public void onAction(void(ActionEvent) fn) {
...
}
}
Which I think is more a counter-example when it comes to "benefit". Not because of any syntax/formal arguments but because it subtly goes against Swing's grain in the particular realm of ActionListener/Action: the way to go is to use Action instead of ActionListener. The reason is that the Action has state ("enabled") which is important for the button's functionality (must respect).
<wild-shot-and-jab> I suspect that the actionListener would have died out long ago if it weren't for those fancy IDEs and builders which are too dumb to make use of "old latest" (since 1.3, or was it 1.2?) evolution. </wild-shot-and-jab>
That said, I think (could be way off, see disclaimer above that SwingX has a "kind-of" action function pointer implementation - that's the BoundAction. Which makes use of core (not only Swing) "kind-of" function pointer implementation: EventHandler. It uses reflection to invoke an arbitrary method on an some handler triggered by some event.
// now
SomeListener l = (SomeListener) EventHandler.create(
SomeListener.class, targetHandler, targetMethodName);
myButton.addSomeListener(l);
// with closure
myXButton.onSomeEvent({ targetHandler.targetMethod });
Hmmm ... not sure if I would trade the gain for a complicated syntax, but I often do use EventHandlers. So ... feeling a slight fluttering desire returning 
Interesting thread!
Jeanette
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 6:22 AM
in response to: Kleopatra
|
|
|
Jeanette:
At this point, one meta-thing I've certainly learned from this thread is to never use JButton/Action/ActionListener as an example again
(( In my mind, it's just the simplest case of event management - it doesn't carry a lot of semantic baggage and isn't associated with more complex widgets or user interactions ))
The distinction between ActionListener and Action is reflected in JGA's swing package. I've defined generic/scriptable implementations of both there - GenericActionListener and GenericAction. Both take the same argument: a function returning void that takes an ActionEvent. In the new syntax, that's "void(ActionEvent)" while in JGA, it's "UnaryFunctor<ActionEvent,?>" (although I'd like it better if I could support "Function<void,ActionEvent>" for any number of argument types).
So suppose we have an action w/ closure support (which is really just a syntactic variation of GenericAction).
btn.setAction({ btn.setText("Thank You") });
// or
btn.setAction(new ScriptedAction( {btn.setText("Thank You") ));
// instead of
btn.setAction(new Action(){
public void actionPerformed(ActionEvent e) {
btn.setText("Thank You");
}
});
IMO, one of the advantages is that we can have an implementation of an existing abstraction, like Action, that everyone can reuse -- it becomes part of the standard package. Yes, it makes the standard package a little bigger: in return _all_ of the user's distributions get smaller.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 31, 2006 9:28 AM
in response to: david_hall
|
|
|
Somebody said that Closures would make Swing more complex because there would now be two ways to do everything.
But that's assuming that the Swing project would be updated to the latest APIs, which hasn't been the case historically: - the List interface was introduced with Java 1.3 but you still can't create a JComboBox with one. You need a Vector! - Generics came out in Java 1.4, but ListModel, an obvious candidate), doesn't use 'em - ButtonGroup uses Enumeration, but Iterators are the new hotness
I'd love to see Swing get refreshed to the Java 1.5 way of doing things.
Cheers, Jesse
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 1, 2006 5:04 AM
in response to: david_hall
|
|
|
Dave,
> > At this point, one meta-thing I've certainly learned from this thread is to never use JButton/Action/ActionListener as an example again
<g> I don't think that it's a bad example for the sake of the discussion, only not the best example to highlight potential benefits of closures (aka "function pointers"). It's more like scraping at the boundaries of their usefulness.
The example combines the simplemindedness of an ActionListener (it does nothing but invoke a method) with the singularity of an Action (there's at most one for each button). Doing so, it looks attractive. But it leaves out the listener's multiplicity (there might be several) as well as the Action's state (which a button must synch to). Both have impact on the button's api - actually I don't know how you want to solve the state issue when using a function pointer on the button level (as opposed on the Action level).
I'm aware that you are aware of it - just want to spell it out again: button.addActionListener(..) is different from button.setAction(..), so we have to keep the distinction when we play with KindOfJava syntax
button.addActionFunction({ btn.setText("Thank You") });
// open: how to remove?
Action action = new AbstractActionExt({ setName("Thank You")});
button.setAction(action);
Actually, this action is not jumping far enough - a more real worldish example probably would turn off enabled as well. Hmm ...
Action action = new AbstractActionExt("Click to Process") {
void actionPerformed(...) {
setName("Thank You");
setEnabled(false);
}
}
// with function pointer?
> > (( In my mind, it's just the simplest case of event management - it doesn't carry a lot of semantic baggage and isn't associated with more complex widgets or user interactions )) >
starting with a simple case sounds good - experimenting a bit further: what happens in the more complicated cases?
button.addMouseEnteredFunction({..});
button.addMouseExitedFunction({...});
button.addMouseXXFunction{{...});
looks like an exploding api to me. With the additional disadvantage of loosing coupling between f.i. entered and exited, which usually are related.
Have a nice weekend (mine starts early today  Jeanette
PS: a benificial side-effect of this discussion is that at last I took a look at jga, it's impressive! Using a formatting/parsing functor in renderers/editors is a nice tweak Only, can't get the current jga (today's cvs checkout) to compile - mainly due to missing ParserException and JXFParser. Not a big deal, though, can play against the binary distribution.
PPS: I hate boilerplate code, too.
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 1, 2006 7:30 AM
in response to: Kleopatra
|
|
|
Quick thought: One direction to go in with this is to look at two use cases that are poorly served by the current APIs. One is where beginners want to get a Swing app up and running very quickly, and the second is where an experienced Swing programmer wants to get a prototype up and running very quickly. In either case, arguably having the flexibility of Actions (which may be easily categorized, save and reused across the app) is conceptual overhead that gets in the way.
To that end, the closer we can get to: create a button assign the "onClick" behavior
the better.
Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 1, 2006 9:40 AM
in response to: Patrick Wright
|
|
|
I know you guys don't like to hear "the IDE easily handles this scenario", but it's true in this case. If an experienced Swing developer wants to get a prototype up and running quickly, then mocking it up with Matisse and wiring the components together with the wizards is very fast and code free for the developer. I'm not a fan of boilerplate code either, but that's usually why an IDE generates it for you. So in this scenario, what is the advantage of closures if the IDE generates this stuff for me?
Also, it seems strange to me that some of you guys are using the argument that closures will make Swing a little easier to use, but don't think there is anything to be done in the "ease of use" department for developers to know that a JComboBox is a compound component and must be treated differently at times. The specific JComboBox example in a prior thread was adding a Focus Listener to the combobox unless it is editable. In that case, you must "know" to add the listener to the editor instead of the combobox. This was brushed aside as being the responsibility of the IDE to make it easier, but apply the same logic to closures and you guys all disagree. So it's better to modify the language to save a few lines of code for a few developers than it is to make the Swing APIs consistent? I'm having trouble understanding this.
Erik
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 1, 2006 10:36 AM
in response to: evickroy
|
|
|
About swing events, i feel that bouy as a better way... no anomynous inner classes clutter, just the method name and the type of event to listen. This is why why like closures, since them seem equivalent to how bouy handles "anomynous inner classes that only call one function"
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 2, 2006 4:04 AM
in response to: evickroy
|
|
|
Hi Erik,
> > Also, it seems strange to me that some of you guys are using the argument that closures will make Swing a little easier to use, but don't think there is anything to be done in the "ease of use" department for developers to know that a JComboBox is a compound component and must be treated differently at times.
Looks like what I meant didn't come over too clearly 
So to clarify: I _don't_ argue in favour of closures - I argue in favour of exploring and understanding the possibilities, both pros and cons. My usual means of trying to understand something is to use concrete examples.
Until now, I have seen nothing which would sway me to favour closures (even though I hate the boilerplate <g>), the trade-off seems disfavourite. Some of my arguments are very much similar to those of the combobox/focuslistener debate - we can't change the behaviour of what's already there, if we add something, it has to fit snuggly into the current environment: in the closure/listener debate we can't change the action/-listener/button interaction semantics, in the focus listener context we can't change the focus spec. But we can add a new layer of abstraction if it is helpful/required and doesn't lead to inconsistency.
I'm very sorry that you felt "brushed off" in the older debate, as far as I remember the thread petered out somehow - my (concededly raw) suggestions didn't draw much interest 
Jeanette
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 2:44 AM
in response to: evickroy
|
|
|
Hi Erik
On 9/1/06, jdnc-interest@javadesktop.org <jdnc-interest@javadesktop.org> wrote: > I know you guys don't like to hear "the IDE easily handles this scenario", but it's true in this case. If an experienced Swing developer wants to get a prototype up and running quickly, then mocking it up with Matisse and wiring the components together with the wizards is very fast and code free for the developer. I'm not a fan of boilerplate code either, but that's usually why an IDE generates it for you. So in this scenario, what is the advantage of closures if the IDE generates this stuff for me?
I think one needs to decide where one stands with the IDE/Swing question in the first place. I think, on the on hand, that working to make it easy/easier to develop Swing apps using an IDE is a good thing. On the other hand, there are many times where I need to prototype something and don't want to fire up the IDE, open or create a project, create a form, add the form to a frame, etc. just to try out some ideas in Swing. At least for my purposes, the complexity of the Swing APIs is counter-productive for rapid prototyping. So I'm asking myself, with that in mind, whether closures actually help or not.
I've developed and deployed a couple of Swing apps using NetBeans over the last few years and I found it generally to be an enjoyable experience. But conversely, when I wanted to get something up and running quickly, I found the IDE to get in the way (e.g. I wanted to just be up and running, and a text editor was the easiest way to do so) and find some of the boilerplate tiresome.
> > Also, it seems strange to me that some of you guys are using the argument that closures will make Swing a little easier to use, but don't think there is anything to be done in the "ease of use" department for developers to know that a JComboBox is a compound component and must be treated differently at times. The specific JComboBox example in a prior
Who said that? I think you're referring to a different discussion.
Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 10:30 AM
in response to: evickroy
|
|
|
> Also, it seems strange to me that some of you guys > are using the argument that closures will make Swing > a little easier to use, but don't think there is > anything to be done in the "ease of use" department > for developers to know that a JComboBox is a compound > component and must be treated differently at times. > The specific JComboBox example in a prior thread was > s adding a Focus Listener to the combobox unless it > is editable. In that case, you must "know" to add > the listener to the editor instead of the combobox. > This was brushed aside as being the responsibility > y of the IDE to make it easier, but apply the same > logic to closures and you guys all disagree. So it's > better to modify the language to save a few lines of > code for a few developers than it is to make the > Swing APIs consistent? I'm having trouble > understanding this.
This is a _really_ good point. In the end, closure or no closure will make very little difference to application development. The APIs we write, and the way they are used, makes a _much_ bigger impact.
Richard
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 2:50 AM
in response to: Kleopatra
|
|
|
> The example combines the simplemindedness of an ActionListener (it does > nothing but invoke a method) with the singularity of an Action (there's > at most one for each button). Doing so, it looks attractive. But it > leaves out the listener's multiplicity (there might be several) as well > as the Action's state (which a button must synch to). Both have impact > on the button's api - actually I don't know how you want to solve the > state issue when using a function pointer on the button level (as > opposed on the Action level).
I always thought (and maybe am missing a large piece of the picture here) that Actions provided two advantages:
a) certain properties, like "enabled", short/long descriptions, and key mappings, can be bound to an action, and inherited by the action's owner
b) actions can be reused across multiple UI components, and thus the properties controlled in one place
While b) is certainly a good case for using actions, I'm not convinced that I always need actions--for example, if the UI component in question can never be disabled, or if the properties aren't otherwise shared.
In HTML/JavaScript, people are used to setting a function call (or scriptlet) on the "onClick" handler--this seems very natural and besides, allows for low-overhead quick prototyping. I haven't met a programmer who found this conceptually confusing, in fact, most people would probably say it's quite a straightforward way to have something happen when a component is clicked.
Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 5:27 AM
in response to: Patrick Wright
|
|
|
Patrick Wright wrote: > a) certain properties, like "enabled", short/long descriptions, and > key mappings, can be bound to an action, and inherited by the action's > owner > > b) actions can be reused across multiple UI components, and thus the > properties controlled in one place > > While b) is certainly a good case for using actions, I'm not convinced > that I always need actions--for example, if the UI component in > question can never be disabled, or if the properties aren't otherwise > shared. >
most probably they need not _always_ (nothing is absolute <g>) be mutable/shareable - but in my experience (in rich client environments) that's such a rare case that I wouldn't waste time/thought to not go Action right from the start. Sooner or later each and every single command needs to be configured (f.i. dynamic localization), its enablement controlled (based on dynamic context), made accessible in different places (menu, toolbar, bound in a component's ActionMap, added to a context menu, custom "action containers") ...
Jeanette
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 7:20 AM
in response to: Kleopatra
|
|
|
> most probably they need not _always_ (nothing is absolute <g>) be > mutable/shareable - but in my experience (in rich client environments) > that's such a rare case that I wouldn't waste time/thought to not go > Action right from the start. Sooner or later each and every single > command needs to be configured (f.i. dynamic localization), its > enablement controlled (based on dynamic context), made accessible in > different places (menu, toolbar, bound in a component's ActionMap, added > to a context menu, custom "action containers") ...
I agree with that for general app development, but my point is that for quick prototyping an Action is unnecessary for simple component setup and usage.
Patrick
--------------------------------------------------------------------- To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 1, 2006 6:29 AM
in response to: david_hall
|
|
|
[duplicate - copied from message sent to the mailinglist 1.5 hrs ago - don't know if it's normal delay or broken again - and don't have the time to check now ... ARRRRGGGHHH]
Dave,
>> >> At this point, one meta-thing I've certainly learned from this thread is to never use JButton/Action/ActionListener as an example again
<g> I don't think that it's a bad example for the sake of the discussion, only not the best example to highlight potential benefits of closures (aka "function pointers"). It's more like scraping at the boundaries of their usefulness.
The example combines the simplemindedness of an ActionListener (it does nothing but invoke a method) with the singularity of an Action (there's at most one for each button). Doing so, it looks attractive. But it leaves out the listener's multiplicity (there might be several) as well as the Action's state (which a button must synch to). Both have impact on the button's api - actually I don't know how you want to solve the state issue when using a function pointer on the button level (as opposed on the Action level).
I'm aware that you are aware of it - just want to spell it out again: button.addActionListener(..) is different from button.setAction(..), so we have to keep the distinction when we play with KindOfJava syntax
button.addActionFunction({ btn.setText("Thank You") });
// open: how to remove?
Action action = new AbstractActionExt({ setName("Thank You")});
button.setAction(action);
Actually, this action is not jumping far enough - a more real worldish example probably would turn off enabled as well. Hmm ...
Action action = new AbstractActionExt("Click to Process") {
void actionPerformed(...) {
setName("Thank You");
setEnabled(false);
}
}
// with function pointer?
>> >> (( In my mind, it's just the simplest case of event management - it doesn't carry a lot of semantic baggage and isn't associated with more complex widgets or user interactions )) >>
starting with a simple case sounds good - experimenting a bit further: what happens in the more complicated cases?
button.addMouseEnteredFunction({..});
button.addMouseExitedFunction({...});
button.addMouseXXFunction{{...});
looks like an exploding api to me. With the additional disadvantage of loosing coupling between f.i. entered and exited, which usually are related.
Have a nice weekend (mine starts early today  Jeanette
PS: a benificial side-effect of this discussion is that at last I took a look at jga, it's impressive! Using a formatting/parsing functor in renderers/editors is a nice tweak Only, can't get the current jga (today's cvs checkout) to compile - mainly due to missing ParserException and JXFParser. Not a big deal, though, can play against the binary distribution.
PPS: I hate boilerplate code, too.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 2, 2006 2:09 PM
in response to: kleopatra
|
|
|
Well, actually addActionListener could be reused as a Closure assigned to it will be transformed into an ActionListener. The call is simple and clear:
btn.addActionListener(ActionEvent e) {
// code
}
Jeanette:
You gave this code and asked how to remove the listener:
button.addActionFunction({ btn.setText("Thank You") });
Now, first we won't need the addActionFunction-method. Defining, adding and removing the closure/listener would therefore look like this:
void(ActionEvent) handler = void(ActionEvent e) {
btn.setText("Thank you");
}
// alternative: void(ActionEvent) handler = void(ActionEvent e) : btn.setText("Thank you");
btn.addActionListener(handler);
btn.removeActionListener(handler);
Now, I'm all against using closures together with Actions. They're really fine for ActionListeners and stuff like that, but never ever use them when a proper object with state is requested.
The workaround to your problem is quite simple, though:
void(ActionEvent, Action) handler = void(ActionEvent e, Action a) {
a.setName("Thank you");
a.setEnabled(false);
}
Action action = new ClosureAction(handler);
One could probably argue to remove the ActionEvent and let the second argument be a ClosureAction, that'd have a method getCurrentActionEvent or something like that. Maybe one would also add a static factory method to that class (this could probably be done using a normal constructor as well), so the client code might look like this:
Action action = ClosureAction.create("Click to Procress") (ClosureAction action) {
action.setName("Thank you");
action.setEnabled(false);
}
Looks quite fine, but I'm still against using a closure for anything that is an object with its own state.
The MouseListener code you gave is a little bit more complicated, though. I don't think that there'll be a way to do this using closures only, except by adding the methods you named, but I don't like this approach.
One alternative to think about is this:
btn.addMouseListener(mouseEntered (MouseEvent e) {
// your code here
});
Where "mouseEntered" is a static imported method (or use the qualified name - it's up to you) in some utility class that wraps the closure into a MouseListener, delegating the mouseEntered event to it.
The problem with this approach is that it'll blow up the number of listeners, so it's probably not a good choice.
Another choice could be something like this:
ClosureMouseAdapter handler = new ClosureMouseAdapter();
handler.onMouseEntered = void(MouseEvent e) {
// your code here
}
handler.onMouseExited = void(MouseEvent e) {
// your code here
}
btn.addMouseListener(handler);
This is a little bit more verbose (two lines more), but cleaner and doesn't introduce the problem of the other version.
Maybe a builder-approach could be used, too, but for my taste that'd have to many braces. 
ClosureMouseAdapter handler = new ClosureMouseAdapter()
.onMouseEntered(void(MouseEvent e) {
// your code here
})
.onMouseExited(void(MouseEvent e) {
// your code here
});
btn.addMouseListener(handler);
That really defeates the purpose of closures, if you're asking me. An inner class would look a lot cleaner here. Maybe a mixture (meaning: both together) of the second (using the static utility method) and the third example would work out well.
The cool thing about the second example is that you could have a hole lot of fun with it by switching the "implementation" (=closure) for specific events at runtime. Most of my MouseListeners would probably benefit from something like this, because the resulting code would be much clearer.
Let me repeat this: A closure shouldn't have a state at all (except for the state of it's context - the method/class where it is declared). If there's coupling between mouse-enter and mouse-exit, then you'll want to go for an object that has a state of its own.
Shai: > Approximately 56 new methods that replicate existing functionality.
Approximately zero new methods that replicate no existing functionality would be added to Java if closures were to make it into the language, but I explained that above. I believe it was Neal Gafter who explained this in his blog.
> Complex JavaDoc and declaration syntax such as this *simple* example from Patrick Gotthardt just imagine a complex example and how this will look in the JavaDoc: public <T> void each(Collection<T> c, void(T) handle)
Well, probably the description would say something around the lines of "Will invoke 'handle' for each E in 'c', passing E as parameter to 'handle'." If written with beginners in mind, it'd also give a code sample:
List<String> names = Arrays.asList("Shai", "Patrick");
each(names) void(String name) {
System.out.println(name);
}
Hmm... I should've come up with a better example... now don't tell me you could do that much easier with a for-loop. I know that quite well. 
> I hope they won't but look at all the examples people are giving for how Swing will improve with closures... Most experienced Swing developers don't use action listeners we use Actions so there goes that advantage, so how will Swing benefit from closures? That's the topic of this thread... It won't.
I do hope that most people are using Actions over ActionListeners. Most of the time that'll be the better way. However, there are cases when it's not. I'm maintaining a fork of the old syntax component from JEdit. It has a class that handles keyevents and it is full of ActionListeners. Really full. Every time I add another ActionListener, I'll write the ActionListener code:
public static class SomeStupidName implements ActionListener {
public void actionPerformed(ActionEvent e) {
// finally the code I wanted to write all the time!
}
}
then I'll procede with adding a static field to the class, as these ActionListeners are always singletons...:
public static final ActionListener SOME_STUPID_NAME = new SomeStupidName();
and then I can proceed with adding it to the map. The alternative using closures? Here it is...:
public static final ActionListener SOME_STUPID_NAME = void(ActionEvent e) {
// already done?!?
}
Well, to be fair: I could already make it a little bit easier for myself:
public static final ActionListener SOME_STUPID_NAME = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// already done?!?
}
}
That's still much more verbose than what it should be. Could I use an Action instead? Of course. That'd have been the best choice to start with, but it wasn't used (just like ActionMap/InputMap are not being used) and I don't have the time to rewrite it. I admit being a little bit feared about the stuff that might break if I change anything in there. Have had to much bad experience with other minor changes in that code... so I'll keep it the way it is for now. 
The funniest thing is that I'm now reusing Jeanetts MouseListener-example to give you an example of where closures could be extremly useful in Swing:
ClosureMouseAdapter handler = new ClosureMouseAdapter();
void(MouseEvent) copy = void(MouseEvent e) {
// copy something at e.getPoint()
}
void(MouseEvent) cut = void(MouseEvent e) {
// cut something at e.getPoint()
}
handler.onClick = void(MouseEvent e) {
handler.onMouseDrag = e.isControlDown() ? cut : copy;
}
panel.addMouseListener(handler);
panel.addMouseMoveListener(handler);
The alternative using the common syntax:
MouseInputAdapter handler = new MouseInputAdapter() {
// we hold the state so the user doesn't have to hold the key
boolean isCtrlDown = false;
public void mouseClicked(MouseEvent e) {
isCtrlDown = e.isControlDown();
}
public void mouseDragged(MouseEvent e) {
if(isCtrlDown) {
// cut something at e.getPoint()
} else {
// copy something at e.getPoint()
}
}
};
panel.addMouseListener(handler);
panel.addMouseMoveListener(handler);
That's still simple, but code get's more complicated if there are more steps to perform. Closures would help to separate the steps, preventing overly blown code. I've some code for a simple reorderable toolbar-panel on my PC and I can really see how it could be improved using this kind of closure.
Besides these use-cases, there's of course my favorite example:
SwingUtilities.invokeLater {
// code here
}
Won't introduce any new API - just plain cool.
> People have raised points like Currying as an advantage, but they still fail to provide practical use cases where currying helps just some theoretical use cases that aren't practical. Can you think of a single API in Swing or anywhere that would make use of such a feature? I asked the commenters on my blog this question and not a single example came in response.
Good question... let me think of it... Ok, here we go. This is a simple example, but with some fantasy you should be able to imagine some use-cases of this principle on your own:
void(String,ActionEvent) printMessage = void(String text, ActionEvent e) {
System.out.println(text);
}
btn.addActionListener(printMessage.curry("Hello World!"));
otherBtn.addActionListener(printMessage.curry("Hello Universe!"));
If "printMessage" was more complicated, you'd have gained quite a lot lines of code - code that now hasn't to be read by those maintaining the code. A bigger impact is refactoring: Now you'll only change printMessage and get the requested effect for both buttons. And by currying, you've converted a closure that wouldn't have fit the ActionListener-interface to one that fits perfectly.
Still no idea of when this might be useful? Ok ok... here we go:
void(JFileChooser, ActionEvent) fileOpenHandler = void(JFileChooser jfc, ActionEvent e) {
File selectedFile = ...
EventBus.getInstance().fireEvent(new FileOpeningRequestEvent(selectedFile);
}
// this button will only allow directories to be chosen
JFileChooser jfc = new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
openDirectoryBtn.addActionListener(fileOpenHandler.curry(jfc));
// this button will only allow files to be chosen
jfc = new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
openFileBtn.addActionListener(fileOpenHandler.curry(jfc));
I'm sure you can come up with your own examples now.
Hope that was useful for the discussion, if not: just ignore it.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 6:33 AM
in response to: pago
|
|
|
Pago, the code that you use to answer to jeanette doesn't works. Closure conversion only works with closure, it doesn't work neither with function type nor with local function.
void(ActionEvent) handler = void(ActionEvent e) {
btn.setText("Thank you");
};
btn.addActionListener(handler); // function type convertion
btn.removeActionListener(handler); // function type convertion
Furthermore, even if a convertion is defined, nothing will insure that the ActionListener created underneath will be the same object each time.
However, this code should work :
ActionListener handler=void(ActionEvent e) {
btn.setText("Thank you");
};
btn.addActionListener(handler); // ok
btn.removeActionListener(handler); // ok
Rémi Forax
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 8:07 AM
in response to: forax
|
|
|
> btn.addActionListener(handler); // function type > convertion > btn.removeActionListener(handler); // function type > convertion > [/code] > > Furthermore, even if a convertion is defined, > nothing will insure that the ActionListener > created underneath will be the same object each > time.
Does anyone else find that absolutely frightening? Surely there ought to be some kind of warning in the code about what may or may not be happening.
btn.addActionListener(maybenew handler);
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 9:17 AM
in response to: tackline
|
|
|
{{ still working on responses to others in this thread -- Shai & Kleopatra have raised some great points that I'm still digesting }}
> > btn.addActionListener(handler); // function type > > convertion > > btn.removeActionListener(handler); // function > type > > convertion > > [/code] > > > > Furthermore, even if a convertion is defined, > > nothing will insure that the ActionListener > > created underneath will be the same object each > > time. > > Does anyone else find that absolutely frightening? > Surely there ought to be some kind of warning in the > code about what may or may not be happening. > > btn.addActionListener(maybenew handler);
Looks like autoboxing, extended to one method interfaces. If the function being passed matches the signature of the interface method, then an instantiation of the listener interface can be created invisibly. How many one-method interfaces are there in the standard Java library (or in all of the major third-party Java libraries that are in wide use) that could be de-emphasized using this?
I like it, but I expect that, perhaps, others may not.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 4, 2006 12:57 PM
in response to: forax
|
|
|
You're right. Well, it was just an example and the difference isn't that big, isn't it? 
tackline: > Does anyone else find that absolutely frightening? Surely there ought to be some kind of warning in the code about what may or may not be happening.
That's not going to be a problem. The spec would clearly define what's going to happen here and forax' second example should work just fine. Also this behaviour isn't to far away from what autoboxing does, so again: no problem.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Sep 5, 2006 8:17 AM
in response to: pago
|
|
|
> You're right. Well, it was just an example and the > difference isn't that big, isn't it?  > > tackline: > > Does anyone else find that absolutely frightening? > Surely there ought to be some kind of warning in the > code about what may or may not be happening. > > That's not going to be a problem. The spec would > clearly define what's going to happen here and forax' > second example should work just fine. Also this > behaviour isn't to far away from what autoboxing > does, so again: no problem. 
No problem?!?!
I think I know Java quite well and knew about the autoboxingconversionthing of closures, but didn't anticipate this problem. I wouldn't expect anyone reading the entire JLS4 and beans specs to realise. It's not as if many Java programmers read the specs anyway.
Fixing in the spec something so critically broken doesn't strike me as a great idea.
|
|
|
|
|
|
|
|
Re: Closures and Swing
Posted:
Aug 30, 2006 10:41 AM
in response to: david_hall
|
|
|
> > This is interesting, but this is not the forum for > discussing how > > closures might impact SwingLabs projects. Maybe > you'd like to join one > > of the open discussions, say on JavaLobby? > > On the contrary: if we're going to discuss how > anything affects the swinglabs projects and > particularly ideas that might be incorporated into > swing, it seems like this is the place to do it. I > know I'm thinking way out ahead, but this forum has > exactly the set of people who I think would be most > interested in discussing the issue and who are in the > position to take the ideas discussed and apply them > to swinglabs (and swing). We also don't have the > traffic of JavaLobby/TSS/JRoller, so discussions > around here tend not to degenerate like those do.
Dave--my sincere apologies--the entire thread started being sent to the mailing list as of tackline's response, and I thought it was coming out of nowhere (I missed the Re: in the subject header). Now I've found it on the forum, I think the discussion makes sense.
Regards Patrick
|
|
|
|
|