Leaky Functions\Barrel of Bugs

Leaky Functions\Barrel of Bugs

  • Comments 16

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

Leave a Comment
  • Please add 3 and 1 and type the answer here:
  • Post
  • <quote>There’s no way at all to change a .NET string once it’s been created.</quote>

    don't forget about reflection.

    http://blogs.tedneward.com/CommentView,guid,1490880b-832f-402e-9b18-4c101c4a5206.aspx

    messing around with interned strings is a great way to foul up almost any .net program

  • Even as I wrote it I knew using the words "no way at all" was probably asking for trouble. I did know about the unsafe technique but I wasn't aware of the reflection method.

    I stand corrected. Still, strings protect you against all but the gnarliest opponent (err, I mean co-worker).

  • C# and .NET need a proper, integrated, and wholistic treatment of immutable values - including support for the property initializer syntax.

  • Jomo Fisher --I recently got a question via my blog that dovetailed nicely with something I’ve been working

  • You've been kicked (a good thing) - Trackback from DotNetKicks.com

  • Back when I started out programming (lo these many 3 years ago), filled with the knowledge of OO and data hiding, and I saw private objects being handed willy nilly out to any caller, I thought to myself "Something is Wrong Here."  

    Well, now I'm an old and crusty hand at this programming biz, and I know that sometimes its bad, and sometimes its not.  The real trick (and this is where us pros make our cash) is knowing when.  If you're writing a class that's exposed as part of your API, you might want to think of wrapping that class to make it immutable.  Its definitely a valid and important question.

    Nice article; fuggen saved and passed to noobs.

  • Good article and grats for the blog! :)

  • Jomo Fisher—A lot of people (myself included) have written about LINQ in the next version of C#. LINQ

  • Nice post. I think, though, that using Point for the examples is not a good idea because System.Drawing.Point is a value type, so the bugs mentioned here would not occur when using System.Drawing.Point.

  • Now that we have covered the basics, in minutes 8 - 14 we will cover the foundational concepts and types

  • Lists represent the backbone of functional programming and in order to be an effective F# programmer

  • 在上篇文章里,我们写出了F#的第一个程序,本文我们来看一些F#语言的核心部分,包括值的不变性,模块,Tuple,柯里化,Union类型,模式匹配,Record类型,序列和集合等内容,读完此文后,希望能让您对F#有个整体的认识。

  • I've been complaining about many of these aspects of .NET for a long time.  But F# and immutable values is not the only solution.  Many of these problems could be solved in C# and OO language by enabling a feature that C++ had, and used for many years... const!

    You could pass values into a function as const reference, and you could also declare methods (or properties) as const, and the compiler would check to make sure that this method did not change any internal variables.

    By passing references around everywhere in .NET, we have create many problems that were once solved.

  • 原文链接:http://www.cnblogs.com/anderslly/archive/2008/08/10/fs-in-20-minutes-core.html

  • OMG! I got pulled off my usual job of doing a bunch of things and have been focused on getting students

Page 1 of 2 (16 items) 12