|
|
||
David Walend's BlogJ2SE ArchivesWhooshing SoundsPosted by dwalend on September 09, 2006 at 08:54 AM | Permalink | Comments (0)Back in May I blogged about simplifying my generics code with dot accessors to the type parameters, to simplify code that currently looks like this: into something more like this: The request for enhancement made it into Sun's database. Seven of you voted for it in as many hours. Thanks. I also had what I think was a revealing back-and-forth with a Sun engineer. I'm a bit disappointed it ended as quickly as it did, but I hope my suggestion planted some seeds for further thought about how the Generics language features can mature. I think the dialog in the RFE makes interesting reading. What Giants? - Vote For My Generics RFEPosted by dwalend on July 18, 2006 at 05:30 AM | Permalink | Comments (14)Back in May I blogged about simplifying my generics code with dot accessors to the type parameters, to simplify code that currently looks like this: into something more like this: The request for enhancement made it into Sun's database. That whooshing sound may not be a windmill after all. If you can spare a bug vote, please vote for this RFE. Judging by the evaluation from Sun's engineer, this RFE needs some votes raising it up so the Sun language giants might spot it. The RFE will also need some good rational discussion. I held back my irrelevant knee-jerk reaction -- "Didn't we all out-grow one-letter-variables when we traded our PETs for C-64s?" I could send a link to an old blog, but even that might distract from the cause. Please keep in mind that we want these folks to do us a favor. I'm working on a response that frames the RFE as "encapsulation vs. exposure," to dispel the "inference vs. explicitness" suggestion. No Giant or Windmill, Just a Deranged MuppetPosted by dwalend on May 30, 2006 at 10:36 AM | Permalink | Comments (0)I gave a talk on the trouble I'm having using complex generics code at the java.net community pavilion at JavaOne. It was a great experience. About a dozen people dropped by to listen; most settled in for the whole twenty minutes. Chris Adamson and the java.net team put together a great facility, with couches, a video screen for slides and -- most important -- an amplification system. My voice doesn't carry well and I was a bit worried that people would not be able to hear me over the 85 decibel din. Inside my head I sound like James Earl Jones. During the talk I thought I was shrieking like a punk rocker. Instead I sounded like a deranged muppet. Chris recorded it for posterity. The amazing thing about the pod-cast is the lack of background noise. I've linked to the slides and the pod-cast, but I think the original blog entry is more clear than me yelling at a slide projector. I had to dumb down the code just to make it fit on slides. I've heard no word yet from Sun about the RFE. That's long compared to Sun's usual timeliness. My hope is that the person who reviews language RFEs was getting ready for JavaOne, then at JavaOne, and is taking a week or two off to recover. (Shortly after posting that RFE, I asked Sun to post a package-list file for Taglets' JavaDoc. Sun picked up that one after about 18 hours. I've gotten used to quick turn around.) I'll blog again when I've got a public tracking number. Tilting at the Generics WindmillPosted by dwalend on May 01, 2006 at 04:26 PM | Permalink | Comments (8)I've got a quixotic streak that needs exercise every so often. It's time. I'm doing a talk on usability problems in generics that I think can be fixed at 2:30 pm on Thursday in the Java Community pavilion at JavaOne. That windmill aught to break a lance. Just before JavaOne 2005 there was a huge dust-up over generics as people started using them, and trying to teach how they work. Ken Arnold blogged "Generics are a mistake... A design should have a complexity budget to keep its overall complexity under control. Generics are way out of whack." Trashing generics became the season's fashion. Chris Adamson retorted that we were experiencing "Buyer's remorse for Generics." After all, JSR-14 -- the generics proposal -- started in 1999, but did not appear in a release until JDK5 in late 2004. Any of us could play with generics in Java using the gj and pizzac compilers. We had five years to point out problems we found using the syntax. For example, borrowing C++ template syntax would look too much like XML. (If we get direct manipulation of XML, it won't look like XML. I'm not sure that's a bad thing. XML is pretty hard on the eyes. The angle brackets do make writing html about Generics or XML really painful -- <s everywhere.) That's water over the dam at this point. I'd like to start a conversation about finding ways to fix the stumbling blocks we've found, targeted for Dolphin. I like generics. I use them (and abuse them. See below) in my JDigraph project. I wrote JSDK 1.4 code in a Digraph interface that looked like this:
which caused frequent . The compiler couldn't point out that the second argument was supposed to be a node and the third was supposed to be an edge. Autocompletion in IDEs, combined with some developers' habit of grabbing the top argument in the autocomplete list led to NodeMissingExceptions, confusion and frustration. In JDK 5, the code looks like this: Just as Keys and Values in Maps are rarely of the same class, Nodes and Edges rarely share an ancestor closer than Object. The compiler helps the developers get things right. My code is much clearer to me (easier to figure out what I did) and much clearer to people trying to use it (fewer agitated developers at my office door).
One of Ken's specific complaints was about the complexity of becomes something like so that YourEnums is always an Enum of YourEnums. To define the Enum class, it'd be great if someone at Sun could just code and remove the guesswork. It's a corner case. I ran into something similar while I was generifying JDigraph's HasState interface. HasState provides a method to compare two objects with different representations, but share a defining principle interface that defines the interesting part of the state. For example, Digraphs and Subgraphs have the same principle interface, Digraph. Two Subgraphs are not equal if they are Subgraphs of different Digraphs. However, if the Subgraphs have the same nodes connected by the same edges then they have the same interesting internal state. I'd love to say but had to limit the generic type parameters to and hope that a developer implementing HasState doesn't do something diabolically mismatched between the type specification and the filling for
The compiler has all the pieces to sort out Enum and HasState puzzles, but there's no way in the language to direct the compiler to do the right thing in the code for the abstract class or the interface. Since In contrast, I do think we need something to help us avoid generics mismatch Hell. I think just having dot access to type parameters' type parameters would work well. It would look and feel about the same as using inner classes. The JDigraph project is my demonstration of reusable directed graph algorithms. It uses a general purpose graph containers inspired by the Java collections kit, built off of the Digraph interface. Here's the illustration, with examples from JDigraph: is fine. You can specify any class to be Node, and any class to be Edge. Generics actually make the code easier to follow, as people stop confusing nodes with edges. (IndexedDigraph is a Digraph with indexed access to the nodes and edges. You'll see that in a few paragraphs.) Generics mismatch Hell starts innocuously enough. Subgraph is an interface for directed graphs that hold subsets of the nodes and edges of some Supergraph. Someone using Subgraph has to match up the Node and Edge type specifications for a Subgraph with the Supergraph. could be a bit simpler with dot access, because the compiler knows that Supergraph is a Digraph, and has type parameters for Node and Edge. It's not a huge difference, and in fact takes more characters. However, Subgraph's definition could do the work to line up the type parameters. Also, Subgraph would only need one type parameter, not the three required above. The complexity grows from there. OverlayDigraph is an interface for representing a Digraph that shares nodes with an underlying Digraph, but has its own edges. Think about it like someone laying a transparency sheet over a bunch of dots and connecting the dots her own way with a sharpie. The compiler knows what Undergraph will be using for Node and Edge. This is just generics mismatch Heck. Someone using this interface has to get the Node and UnderEdge type specs correct. It'd be a lot nicer to be able to take advantage of the compiler's knowledge of Undergraph's type parameters with something like and use Undergraph.Edge instead of UnderEdge in the code. That's two type parameters to fill in instead of four. (You're about to see IndexedMutableOverlayDigraph, which is an OverlayDigraph with indexed access to the nodes and mutators to add and remove edges.) Semirings define a set of useful operators for general graph labeling and graph minimization algorithms that work on Digraphs. The theory is right out of CLRS chapter 26.4. Semirings hold identity and annihilator label constants, and extension, summary and relax operators. The extension operator calculates the label to move from one node to another across an edge. The summary operator calculates the label combining two alternative labels. The relax operator calculates a new label by combining the existing label with a new, alternative label. These operators are the basic parts for building the Floyd-Warshall, Dijkstra, Prim's, Johnson's, Bellman-Ford and A* algorithms. I also made Semiring responsible for creating the initial OverlayDigraph of Labels. Encapsulating these things in Semiring has saved me writing the same tricky algorithm code for every new graph minimization problem. Still with me? Hold on to your synapses. Semiring's declaration looks like this: All five of the type specifiers have to line up correctly to compile code using this vile beast. It's hard for me to tame, and I wrote the thing. This is a big part of why JDigraph only does alpha releases. That's generics mismatch Hell. If the compiler were a bit smarter, Semiring's declaration could just be Five type specifiers could collapse to just one! You tell the compiler what to use for LabelDigraph. LabelDigraph knows Undergraph and Label. Undergraph knows Node and Edge. The Semiring interface and the compiler could do all the work to match up the types. Remember, Semiring's reason to exist is to encapsulate all those operators so I can write generic algorithms. Dot access to type parameters would let Semiring encapsulate all the gory details of type parameters, too. The Floyd-Warshall is about the simplest graph minimization algorithm there is (three nested for() loops). Got any synapses left? Here's what its declaration looks like now: Six! Six type parameters! Ah ha ha! I feel like that vampire from Sesame Street. (Dijkstra's algorithm and AStar need a Comparator, for a total of seven!) Letting dots access type parameters would let Semiring encapsulate all the type complexity, as well as the operators. Using dots to access contained parameters would be a Get out of Hell free card for this sort of problem. As more people decide to use generics, it's likely to help a lot of people a little bit. It would help JDigraph immensely. The next step is to figure out where in the community to propose the change. Graham Hamilton's blog on language changes in Dolphin is a bit dated. My own blog and a JavaOne community talk should be a good start. Did I Miss Generic Array Creation?Posted by dwalend on January 07, 2005 at 05:07 AM | Permalink | Comments (10)While sweeping up sawdust before the latest release of JDigraph, I used -Xlint to spot remaining places where I have some things to clean up. I have just a handful to go. I'm having the most trouble with creating Arrays in collection-like classes. JDigraph is a generic efficient directed graph representation, so these arrays are everywhere. I've taken examples from FibHeap.java.
results in a waring from lint.
The first thing I tried didn't compile:
results in
I tried dynamically creating the array using java.lang.reflect.Array:
which gives me the warning from lint again.
I've tried doing other things, especially to the HeapMember.class argument, but haven't found a solution that compiles with no warnings. Is there some bit of API I missed? Is there a good reason not to create arrays of generics? Or should I report a RFE to Sun asking them to add generic parameters to Array.newInstance()? Thanks, Naming Generic TypesPosted by dwalend on December 05, 2004 at 04:55 PM | Permalink | Comments (16)Naming Generic Types We've had blogs covering DRY and magic Strings in the last week. I'm going to blog about generic type names, specifically using names longer than one letter. Some of us are old enough to have used systems with a limit the length of variable names. But I haven't seen anyone use "x" as a generic double name in years (caveat coordinates). We left that habit behind because of the confusion it caused. We now teach people to write self-documenting code with descriptive variable names. The generics tutorial that comes with JDK 5 suggests using one capitol letter to represent generic types: "A note on naming conventions. We recommend that you use pithy (single character if possible) yet evocative names for formal type parameters. It’s best to avoid lower case characters in those names, making it easy to distinguish formal type parameters from ordinary classes and interfaces. Many container types use E, for element, as in the examples above." I tried to follow this advice; I used N for the node type and E for the edge type.
wasn't so bad. But the typespec for Semirings has five generic types.
It got painful quickly. What's L? What was E again? Element?
Using fully spelled out names removes the guessing from Digraph:
and changes Semiring from cryptically intimidating to merely complex:
Changing "E"s to "Edges", etc. was mindless drudgery. "E"s and "N"s are much more common than "x"s. I made mistakes during the cleanup. Changing full names would have been much easier for me. Reading full names should be easier for everyone else. I like to name generics after the role they play in code. I didn't have any problem distinguishing the generic names from interfaces or classes. JDigraph doesn't have a Node, Edge or Label class (which is much easier to figure out now that I've used generics to cut the number of classes in half).
To avoid abbreviations in code, I keep a thesaurus on my desk. My thesaurus is probably the right tool to clear up any confusion between generic typespecs, classes and interfaces.
Amazing -XlintPosted by dwalend on November 13, 2004 at 10:52 AM | Permalink | Comments (1)I've been reorganizing JDigraph to take advantage of generics. I've been able to implement generic versions of Floyd-Warshall and Dijkstra's algorithms -- hopefully using generics means doing this for the last time. I want to highlight -Xlint, a JDK 5 feature that's saved me a lot of grueling code reads as I've learned generics. I wish I'd found it sooner. My common-build.xml file's javac task now looks like
The feature pointed out a few hundred spots where I hadn't specified types on my first "make it work" pass. lint made short work of the clean-up pass. Further, lint pointed out places that needed some more thought, and helped keep me honest. I've fielded a lot of questions about generics over the last six weeks; none of the people asking had found -Xlint. Try it out. I found it more useful than any of the tutorials. Test Driving GenericsPosted by dwalend on July 14, 2004 at 09:53 PM | Permalink | Comments (4)I'm impressed that people can blog while attending JavaOne. My head's just clearing up from all the new ideas slamming into the old ones. To relax on the way home, I started stitching generics into JDigraph, a general library for representing directed graphs. The effort mostly went smoothly, with a few hiccups. Scouting The documentation for generics in the jdk 1.5 beta is pretty thin. "This long-awaited enhancement to the type system allows a type or method to operate on objects of various types while providing compile-time type safety. It adds compile-time type safety to the Collections Framework and eliminates the drudgery of casting. Refer to JSR 14." That's right, it says read the spec for JSR-14. JSR-14 was pretty easy to read even though it's primarily for compiler writers. However, it didn't have any advice on how or when to use generics. I wound up unzipping the jdk 1.5 src.zip file and looking at the examples in java.util's collection kit. Bags -- Something Easy First The net.walend.collection package has the Bag interface and MapBag implementation. Bag is a multi set -- an implementation of Collection that can contain zero or more of an Object in no particular order. I used generics to create a Bag that contains a specific type of thing, much the way the rest of the collections kit works. It was pretty straightforward. I changed the Bag interface to Bag<Elem> extending Collection<Elem>, and the MapBag class to MapBag<Elem> implementing Bag<Elem>. MapBag uses an internal Counter class to track how many times an Elem appears in the Bag, so I made the internal Map be a Map<Elem,Counter>. Then I replaced all the Object parameters and return types to Elem parameters, and all the inbound Collections to Collection<Elem>s. From there, I let the compiler do most of the work, pointing out places where Collection's use of generics didn't match my own. The only remotely tricky part was the inner class BagIterator. It turns out that the outer class' generics are available to the inner class, so I caused myself some grief by declaring BagIterator<Elem> instead of just leaving it alone. I wound up changing it back. The other thing I stumbled on was the exactness of the match for methods in the interface and implementation. I had thought that <?> was basically a no-op that I could leave it out, and that <? extends E> was as the same as <E>. I may be missing some subtlety here; they seem to mean the same thing to me. But they don't look the same to the compiler. Where Collection asks for <?>, I had to use a <?>, and where Collection specifies a <? extends E> I had use <? extends E> instead of <E>. The crew updating the collections kit at Sun seems to have used generics only where they could save a cast. For example Collection's boolean contains(Object o) did not change to boolean contains(E o). The compiler won't balk at a developer coding a contains() call with the wrong type, but will balk if a code calls add() with the wrong type. This change breaks code only when the type safety is an issue. I'd argue that calling contains with the wrong type is probably a problem in the code, but it's a tough choice either way. The other odd thing were the toArray() methods. Colleciton.toArray() still returns Object[], not E[]. Collection.toArray(T[] array) returns an array of Ts (also not Es). The source code has a nice trick for getting the class of T out and constructing an array of Ts. Heaps -- Something More Complex The net.walend.collection package also defines a Heap interface, and a Fibonacci Heap implementation. A Fibonacci heap is a fairly complex animal. I wanted to make sure I could use generics to create general implementations of algorithms, and use generics to unite a family of specific classes designed to work together. (My long-term hope is to use generics to define semirings, but that's a different blog.) My Heap code required the Heap and HeapComparator interfaces, plus the FibHeap and HeapMember classes. Heap has three type variables: <Key>, the key in the heap. <Comp>, a HeapComparator that works on <Key>s. And <Memb>, a HeapMember that works with <Key>, <Comp> and <Memb> (oddly enough). Now someone can use a FibHeap that uses doubles as <Key>s, largest double first. Someone else can use a FibHeap that uses BigDecimals as <Key>s, smallest first. And someone else can use Strings as <Key>s, last in alphabet first. All three use the same FibHeap algorithm code. The Heap system works well, but has a strange feel to it. <Key> can be any class (provided the class can support HeapComparator's getMinimumPossible() method). <Comp> has to be a HeapComparator that works with <Key>s. <Memb> is the strange one; <Memb> has to know a bit about the Heap that contains it, plus it has to know about itself. I didn't find a way to say that this specific HeapMember must be <Memb>. I might have just missed a way to make this circular declaration. Both interfaces and superclasses in the type parameters list use the "extends" key word (not implements). In this system of objects with three type parameters, one-letter-name type parameters quickly gave me a headache. The java.util package uses mostly T and E. I had to leave that behind to keep things straight. There's an art to naming the type parameters that I have yet to master. Digraphs -- A Big System of Classes The net.walend.digraph and net.walend.digraph.path packages define three families of directed graph representations. This package shows the boundary for sane use of interfaces. I want to be able to have generified Objects for Nodes and Edges (where they exist). Digraph<Node> is the top-level interface for directed graphs. GEDigraph<Node> (all the edges are identical) and CEDigraph<Node,Edge> (edges can repeat, but are individual objects and have to be represented as such) extend Digraph<Node>. Interfaces that describe mutable versions of GEDigraph and CEDigraph extend those interfaces, followed by implementations. The path subpackage includes interfaces for Path<Node> (which extends Digraph<Node>), GEPath<Node> (which extends Path<Node> and GEDigraph<Node>) and CEPath<Node,Edge> (which extends Path<Node> and CEDigraph<Node,Edge>), plus mutable versions of these interfaces, and implementations built on List and a Digraph of Paths (useful for path algorithms). It's a big system. Generics should let me eventually convert the net.walend.measured package from shortest (double) path algorithms that operate on CEDigraphs into semiring algorithms that operate on any Digraph. While retrofitting net.walend.digraph, I found starting at the most general interface (Digraph) and working my way toward the most specific worked best. I think that's a side effect of generics being grafted on Java late; a subclass or subinterface can simply ignore the super's generics and still compile. I was able to work with just the <Node> type parameter first, then move through the classes where the <Edge> type parameter should exist. However, I was not able to mix the two approaches well; if a subclass uses one type parameter, it needed to recognize both. To mitigate that, I found I could set the extra type parameter to <Object> and change it later. I was disappointed that Throwables can't have type parameters. NodeMissingException can hold the missing node as an Object, but not a Node. And I found a strange interaction between inner classes, type parameters and instanceof that I still haven't puzzled through. The outer class' type parameters carry through to the inner classes, and work fine for everything I tried except instanceof. I had to add a type parameter to the NodePair inner class in AbstractCEHashMap and AbstractGEHashMap. Overall, generics worked well and promise to let us build powerful libraries of general algorithms.
Reading Version Control With Subversion, Pilato, Collins-Sussman, and Fitzpatrick (Thanks, Helen. When do we get Subversion on java.net?) Design For ExceptionsPosted by dwalend on October 06, 2003 at 04:57 AM | Permalink | Comments (25)I read Bill Venner's interview with James Gosling, "Failure and Exceptions," and with Anders Hejlsberg, "The Trouble with Checked Exceptions," and was a little surprised. I thought exceptions would be in .Net since .Net has taken so many other features from Java. I've never found checked exception clauses to be much of a burden. It's one of my favorite features of Java. Anyway, given all the talk about exceptions and exception handling, I thought I'd take a minute to describe what I do and ask how others use them. I think the problems that Dr. Hejlsberg describes, versionability and scalability, are easy to contain if the development team decides how they're going to handle trouble before they get too deep into their work. Here's what I usually do:
When I start a package, I create a handful of support classes. These classes are simple, but having them there encourages developers to use them instead of creating custom solutions. One of these classes is an abstract exception, a parent for all the concrete exceptions in that package. When developers discover they need a new exception, they extend this exception. The API for the package only throws subclasses of this exception. The abstract exception from JDigraph's net.walend.digraph package looks like this:
If I can't handle a checked exception, I like wrapping the exception with my own subclass of my package's abstract exception, then throw the wrapping exception. My API still only throws subclasses of my abstract exception. The overhead is just constructing the new exception. Wrapping exceptions bounds the scaling problem Dr. Hejlsberg describes by limiting what can appear in the throws clause. Here's the part that's worth discussing: I like keeping my methods' throws list very specific, limited to the concrete exceptions actually thrown. This choice means that people writing code that calls these methods will be cognizant of each exception. If they like, they can still catch the common parent exception. The alternative is having all methods declare that they throw only the same abstract exception. If you believe your public API can never be changed, this is the way to go. This approach solves the versioning problem Dr. Hejlsberg describes by insulating code from changes in the exceptions actually thrown, but does not give great hints for how to handle the problem. For most of my work, the versioning problem is overstated. Most of the source code developers create stays small in scope. I understand that after some point in the development life cycle of code reused across many projects the throws clause in a method can't be changed anymore. If a project becomes popular enough, these detailed throws clauses will break down and having the parent exception in the throws clause is a better decision. I think that popularity is pretty rare: Interfaces from a JSR, or public methods in a popular apache project, or from a core software team at a big company should declare that they throw a general parent exception from day one. However, most code we write has a fairly small and well-defined group of developers. Changing the throws clause doesn't wag many lines of code. That code may need to be changed to handle the new exception in a thoughtful way. If the library is becoming more popular while it is still being developed, adding the parent exception to the end of the throws clauses is easy and well-received. If that last paragraph doesn't generate some interesting talk back, the next two will. When I've tried to use the standard exceptions available in java or javax packages, I've discovered that very few of these exceptions have constructors that take nested exceptions. Generally, developers will use constructors that take an exception, but will not use the initCause() method on their own. I usually have to subclass them to either call the initCause() method in the constructor or override getCause() (to stay compatible with JDK 1.3. See Felipe Leme's latest blog.) I avoid throwing my own RuntimeExceptions except at fairly high levels when it's time to stop or reset the application without cluttering the API. And I'll sometimes use them to mark states I think are impossible. If I control the main event loop, my code catches these exceptions and tries to bow out gracefully, whatever graceful means in the context. I've also used RuntimeExceptions when I was trying to make quick fixes to an existing code base. But I've regretted this shortcut in the past.
Do other people do anything radically different? Is it ever OK to use throws Exception in a declaration? Or, like .Net, to use all RuntimeExceptions no matter what?
SomnifugiJMS for User Interfaces and Simple-Enough APIsPosted by dwalend on September 11, 2003 at 04:56 AM | Permalink | Comments (2)Somnifugi JMS is an implementation of the Java Messaging Service built on top of Doug Lea's Channels. This JMS implementation runs inside a single JVM, quickly delivering messages between java Threads. A few years back, I created Somnifugi JMS to speed up a project where the architects had gone overboard with messaging. I used Somnifugi JMS to prototype and test the next project, and left it in place to keep things fast. The project after that, I used a Somnifugi JMS Topic to communicate from the AWT Thread to other Threads where the controllers and models live. It worked great; I've used it in every Swing project since then, and a few others have started using it this way, too. I have trouble tracking all the issues in building a Swing interface: Swing's API has about a hundred top-level classes, each with a few dozen methods, plus nine subpackages, AWT, and Java2D to get things just right. Getting a group of people to all use MVC, JavaBeans and Threads the same way is hard. The model always has its own dynamics, and usually changes a few times a day. Add users unfamiliar with the new UI to make the project even harder. The "Use Topics to communicate from the view to the controllers" pattern is a nice complement to the "Use SwingUtils.invokeLater() to communicate from the controllers to the view" pattern. Extending the pattern to place model handling in separate Threads is just a matter of adding extra Topics or Queues for the controller to consume. Plus if I need to make the application fit a client-server model, all I have to do is swap the model's Somnifugi JMS Topics for distributed JMS Topics. I think the power in this pattern comes from breaking up the task into small, easy-to-grasp pieces. Using a Topic to communicate from the view to the controller simplifies both by decoupling them. The view generates messages whenever any user action happens. The controller digests those messages. The JMS API is small and easy to learn and use. Using Topics simplifies performance decisions about handling Threads and shared Objects. The projects become more predictable, easier to decouple and test, and more pleasant to work on. I think a lot of this gain is because a JMS Topic is easier to use than Java's threading support. The JMS specification is one of the best written specifications to come out of the JCP. The underlying ideas work without bending the universe to match. Each interface fills an outlined role and I don't have to do anything weird to my own code to use them. There's no requiring me to inheriting from someone else's superclass for example. (See Allen Holub's article, "The fragile base-class problem".) I needed a single afternoon to read the spec, and I understood without strain. I spoke briefly with Joseph Fialli (one of the authors of the JMS spec) after he gave an invited talk (on JaxB) at a local user group. I described how I was using JMS behind Swing interfaces. He thought the pattern was pretty slick. He was the only person ever to compare it to InfoBus.* After the talk, I found my notes from reading the InfoBus spec in 1999. "InfoBus API looks more complex than just using the Thread API. We'd need to fill in most of the JavaBeans event spec. Not a good fit for our problem." Over the years, I've never seen a project that uses InfoBus, despite the hype it received in the late 90's. A JSR to update the InfoBus specification was started in 1998 but withdrawn in 1999. I think the InfoBus spec has been abandoned, but some ideas live on in the JavaBeans spec. I think there's a strong correlation between simple APIs and how likely developers are to use those APIs. JMS survives and thrives because it meets a need that developers recognize with relatively little overhead. JMS exemplifies a "Simple-Enough Principle" for API design. Developers never adopted InfoBus in large numbers because we didn't think InfoBus was any better than what we had before. Because all the code I write becomes library code, I try to keep this principle in mind when I define APIs. I want to create an API rich enough to do the job, but simple enough for another developer to be able to use without expanding the problem he's working on. Perhaps the advances in Aspect-Oriented code will reduce the typing overhead for JavaBeans to the point where developers can meet the specification. But that's a different blog.
* As I added mark up to this article, I got email from Ted Shab asking about Somnifugi JMS, "We are looking for InfoBus-like functionality, as well as some other related concepts."
| ||
|
|