|
|
||
Ethan Nicholas's BlogJune 2006 ArchivesSo long, and thanks for everythingPosted by enicholas on June 28, 2006 at 10:25 AM | Permalink | Comments (24)When you work at a major Internet company like Yahoo!, deployment is a Big Deal. You have millions of customers running every version of every OS imaginable, some with marginally working computers, and they all need to be able to run your software. And they need to run it now -- make them wait too long, or download too much, and they'll give up and move on to your competitors. While I'm definitely a huge Java fan, it's a hard technology to deploy to end-users. If a particular user doesn't have Java installed, or doesn't have the right version of Java installed, there are major challenges surrounding the detection, installation, and upgrading process. Even if users have the right version of Java installed, its behavior in web browsers isn't necessary all that reliable. I posted a couple of high-profile rants about Java deployment issues recently, to try to call some attention to these issues. I wasn't really expecting much of a response. I figured some fellow complainers would show up, we'd talk amongst ourselves for a little while, and that would be the end of things. I wasn't expecting Sun to even notice my complaints, let alone actually do something about them. I was happy to be proven wrong. I was asked to put together a resume, and invited to interview with the Java Deployment team. After two rounds of phone interviews and a grueling eight-hour interview process in Burlington, I accepted an offer to join Sun, and will finally have the opportunity to address some of the problems that have been bugging me for so long. This is a really exciting change for me -- to finally be working on Java, instead of just with it, and to be able to influence where things are headed... well, it's a Java geek's dream come true. Or at least it's this Java geek's dream come true. We're still working out the details, but I should be starting at Sun in about a month. Yahoo! is a great company, and has been very good to me over the years, but this was an opportunity I just couldn't pass up. To dispel any rumors...Before any rumors get started, let me be the first to say that just because I blogged about some deployment ideas does not mean that any of those ideas will necessarily get implemented. Sun obviously found them interesting, or I daresay I wouldn't have been hired, but there's a big difference between finding an idea interesting and actually putting in the time and money necessary to implement it. In particular, don't expect a Java Browser Edition -- much as I would love to see it happen, I'm not naive enough to believe that it's at all likely. I do have a lot of ideas for improvements to the Java Plug-In and Java Web Start; reasonably small, practical features that will nevertheless make a huge difference in how easy it is to deploy Java programs. Hopefully some of them will actually get implemented eventually, but at this point it's far to early to speculate on how things will work out. Rest assured that I will be doing my best to push for easier deployment solutions, and I'm all ears if you have any suggestions of your own. What about JAXX?What does this mean for JAXX, the declarative XML user-interface language I'm working on? In the short term, not much. The position I was hired for has nothing to do with JAXX, and I will still be doing all JAXX work in my spare time, rather than as a Sun-sponsored activity. What about the long term? Your guess is as good as mine. All I know for sure is that I have a lot of ideas for the future of JAXX, and will continue to crank away on it. If the Swing team decides to add a user interface language to Java at some point (which I know they have considered), I expect I would at least be involved in the discussion. Other than that... who knows? Looking aheadThe decision to leave Yahoo! was both difficult and painful, but I think I made the right choice. I'm very excited to be joining Sun, and I hope that I will be able to really make a difference. Wish me luck! All about intern()Posted by enicholas on June 26, 2006 at 02:16 PM | Permalink | Comments (13)Strings are a fundamental part of any modern programming language, every bit as important as numbers. So you'd think that Java programmers would go out of their way to have a solid understanding of them -- and sadly, that isn't always the case. I was going through the source code to Xerces (the XML parser included in Java) today, when I found a very surprising line: com.sun.org.apache.xerces.internal.impl.XMLScanner:395 There are a number of strings defined like this, and every one of them is being interned. So what exactly is intern()? Well, as you no doubt know, there are two different ways to compare objects in Java. You can use the == operator, or you can use the equals() method. The == operator compares whether two references point to the same object, whereas the equals() method compares whether two objects contain the same data. One of the first lessons you learn in Java is that you should usually use equals(), not ==, to compare two strings. If you compare, say, new String("Hello") == new String("Hello"), you will in fact receive false, because they are two different string instances. If you use equals() instead, you will receive true, just as you'd expect. Unfortunately, the equals() method can be fairly slow, as it involves a character-by-character comparison of the strings. Since the == method compares identity, all it has to do is compare two pointers to see if they are the same, and obviously it will be much faster than equals(). So if you're going to be comparing the same strings repeatedly, you can get a significant performance advantage by reducing it to an identity comparison rather than an equality comparison. The basic algorithm is: 1) Create a hash set of Strings After following this algorithm, you are guaranteed that if two strings contain the same characters, they are also the same instance. This means that you can safely compare strings using == rather than equals(), gaining a significant performance advantage with repeated comparisons. Fortunately, Java already includes an implementation of the algorithm above. It's the intern() method on java.lang.String. new String("Hello").intern() == new String("Hello").intern() returns true, whereas without the intern() calls it returns false. So why was I so surprised to see protected final static String fVersionSymbol = "version".intern(); in the Xerces source code? Obviously this string will be used for many comparisons, doesn't it make sense to intern it? Sure it does. That's why Java already does it. All constant strings that appear in a class are automatically interned. This includes both your own constants (like the above "version" string) as well as other strings that are part of the class file format -- class names, method and field signatures, and so forth. It even extends to constant string expressions: "Hel" + "lo" is processed by javac exactly the same as "Hello", and "Hel" + "lo" == "Hello" will return true. So the result of calling intern() on a constant string like "version" is by definition going to be the exact same string you passed in. "version" == "version".intern(), always. You only need to intern strings when they are not constants, and you want to be able to quickly compare them to other interned strings. There can also be a memory advantage to interning strings -- you only keep one copy of the string's characters in memory, no matter how many times you refer to it. That's the main reason why class file constant strings are interned: think about how many classes refer to (say) java.lang.Object. The name of the class java.lang.Object has to appear in every single one of those classes, but thanks to the magic of intern(), it only appears in memory once. The bottom line? intern() is a useful method and can make life easier -- but make sure that you're using it responsibly. The Great SwitchPosted by enicholas on June 20, 2006 at 06:02 AM | Permalink | Comments (6)I'm on vacation with my family right now. Vacation time is pretty hard for me to come by -- one of the dangers of being "essential" is that nobody wants to let you leave -- so this is a noteworthy event, made possible only by the fact that I agreed to bring my cell phone and work laptop, ensure the availability of Internet access at my destination, and remain reachable twenty-four hours a day. When we arrived, I got out my laptop and booted it up to check my email. It got as far as showing a blank Windows desktop and then... sat there. Uh-oh. I spent a while fiddling with it, but sadly when your machine won't even boot into Safe Mode and you have no other bootable disks with you, there really isn't much you can do. So here I was, stuck without a functioning computer, when having a functioning computer and Internet connection was part of my vacation deal. A whole week without being able to check email, or read my webcomics, or being able to post blog entries... a whole week without Internet access of any kind. I don't think I can take that kind of punishment, so I did whatever any true geek would do: I used this situation as an excuse to buy a new computer. I (a long-time Windows user) had been lusting after the new MacBooks for quite a while, and my wife was well aware of this. She was also well aware that Fathers' Day was just around the corner, and, well, to make a long story short I love my wife very much and I'm typing this on my new 13" MacBook. Obviously I'm not the first Java programmer to realize that a Mac is pretty great Java environment. When I was at JavaOne, I was shocked at the number of Mac laptops being toted around -- it seemed like every other system was a Mac. But after setting my system up, installing Eclipse, and getting to work on it, I really don't understand how I managed to put up with Windows for so many years. My Mac runs all of the software I need, Java programs run as smooth as silk, and (despite having theoretically less power) it feels faster than my most powerful Windows system. I could spend all day babbling about all of the things I love about it, but one thing is certain: I'm not going back. Oh, and the Windows laptop? I decided to leave it on for an extended period of time, and checked on it periodically. After eight hours, there was still no change, so I went to bed. When I woke up in the morning, I saw that it had actually managed to finish booting. So after somewhere between eight and sixteen hours of sitting there, it finally got to the desktop. I realize that this is pathological -- when your computer takes more than eight hours to boot, something is clearly screwed up and I can't just say "Ha! Windows sucks!", but I sure feel like saying exactly that. I was eventually able to fix it by disabling some startup items... but hey, I got a new Mac out of the deal. Thanks for dying, work laptop! JAXX: new version, long-term plansPosted by enicholas on June 12, 2006 at 08:43 AM | Permalink | Comments (5)(For an introduction to JAXX, start here.) First things first: JAXX 1.0.1 is finally out. This version contains a lot of bugfixes and significant improvements to the quality and size of the generated Java code. Download it here. Now that the major 1.0 bugs are fixed and a solid baseline has been established, I'm making plans for the future. Where is JAXX headed? What's next? I've posted a first pass at the JAXX roadmap and am seeking feedback. It's still early and subject to change, and there will be a lot more detail added as time goes on -- but I think it's a fairly decent stab at where things are headed. I'm particularly excited about the addition of animation, based on Chet Haase's Timing Framework. The first animation features are going to be simple and straightforward, based on the current CSS pseudoclasses. Right now you can use a pseudoclass to, say, make a label turn blue when moused over:
<style>
#hoverLink:mouseover {
foreground: blue;
}
</style>
<JLabel id='hoverLink' text='Mouse over to turn me blue'/>
This effect is applied instantly -- the second the mouse enters the label, it turns blue. The initial animation features will allow you to have effects like this be applied gradually over time:
<style>
#hoverLink:mouseover[duration=500ms] {
foreground: blue;
}
</style>
<JLabel id='hoverLink' text='Mouse over to turn me blue'/>
Note the [duration=500ms] on the pseudoclass. There will be other properties for controlling acceleration, deceleration, and perhaps other features of the animation. This a simple change, to be sure, but I don't want to go overboard yet. More dramatic animation features will be added in good time. What else is going on with JAXX? You'll have to take a look at the JAXX roadmap -- just be sure to let me know what you think! Mnemonic MagicPosted by enicholas on June 05, 2006 at 10:18 PM | Permalink | Comments (20)Swing's mnemonic system is based around two properties: mnemonic (or displayedMnemonic) and displayedMnemonicIndex. They're powerful enough to do everything you need, but then again, so is machine code. There are a number of problems and limitations with the skeletal mnemonic support built in to Swing. The Problems
Because of these annoyances, the unfortunate fact is that most Swing programs (at least among the ones I've seen) don't actually use mnemonics at all. That's sad, especially when you consider that other toolkits don't seem to share this aversion for mnemonics. The SolutionThe solution I propose is twofold. First, combine all three properties into a single value. Second, eliminate the need to specify mnemonics at all in most cases. Combining all three properties is quite easy. You just need to embed the mnemonic and mnemonicIndex information into the label itself. Before: action.saveAs.name = Save As... action.saveAs.mnemonic = A action.saveAs.mnemonicIndex = 5 After: action.saveAs.name = Save _A_s... I chose to use a pair of underscores surrounding the mnemonic character to identify it, as opposed to most toolkits which use a single escape character. Windows, for example, would have specified the label as "Save &As...". The advantage of the underscore encoding is that there is essentially no chance of ever "accidentally" specifying a mnemonic character, whereas you might legitimately try to use an ampersand in a control, which in Windows would lead to an incorrect mnemonic. Being able to specify the mnemonic character in this fashion carries a lot of benefits. Because it's a single value, specifying it in properties files is much easier, internationalization is much easier, and it's impossible to accidentally have a mismatch between the index and the mnemonic character. While this is much easier to deal with than three separate properties, it doesn't solve some of the other thorny problems, like trying to prevent duplicate mnemonics. The rest of the solution is automatically assigning mnemonics. This is easier than it sounds, because we tend to follow certain heuristics when assigning mnemonics to actions and labels, and we can just turn those heuristics into a program. The algorithm I use is as follows:
So my framework automatically assigns mnemonics to all actions (and specified components) based on these rules. 99% of the time it picks the same mnemonic you yourself would have. If it doesn't do what you want, you can manually specify it using a pair of underscores around the character in question. You can also force it not to choose a mnemonic at all by putting two underscores in a row at the end of the string. This makes translators' lives far easier, because they can generally just not worry about mnemonics and let the program "do the right thing". Furthermore, my framework has automatic error checking and will, if assertions are enabled, throw an AssertionError when a menu or dialog contains duplicate mnemonic characters. Unfortunately...There are some other details, of course, like the API calls necessary to actually work with this framework, but they aren't relevant because I can't release the code to the public. It's part of a proprietary application which my employer owns the rights to, so you'll just have to use your imagination. Fortunately the code itself is relatively straightforward -- you could easily duplicate this setup if you wanted to, and probably save yourself a lot of time overall (if you're working on a big application). There is hope, however... JSR 296JSR 296, "Swing Application Framework", aims to (among other things) define a standard way of representing and managing Actions. My hope is that, as part of this, JSR 296 will include a better means of managing mnemonics than having to specify three properties individually. At the very least I'd like to see the mnemonic be able to be embedded directly into the string (as in "Save _A_s...", "Save &As...", or something equivalent), but trust me when I say that the automatic mnemonic management is incredibly nice also. Considering that I have a seat on the JSR 296 expert group, I will definitely be pushing for some sort of solution to these issues. I haven't actually discussed this with anyone yet, though, so maybe they already have an even better solution in mind (yay!) or have decided that this issue isn't worth pursuing (boo!). It's also entirely possible that I'm the only weirdo that considers this a significant issue in the first place. JAXXIf you've used my JAXX framework, you may be a little surprised about this entry, considering that JAXX doesn't do automatic mnemonic management or allow you to embed mnemonic markers directly into the label. That was a deliberate, albeit painful, decision, and it comes back to JSR 296. Given that there's eventually going to be a standardized Swing application framework, I'm taking a wait-and-see attitute, carefully avoiding doing anything in JAXX which might conflict with the Swing framework-to-be. If JSR 296 does define a standard way to identify mnemonics, I'll use the same syntax. And if it doesn't, I'll do it my way. Regardless of the outcome, I expect that JAXX will eventually support this sort of mnemonic magic. What do you think?So, what do you think? Do you agree that Swing's approach to mnemonics could use some improvements? Want automatically managed mnemonics? Hate the idea? Like being able to specify mnemonics directly in the string, but don't like the syntax? Or am I just altogether crazy? | ||
|
|