new

Created 24th February, 2008 06:31 (UTC), last edited 24th February, 2008 07:36 (UTC)

I just love it when people rediscover advice that they could have had much earlier, had they only been aware of the prior art in the field.

More language features revisited, Ted Neward

What isn't to love about that?

The matter occupying Ted has to do with the use of new and constructors in the statically typed object-oriented languages¹ [1He lists C++, Java and C#/VB.NET as the “canonical O-O languages”, which seems odd to me. Isn't Smalltalk the canonical OO language? I guess he missed “statically typed” out.].

What Ted was talking about was a quote by Chris Falter in "New" Statement Considered Harmful.

In his excellent podcast entitled “Emergent Design: The Evolutionary Nature of Software Development,” Scott Bain of Net Objectives nevertheless makes a strong case against the routine use of public constructors. The problem, notes Scott, is that the use of a public constructor ties the calling code to the implementation of Foo as a concrete class. But suppose that you later discover that there need to be many subtypes of Foo, and Foo should therefore be an abstract class instead of a concrete class—what then? You've got a big problem, that's what; a lot of client code that has been making use of Foo's public constructor suddenly becomes invalid.

I'm not sure that I really get this argument at all, and as a library writer this sort of issue is something that concerns me greatly. The reason why I don't get it is that even though Foo is a concrete class, the right way to think about it is as an interface, but not quite the Java idea of one.

In our design of Foo we have already created a contract with the client code that uses it which includes the method of construction (and more subtly the expectations of the language we are implementing in). If we find that we need a more complex implementation that uses sub-classing it would seem that we need to break that contract, but is that really the case?

Here is the code that Chris suggests that we end up with:

public class Foo
{
  [Obsolete("Do not use--provided only for use by XmlSerializer.  Client code should call Foo.Create().")]
  public Foo() {}

  public static Foo Create() { return new Foo(); }
}

The problem with this is that it forces the user of Foo to use a non-idiomatic construction method. Here is an alternative way² [2I'm very new to C#, so there's probably syntax errors here, but you should get the idea.]:

class FooImplementation {}

public class Foo
{
  private FooImplementation  m_foo;
  public Foo() { m_foo = new FooImplementation(); }
}

This gives exactly the same effect as does the indirection through Create in Chris' example, but now the user of Foo doesn't need to know anything about it. Maybe there is some Java or C# specific reason why this doesn't work well in those languages, if so what is it?

In C++ there are two common idioms that are both variations on this technique: the pimpl idiom and smart pointers. The difference depends on whether you want to expose the hierarchy or not.

I think when we design library APIs it is fine to force users to do slightly unconventional things to use the library, but only when they are doing something that really is unconventional. We shouldn't force them to do so just because we're afraid we might have to change an implementation later.

Really the library should be as simple and obvious to use as possible, and if this complicates your job as a library author then so be it. You should be moving complexity into your library and keeping it there rather than forcing your users to share it, and although this is especially important in libraries it is also true for application code.


Categories: