Alex headshot

AlBlue’s Blog

Macs, Modularity and More

10 things I hate about Eclipse

2006, eclipse, rant

Following on from my recent piece on "10 things I hate about Mac", I give you "10 things I hate about Eclipse" (ideas which will be reminiscent of this thread on www.eclipsezone.com) in no particular order:


  1. It's not a proper Mac application. A Mac app should be fired up by a single program; the Eclipse app is actually a call to the eclipse launcher, which in turn fires up the Eclipse program. This causes all sorts of issues (for example, running AWT and Eclipse is problematic because Eclipse refuses to listen to AWT events on the thread it should do) which mean that it is definitely not a well behaved program. Normally, with a Mac app, it should be possible to double-click it a second time and have it take you back to the open program; with Eclipse, it starts up a new application each time. It also means that some features -- like dragging a file over the .app icon -- aren't available.

    The program layout is entirely non-Mac like either; because of the inflexible build process, there has to be a file called eclipse in the root directory (which is why you see that next to the Eclipse.app) Totally unnecessary on a Mac, but the Eclipse release team demand that it be present. They don't even get the MacOSX SWT example right:

    Spot the difference
    Mac Java guidelinesSWT example
    The directory layout should look like this:
    YourApplicationName.app/
        Contents/
            MacOS/
            Resources/
                Java/
     ...
    Copy your Java .jar or .class files into /Contents/Resources/Java/
    
    SWTHello.app/Contents/Info.plist
    SWTHello.app/Contents/Resources/swthello.icns
    SWTHello.app/Contents/MacOS/swthello
    SWTHello.app/Contents/MacOS/SWTHello.class
    SWTHello.app/Contents/MacOS/swt/libswt-*.jnilib
    SWTHello.app/Contents/MacOS/swt/swt.jar

    Lastly, no other Mac universe in the known world (even before, when it was NeXTstep) ever, ever used a shell script in the .app launch file. It's frankly embarrassing.

  2. It turds files over the application install directory. This is completely contra to almost every operating system's guidelines, who already have areas set aside for user-specific documents (e.g. ${user.home}). Even with recent builds, Eclipse still feels the need to generate a configuration directory that it uses to store a global pointer of the user-specific location that hosts the workspace. And although it can contain references to the @user.home, if one were to change that in the default install then all users would suddenly be moved to that different location. OK, so it doesn't create one if it can't have the rights to create files in that directory; so why does it feel the need to create one just because it can?

  3. The scrapbook page is both brilliant and pants at the same time. It allows people to 'try out' code semi-interactively, so it's great for testing methods and the like. However, it insists that you save the result to a file before you can run it. Why? I'm trying out code, not saving it for posterity.

    Granted, there may be times when I want to save it as a file in order to recreate testing work later, but most of the time I just want to experiment with something before copying it into a class. It's just completely unnecessary to make me save it; after all, the file gets translated on-the-fly to a temporary class, so the temporary class will almost certainly be generated somewhere, right? Why can't it use that instead?

    And what's up with having to select text before you can run it? There's five lines of text there. I want to run them all, dummy. And don't get me started with the frigging error messages; when has a non-interactive compiler or interpreter ever (in any other language, any other IDE) decided to mix the error results in with your source code? It's not like it's impossible to show a dialog, or have a split screen, or even printing it to the console.

  4. SWT and memory management. There's an argument that if you encourage developers to work in a good way, then they'll follow that later. dispose()ing of resources when you've finished with them (or using an appropriate resource manager) is encouraging things the good way. However, if you don't dispose them, they'll just eat up more system resources until you finally run out of memory.

    It would seem sensible then, to write a finalizer that ensures should a SWT widget be garbage collected before the system resources are disposed, that the dispose() method is called automatically. Apparently not. If you've been smoking what Joshua Bloch is smoking (he who doesn't know how to implement an equals method and who doesn't think size should be getSize() because no-one uses JavaBean conventions) then there's this bizarre set of circumstances which means that you can't guarantee finalization. The argument goes something like: "We can't guarantee that the finalizers will not be called, so because we can't guarantee that it will always happen, it's safer for it never to happen". In particular, they can't guarantee that the finalizers will be called in a timely fashion (i.e. they may be late) or that they won't get called when the VM shuts (yes, I know, unless you set System.runFinalizersOnExit(true)).

    But let's face it, at best finalize() is a helper method that can help to do certain things (closing a file, for example) if it is called. Arguing that it might not be called as a reason to not implement it is like arguing that because you can't save everyone's life with medicine, it's safer not to give anyone any medicine but teach then to live healthily. The code example of why it shouldn't be called is also spectacularly bad; rather than checking whether the resource has already been disposed first, they litter the UI queue with requests for disposal. It's not like a call to isDisposed() needs to be synchronised in the UI block. The code doesn't even compile because they've forgotten about the throws Throwable declaration. Here's how it should look:

    protected void finalize() throws Throwable { // remember to throw Throwable
      if(!isDisposed()) {
        display.syncExec(new Runnable() {
          public void run() {
            if(!isDisposed())
              dispose();
          };
        });
      }
      super.finalize(); // call it at the end, not the beginning
    }
    

    If you think this is a no-brainer, add your comments to bug 123765, but don't hold your breath.

  5. PDE manifest files. Although Eclipse is getting buzzword compliant (OSGi enabled!) the decision to move to OSGi isn't a great one. (It's not even as if OSGi stands for anything any more; if you read their FAQ the OSGi alliance is recursively defined as members of the OSGi alliance.) The Manifest file format is underspecified (for example, the Java Manifest.MF is limited to 72 characters per line; did you know that? I bet that the Eclipse Manifest.MF doesn't obey those limits) and there are some weird issues reminiscent of Makefiles (a leading space indicates that the line continues from the previous one but is trimmed off -- in other words, if you want to have a separate space-separated entry on different lines, you must have a trailing space. That's why if you edit Manifest.MF files by hand, a Java runtime engine can complain that it can't find xerces.jarxalan.jar; because it's stripped off the leading spaces and there's no trailing space on the xerces.jar line.

    Manifest files are also pretty bad at being processed by computer; there's no standard parser for them, and the syntax is so loose that you aren't even guaranteed to have the same behaviour with different devices. Does anyone know of any other systems that use OSGi manifest files, other than Eclipse-related projects? And to think all this information used to be in nice, easily understandable and parseable XML files. Heck, you could even set up automated build tools to process the plugin.xml files to automatically generate an ant build file...

  6. Launch configurations. Most IDEs have a single click to launch and run your program. Eclipse requires you to have two clicks (to set up a default launch configuration) after which you can revert to a single click to re-run it. It's not that the idea of launch configurations is bad -- sometimes they can be very useful, for example, if you need to set up Java properties or add extra Jars to the classpath. However, these properties/jars are specific to that launch configuration, so if you've got another main() method in the same project, you have to duplicate your work.

    Worse still, the menu is pretty horrible; it doesn't matter which file you have open, clicking on the run icon Eclipse run icon will run the program that you ran last time. This is a classic problem for novice users, but perhaps a useful feature of larger systems (where you tend to be editing implementation details deep into a system and doesn't have a main() method). But what about figuring out that if the open editor is runnable (has a main() method, or whatever else determines runability, like a JSP or Servlet) then that one is selected instead? And what's with the Run->Run... menu item? And have you noticed that essentially the Debug->Debug... menu is identical, and that both the Run... and Debug... menu items result in the same dialog? What about having one menu option for managing launch configurations, and provide a 'Run' or 'Debug' button on the launch configuration dialog? To be honest, the idea of launch configurations is somewhat specific to a single executable. It would be much better if there was a launch environment (e.g. a server, or a set of pre defined properties/Jars) that you could simply select to run a main() method in. That way, multiple main() methods could share the same environment and properties.

  7. UTF-8 encoding. The world has decided that the concept of 8-bit character sets derived from ASCII or otherwise are passé. We've had a universal character set since before the start of Java (over 10 years ago) and it's even become the internal lingua fran&cedlia;a of Java programs. (Sadly, languages like Ruby and Pyhton are less well integrated, but even they can support UTF-8.)

    The UTF- encodings can be used regardless which country or which operating system you happen to be using at the time. All major versions of operating systems support UTF- in their editors, and it's trivial to convert between UTF- and obsolete character sets. Not only that, but the majority of documents at present exist solely within the ASCII space which is a strict subset of UTF-8 in the first place. As such, not only are programs written with Eclipse unnecessarily tied down to the operating system on which they are developed, they are also unnecessarily tied down to the region as well. Especially since Eclipse's customer base is world-wide, and development in shared servers global, this is a fundamental mistake. It's not even possible to reliably represent accented characters in standalone RCP applications either; instead of taking UTF-8 as the default, it adopts whatever OS/Locale you happen to be sitting with. If you think this is a fundamentally stupid mistake, vote for it to become one of the higher ignored bugs list.

  8. Bugs in Bugzilla. Whilst I appreciate that any product has bugs in, and that there are only so many fixes that can be done in a given timescale, Eclipse seems to have a tendency of ignoring bugs at inopportune times. For example, during the final few milestones of Eclipse, the bug fixing frequency tends to increase as the quality becomes polished. However, people are busy reporting (and fixing) bugs in code that's just been developed rather than necessarily going through the old bug reports. And if you suggest a new feature -- even if it would be a stunningly good addition to the project -- then it's more than likely to get closed RESOLVED LATER if it's reported in the last few cycles.

    Unfortunately, whilst RESOLVED LATER is technically a non-terminal state, there's very few bugs that make it out of this state and into a reopened state. And for pity's sake, don't file a bug that would have a really useful enhancement in the last six or so milestones/release candidates of Eclipse. All that will happen is that it will get closed RESOLVED LATER, and every single person who files that bug against the newer release will just have the bug closed RESOLVED DUPLICATE (without even considering the possibility of reopening the original bug). In other words, filing a bug enhancement in the dying stages of an Eclipse milestone is about as good as you'll ever get to ensuring that functionality never gets implemented in Eclipse. (I expect that Netbeans fans will find a way to drive home some kind of advantage.)

    Here's a hint: RESOLVED LATER is a synonym for RESOLVED NEVER. There's also the classic responses to bugs that would otherwise make Eclipse a better place (e.g. the addition of subversion support into the base install of Eclipse), following the new and improved WAGNI agile principle. (That stands for We Aren't Going To Need It.) If the Eclipse committers can't see themselves using it, it's not going to get past the front door. That's probably why other bugs don't get closed, like UTF-8; after all, they just use Windows with a US codepage.

  9. Lack of detailed documentation. The amount of documentation is definitely not a bad thing in Eclipse. However, the detail sometimes leaves a lot to be deserved. The API often tells you what the parameters are, but not what they're supposed to represent or how they are used. Granted, you can't have a tutorial for every class, but they're not always easily understandable as to their purpose, and the JavaDoc for methods are often only one-liner. What's worse is there are methods like new Label(int style, Shell shell); the possibilities for the 'style' flag are enormous (SWT, which holds most of them, has over 350 constants defined).

    Then there's the IAdaptable pattern that's used extensively (which I've written about before). Although it's a great way of providing flexible extensivity in a strongly typed language like Java, the documentation of what adapters the class supports is minimal at best. And despite having a global registry of adapters (hosted by the platform manager), there's a lot of objects that don't delegate to it (like the Navigator, for example) which makes it next to impossible to override to provide certain features.

  10. Update sites and features. Eclipse has a wonderful mechanism for distributing updates to your application. However, there are parts that the update manager can't reach; for example, it can't handle the launcher that's used to kick off Eclipse in the first place, or anything else outside of the plugins/ or features/ directories. That means that the update manager can't be used to upgrade from previous versions of Eclipse (which in itself isn't necessarily a bad thing, but it does mean that it's really only useful for distributing minor updates).

    However, even though the update manager has existed since the early days of Eclipse, there are very few uses of it in the real world. Even most of the other sub-projects hosted at Eclipse (e.g. BIRT, CDT, WTP etc.) don't have update sites, but instead either provide full zip files for you to download or have a folder that 'you can unzip into your plugins directory'. About the only Eclipse use of update sites is the Eclipse install itself -- and even that's screwed up recently, thanks to the fact that Eclipse changed update URLs in the middle of a release cycle. If you've still not upgraded to 3.1.2 because your software updater can't find it, it's because you were using the URL that came from the original feature that got it in the wrong place. You need to add http://update.eclipse.org/updates/3.1 in order to see it.

    However, one of the reasons that it's under utilised is that there's so many hoops to go through that it's far easier for people just to offer a zip file. For example, if (as a small developer) you create com.cool.plugin_1.0.0, and want to let others download it, is it as simple as just uploading it to a website? No. You have to create a feature (com.cool.feature_1.0.0) which contains a pointer to the plugin, and then you have to create a site.xml that contains a pointer to the feature. (Oh, and if you want extra information to be displayed about your feature, you have to have com.cool.feature.plugin_1.0.0 as well.)

    It's not like this extra series of steps has any particular use for a small developer, but there's not even any real reason to have them for larger installs either. Every plugin (bundle) has dependencies on other plugins (bundles). So why do we need something else to tell us what to depend on? We even need a master 'branding' plugin to do anything useful with a feature, in any case; so why not combine the concept of a plugin and a feature into one plugin-feature type. It could even be called a plugin. After all, Eclipse is a highly extensible architecture for managing plugins, isn't it? Why not have everything as a plugin?

    It's not as if features even give anything useful to the environment; we've had capabilities for ages (which, incidentally, can be turned on or off) so in a feature-less world, we'd have our 'master' plugin that defined all the dependencies, the branding, and the capabilities that this plugin set created.

    Of course, there would be some changes; for a start, the update manager would change from listing features to listing plugins. But that would be beneficial too; you could easily see which individual plugins there were updates for, instead of having to download feature updates all the time. It would aid smaller shops that don't care about features (but they just want to contribute plugins) and there wouldn't be any issue for the larger developers, who'd still be shipping the branding plugin that is so intimately involved with the feature.

    You could even go one step further; instead of requiring the directory structure to be 'eclipse/features' and 'eclipse/plugins', you'd just tell it where the plugins directory was. None of this crap with generating extension locations (how crazy is it that in order to use plugins from somewhere else -- say, a user's ~/Library folder -- that you have to:

    • Create a directory called eclipse (no, it *must* be called eclipse -- you can't call it anything else; after all, it's free advertising, right?)
    • Create an empty directory called features and one called plugins, even if you don't want to store features there
    • There must, absolutely, positiviely has to be, so important that it couldn't possibly work without it; a file called .eclipseextension. What type? It doesn't matter. Doesn't have to be anything. Can be a zero-byte file that you create with touch. But this is the fundamental key in the puzzle that is Eclipse repository locations. Clearly, there's something deeply wrong with the JVM that it couldn't possibly operate unless an empty file with a specific name exists.

    But seriously, get rid of the features, and everything -- and now, everything -- is a plugin. You can then define a plugin path that allows you to search for plugins, so if you wanted to try and use the latest-and-greatest of a particular product (but wanted to be able to remove it easily) then you could just add any directory, no matter what it was called and how many zero-byte magic files were or weren't in there, to your Eclipse startup. People could even pass in command line parameters that specified what the plugin path was called. Heck, you could even call it PLUGINPATH and set it up as an environment variable. (Sun graciously finally decided to put System.getenv() back in after five years absence (and four years 354 days after people started complaining about it), because everyone wrote their own implementation as soon as they took it out.) Heck, you could even start following OS conventions and automatically prepend ~/Library/Application Support/Eclipse/Plugins on the PLUGINPATH.

I know it sounds like I've got a lot against Eclipse. I haven't, really. These are things that have annoyed me (at varying levels of irritability) for some time, and it would be so nice to get them fixed. Of course, I'[m just as guilty; I'm capable of fixing most of these problems myself, but I haven't authored any code myself in Eclipse (perhaps other than a bug fix here and there). So I'm volunteering to fix these problems. It will take me a while, and I'm guessing that a lot of it won't be supported by Eclipse, but I'll make all the changes freely available and provide the source/binaries for stuff that I have changed that's not incorporated into Eclipse. I just can't promise a timetable right now; but I've been looking for the next challenge in life, and this could be it.