Java Tip 50: "On the Parameter Constants pattern" by Jon Steelman
Gosling sets the record straight
To James Gosling,
I have a very earnest question about the Java specification that I believe only you can answer. When you were developing the initial specification for Java, what prompted you to decide not to include enumerated primitive data types? Several recent articles (I notice they're popping up everywhere) describe how to accomplish the same sort of compile-time range-checking, most notably JavaWorld's Java Tip 50.
I've begun a correspondence with Jon Steelman, author of this article, and we agree that all these interesting designs for accomplishing this task could be avoided if enumerated types were available. This isn't necessarily a criticism, but I was wondering if there's a specific reason for this omission. I've been unable to find the answer elsewhere, which is why I came straight to the source.
Thank you for your time and consideration (and for the Java language, of course).
Kyle, Enumerations were left out of the Java spec not because I think they're a bad idea, but because I couldn't converge on a design that made sense. Enumerations means different things to different people. One version of enums is that found in early versions of C, where they were essentially just integers. Very simple, but no type checking. Later versions of C made enums proper types, but the type algebra was pretty simplistic, and the only way to use them involved lots of casting, which breaks type safety (to use enums as array subscripts you have to cast them to
(int)). Pascal has a somewhat more complete type algebra (they're at least type safe), but many of the useful things folks do with C enums are impossible here (having defined mappings to integers for SCSI function codes). Another contingent wanted enums to be abstract qualities from a dynamically extensible set (the enum patterns that use instances of content-free object instances as values). There was more than enough grayness in the area that I decided to put the issue aside for the time being. James Gosling
The hidden power of inner classes
Great article! I've been using the type-safe enums since Java was in beta (a friend and I came up with the idea to get around the fact that Java didn't have enums and found that we actually liked this scheme -- with its compile-time type safety and bounds checking -- better than the traditional enum). So I didn't find the first tip regarding using this method very useful; but I have to admit I didn't think of combining the new inner-class abilities with this method to get an easier-to-reference version.
Scott, I'm glad you found a new application of the power of inner classes. I personally think that inner classes are underutilized, that people unfortunately avoid them or at most use them for event adapters. I appreciate the positive feedback. Check out Java Tip 27 by Philip Bishop for its relevance to your enums. Even better, see the article, "Create enumerated constants in Java" by Eric Armstrong. Was your enum design similar to the one Eric describes here? Jon Steelman
The mysteries of accessibility
I have a question regarding your tip on parameter constants.
The last block of code includes a private constructor with the comment "private constructor for type safety but accessible in both containers: Parameters & Calendar."
How is that private constructor accessible?
If it were a private method in the interface, I understand how it would be accessible in any class that itself implemented the interface. It's not in the interface, however, but in another class; I would think that it wouldn't be accessible from outside that class.
What's the special aspect of nested classes (or interfaces) that renders the constructor accessible from classes that implement the containing interface?
Daniel, The specification for inner classes makes even private members of inner classes accessible to outer classes. Conversely, private members of containers are likewise accessible from the inner classes. The accessibility, therefore, has nothing to do with implementing the interface and everything to do with the containment relationship. Some of the bugs in JDK 1.1.x relate to this issue. In one particular case, the private member is not accessible, but again this is a bug that deviates from the specification. See bug #4051281 on the Java Developer Connection. Generally, these bugs are being fixed for 1.2. I've not found that the code in my sample runs into any of these bugs. Jon Steelman
JavaBeans: "Doing it the Nescafé way with freeze-dried JavaBeans" by Mark Johnson
I loved your article "Do it the 'Nescafé' way -- with freeze-dried JavaBeans," but it should be titled Do it the Taster's Choice way... Taster's Choice is the freeze-dried Nestle coffee, not Nescafé. (Just for your information!)
Our factory in Freehold, NJ, is the only North American producer of Taster's Choice instant coffee, and darn proud of it!
Gregory, I knew the instant I saw this letter that I'd have to come up with some dry comments about it. Though at first I thought it would drive me to drink, I found a solution (though I really had to concentrate). I've been in more hot water about the freeze-dried Java issue than any other, but I haven't been losing any sleep over the roasting I've received. Because testability is one of the benefits of software component technology, perhaps I should have entitled the column Tester's Choice. Mark Johnson
Design Techniques: "What's a method to do?" by Bill Venners
Flexible Java, coming soon to a bookstore near you...
Your Design Techniques articles are great. I'm a student at Ocean County College, and we're using Java as the core language for our classes. Your articles have helped me shrink Java down to a more understandable level. Is your column part of a book that I can purchase?
William, I'm glad you get a lot out of my articles. There is no book as yet, but I am working on one called Flexible Java, in which much of the material from my Design Techniques column in JavaWorld will appear. Bill Venners
Mind those XYZs
I enjoyed your article, but I'm not sure it answers my question. Assume I have an object X contained in object Y contained in object Z. I want to invoke a method on X, but I only have access to Z. I currently have to pull Y out of Z, then pull X out of Y, then make the method call once I have X in hand.
I vaguely remember reading about a post-office pattern that would allow me to send a message for X through Z. I can think of a way to do this via strings and the Reflection package, but it seems kind of crude. Any ideas?
Stephen, Well, it all kind of depends on what X, Y, and Z represent, but in general, I'd say that it would be nice if Z offered a method that does the job you need done (with X), if possible in a way that doesn't really require you to know so much about X or even Y. Let's say the method is
z.getZJobDone(). What would likely happen when you invoke
getZJobDone() is that it would invoke a method on Y (which is part of Z's internal implementation, referenced by an instance variable in Z), say
getYJobDone(). And what
getYJobDone() would do is invoke
getXJobDone() on the reference to an X that Y has in its instance variables. This way, the X, Y, and Z methods offer services, rather than simply offering access to internal data. In addition, this way yields the message passing scheme you were talking about. When you invoke
getZJobDone(), you are passing a message to Z, which then passes its own message to Y by invoking
getYJobDone(), which in turn passes a message to X by invoking
getXJobDone(). But the client of Z just invokes
getZJobDone() and doesn't have to think about Xs and Ys and the details of how
getZJobDone() gets the job done. On the other hand, there will likely be times when you feel clients of an object need access to internal data, and the accepted way to do that in Java is with
set/get methods. Z could have a
getY() method and Y could have a
getX() method. It sounds like this is what you're currently doing. So the answer is that
set/get methods are OK, but first you should try to think about designing X, Y, and Z as bundles of services (their accessible methods are the services), not just as wrappers of data. Bill Venners
Breaking the mold
Nice job! I like your column and it seems clear to me, from the presentation that you used, that you have a design patterns background . That is, you discussed a problem in a context, along with the constraints that drive decision making. The summary was a good way for me to park the information (pattern) in my brain. Thanks again and I look forward to more of your best practices.
Russ, I've found that some things are best described as patterns and others are best described as guidelines. I'm thinking of packaging this material into a book of guidelines along the lines of Effective C++, but with a few "best practice" patterns sprinkled in. I don't know if you've ever seen Kent Beck's Smalltalk Best Practice Patterns, which covers the same type of material for SmallTalk, but in a patterns (not guidelines) mold. It's a great book, but I think it sometimes strains to get guideline pegs to fit into pattern holes. Bill Venners
In your article, you note that coupling doesn't have an analog in the writing domain -- sure it does!
How about a document that's littered with see X, and refer to Y references or links? That document doesn't stand on its own -- it requires the reader, in order to understand one document, to access input from other documents.
Jay, Oops! You're right. In my attempt to be uncohesive, I was also inaccurate. (I think this reply is "coupled" to your comment, because it would make no sense in the absence of your comment. All kinds of coupling in writing.) Bill Venners
Java Tips Q&A with John D. Mitchell
I enjoyed your article on system properties.
One question, though. Your article implied that you can get the environment variables defined in DOS/Windows. Running your program doesn't return any of the environment variables that I have defined, however, in either Windows NT or Windows 95. Do you know of a "pure" way to get these environment variables?
Mike, Glad to be of service! I don't think there was any such implication. The article certainly does compare properties to environment variables, but I don't recall anything that stated that OS environment variables do or do not make it into the system properties list. Perhaps I should have made that clear in the article. Sorry for the confusion. The only way to get the OS system variables is to have them passed in on the command line which starts the Java runtime. This is problematic for applets, but for applications, just wrap the invocation of the Java runtime in a batch/shell script. There are tons of portability problems trying to rely on OS-level environment variables; as a result the system properties have been developed to allow you to get more or less the same information everywhere. John D. Mitchell
Servlet permissions quandary
I am a CIS student at Kansas State University working on a Web site project. I have a question about Java Tip 41.
I need my servlet to write to a file -- the same operation your example code (
PosterServlet) performs. I am getting the error:
unable to open output file. I've had trouble getting permissions set correctly. What exactly do I need to set the permissions to? Also which permissions are these (just permissions for the directory, or is there something in the server configuration)? I have set up my own Apache 1.2.5 server with the servlet patch.
Julie, Different servlet runners have you do things somewhat differently (due to the unspecified nature of some things). The default directory that a servlet opens files in seems to be one of those things. I haven't used Apache, so your best bet is to check out the java.apache.org documentation. For the example
PosterServlet, running under Sun's Java Web Server on a Linux box, the default directory is the root server directory (so the /posters directory is directly under the top), and I've specified 775 (that is,
rwxr-xr-x) permissions -- although that's not particularly tight (or secure!). Other servlet runners may default to the directory from which the servlet's class file was found. Please let me know what you find out. John D. Mitchell
Multiple callbacks in the same class?
Thanks for Java Tip 10, which discusses callbacks in Java. I am struggling with the following problem. How do you set up multiple callbacks in the same class? I'd like to avoid a
switch(...) in the "main" callback (the one defined in the interface, and, at the same time, I'd like to avoid declaring a callback vector in the interface. Any hints?
Andrea, You have the basic idea of how to do callbacks. After that you can pretty much do whatever you like to build more complicated systems. A vector is a good solution, or you can use multiple, anonymous inner classes. Depending on your needs, you could have a single demultiplexer object, which knows how, who, and what to call when the event happens, installed as the callback. You might also want to look at how the various events and listeners are implemented by the AWT. John D. Mitchell
Out of the sandbox?