Tuesday, April 25, 2006
Book 13: The Algebraist (Banks)
More Banks! This is one is, again, the best Banks I've yet read. Am I just getting lucky order-wise, or is he getting better? This one seems not to be a Culture novel, but it includes humans in space. The Dwellers were very funny.
Book 12: Bel Canto (Patchett)
South American revolutionaries crash a Japanese industrialist's birthday party and hold everyone, including the entertainment, hostage. Things develop.
Very very good.
Very very good.
No Such Interface (E_NOINTERFACE)
Last week, my COM server (C#, VS2005) stopped working. The client call to "CoCreateInstanceEx" started throwing a "No Such Interface" exception (E_NOINTERFACE) on a class that had always worked before. An old DLL (thanks Dan) still worked. Probably not coincidentally, the COM server also stopped working on Dan's machine.
I tried backing out some recent OS upgrades, without success. (It's possible that the backouts didn't work.) I did lots of web searches, without success.
I tried rebuilding the server one piece at a time, and found that the problem came from an XSD-generated class. My COM server sends WebService requests defined by an XSD file and I had used the VS2005 'xsd.exe' utility to generate C# classes represeting the WebService message structure. Simply including this file in my VS2005 project resulted in a DLL that caused the "No Such Interface" exception. So I commented the whole generated class and used the compiler to tell me which parts to uncomment (a tedious process). Luckily, it turned out that this fixed the problem. So there's something in the commented-out schema-generated class that's causing the exception. Or, conceivably, maybe the sheer size of the generated class is a problem, although it's "only" 14K lines or so.
Chalk this one up to "I don't know why it broke, but I found a workaround."
I tried backing out some recent OS upgrades, without success. (It's possible that the backouts didn't work.) I did lots of web searches, without success.
I tried rebuilding the server one piece at a time, and found that the problem came from an XSD-generated class. My COM server sends WebService requests defined by an XSD file and I had used the VS2005 'xsd.exe' utility to generate C# classes represeting the WebService message structure. Simply including this file in my VS2005 project resulted in a DLL that caused the "No Such Interface" exception. So I commented the whole generated class and used the compiler to tell me which parts to uncomment (a tedious process). Luckily, it turned out that this fixed the problem. So there's something in the commented-out schema-generated class that's causing the exception. Or, conceivably, maybe the sheer size of the generated class is a problem, although it's "only" 14K lines or so.
Chalk this one up to "I don't know why it broke, but I found a workaround."
Wednesday, April 12, 2006
Test Coverage
Writing unit tests to hit a particular code coverage percentage is a sucker's game. It's very easy to write "tests" that exercise the code but don't determine whether it does the right thing. So you can get a nice high coverage number without having any good tests. This is especially tempting when you're writing the tests after the code.
Sometimes you can't exercise all the code. Or you decide that it's not important or too difficult to test. But writing tests to cover code always gives you a better coverage percentage than officially ignoring code. For example, if your test currently covers four of ten lines (40%), then ignoring two lines gives you 50% coverage (4/8), but writing tests to cover those two lines gives you 60% coverage (6/10). Not a profound insight, but there it is.
Sometimes you can't exercise all the code. Or you decide that it's not important or too difficult to test. But writing tests to cover code always gives you a better coverage percentage than officially ignoring code. For example, if your test currently covers four of ten lines (40%), then ignoring two lines gives you 50% coverage (4/8), but writing tests to cover those two lines gives you 60% coverage (6/10). Not a profound insight, but there it is.
Monday, April 10, 2006
Java Generics Note
Suppose "Circle extends Shape".
Circle is Shape: TRUE
is : FALSE
is : TRUE
A String is an Object, but an Object is not necessarily a String
A list of Strings is a list of Objects, but a list of Objects is not necessarily a list of Strings
Circle is Shape: TRUE
A String is an Object, but an Object is not necessarily a String
A list of Strings is a list of Objects, but a list of Objects is not necessarily a list of Strings
Thursday, April 06, 2006
My Singleton Stupidity
Reading Steve Yegge's article Singleton Considered Stupid made me think about a place I used a Singleton in a recent project: the Logger class. Briefly, our code uses the Logger class like this:
Logger is a pretty classic Singleton. In another recent project, I even made the "mistake" Steve talks about by making the Warning method public static, so I'd invoke the Warning method like this:
So maybe I take Steve's article to heart and decide that Logger should not be a Singleton. Perhaps because we want different versions of it. The only reason I can think of for wanting different versions is that maybe we want different implementations, like FileLogger and DBLogger. If that's the case, I guess we need an interface, a factory and an implementation, something like this:
LoggerFactory.GetFileLogger().Warning("Some warning",this);
or, more complicatedly (unless that's not a word):
Log4J is the one logging framework I know a little about. It doesn't exactly use a Singleton. I think each class that wants to do logging creates a class variable (static) of type Logger on which it calls methods like "info", "warning", etc. Nevertheless, all the logging configuration happens centrally, outside of Log4J's clients.
The other place I've used Singletons is to implement DB caches. If there's a table that changes rarely and is small (for some value of "rarely" and "small"), I'll create a Singleton to hold the contents of the table.
Logger.GetInstance().Warning("Some warning",this);The GetInstance method is public static and returns the (unique-within-the-VM) instance of Logger. The Warning method is public and non-static, but the constructor's private, so the only way to get to it (the Warning method) is through the GetInstance method.
Logger is a pretty classic Singleton. In another recent project, I even made the "mistake" Steve talks about by making the Warning method public static, so I'd invoke the Warning method like this:
Logger.Warning("Some warning",this);
So maybe I take Steve's article to heart and decide that Logger should not be a Singleton. Perhaps because we want different versions of it. The only reason I can think of for wanting different versions is that maybe we want different implementations, like FileLogger and DBLogger. If that's the case, I guess we need an interface, a factory and an implementation, something like this:
ILogger (interface)With all that code roughly defined, I think we'd now use Logger like this:
public void Info(String msg,Object requester);
public void Warning(String msg,Object requester);
...
LoggerFactory (factory)
public static ILogger GetFileLogger();
public static ILogger GetFileLogger(String logfilename);
public static ILogger GetDBLogger();
public static ILogger GetDBLogger(String connectionstring);
FileLogger implements ILogger (implementation)
public FileLogger(){
super(DEFAULT_LOGFILE_NAME);
}
public FileLogger(String logfilename){
this.theLogFileName=logfilename;
}
LoggerFactory.GetFileLogger().Warning("Some warning",this);
or, more complicatedly (unless that's not a word):
String connString=ConfigHelper.GetString("logdbconnstring");Does this seem better? It's definitely more flexible in the client code, at the cost of putting more information into the client code. The client code now knows which kind of Logger it's using (FileLogger or DBLogger), which seems wrong. We could keep the client code happily ignorant of the various types of Logger by adding a "GetDefaultLogger" method to the LoggerFactory. So, if the client didn't want to override the default logger, the client would execute something like this:
LoggerFactory.GetDBLogger(connString).Warning(
"Some warning",this
);
LoggerFactory.GetDefaultLogger().Warning("Some warning",this);This seems like the best I can do, though it looks a lot like where I started from!
Log4J is the one logging framework I know a little about. It doesn't exactly use a Singleton. I think each class that wants to do logging creates a class variable (static) of type Logger on which it calls methods like "info", "warning", etc. Nevertheless, all the logging configuration happens centrally, outside of Log4J's clients.
The other place I've used Singletons is to implement DB caches. If there's a table that changes rarely and is small (for some value of "rarely" and "small"), I'll create a Singleton to hold the contents of the table.
Wednesday, April 05, 2006
Continuations in Java
I was interested in finding out what continuations are all about and I stumbled across an article called Continuations Made Simple and Illustrated by a guy named Denys Duchier. It uses examples in Python.
Briefly, and probably mostly inaccurately, Continuation Passing Style (CPS) programming uses functions that pass their results to another function instead of more familiar (to me) functions that return values. That other function then "continues" the computation. CPS programming has been (derogatorily?) called "gotos with arguments". The Wikipedia article on continuations describes them as saving the executation state of a program for later resumption.
I wondered what continuations would look like in Java. To prepare, here's a brief summary of the example from Duchier's article.
Suppose we want to implement a function that computes 2*x+y using continuations. Further suppose that we have continuation-style multiplication and addition methods, with signatures
and
We'd define our new function (baz) as
There's some non-Java code in our invocation of the multiply method:
The purpose of this code is to create a new anonymous function (a closure, but that's a whole other topic that I need to learn about) that accepts the result of the multiply, y and the "top-level" continuation and invokes the CPS-style add method. Another way to think about it is that we're creating a new continuation, initializing it with y a c and then invoking it with z (2*x).
So how can I implement the continuation in Java? I start with a Continuation interface:
Then I create a helper Continuation class that dumps its results to stdout:
Now I'm ready to create a poorly-name Functions class that contains the CPS add, multiply and baz functions.
Note that
I think AdderContinuation is the most interesting class. It's a Continuation that you initialize with a long (
Briefly, and probably mostly inaccurately, Continuation Passing Style (CPS) programming uses functions that pass their results to another function instead of more familiar (to me) functions that return values. That other function then "continues" the computation. CPS programming has been (derogatorily?) called "gotos with arguments". The Wikipedia article on continuations describes them as saving the executation state of a program for later resumption.
I wondered what continuations would look like in Java. To prepare, here's a brief summary of the example from Duchier's article.
Suppose we want to implement a function that computes 2*x+y using continuations. Further suppose that we have continuation-style multiplication and addition methods, with signatures
long add(long x,long y,Continuation c)and
long multiply(long x,long y,Continuation c)We'd define our new function (baz) as
long baz(long x,long y,Continuation c){
multiply(2,x,lambda z,y=y,c=c: add(z,y,c);
}There's some non-Java code in our invocation of the multiply method:
lambda z,y=y,c=c: add(z,y,c)The purpose of this code is to create a new anonymous function (a closure, but that's a whole other topic that I need to learn about) that accepts the result of the multiply, y and the "top-level" continuation and invokes the CPS-style add method. Another way to think about it is that we're creating a new continuation, initializing it with y a c and then invoking it with z (2*x).
So how can I implement the continuation in Java? I start with a Continuation interface:
public interface Continuation{
public void call(long l);
}
Then I create a helper Continuation class that dumps its results to stdout:
public class PrintContinuation implements Continuation{
public PrintContinuation(String name){
this.setName(name);
}
public void call(long x){
System.out.println(this.getName()+"="+x);
}
private String theName;
public void setName(String name){
this.theName=name;
}
public String getName(){
return this.theName;
}
}
Now I'm ready to create a poorly-name Functions class that contains the CPS add, multiply and baz functions.
public class Functions{
public void add(long x,long y,Continuation c){
c.call(x+y);
}
public void multiply(long x,long y,Continuation c){
c.call(x*y);
}
public void baz(long x,long y,Continuation c){
this.multiply(2,x,new AdderContinuation(y,c));
}
public static void main(String[] args){
Functions f=new Functions();
f.add(3,4,new PrintContinuation("3+4"));
f.multiply(5,6,new PrintContinuation("5*6"));
f.baz(7,8,new PrintContinuation("baz(7,8)"));
}
}
Note that
baz's implementation computes 2*x and passes the result to a Continuation that adds it (2*x) to y and passes the result (2*x+y) to the Continuation parameter. baz's implementation uses an up-until-now-undefined class called AdderContinuation:
public class AdderContinuation implements Continuation{
public AdderContinuation(long y,Continuation c){
this.setY(y);
this.setContinuation(c);
}
public void call(long x){
Functions f=new Functions();
f.add(x,this.getY(),this.getContinuation());
}
private long theY;
public void setY(long y){
this.theY=y;
}
public long getY(){
return this.theY;
}
private Continuation theContinuation;
public void setContinuation(Continuation
this.theContinuation=continuation;
}
public Continuation getContinuation(){
return this.theContinuation;
}
}
I think AdderContinuation is the most interesting class. It's a Continuation that you initialize with a long (
y) and a Continuation and that accepts a single parameter (x in call). When called, it invokes the CPS add method, passing in x, y and the Continuation. AdderContinuation is basically a Java implementation of the Python closure lambda z,y=y,c=c:add(z,y,c), in twenty-four lines! Using this architecture, I'd have to create [function]Continuation classes for every function I want to wrap in a Continuation. So, while I can implement continuations and closures in Java, there's a lot of boilerplate code. (Steve Yegge has some interesting and funny comments on this.)
Tuesday, April 04, 2006
Book 11: Use of Weapons (Banks)
Stay away from internet discussions of this book until you've read it. It's very spoiler-vulnerable. That said, this is the best Banks I've read. Better than Consider Phlebas, maybe not quite as good as Player of Games. There's a lot more humour in this one, too. Skaffen-Amtiskaw's gift to Zakalwe is truly hilarious. I recommend it.
Windows NT Command Completion
I can't believe I've lived without command completion in NT for so long! You can turn it on by setting HKEY_CURRENT_USER/Software/Microsoft/Command Processor/CompletionChar to x00000009
Subscribe to:
Comments (Atom)