The Capability Pattern: Future-Proof Your APIs
Here is a simple pattern which you can use to make your APIs extensible, even by third parties, without sacrificing your ability to keep backward compatibility. It is very frequent to create a library which has two “sides” — an API side and an SPI side. The API is what applications call to use the library. The SPI (Service Provider Interface) is how functionality — for example, access to different kinds of resources, is provided. One example of this is JavaMail: To read/write email messages, you call JavaMail's API. Under the hood, when you ask for a mail store for, say, an IMAP mail server, the JavaMail library looks up all the providers registered (injected) on the classpath, and tries to find one that supports that protocol. The protocol handler is written to JavaMail's SPI. If it finds one, then you can fetch messages from IMAP servers using it. But your client code only ever calls the JavaMail API - it doesn't need to know anything about the IMAP service provider under the hood. There is one very big problem with the way this is usually done: API classes really ought to be final in almost all cases. SPI classes ought to be abstract classes unless the problem domain is extremely well-defined, in which case interfaces make sense (you can use either, but in a not-well-defined problem domain you may end up, over time, creating things with awful names like LayoutManager2). I won't go into great detail about why this is true here (my friend Jarda does in his new book and we discuss it somewhat in our book Rich Client Programming). In abbreviated form, the reasons are: You can provably backward compatibly add methods to a final class. And if the class is final, that fact has communication-value — it communicates to the user of that class that it's not something they might need to implement, where an interface would be more confusing. You can backward compatibly remove methods from an SPI interface or abstract class, if your library is the only thing that will ever call the SPI directly is your library. Older implementations will still have the method, it just will never be called (in a modular environment such as the NetBeans module system, OSGi or presumably JSR-277, you would enforce this by putting the API and SPI in separate JAR files, so a client can't even see the SPI classes). A minor benefit of using abstract classes is that you can semi-compatibly add non-abstract methods to an abstract class later. But do remember that you run the risk that someone will have a subclass with the same method name and arguments and an incompatible return-type (the JDK actually did this to us once in NetBeans, by adding Exception.getCause() in JDK 1.3). So adding methods to a public, non-final class in an API is a backward-incompatible change. Given those constraints, what happens if you mix API and SPI in the same class (which is what JavaMail and most Java standards do)? Well, you can't add methods compatibly because that could break subclasses. And you can't remove them compatibly, because clients could be calling them. You're stuck. You can't compatibly add or remove anything from the existing classes. As I've written elsewhere, it is the height of insanity that an application server vendor is supposed to implement interfaces and classes that its clients directly call — for exactly this reason. It would be much cleaner, and allow Java APIs to evolve much faster, if API and SPI were completely separated. But part of the appeal to vendors, for better or worse, to implement these specifications, is that they can extend them in custom ways that will tie developers who use those extensions to their particular implementation. This behavior not entirely about being evil and locking people in. There is a genuine case for innovation on top of a standard - that's how standards evolve, and some people will need functionality that the standard doesn't yet support. Enter the capability pattern. The capability pattern is very, very simple. It looks like this: public getCapability (Class type); That's it! It's incredibly simple! It has one caveat: Any call to getCapability() must be followed by a null-check. But this is much cleaner than either catching UnsupportedOperationExceptions, or if (foo.isAbleToDoX()) foo.doX() or if (foo instanceof DoerOfX) ((DoerOfX) foo).doX(). A null-check is nice and simple and clean by comparison. It's letting the Java type system work for you instead of getting into a wrestling match with it. Now, what can you do with it? Here's an example. In my previous blog I introduced an alternative design for how you could do something like SwingWorker. It contains a class called TaskStatus, which abstracts the task status data from the task-performing object itself. It is a simple interface with setters that allow a background thread to inform another object (presumably a UI) about the progress of a task. In light of what we just discussed, TaskStatus really ought to be a final class. So let's rewrite it a little, to look like this. We will use a mirror-class for the SPI. public final class TaskStatus { private final StatusImpl impl; TaskStatus (StatusImpl impl) { this.impl = impl; } public void setTitle (String title) { impl.setTitle (title); } public void setProgress (String msg, long progress, long min, long max) { //We could do argument sanity checks here and make life //simpler for anyone implementing StatusImpl impl.setProgress (msg, progress, min, max); } public void setProgress (String msg) { //...you get the idea //... } public abstract class StatusImpl { public abstract void setTitle (String title); public abstract void setProgress (String msg, long progress, long min, long max); public abstract void setProgress (String msg); //indeterminate mode public abstract void done(); public abstract void failed (Exception e); } So we have an API that handles basic status display. But people are going to invent new aspects to status display. We can't save the world and solve everybody's task-status problems before they even think of them - and we shouldn't try. We don't want to set things up so that it's up to us to implement everything the world will ever want. Luckily, it doesn't have to be that way. Since we've designed our API so that it can be compatibly added to, we let the rest of the world come up with things they need for displaying task status, and the ones that a lot of people need can be added to our API in the future. The capability pattern lets us do that. We add two methods to our API and SPI classes: public abstract class StatusImpl { //... public T getCapability (Class type); } public final class TaskStatus { //... public T getCapability (Class type) { return impl.getCapability (type); } } Let's put that to practical use. Someone might want to display how much time remains before the task is done. Our API doesn't handle that. Through the capability pattern, we can add that. We (or anyone implementing StatusImpl) can create the following interface: public interface StatusTime { public void setTimeRemaining (long milliseconds); } A task that wants to provide this information to the UI, if the UI supports it, simply does this: public T runInBackground (TaskStatus status) { StatusTime time = status.getCapability (StatusTime.class); for (...) { //do some slow work... if (time != null) { long remaining = //estimate the time remaining time.setTimeRemaining (remaining); } } } Even better, our Task API is, right now, not tied specifically to Swing or AWT - it could be used for anything that needs to follow the pattern of computing something on a background thread and then doing work on another one. Why not keep it un-tied to UI toolkits? All we have to do is make the code that actually handles the threading pluggable (I'll talk about how you do this simply using the Java classpath for dependency injection in my next blog). Then the result could be used with SWT or Thinlet as well, or even in a server-side application. Instead of a SwingWorker, we have an AnythingWorker! But we know we need a UI - and we know we are targetting Swing right now. How can we really keep this code completely un-tied from UI code and still have it be useful? The capability pattern comes to our rescue again - very very simply. An actual application using this UI simply fetches the default factory for StatusImpls (you need such a thing if you want to run multiple simultaneous background tasks and show status for each — my next blog will explain how this can be injected just by putting a JAR on the classpath) and does something like: Component statusUi = theFactory.getCapability (Component.class); if (statusUi != null) { statusBar.add (statusUi); } (or if we want to allow only one background task at a time, we can forget the factory and put the Component fetching code directly in our implementation of StatusImpl). If you are familiar with NetBeans Lookup API, the capability pattern is really a simplification of that (minus collection-based results and listening for changes). The point here is that the capability pattern lets you have an API that is composed completely of nice, future-proofed, evolvable, final classes, but the API is extensible even though it is final. The result is that the API can evolve faster, with fewer worries about breaking anybody's existing code. Which reduces the cycle time to improve existing libraries, and all our software evolves and improves faster, which is good for everyone. It also helps one to avoid trying to “save the world” — by allowing for extensibility, it is possible to create an API that is useful without needing to handle every possible thing anyone might ever want to do in that problem domain. Trying to save the world is what leads to scope-creep and never-finished projects. In this tutorial I discuss the don't try to save the world principle in a practical example. Does the mirror-class design seem a bit masochistic? I think it does point up a weakness in the scoping rules of the Java language. It would definitely be nicer to be able to, on the method level, make some methods visible to some kinds of clients, and other methods visible to other kinds of clients. But regardless of this, it's even more masochistic to end up “painted into a corner,”[1] and unable to fix bugs or add features without potentially breaking somebody's code. That's how you end up with ten-year-old unfixed bugs. [1]painted into a corner — An English idiom meaning to leave yourself with no options — you were painting the floor of a room in a pattern such that you end up standing in an unpainted corner of the room, and you can't leave the corner until the paint dries. From http://weblogs.java.net/blog/timboudreau/
August 29, 2008
·
19,356 Views
·
0 Likes
Comments
Apr 07, 2012 · Antonio Santiago
I posted a slightly heretical blog - http://weblogs.java.net/blog/timboudreau/archive/2005/09/patterns_schmat.html - on this topic some years ago, and stand by it.
I think discovering patterns has about the same effect as discovering object oriented programming - there's an aha, and you walk around for a week applying it to everything and thinking it's really really cool, rewiring a few neurons as you go, and then you realize that it's just a cool name for a bunch of obvious stuff you were doing in some form all along.
What scares me is the people who never get past the "patterns will save the world" phase, for the same reasons that people who never get past the "objects will save the world" phase scare me - both provide a vocabulary for talking and thinking about what a computer does, but that's it. Both lead to measuring quality of results and code by how well it adheres to the tenets of a religion rather then whether the code is doing something sane. Both appear to offer shortcuts to being a good programmer when they really only offer shortcuts to not being a horrific one.
Apr 07, 2012 · Mr B Loid
Apr 04, 2011 · David O'meara
Re circular dependencies - IMO using test-jar is a rare enough case that it seems to me that circular test dependencies should be allowed, but the onus should be on the plugin that implements test-jar to detect if a circular test dependency exists and fail the build in that case - i.e. exclusively allow either circular test dependencies or creation of test artifacts.
Re #9: IMO, the bug is the use of the word "parent" in terms of a Maven parent project. I have never seen a Maven parent project which did not consist entirely of shared configuration. In short, there is nothing parent-like about a Maven parent project, at least in any project I have worked with (it is also odd, though probably necessary, that the parent lists its children and the child lists its parent). It seems like it is just a weird hack to shoehorn some shared configuration into something Maven will let you run targets on.
Apr 04, 2011 · David O'meara
Re circular dependencies - IMO using test-jar is a rare enough case that it seems to me that circular test dependencies should be allowed, but the onus should be on the plugin that implements test-jar to detect if a circular test dependency exists and fail the build in that case - i.e. exclusively allow either circular test dependencies or creation of test artifacts.
Re #9: IMO, the bug is the use of the word "parent" in terms of a Maven parent project. I have never seen a Maven parent project which did not consist entirely of shared configuration. In short, there is nothing parent-like about a Maven parent project, at least in any project I have worked with (it is also odd, though probably necessary, that the parent lists its children and the child lists its parent). It seems like it is just a weird hack to shoehorn some shared configuration into something Maven will let you run targets on.
Apr 04, 2011 · David O'meara
Re circular dependencies - IMO using test-jar is a rare enough case that it seems to me that circular test dependencies should be allowed, but the onus should be on the plugin that implements test-jar to detect if a circular test dependency exists and fail the build in that case - i.e. exclusively allow either circular test dependencies or creation of test artifacts.
Re #9: IMO, the bug is the use of the word "parent" in terms of a Maven parent project. I have never seen a Maven parent project which did not consist entirely of shared configuration. In short, there is nothing parent-like about a Maven parent project, at least in any project I have worked with (it is also odd, though probably necessary, that the parent lists its children and the child lists its parent). It seems like it is just a weird hack to shoehorn some shared configuration into something Maven will let you run targets on.
Apr 04, 2011 · David O'meara
Re circular dependencies - IMO using test-jar is a rare enough case that it seems to me that circular test dependencies should be allowed, but the onus should be on the plugin that implements test-jar to detect if a circular test dependency exists and fail the build in that case - i.e. exclusively allow either circular test dependencies or creation of test artifacts.
Re #9: IMO, the bug is the use of the word "parent" in terms of a Maven parent project. I have never seen a Maven parent project which did not consist entirely of shared configuration. In short, there is nothing parent-like about a Maven parent project, at least in any project I have worked with (it is also odd, though probably necessary, that the parent lists its children and the child lists its parent). It seems like it is just a weird hack to shoehorn some shared configuration into something Maven will let you run targets on.
Sep 25, 2010 · Mr B Loid
Offhand, the two major paradigms I can think of offhand are message-based APIs, and the functional programming model (c.f. Concurrent Clean) where there simply is no global state (in which case, everything is parallelizable, but as soon as you have something that reality dictates really is global and shared, such as a screen, a window, a socket connection or a file, you end up in a through-the-looking-glass world of weirdness as the language tries to shoehorn persistent state into a worldview that can't express that).
Or are we evaluating constructs along the lines of SwingWorker (good idea, awful design) and how a language embeds such constructs so that coders don't have to invent them themselves?
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Ida Momtaheni
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 21, 2010 · Tim Boudreau
What, IMO, Java generics really need is a first-class way to define to an aggregate type exactly once, with a simple syntax. I.e.
or and then *everything* else can just use that. The problem is that generics really do let you make more reusable code, but the verboseness fundamentally limits how much power people actually get out of them, because the code quickly becomes unreadable once you really start taking advantage of them.It should be enough to express a complex signature once, give it a name and then use that name everywhere you need that type combination. Having to repeat a
List <T extends Thing & Comparable<Thing>>
signature everywhere is pointless, unreadable and violates the DRY principle - if you change the generic type signature, you have to refactor it everywhere manually, which is a huge waste of time.It wouldn't be an enormous stretch to make javac capable of understanding reusable signature definitions.
Sep 20, 2010 · Ida Momtaheni
@Alessandro: This was the other possibility I'd considered - and I think I'm concluding that it's preferable, as it's a bit more normal looking.
@Owen: Yes, or course practical uses will involve specific types; these are unspecified here because it's an expression of a general pattern. This class comes with another class, ThreadLimitedResource<A,B,C> (see what I mean?) which can be passed a ResourceAccessor. It implements the general pattern of allowing a fixed number of threads in (and collecting contention statistics) without all the potential bugs of directly exposing a Semaphore. Since I do not want to dictate all the things in the universe that could be accessed using this pattern, this would be the wrong level for imposing specific typing - the thing that's protected could be a socket connection, database connection, regions of a file, anything imaginable.
@Milos: "you better remember" is exactly what I want to avoid - but maybe I'm not understanding you.
@Karl: Single letters are fine if you only have one or two types; and if you have more than one or two, it's very likely that those types are not arbitrary.
When you get to something like this (yes, it's an extreme example, but it is real code - although I changed it to use single letter names) it becomes a complete mess:
What on earth is this stuff, and who can possibly keep track of it? At least some kind of descriptiveness is needed - this is at least comprehensible: but it does suffer from the problem I brought up in my original post - it looks as if there are really Java classes called SourceType, TargetType, etc.So you all don't consider me crazy, I'll have you know this class is not going to be used in real life - it's simply too much to ask of others to deal with this degree of ugliness (a type-specific subclass could hide it, but that would defeat code-reuse across heterogenous types).
It is, however, a genuinely generic pattern - a model for a collection of sets of subject-object-relationship relations, where the kind of relation must be an enum (collapsable to a bitmask), and each "subject" and "object" (as in object-of-the-sentence, not Java object) is identified by an Identifier (in practice, a Long - but I don't want to have parameter-order bugs, so each identifier type is tightly tied to its object type and vice-versa). Sure, you could write it as just some longs and an enum, but then you give up the benefit of using the Java type system to eliminate any chance of getting parameters swapped - a whole category of bug you don't have to have.
This is definitely the sort of data structure that is hard to write, and I'd much rather write it once and reuse it in every situation where this pattern appears (and I have a few). That makes it a good example of how generics can really get you more code reuse and fewer bugs (with the caveat that the syntax is way too verbose).
@Slava: Yeah, all upper-case would work too, good point.
@Karl - second post: Yes, they're gone when the code is really used. But somebody will have to read the code. Given how late in the game generics were introduced, I don't think the JDK is a great place to look for examples. Have a look at javac's codebase, though - plenty of generics use in there.
@Erwin: In my initial use-case, ProtectedResource is actually a
java.sql.Connection
- JDBC is fundamentally misdesigned in this respect, and by introducing a usage lifecycle you can eliminate an entire category of bugs. Trusting that every caller, everywhere, will always remember to close a connection, release a lock, close a file, etc. is insane, when you could reduce code and guarantee the resource is always managed correctly using a Runnable/Callable-like structure.I like designs that eliminate entire categories of bug - it's a much better use of time than fixing them later.
Sep 20, 2010 · Tim Boudreau
@Alessandro: This was the other possibility I'd considered - and I think I'm concluding that it's preferable, as it's a bit more normal looking.
@Owen: Yes, or course practical uses will involve specific types; these are unspecified here because it's an expression of a general pattern. This class comes with another class, ThreadLimitedResource<A,B,C> (see what I mean?) which can be passed a ResourceAccessor. It implements the general pattern of allowing a fixed number of threads in (and collecting contention statistics) without all the potential bugs of directly exposing a Semaphore. Since I do not want to dictate all the things in the universe that could be accessed using this pattern, this would be the wrong level for imposing specific typing - the thing that's protected could be a socket connection, database connection, regions of a file, anything imaginable.
@Milos: "you better remember" is exactly what I want to avoid - but maybe I'm not understanding you.
@Karl: Single letters are fine if you only have one or two types; and if you have more than one or two, it's very likely that those types are not arbitrary.
When you get to something like this (yes, it's an extreme example, but it is real code - although I changed it to use single letter names) it becomes a complete mess:
What on earth is this stuff, and who can possibly keep track of it? At least some kind of descriptiveness is needed - this is at least comprehensible: but it does suffer from the problem I brought up in my original post - it looks as if there are really Java classes called SourceType, TargetType, etc.So you all don't consider me crazy, I'll have you know this class is not going to be used in real life - it's simply too much to ask of others to deal with this degree of ugliness (a type-specific subclass could hide it, but that would defeat code-reuse across heterogenous types).
It is, however, a genuinely generic pattern - a model for a collection of sets of subject-object-relationship relations, where the kind of relation must be an enum (collapsable to a bitmask), and each "subject" and "object" (as in object-of-the-sentence, not Java object) is identified by an Identifier (in practice, a Long - but I don't want to have parameter-order bugs, so each identifier type is tightly tied to its object type and vice-versa). Sure, you could write it as just some longs and an enum, but then you give up the benefit of using the Java type system to eliminate any chance of getting parameters swapped - a whole category of bug you don't have to have.
This is definitely the sort of data structure that is hard to write, and I'd much rather write it once and reuse it in every situation where this pattern appears (and I have a few). That makes it a good example of how generics can really get you more code reuse and fewer bugs (with the caveat that the syntax is way too verbose).
@Slava: Yeah, all upper-case would work too, good point.
@Karl - second post: Yes, they're gone when the code is really used. But somebody will have to read the code. Given how late in the game generics were introduced, I don't think the JDK is a great place to look for examples. Have a look at javac's codebase, though - plenty of generics use in there.
@Erwin: In my initial use-case, ProtectedResource is actually a
java.sql.Connection
- JDBC is fundamentally misdesigned in this respect, and by introducing a usage lifecycle you can eliminate an entire category of bugs. Trusting that every caller, everywhere, will always remember to close a connection, release a lock, close a file, etc. is insane, when you could reduce code and guarantee the resource is always managed correctly using a Runnable/Callable-like structure.I like designs that eliminate entire categories of bug - it's a much better use of time than fixing them later.
Sep 19, 2010 · Mr B Loid
I am, however, in favor of one methodology. I call it the hire smart people methodology. It's worked every place I've seen it tried.
Sep 09, 2010 · Mr B Loid
Sep 09, 2010 · Alex J. Champandard
Consider any project which is divided into data-storage vs. data-processing domains. These are neat, clean concepts. Then you have a query or kind of processing that could be done very efficiently if done inside the database or filesystem, and is ruinously expensive otherwise. Now the data-processing domain is starting to invade the data-storage domain. Oh no! Our beautiful conception has failed to map to reality! What's really happened is that the shapes and maybe the names of the boxes need to change. It's not that they're wrong so much as they were never real in the first place.
That's only painful if you're attached (code-wise, organizationally or emotionally) to those domains - "domains" are just useful cognitive labels for something that, in the end, is CPUs moving and doing math on bytes.
Sep 09, 2010 · Mr B Loid
With minimal additional code you can ensure that such a situation is nearly impossible - just make the locking construct private and used in only one method, so the try-finally block is guaranteed; guard any resource that should only be accessed while holding the lock by passing that resource into a Runnable-like object's single method. I.e.
Obviously, sometimes you're stuck with existing code that needs some locking, and this sort of thing is not possible. But where you can use this pattern, it's both less bug-prone and has benefits for anyone calling the code - it's much easier to remember "to use a Thing, you have to write a ThingUser" than it is to remember "if you call a Thing, you should be holding this lock". This way, you build a real, but fairly transparent locking model, and all of the points where the lock is used are known and easily findable by a class usage search, so you never have to do a pass of looking at every usage of mutex.acquire() or synchronized() in your codebase when you want to change the locking model.Sep 09, 2010 · David O'meara
I'm also coming from years of working mostly in an environment (the NetBeans module system) where dependencies are something which are managed very strictly - so the idea of managing the classpath doesn't disturb me nearly as much as the idea of not actually knowing what I'm deploying, or adding one JAR to my project logically adding 30 JARs without me realizing it until I've already written code that depends on that one JAR.
@Jiles
I agree with both you and Loren on this :-) There are a lot of really cool things you can do (effortless, 100% accurate refactoring and code analysis, or making formatting simply an attribute of the view, and semantic diffs, all for free, for example) if code is stored in some kind of database-like back-end which actually understands the code semantically.Alas, the problem with that is that, to make that into a wonderful new world instead of a nightmarish prison, you need the entire rest of the world to decide they're going to store everything that way too. Files are the lowest common denominator, so they end up being the only thing somebody making a tool can reliably depend on talking to, so to reach the widest audience, it's a race-to-the-bottom. It's kind of like SQL - great language for running reports, and totally the wrong tool for the kinds of things it is often used for (a rant for another day). What you get in the exchange for holding your nose is lots and lots of tools that can speak SQL and databases with hundreds of years of person-hours invested in optimizing them (as with files and filesystems). That doesn't change the fact that the paradigm is fundamentally mismatched to the domain, but it can make it worth living with.
@Martin: Groovy-in-Maven could be interesting, if it really is free to customize the build sufficiently. My suspicion is that a bunch of the things I want (optionally test against .class files, perform minor custom code generation, tee test output handling to be developer-friendly and report-friendly at the same time, allow circular test dependencies, generally behave differently when dealing with dependencies vs. JAR dependencies) are so low level that they won't be overridable without having to duplicate functionality that you otherwise get for free (could Groovy *really* just plug into classpath assembling or output handling, without having to write a replacement for a much bigger build step?). But you're right, there is some hope.
Sep 07, 2010 · Alex J. Ma
Sep 07, 2010 · Geertjan Wielenga
Sep 03, 2010 · Shekhar Gulati
One place multiple bounds is useful is when working with Enums. For example:
defines a generic data structure for relationships between objects, where the relationships will be some kind of enum which implements an interfaceRelated
.Another pattern that is very useful is where you have a reusable runnable-like object which ought to take an argument, and you want it to be stateless and take an argument of an unknown type:
Not only is it easy to have Operation implementations which are stateless, reusable wads of logic this way, but it is trivial to write an Operation subclass which chains together multiple Operations, feeding the output of one into the argument of the next, and all of this can be done by code which knows nothing about the concrete types of the inputs and outputs.Here is an odd pattern (similar to the slightly baffling way the JDK defines Enum<T extends Enum<T>>, which is really a trick to ensure an Enum subclass can never be parameterized on anything but itself) that can be useful in a system where you have, say, a lot of
basically welds together User and UserIdentifier so that you cannot possibly have a UserIdentifier which identifies something which is not a User, or vice versa. While you could do this without generics, with generics, you can have generic, reusable data structures which work like our RelationshipTable above (have SubjectType and ObjectType extend Identifiable), upon such objects, which have type-safety all the way down, yet are able to collapse any set of "relationships" down to three numbers for storage (a Set<Enum> is easily converted into a bitmask - which is exactly what EnumSet does internally).long
s that refer to different kinds of object, and want to ensure that you cannot have the type of bug that occurs where you, say, mix up parameter order of a bunch of longs and end up with invalid references to things:The problem is, other developers seem to be terrified when they see class signatures like this. Which is rather sad, since generics really do let you write data structures which are more generic in the sense of can be reused against more things - resulting in less code, less testing needed, more type-safety and fewer bugs. Generics are hugely useful for much more than just collections.
Sep 03, 2010 · Mr B Loid
I suspect debuggers are the biggest developer time-waster ever invented.
If, say, a value is obviously wrong at some point in your code, you can usually insert 3 logging statements to log the value at various points in the code where the value may be good or bad. If the value is bad at the second logging statement, you know the problem is on the code path between the first and second. If that is still too much code to read and run mentally, insert a logging statement between 1 and 2. If still too big, repeat until you've found the problem - usually one or two lines of logging later.
This activity employs a very efficient algorithm you may have heard of - binary search :-)
Compared to stepping through all sorts of library code in a debugger, I find it is vastly more efficient.
Sep 03, 2010 · Kelly Waters
Often a saner and better thought out solution is to have the ability to lock entire subsystems of the application - i.e. have fewer locks with more well-defined entry-points. It's easy to make locking *more* granular if this approach causes liveness problems; imposing a locking model on a codebase after it has grown very large, on the other hand, is much more difficult.
@Tomasz: If you look at how AtomicInteger and friends are implemented internally, you'll notice that they simply loop until they have successfully set the value - you trade having a lock for spiking CPU usage in one thread until writing the field succeeds. Atomic* are not a substitute for having locks, and are likely to be less considerate of system resources.
Mar 30, 2010 · Patrick Hunlock
I suspect that, since Wicket components are serializable, and serialization is used to implement clustering (so you want to minimize session size to minimize the bytes that need to be sent over the wire), that a strategy of adding ad-hoc listeners to components (where the entire object graph of the listener object will need to be serialized with the component) could easily lead to the same kind of listener-memory-leak issues Swing has, with a serious negative impact on performance in a clustered environment.
What I see here is a solution - but there isn't really any mention of what problem you're trying to solve. Who will create these listeners? Is the only problem that this solves a distaste for inner classes? A desire to have generic multicast support for form submission?
Seems kind of like turning Wicket into JSF...
Sep 17, 2009 · Mr B Loid
IMO the problem is that in a certain set of situations, checked exceptions make sense - for example, if you are modelling in software, say, a hardware device or wire protocol that has a set of well-defined failure modes (think LDAP/JNDI [almost twice as many exception classes as there are non-exception classes in API - monstrous!], for example), or where, if the exceptional state is unhandled, an airplane will crash.
But software being what it is, and Java being what it is, you end up with an of API that ends up being (ab)used well beyond its intended scope, where in fact those exceptions will never happen and don't make sense. Inheritance being what it is, there is no way to convert a parent class's exceptions into unchecked exceptions. So we end up with APIs full of checked exceptions because they're (ab)using or inheriting from something else that throws checked exceptions.
Think about it - there are plenty of exceptions that would be *useful* as checked exceptions some small part of the time (NumberFormatException, for example; MalformedURLException if you're writing a web browser, but practically never otherwise). The problem might be that the division of checked/unchecked is too rigid in Java, not that one is necessarily always preferable to the other.
-Tim
Sep 13, 2009 · Lebon Bon Lebon
Interesting thought, but logical fallacy. You can posit that architecture is correlated with inflexibility; that does not mean that there is a cause and effect relationship - either architecture causing inflexibility, or inflexibility causing architecture :-) It is entirely possible to have more- and less-flexible architectures for a given problem set; and also very easy to create something with little discernable architecture which is also highly inflexible.
Architecture is a matter of interpretation. If you give me a hunk of (perhaps obfuscated) source code with no documentation, and I analyze and come to understand it, my interpretation of what are the components of its architecture, and the roles of those components, may be completely different than the original author's understanding of them. Yet if my understanding allows me to use the system effectively, it is equally valid. The "architecture" only exists insamuch as it is a tool for communicating an understanding of the system, and a mental toolkit for conceiving the system.
I agree about modularity being important - I've been giving talks on the importance of modular *architecture* for years :-) The fact is, the more modular the software, the greater the requirement for stable contracts - ahem, architecture - to enable the software to function, to allow components to be updated compatibly, etc.
-Tim
Sep 05, 2009 · Mr B Loid
Sep 05, 2009 · Mr B Loid
Sep 05, 2009 · Mr B Loid
Sep 05, 2009 · Peter Stofferis
I've certainly found it useful on a few occasions to hand-write collections-like classes for primitives (particularly if you're indexing a data structure that only grows at its tail, there are lots of very nice optimizations you can do since you can guarantee the data to be pre-sorted).
Never really thought of collections and a database as interchangeable - doesn't seem like there are a lot of problems where you don't know which one is the right tool for the job before you start coding.
For large but fixed-record-size data structures, memory mapped files work quite well to keep data off the Java heap but generally quickly accessible.
Aug 05, 2009 · Lebon Bon Lebon
Why not intergrat Bean Validation standard into NetBeans platform , and apply validation on DataModel...
I'm aware of the Bean Validation project (although its status seems nebulous). The important thing here was ease of integration into existing user interface code. I created this for selfish reasons - I inherited a bunch of customizer code that does no validation whatsoever (try entering garbage into a mobility project's file encoding field - it will accept it without complaint and then throw exceptions). Also, data models for Swing components don't always follow the bean model terribly clearly. And nobody likes writing code like
and NetBeans and many other Swing codebases are littered with this stuff.Anything that sets out to solve all the world's validation problems is going to be too general (and large - both in size and conceptual surface area) for the problem I'm trying to solve, which is to allow you to take an existing piece of UI code, and retrofit validation and good error reporting with a minimum of code and a learning curve near zero.
I looked at (and link to) the JGoodies Validation stuff. It looks very good - if you're creating a UI from scratch or have the time and luxury to rewrite it to have a data model for the entire UI's contents and so forth. But if you're bug-fixing existing UI code, and have plenty of other tasks on your list, a framework designed for UIs you are writing from scratch is not going to help.
So my hope is that this project fills the niche for the programmer who has some UI code, needs good error reporting and validation, and wants a solution that lets them add this to a fairly complex panel in under an hour.
I see it complementing, not competing, with the existing validation solutions out there - in fact, for those that provide their own validators, it would be relatively easy to write an adapter Validator subclass from this framework that works with those others. Or the other way around.
-Tim
Jan 21, 2009 · Mr B Loid
I've had some interesting discussions with colleagues I respect about the merits of this. I always find the IWhatever convention somehow irritating. But as a friend pointed out, it's less verbose than WhateverImpl.
In this day and age, most people have a lot of class metadata available in their IDEs, and use code completion to fill in things like "implements Whatever". I think the value of using a naming convention was greater when tools were not as advanced. At this point, because of the tools I'm using, I know whether something is an interface or not very quickly. And also, it seems contradictory to have a naming convention like that for interfaces, but not abstract classes.
If it's a case where there is only ever going to be one implementation of the interface, then the *Impl question is resolved easily: The interface probably doesn't need to exist in the first place. For cases of multiple implementations, more information can be provided by giving it a meaningful name, such as FooWhatever. In which case it's more than clear enough (especially with the visible metadata from tools) that it's redundant to call it FooWhateverImpl. So in the case of Java, anyway, I think there's little value in the I-for-interface convention.
Similarly, I've been thinking the same about package names - if the function of the class is indicated by the package name, should it be repeated in the class name as well? It adds verbosity, lengthens paths (this is a real issue on some version control systems that limit maximum path length). Does that still add clarity? As in, if I have com.myapp.actions, does it make more sense to call a class in that package SaveAction or just Save? This is a little murkier issue, because typically the package info is in the import statement, and "new Save()" could be a bit enigmatic in code - but the reduced verbosity is appealing.
-Tim
Jan 19, 2009 · Stacy Doss
Jan 19, 2009 · Geertjan Wielenga
Oct 22, 2008 · Lebon Bon Lebon
Slight preference for
to notify() as the method name. Generally on* makes a more readable pattern for listener-like things (and avoids confusion with Object.notify() and friends.
-Tim
Sep 30, 2008 · Lebon Bon Lebon
There is a unique ID - IIRC it's a random long, generated on first start and saved in the user settings dir. No registration or personal info going over the wire. So, it's not perfect (that *would* require registration), and multiple copies of NetBeans would show up as multiple users (but AFAIK that chart only tracks UIDs from releases of NetBeans, not development builds). It might be that if you choose to import settings from a previous version when you install a new version, the uid is preserved.
Actually, a lot of effort goes into making sure those numbers are as good and as accurate as possible - and keeping them conservative (for example, it doesn't count anyone behind a firewall that doesn't let autoupdate traffic through - this is true of many developers in India and China). These numbers are one of the things that justifies Sun continuing to pay us to work on NetBeans :-)
After all the time I've spent in Brazil (about four months out of the last three years) giving talks about NetBeans, plugin development and general Java development, I'm very happy to see Brazil coming in #2 here! There are some great programmers there.
-Tim
Sep 30, 2008 · Lebon Bon Lebon
There is a unique ID - IIRC it's a random long, generated on first start and saved in the user settings dir. No registration or personal info going over the wire. So, it's not perfect (that *would* require registration), and multiple copies of NetBeans would show up as multiple users (but AFAIK that chart only tracks UIDs from releases of NetBeans, not development builds). It might be that if you choose to import settings from a previous version when you install a new version, the uid is preserved.
Actually, a lot of effort goes into making sure those numbers are as good and as accurate as possible - and keeping them conservative (for example, it doesn't count anyone behind a firewall that doesn't let autoupdate traffic through - this is true of many developers in India and China). These numbers are one of the things that justifies Sun continuing to pay us to work on NetBeans :-)
After all the time I've spent in Brazil (about four months out of the last three years) giving talks about NetBeans, plugin development and general Java development, I'm very happy to see Brazil coming in #2 here! There are some great programmers there.
-Tim
Sep 30, 2008 · Lebon Bon Lebon
There is a unique ID - IIRC it's a random long, generated on first start and saved in the user settings dir. No registration or personal info going over the wire. So, it's not perfect (that *would* require registration), and multiple copies of NetBeans would show up as multiple users (but AFAIK that chart only tracks UIDs from releases of NetBeans, not development builds). It might be that if you choose to import settings from a previous version when you install a new version, the uid is preserved.
Actually, a lot of effort goes into making sure those numbers are as good and as accurate as possible - and keeping them conservative (for example, it doesn't count anyone behind a firewall that doesn't let autoupdate traffic through - this is true of many developers in India and China). These numbers are one of the things that justifies Sun continuing to pay us to work on NetBeans :-)
After all the time I've spent in Brazil (about four months out of the last three years) giving talks about NetBeans, plugin development and general Java development, I'm very happy to see Brazil coming in #2 here! There are some great programmers there.
-Tim
Sep 26, 2008 · Andrew Glover
Sep 26, 2008 · Meera Subbarao
Aug 30, 2008 · Rushabh Joshi
Over-identifying with the system and its processes!
[/quote]
The irony being that object-oriented programming is (IMHO) successful because it lets people harness thinking-skills that are already wired in because of being human beings. It is going to encourage such identification. I never thought about the notion that it comes at the cost of being able to communicate about the code (i.e. to communicate most naturally about it, the person you're communicating with has to identify with the elements of the code in a similar way and the communication filtered through that identification has to be mutually intelligible). Food for thought!
Aug 30, 2008 · Rushabh Joshi
Over-identifying with the system and its processes!
[/quote]
The irony being that object-oriented programming is (IMHO) successful because it lets people harness thinking-skills that are already wired in because of being human beings. It is going to encourage such identification. I never thought about the notion that it comes at the cost of being able to communicate about the code (i.e. to communicate most naturally about it, the person you're communicating with has to identify with the elements of the code in a similar way and the communication filtered through that identification has to be mutually intelligible). Food for thought!
Aug 30, 2008 · Rushabh Joshi
Over-identifying with the system and its processes!
[/quote]
The irony being that object-oriented programming is (IMHO) successful because it lets people harness thinking-skills that are already wired in because of being human beings. It is going to encourage such identification. I never thought about the notion that it comes at the cost of being able to communicate about the code (i.e. to communicate most naturally about it, the person you're communicating with has to identify with the elements of the code in a similar way and the communication filtered through that identification has to be mutually intelligible). Food for thought!
Aug 18, 2008 · admin
Well, 15 of the 40 teachers are parents of preschoolers. They need morning slots due to day-care constraints. 3 of the teachers are having extra-marital affairs with five of the other teachers (well, one in common). 7AM is fine for them, but they're not going to give up that lunch hour of bliss, so they're after morning slots too. Then there's the brilliant english teacher who is a wretched drunk by night, but nonetheless brilliant if you catch him after noon. Maybe we'll pencil him in to teach history too?
Somehow I think no algorithm is going to nail this all down optimally...
But it looks good on paper or as a thesis project.
-Tim
Aug 15, 2008 · paul brauner
Aug 14, 2008 · Stacy Doss
Agreed, JavaFX's threading model needs to be communicated - and hopefully handled more strictly than Swing's.
One handy trick I sometimes do with the JDK sources is just to compile a JAR with a copy of java.awt.Component, add
to the constructor (I suppose AOP would be more elegant, but this works), and run NetBeans or whatever I'm working on to see if there's any threading evil happening.Aug 11, 2008 · paul brauner
I get the feeling all of the people saying "use XPath" or "use this DOM thingy" have never programmed in an environment where you can't, are not allowed to, or just from common-sense, shouldn't touch DOM with a ten foot pole. DOM-based stuff eats memory like there's no tomorrow and becomes completely unmanageable for very large documents.
I remember a trying to open the DocBook XML sources of our first book in a DOM-using XML editor with a tree view, back when we were writing it. It took 34 minutes to build the DOM tree for it (500+ page book and a humungous DTD).
The various DOM-based APIs for XML parsers are definitely convenient and useful if you know what you're dealing with is small. But even there, you run the risk that something will hold a reference to a stale tree, which will run you out of memory pretty quick.
I won't be a curmudgeon and say "If you're not writing a browser, you shouldn't be using DOM," (although I think it sometimes), but please appreciate that there are some places, particularly handling arbitrarily long documents which can be very big, where it's really the wrong tool for the job. In those cases you want a visitor-based API like SAX, where you can extract whatever minimal data you need as you go and be guaranteed able to do it in a finite amount of memory.
Aug 10, 2008 · Rushabh Joshi
Aug 07, 2008 · paul brauner
Jun 18, 2008 · Stacy Doss
Have you looked at the Timers API in NetBeans? I think it still maybe in "friend" mode (i.e. only JARs that it knows about can call it, but you can get added to the list), since it's not in the officialjavadoc. If you're using a dev build, you can pull up aRun Time Watches window (not present in release builds).The team redoing the Java editor created this for doingexactly the kind of continuous profiling it sounds like you're talking about. I don't know for sure that it'sapplicable, but I think it might be - and should below-overhead.I don't know too much about it, but it sounds like itmight be what you're looking for - it's all about collecting timings for things that should remain fast at runtime.
Not the same as a unit test for performance regression (hard to do on all platforms, particularly with imaging where you're dealing with platform and hardware specific stuff, but still a worth goal and doable in the abstract).
Our biggest effort in NetBeans 6.1 was not improving performance, but finding ways to make sure that someone cannot commit a change that regresses performance and not know it. It's a hard problem.
Jan Lahoda in Prague is, AFAIK, the author of the Timers API and its UI. I'll point him at this thread.
-Tim
Jun 17, 2008 · Olivier Ziller
Simpler way on Mac-OS:
cd /Applications/NetBeans\ 6.1.app/Contents/Resources/NetBeans/etc/
sudo vi netbeans.conf
add
-J-Dorg.netbeans.spi.java.project.support.ui.packageView.TRUNCATE_PACKAGE_NAMES=true
inside the quotes to the definition of netbeans_default_options.
May 11, 2008 · Alex Johnson
"Does this not doom GWT and Wicket, and projects that attempt similar approaches, to being adopted by only a very small subset of companies in the real world?"
I suspect the economics of software development cause a general gravitation toward toolsets that make the problem as simple as it is and no simpler (in the java world, certainly making the problem more complex than it is has its own history, but that's pathological). Make a problem simpler than it is and you end up with something people adopt and then it breaks down in real world use cases.
The biggest problem Wicket has is that there is not some big company out there flogging it (its fatal flaw may be that it doesn't overcomplicate things, so it ever feeding armies of consultants is unlikely - if I wanted to teach a 14-year-old web development I would teach them Wicket, unquestionably). That being the case, the level of adoption it has gotten is remarkable and quite a testament to how well it solves the problem it sets out to solve.
So I don't think there's much difference in the examples - the RichFaces example uses some javascript to feed in "map.setZoom(this.value)" but there's a lot of code somewhere driving what "this.value" is, and at some point it involves some coding. Also, the GMap component doesn't appear to follow typical Wicket design patterns - the listener pattern is absent from Wicket for a good reason. It is certainly possible to design a gmap component that requires less verbose initialization.
-Tim
May 11, 2008 · Alex Johnson
May 11, 2008 · Alex Johnson
May 11, 2008 · Alex Johnson
May 11, 2008 · Alex Johnson
May 10, 2008 · Alex Johnson
I don't know that the source comparison above is really fair - you set a bucket-load of properties on the wicket component, but can you set all of those with RichFaces, and if so, is the markup that simple if you do?
Figure that some of the context (what the map is showing, etc.) is going to come from the server-side (even if the actual code extracts it from somewhere else on the page via javascript as the RichFaces example does). I don't really see that the fact that RichFaces lets you embed a map with a single tag really helps, since somewhere there has to be enough code to inject contextual information. That code is explicit in the Wicket example and missing in the RichFaces example. How easy or hard is it to get all the properties the Wicket example sets into the RichFaces example, and what does the code look like to do it?
-Tim
Apr 03, 2008 · Vera Tushurashvili
Apr 02, 2008 · Vera Tushurashvili
Apr 02, 2008 · Vera Tushurashvili
Mar 10, 2008 · admin
NetBeans modules in the NetBeans source tree expect to build into $NB_SRC/nbbuild/netbeans - contrib/ should be set up as a subdir of $NB_SRC. Since contrib/ is now a separate hg repository, I only gave instructions for how to get contrib (figuring you might just want a look at the source code and contrib/ is a much smaller download). To do a full build, first get the full NetBeans sources:
hg pull http://hg.netbeans.org/main//
and then move your checkout of contrib/ underneath the root of the checkout. Then run Ant against the master build script (you will need to set the environment variable ANT_OPTS=-Xmx512M for the build to complete).
Alternately, you could probably fiddle with the project metadata a bit to convince NetBeans that it's not a netbeans.org source tree module - simplest would be to create a new module project somewhere else on your disk (not under the nb source root), copy the sources and the dependencies section of nbproject/project.xml into the new module's project.xml and that should do it.
Sorry for the confusion - I was trying to save you a huge checkout :-/
Mar 10, 2008 · admin
NetBeans modules in the NetBeans source tree expect to build into $NB_SRC/nbbuild/netbeans - contrib/ should be set up as a subdir of $NB_SRC. Since contrib/ is now a separate hg repository, I only gave instructions for how to get contrib (figuring you might just want a look at the source code and contrib/ is a much smaller download). To do a full build, first get the full NetBeans sources:
hg pull http://hg.netbeans.org/main//
and then move your checkout of contrib/ underneath the root of the checkout. Then run Ant against the master build script (you will need to set the environment variable ANT_OPTS=-Xmx512M for the build to complete).
Alternately, you could probably fiddle with the project metadata a bit to convince NetBeans that it's not a netbeans.org source tree module - simplest would be to create a new module project somewhere else on your disk (not under the nb source root), copy the sources and the dependencies section of nbproject/project.xml into the new module's project.xml and that should do it.
Sorry for the confusion - I was trying to save you a huge checkout :-/
Mar 06, 2008 · admin
To get the sources:
hg pull http://hg.netbeans.org/main//contrib
cd graphicclassview
Or you can browse the sources here.
Feb 28, 2008 · admin
Feb 28, 2008 · admin
Feb 28, 2008 · admin
Rui: If you want to access the Alpha update center from a release build such as 6.0 or 6.0.1, you need to add that update center's URL to Tools | Plugins - go to the settings tab, click Add and use the URL
http://deadlock.netbeans.org/hudson/job/javadoc-nbms/lastSuccessfulBuild/artifact/nbbuild/nbms/updates.xml.gz
-Tim
Feb 28, 2008 · admin
Rui: If you want to access the Alpha update center from a release build such as 6.0 or 6.0.1, you need to add that update center's URL to Tools | Plugins - go to the settings tab, click Add and use the URL
http://deadlock.netbeans.org/hudson/job/javadoc-nbms/lastSuccessfulBuild/artifact/nbbuild/nbms/updates.xml.gz
-Tim
Feb 28, 2008 · admin
Rui: If you want to access the Alpha update center from a release build such as 6.0 or 6.0.1, you need to add that update center's URL to Tools | Plugins - go to the settings tab, click Add and use the URL
http://deadlock.netbeans.org/hudson/job/javadoc-nbms/lastSuccessfulBuild/artifact/nbbuild/nbms/updates.xml.gz
-Tim
Feb 28, 2008 · admin
Sachin: Yes, you can do that. Basically you would either (in NetBeans) call JavaSource.forFileObject(someFile), and then run a Task <CompilationController> against it. You get the TypeDecl's (top level classes in the file) from the CompilationController, and then to each one (unless JDK 1.0 multi-classes-per-file there is only one) you pass your own TreeVisitor, which overrides visitExpressionTree() and whatever else you need (typical is to set a flag when you're in an outer element you know you're interested in, and then override other methods to do more in depth stuff only when you know you are in something you're interested in).
If you know the location of what you want to parse, you can probably start from whatever is there, backtrack until you find the enclosing block and then just work with that.
Feb 28, 2008 · admin
Sachin: Yes, you can do that. Basically you would either (in NetBeans) call JavaSource.forFileObject(someFile), and then run a Task <CompilationController> against it. You get the TypeDecl's (top level classes in the file) from the CompilationController, and then to each one (unless JDK 1.0 multi-classes-per-file there is only one) you pass your own TreeVisitor, which overrides visitExpressionTree() and whatever else you need (typical is to set a flag when you're in an outer element you know you're interested in, and then override other methods to do more in depth stuff only when you know you are in something you're interested in).
If you know the location of what you want to parse, you can probably start from whatever is there, backtrack until you find the enclosing block and then just work with that.
Feb 17, 2008 · Eric Ness
Thanks for the feedback! Generally, when someone tells me they are using ClearCase today, should I assume they mean ClearCase + UCM?
Re the global 'cross project' view, I tend to agree - we don't have that for CVS or SVN either - if you have project B underneath project A, and do a commit on A, project B is not committed - which is exactly right some of the time, and completely wrong some of the time.
Re menu in the editor popup - I actually filed a patch to do that some time ago - the justification for not having it there was to avoid cluttering the editor menu and the idea that that menu should be more for editing-like things. It was closed, I reopened it, and that's the state of it. Feel free to vote for it or add comments.
Re menu disablement and popup dialogs, I've passed that on to the folks working on it, who are also reading this discussion.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 17, 2008 · Eric Ness
Thanks for the feedback! Generally, when someone tells me they are using ClearCase today, should I assume they mean ClearCase + UCM?
Re the global 'cross project' view, I tend to agree - we don't have that for CVS or SVN either - if you have project B underneath project A, and do a commit on A, project B is not committed - which is exactly right some of the time, and completely wrong some of the time.
Re menu in the editor popup - I actually filed a patch to do that some time ago - the justification for not having it there was to avoid cluttering the editor menu and the idea that that menu should be more for editing-like things. It was closed, I reopened it, and that's the state of it. Feel free to vote for it or add comments.
Re menu disablement and popup dialogs, I've passed that on to the folks working on it, who are also reading this discussion.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 16, 2008 · Kevin Long
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 16, 2008 · Eric Ness
I see. Yes, you need to check them both in at the same time; it's best to think of them as if they were one file. If you are using NetBeans ClearCase support, then it should, just as with CVS or SVN, check in both if you right click the Java file (the XML file is invisible in the filesystems view - the node for the associated Java file represents both); FWIW I've never had a problem with accidentally checking in or out one and not the other using NetBeans CVS or SVN support. If you were doing it manually from the command line and used a glob pattern like *.java, I could see how it might be an issue though.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 15, 2008 · Eric Ness
Eugene: I've asked the developers of it to reply with some details here. Since it's already Saturday morning in Prague, you may not get an answer until Monday. In the meantime, here is a link to the UI specification for it, which shows all of the proposed menu contents and therefore what features it supports. It is pretty extensive - the goal is to be comparable to NetBeans (quite good) CVS and SVN support.
Collin: The GUI editor question is a bit off topic in this thread; I'd suggest using nbusers@netbeans.org or a separate thread to discuss that. To briefly answer your question: The java code for the GUI is generated from the XML file. The GUI editor is an editor for that XML file really. When the XML file changes, the code gets regenerated. If you open the GUI editor and make a change, it gets sync'd at that time.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 08, 2008 · admin
Setting it up with Apache was pretty easy - my server is running Ubuntu, and I just got Apache 2 using Synaptic, then it was a matter of making a directory and copying a python file to index.cgi, and tweaking a couple lines of it.
The only thing that took much time and some surfing was setting up two virtual hosts, one with https and one without (you need to make sure you specify the port for each or they'll both try to initialize ssl and you get a cryptic error message). If you don't care about plain http, that's not a problem - I just needed to serve some plain web pages too.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 08, 2008 · admin
Setting it up with Apache was pretty easy - my server is running Ubuntu, and I just got Apache 2 using Synaptic, then it was a matter of making a directory and copying a python file to index.cgi, and tweaking a couple lines of it.
The only thing that took much time and some surfing was setting up two virtual hosts, one with https and one without (you need to make sure you specify the port for each or they'll both try to initialize ssl and you get a cryptic error message). If you don't care about plain http, that's not a problem - I just needed to serve some plain web pages too.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 08, 2008 · admin
Setting it up with Apache was pretty easy - my server is running Ubuntu, and I just got Apache 2 using Synaptic, then it was a matter of making a directory and copying a python file to index.cgi, and tweaking a couple lines of it.
The only thing that took much time and some surfing was setting up two virtual hosts, one with https and one without (you need to make sure you specify the port for each or they'll both try to initialize ssl and you get a cryptic error message). If you don't care about plain http, that's not a problem - I just needed to serve some plain web pages too.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Feb 08, 2008 · admin
Setting it up with Apache was pretty easy - my server is running Ubuntu, and I just got Apache 2 using Synaptic, then it was a matter of making a directory and copying a python file to index.cgi, and tweaking a couple lines of it.
The only thing that took much time and some surfing was setting up two virtual hosts, one with https and one without (you need to make sure you specify the port for each or they'll both try to initialize ssl and you get a cryptic error message). If you don't care about plain http, that's not a problem - I just needed to serve some plain web pages too.
Tim Boudreau
Senior Staff Engineer
Sun Microsystems
Jan 30, 2008 · admin
Tim BoudreauSenior Staff EngineerSun Microsystems
Jan 30, 2008 · admin
Sweet, huh?
Tim BoudreauSenior Staff EngineerSun Microsystems
Jan 30, 2008 · admin
Sweet, huh?
Tim BoudreauSenior Staff EngineerSun Microsystems
Jan 30, 2008 · admin
Sweet, huh?
Tim BoudreauSenior Staff EngineerSun Microsystems
Jan 30, 2008 · admin
Sweet, huh?
Tim BoudreauSenior Staff EngineerSun Microsystems
Jan 30, 2008 · admin
Jan 30, 2008 · admin
Jan 30, 2008 · admin
Jan 23, 2008 · Lebon Bon Lebon
-Tim