Archive

Archive for February, 2008

Virtual by default is better

February 28th, 2008 No comments

I’ve taken quite a few paradigm shifting journeys in my life. Some have been quick insights, instant moments of clarity. Others have been slow processes, spanning over several years. One such slow journey for me has been how I look upon virtual methods of object oriented languages.

Java methods are virtual by default. Unless explicitly marked as final, a method may be overridden in a deriving class.

class A {

  a() { … }

  final b() { … }

}

Class B extends A {

  // B::a overrides A::a
  a() { … }

  // Compile error, A::b is non-virtual
  b() { … }

}

C# on the other hand, takes the opposite approach. There you have to explicitly mark a method as virtual, and an overriding method must be marked with the override keyword.

class A {

  virtual a() { … }

  b() { … }

}

class B {

  override a() { … }

  // This won’t compile since A::b is non-virtual.
  // Without the override keyword though,
  // B::b only hides A::b which produces a
  // warning instead of an error.

  override b() { … }

}

In that sense C# is more expressive, and intention is better communicated with the explicit marks. On the other hand, Java is more flexible and less restrictive.

I used to favor the non-virtual by default approach. Partly because I was kind of born with it – my first OOP language was Object Pascal and Delphi – but also because I appreciate the better control as to how my components are being used. The ability to restrict polymorphism is good because usage in a way that wasn’t intended can create a lot of mess.
To give one non-obvious example, consider a library class A with a method a.

class A {

  a { … }

}

A library user decides he needs to add functionality to A, so he creates a descender B with a method b.

class B: A {

  b { … }

}

Everything works just fine, but two year later a new version of the library is released. In this new version a new method b was added to class A. Suddenly B::b overrides A::b although this was not the original intention. In a language like C# compiling class B will result in an error (since b is not virtual), but in Java and most other object-oriented languages the upgrade may have introduced a subtle bug.

My standpoint regarding virtual methods used to be that the need for control outweighs the need for flexibility, but some five years ago I started to re-evaluate that opinion. The reason was automated testing. I have slowly come to realize that the C# object model is a pain, at least when it comes to putting a piece of legacy code under a testing harness. While there are plenty of situations where sub classing is a bad idea, unit-testing is not one of them. Sub classing can be a powerful dependency breaking technique, and it allows for testing of code that isn’t otherwise testable without refactoring.

One (contrived) example:

class SpecialConnection {

  //…

  send_string(String s) {
    //…
  };

  //…
}

class SomeLegacyClass {

  SpecialConnection _conn;

  SomeLegacyClass(SpecialConnection connection) {
    //…
  }

  //…

  create_and_send_string() {
    String s;

    // some code that builds
    // the string to send

    _connection.send_string(s);
  }

  //…
}

How can I test the create_and_send_string method? Well, if SpecialConnection::send_string is virtual the answer is easy, just subclass SpecialConnection and stub out the method.

Class FakeSpecialConnection: SpecialConnection {
  Send_string(String s) {
    if (s != “expected value”)
    throw new Exception(…);
  }
}

And the test code could be like this:

SomeLegacyClass c = new SomeLegacyClass(new FakeSpecialConnection());
c.create_and_send_string();

On the other hand, if send_string is not a virtual method we must do some refactoring (like extracting an interface from SpecialConnection) before we can do testing without a real connection. One could argue that the code in the example is poorly designed, and that we should refactor it anyway. That’s true, but a prerequisite for safe refactoring is thorough unit-testing, something we don’t have at this point, which is why we’re trying to get this piece of code into a testing harness in the first place; so that we could make safe refactorings.

When it comes to testing, virtual methods means more options, better options, safer options. That is the reason why I have converted, and now value that flexibility more than I fear possible regression.

Cheers!

Categories: programming Tags:

OT: Al Gore and “The Climate Crisis”

February 19th, 2008 4 comments

Sorry for the off-topic.

I saw Al Gore on Swedish television last week. He had received the Gothenburg Sustainable Development Award and was holding a speech at the ceremony. As usual Al Gore was able to capture his audience with a mix of scaring facts and a call for action. This time he conveyed the new prediction that the arctic ice could be gone in as little as five years. While that could very well be a grave exaggeration, we can’t deny that something is terribly wrong with our climate.

Where I live, a coast town in the middle of Sweden, the rising temperature has been particularly noticeable. The first sign came in the late 1980’s when I experienced my first non-white Christmas. Now, having no snow in December has become normal.

This year, the year of 2008 – a year I’ll never forget – we have witnessed something I thought was impossible. This year we had rain in January. Where I live January is the winter month. It’s supposed to be cold and the only thing coming down from the skies should be snow. In my life, and I’ve been on this planet for 37 years, I have never experienced rain in January before. But this year it rained for ten whole days.

So what can we do? Well, Al Gore’s mantra is that “we can do something about it,” and I agree. There are definitely things I can do to reduce my share of released greenhouse gases. I can use my car much less (we have great public transportations here,) and I can, with little effort, save energy. Simple things would be a good place to start; like really turning things off when they’re not used (computers, the TV, lamps), turning heat down (human beings sleep best in 18 degree Celsius) or replacing old energy devouring machines (like our freezer from 1980).

My promise to you, my dear reader, and to the rest of the world, is that 2008 will be the year when I start to implement changes to become a more optimized human being. I will make sacrifices, my life will be less convenient, but I’ll do it happily for the sake of my children and for future generations.

My intentions are not entirely unselfish though, I expect the changes to have a significant and positive effect on my economy as well.

Cheers!

P.S. I can’t help wondering what the world would be like if the outcome of the election had been different.

Categories: off-topic Tags:

The Open-Closure-Close Idiom in D

February 13th, 2008 5 comments

In a Reddit discussion following my last post on object lifetime management in D, bonzinip wondered why the D closures aren’t used with the open-closure-close idiom that is common, for instance, in Ruby.

bonzinip: languages with closures (Ruby, Smalltalk) use them to ensure that the file is closed when you get out of scope, and that does not require new keywords and does not require to bypass GC and possibly get dangling pointers.

NovaProspekt: D actually has full closures

bonzinip: so why don’t they use them with a “try { open; run closure; } finally { close; }” idiom instead?

Well, let’s take a look at how that could be accomplished in D.

To get an image of the open-closure-close idiom, we can look at Ruby’s File class, and particularly the open method.

IO.open(fd, mode_string=”r” ) => io
IO.open(fd, mode_string=”r” ) {|io| block } => obj

With no associated block, open is a synonym for IO::new. If the optional code block is given, it will be passed io as an argument, and the IO object will automatically be closed when the block terminates. In this instance, IO::open returns the value of the block.

What this means is that a File can be opened, either in the normal way with explicit closing (begin-ensure corresponds to try-finally in D)

f = File.open("c:\\log.txt", "w")
begin
  f.puts "Log this"
ensure
  f.close
end

or with a code block (closure)

File.open("c:\\log.txt", "w") do |f|
  f.puts "Log this"
end

In this last example the file is both opened and closed by the open method, in between the method invokes the associated code block with the file object reference as a parameter (f). In essence, that is the open-closure-close idiom.

How could we do this in D? Well, as I’ve written before, D’s delegates in combination with function literals can be used to mimic the code blocks of Ruby. So, a D version of the File::open method could look something like this:

import std.stdio;
import std.stream;

void open_run_close(char[] fn, FileMode fm = FileMode.In,
  void delegate(Stream) closure)
{
  Stream f = new File(fn, fm);
  try {
    closure(f);
  } finally {
    f.close();
  }
}

and be invoked like this:

open_run_close("c:\\log.txt", FileMode.Out, (Stream f) {
  OutputStream os = f;
  os.writefln("Log this");
});

To make it a little more like the original Ruby version, let’s make it support the non-closure variant as well.

Stream open_run_close(char[] fn, FileMode fm = FileMode.In,
void delegate(Stream) closure = null)
{
  Stream f = new File(fn, fm);
  if (!closure) {
    return f;
  } else {
    try {
      closure(f);
      return null;
    } finally {
      f.close();
    }
  }
}

// Example usage
open("c:\\log.txt", FileMode.Out, (Stream f) {
  OutputStream os = f;
  os.writefln("Log this");
});

// Example traditional usage
OutputStream f = open("c:\\log2.txt", FileMode.Out);
try {
  f.writefln("Do log this");
} finally {
  f.close;
}

The open-closure-close idiom is definitely doable in D. It’s not as pretty and natural as in Ruby, but not so far from it either. Whether this particular idiom will be embraced by the D community is yet to be seen.

Cheers!

Categories: D Programming Language Tags:

Managing Object Lifetimes in D

February 7th, 2008 14 comments

The D Programming Language is a modern version of C. It adds productivity features to the performance power of C, features like object oriented programming and garbage collection.

It may seem strange that a language with focus on performance utilizes automatic memory management. A GC equals overhead, right? Well, actually that is a common misconception. These days implicitly memory managed code is generally faster than code where the programmer handles deallocations. One reason for this counter-intuitive fact is that a number of optimizations can be done by the GC, especially on short-lived objects.

But garbage collection isn’t a problem free feature. For one thing, it is indeterministic. Normally, an object that uses external resources acquires them in a constructor and releases them in the destructor.

import std.stream;

class LogFile {
  File f;

  this() {
    f = new File("c:\\log.txt", FileMode.Out);
  }

  ~this() {
    f.close;
  }

  // Logging methods goes here
}

But with a GC there is no way to know when or even if the destructor is run. This may be a problem if you’re dealing with scarce resources like window handles, or file locks. So how can we control object destructions in a GC capable language? One possibility is to trigger a GC sweep explicitly in your code. In D this is done with the fullCollect function.

import std.gc;

fullCollect();

Explicit trigging of garbage collection is usually a bad idea, for several reasons. For one thing, it’s like killing an ant with a bazooka, and still you risk missing the target. Therefore, the normal approach to deal with the problem of indeterminism is to use a dispose method.

class LogFile {
  File f;

  this() {
    f = new File("c:\\log.txt", FileMode.Out);
  }

  ~this() {
    dispose();
  }

  void dispose() {
    if (f !is null) {
      f.close;
      f = null;
    }
  }

  // Logging methods here
}

LogFile log = new LogFile();
try {
  // Do some logging
} finally {
  log.dispose;
}

We don’t have to use the dispose pattern though because in D we have the luxury of choosing between implicit and explicit memory management. We can either free the object ourselves with the delete operator, or leave it for the GC to dispose later.

LogFile log = new LogFile();
try {
  // Do some logging
} finally {
  delete log; // Explicit memory management
}

D has another construct which is very convenient when you need to control the lifetime of an object. With the scope attribute, an object is automatically destroyed when the program leaves the scope in which the object was created.

void function some_func() {
  scope LogFile log = new LogFile();
  :
  // log will be freed on exit
}

The ability to mix explicit and implicit memory management is a simple, yet great feature. It is one of many examples where D provides us with the best of two worlds. Convenience and control, as well as productivity and performance, is blended in a way that has no equivalence in any other language I know.

Cheers!

Categories: D Programming Language Tags: