Leaky FunctionsBarrel of Bugs

Jomo Fisher--Pop quiz. Consider this function call in C#:

a = MyFunction(b);

What information is exchanged between the caller and the function? When is the information exchange done?

It would be nice if the answer was:

MyFunction takes value b and returns value a. When the function finishes no more information is exchanged.

There are several reasons information may leak out of a function call and all of these reasons can cause subtle bugs in your code.

Let me start with the granddaddy of function leaks to illustrate my point:

static int counter = 0;

static int MyFunction(int v) {

    ++counter;

    return v;

}

This is good old-fashioned global data. I think it’s well accepted that globals can cause bugs so I won’t go into that. My point is that there is a family of function leaks and to a greater or lesser degree all these leaks can cause subtle bugs in your code.

Here are some more leaks that have personally caused me grief in the past.

Reference Parameter as Value Assumption

Here, I want to pass a point to a function.

Point pt = new Point();

pt.X = 1; pt.Y = 1;

SetPixel(pt);

class Point { public int X; public int Y; }

static void SetPixel(Point pt) {

    // Do some work...

    pt.X = 0;

}

Did you see that? Whoever wrote SetPixel decided they could change my Point instance behind the scenes.

Well, at least the damage is done once the call to SetPixel is complete. There’s a good chance of finding this bug quickly.

What about this variation?

class Graphics {

    Point lastPixelSet;

    public void SetPixel(Point pt) {

        // Do some work...

        lastPixelSet = pt;

    }

}

Now SetPixel is holding my point and can change it even after SetPixel has returned.

Collection Parameter as Value Assumption

Things get worse for collections:

static void WriteList(List<string> list) {

    // Do some work.

    list[5] = "I like ponies.";

}

You could try changing the signature to take IEnumerable, but trouble can find a way:

static void WriteList(IEnumerable<string> list) {

    // Do some work.

    if (list is List<string>)

        ((List<string>)list)[5] = "I like ponies.";

}

Return Reference Leaks

Function callers can also cause problems:

Optimizer o = new Optimizer();

Point p = o.FindMaxima();

p.X = 0; // Yikes! This changes private data held by Optimizer.

class Optimizer {

    private Point maxima;

    public Point FindMaxima() {

        return maxima;

    }

}

A Patchwork of Fixes

So we’ve identified a coding pattern that can cause subtle bugs, is there anything we can do? One approach people take is to copy structures at function call and return boundaries:

SetPixel(pt.Duplicate());

class Point {

    public int X;

    public int Y;

    public Point Duplicate() {

        Point d = new Point();

        d.X = X;

        d.Y = Y;

    }

}

There are some problems with this. First, who is responsible for making the copy? Is it the caller or the function? If you don’t have a rigorous rule for your code then often you end up with two copies or no copy at all. Second, all those Duplicate calls clutter your code and obscure its intention. This is a maintenance problem.

For collections, there’s a built-in solution that will let you wrap your collection in a read-only façade:

List<string> contacts;

IEnumerable<string> GetContacts() {

    return contacts.AsReadOnly();

}

This is well enough if you remember to do it. You could do a similar thing for your own non-collection classes, but then every class would need another separate class to act as the read-only reference.

An Elegant Solution

You can find a far more elegant solution in the .NET String class. Try this:

string s = "abcde";

DoSomething(s);

static void DoSomething(string s) {

    s[3] = 'x';

}

Does this modify the string from the calling function? The answer is no. In fact, this won’t even compile because there’s no setter implementation on the indexer. This is important:

            There’s no way at all to change a .NET string once it’s been created.

The string class is immutable. You can verify yourself by right-clicking on the string and selecting Goto Definition.

This means that any function that takes a string as a parameter or returns a string has an explicit contract that the function can’t leak through that string reference.

An Immutable Point

Here is the Point class implemented as immutable:

class Point {

    public int X {get; private set;}

    public int Y {get; private set;}

    public Point(int x, int y) {

        X = x;

        Y = y;

    }

    public Point SetX(int x) {

        return new Point(x, this.Y);

    }

    public Point SetY(int y) {

        return new Point(this.X, y);

    }

}

Now, you’re free to pass these Points around without copying them and without worrying about leaky functions. It’s true that you have to copy the point to change it, but I think the fact that string is a successful immutable class means that other immutable classes can also be successful.

I have a similar immutable list implementation which I will save for a future blog entry.

This posting is provided "AS IS" with no warranties, and confers no rights.

kick it on DotNetKicks.com