General musings on programming languages, and Java.

Wednesday, July 12, 2006

Duck Typing in Java, and no reflection

interface CanQuack
{
 void quack();
}

interface CanWalk
{
 void walk();
}

<T extends CanQuack & CanWalk> void doDucklikeThings(T t)
{
 t.quack();
 t.walk();
}
You can pass anything to this method that implements CanWalk and CanQuack. Of course, this is optimally flexible when you have one method per interface, but that's not a problem. I can easily see the dependencies of doDucklikeThings, whereas if I had a larger Duck interface, e.g.:
interface Duck
{
 void quack();
 void walk();
 void eatAFish();
}
I wouldn't be able to tell by looking at the signature of a method that used Duck, whether it would call eatAFish. This works well for reducing coupling, and would probably be better than this Proxy-based attempt. There is no runtime cost, thanks to type erasure. It's rare that someone thanks Sun for type erasure, it seems, but I have got to grips with generics fairly well, thanks to Angelika Langer's excellent generics FAQ, and I find it very useful. I have applied this technique to a lot of the 20kloc program that I work on, IPSim (a network simulator), but I am still in this process. I hope you find this useful, or give me some damn good reasons why it isn't!

Thursday, July 14, 2005

Eclipse 3.1 User Experience

I gave up using Eclipse in favour of vim and ant some time ago, mainly because I did some work from home, on a 233MHz machine (my faster personal machine was stolen last year), and Eclipse was too slow to be useful there. But now I came across a bug in a unit test, and I can't figure out how to write a unit test to find that bug, so I have to do some debugging. Not having Eclipse installed, the first thing I did was launch jdb and type help, which wasn't too 'help'ful. I googled for how to use jdb, and only found a site that seemed inaccurate or out of date. I had a play with ODB (Omniscient Debugger), but couldn't get it to instrument all my classes, just the particular one I was running. So, I'm back with Eclipse, a fresh download. My first thought is that it seems a bit easier to start up, I don't seem to have to tell it on the command line where to put its workspace, it has a nice dialog. I go to Project->New Project and it has an entry for creating the project from an ant build.xml. I'm staggered. So I go about it and it seems to understand the build.xml properly. Eclipse then decides that I've got 100 syntax errors, merely because I haven't told it that I'm using Java 1.5. Let me check that build.xml.. hmm, I didn't have a source="1.5", but the ONLY compiler available on my system is the 1.5 compiler, so Eclipse could easily have detected that and just moved on. The Quick Fix for the first error seems good though - change workspace compliance and JRE to 5.0, or change project compliance and JRE to 5.0. I select workspace. So Eclipse rebuilds and gives me the following warning: taskdef class edu.umd.cs.findbugs.anttask.FindBugsTask cannot be found Back to the build.xml.. etc. I can't see how Eclipse could fail to find that, seeing as ant can. But hey, maybe if I go to Quick Fix I can tell Eclipse where the findbugs task is. Hmm, Quick Fix is greyed out. Thankfully, that's just a warning, so I'll try to ignore this annoyance and continue with my work. All the other warnings seem to be pretty innocent, unused imports, etc. It does seem that Eclipse is hiding some warnings though, as the errors before and the warnings now list exactly 100. Maybe 100 is the limit. I hope it isn't hiding any important warnings. Eclipse seems to italicise my static import of netsim.java.lang.Assertion.assertTrue, which seems like a nice little feature. On further use of the debugger, I see that it is italicising all static methods, nice. Well, I found my bug, mainly that two parameters were the wrong way around, and I've exited Eclipse. I'll still be using vim and ant, but I will keep Eclipse around for its debugger. The build.xml parsing is very handy, but not perfect. I hope Eclipse can improve this. I'll still try other debuggers, but ODB left a sour taste in the mouth - poor documentation. I should have blogged that user experience. Maybe the next one.

Saturday, April 09, 2005

A new design pattern (Farm) and a nifty use of annotations.

It struck me that a difficulty with using interfaces and factories in Java is that you need to know which factory goes with which interface. A naming convention can help here, but it might not be consistent. Instead, I suggest that you annotate your interface, to know about a default implementation. This immediately brings up "Interfaces shouldn't be bound to their implementations!!! This is unpure, evil code!!!". When you are navigating code, trying to find implementations for a particular interface can be annoying and time-consuming. I have set out here the most cohesive way I can think of for finding out which class to use as a default implementation when all you have is an interface. It doesn't 'bind' the implementation to the interface. It neither 'binds' nor mentions the implementation. The interface 'knows about' a factory. I experimented with non-annotation ways of doing this, such as static blocks in interfaces, xdoclet-based solutions (well, I thought about xdoclet), but I decided they were all ugly. I think what I have is the most elegant but pragmatic way. Time for some code. @DefaultFactory(BlobbyFactory.class) interface Blobby {         void doSomething(); } This says that BlobbyFactory is the default factory for the Blobby interface. So when you want a Blobby, you instantiate BlobbyFactory and call its newInstance method. As a convenience, I wrote a Farm class that you can use as follows: Blobby blobby=(Blobby)new Farm().newInstance(Blobby.class); The reason newInstance is not a static method is that you may wish to override the default factory, in some part of your application. So the unit testing part of your application might want a mock object instead of whatever BlobbyFactory gives you (actually a BlobbyImplementation in this case). Farm farm=new Farm(); farm.setFactory(Blobby.class,new MockBlobbyFactory()); then elsewhere: Blobby blobby=(Blobby)farm.newInstance(Blobby.class); In effect, a Farm is a Map with some nice methods for abstracting the rubbish away, and for using annotations when there is no map entry. The code is all available at http://lavender.cime.net/~ricky/farm.zip To build just what you need for using it, run 'ant farm.jar' and farm.jar will be produced. It's released under the BSD licence, because I want you to be able to use it. If there is some problem with my licence choice, let me know. To build an executable example jar, run 'ant farm-example.jar' and farm-example.jar' will be produced. The ant build is not very advanced, so you can work out how to do it using just javac if you don't want to use ant. javac com/rickyclarkson/farm/*.java com/rickyclarkson/farm/example/*.java java com.rickyclarkson.farm.example.Main should work, but I haven't tested that. (Use ant!) This isn't just a Java design pattern, I've also implemented it in C just for fun. Yes, I have a strange idea of fun.

Wednesday, April 06, 2005

Requirement Orientated Development

For a long time I have thought that most software solutions are too far removed from the problem they attempt to solve. The simple answer seems to be to identify the use cases and base the system around those. However, normal software development seems to move away from the use cases, so I have created a new development model, called Requirement Orientated Development, or ROD, which aims to make the use case part of the code. A system consists of a number of UseCases. Each UseCase has a number of Actions which can take inputs and give outputs, and can do some processing. A UserInterface (e.g., ServletUserInterface, SwingUserInterface, AtmUserInterface, UnitTestUserInterface) works out the possible Actions at any particular time and gives the user those to choose from. I have not yet dealt with use cases which can loop, and branching is done with duplication, so it is still quite naive, but I aim to make this progress. Am I reinventing old concepts, simplifying matters too much, or have I come across something worth following up? Let me know your thoughts. I'll post some code in another blog post sometime.

Monday, October 11, 2004

Lame Java Benchmarks - Freeing Memory

Someone said that Java doesn't free up memory to the OS during a program's execution, so this is a simple test of that assertion.

import java.util.ArrayList;
import java.util.List;

public final class Main
{
        public static void main(final String[] args) throws InterruptedException
        {
                allocate();
                System.out.println(Runtime.getRuntime().freeMemory());
                System.gc();
                System.out.println(Runtime.getRuntime().freeMemory());
                System.out.println("Here");

                Thread.sleep(60000);
        }

        private static void allocate() throws InterruptedException
        {
                List list=new ArrayList();

                for (int a=0;a<5000000;a++)
                        list.add(new Object());
        }
}           
The output of running ps aux repeatedly on Linux while this is running shows that the garbage collection never has an external effect. The output of the program is simply : 6207736 66317488 Here This demonstrates that the garbage collection is happening.

Blog Archive

About Me

A salsa dancing, DJing programmer from Manchester, England.