The World According to Nick
Politics, News, Photography, and Triathlons... What don't I talk about?
Thursday, February 26, 2004
<< O'Reilly Launches WindowsDevCenter.com Why Isn't Anyone Asking Her to Resign? >>
Guarantee This Won't Change... I'm Sorry... I const Do It
This will probably be my last software rant for a little while... but this is an important one. I posted a couple days ago on how I really wanted a Deterministic Finalizer in .NET... as part of a list of other desired features in C#. One of the other wishes I had was for a construct similar to passing an argument as a const reference in C++.

void PassByConstRef( const MyClass& foo )
{
   // Do something with foo
}

Why do this? First of all, if my MyClass is large, you don't incur the overhead of creating a new instance of MyClass and copying the contents. However, you also get the safety of passing by value since the foo instance is const (can't be modifed within the scope of the function).

What does C# have? Well... it behaves differently depending on whether the parameter is a value type (int, float, etc.) or a reference type (anything that derives from object). Value types are passed by value by default, so any changes done within the scope of the function are lost. This is good. You can also pass by reference if you wish by placing ref in front of the parameter. This means that any changes made to the parameter are made to the callers version as well. Fine. After all, you specifically declare you wish to have it be reference.

public void PassByVal( int n )
{
   n = 5; // This change is lost to the caller
}
public void PassByRef( ref int n )
{
   n = 5; // This change affects the caller
}


By reference arguments are treated very differently. There is no way to pass by value as above:

public void PassByVal( MyClass foo ) // This is by value right? Wrong!
{
   foo.SomeProperty = 5; // This change affects the caller... doh!
}
public void PassByRef( ref MyClass foo )
{
   foo.SomeProperty = 5; // This change affects the caller
}

So what's the difference between the two. Well, this will illustrate the difference more clearly:

public void PassByVal( MyClass foo )
{
   foo = new MyClass(); // Caller doesn't get the new MyClass object
}
public void PassByRef( ref MyClass foo )
{
   foo = new MyClass(); // Caller does get the new MyClass object
}


But what if we want to prevent the first case, where the function attempts to change a property... and not overwrite the entire object? You can't. You're only recourse is to implement ICloneable, Clone your object, and pass the Clone to the function, then throw away the Clone. Basically you're doing what a C++ copy constructor does. That can be a lot of overhead for a large object. Not to mention the effort of implementing ICloneable where you normally wouldn't need it.

Why should we care? After all, all you have to do is write your function so you don't modify the object right? Wrong. First of all, what happens if you're using a 3rd party library where you don't have the source? Wouldn't it be nice to have some sort of warm fuzzy feeling when you call that function... knowing that the black box of the library isn't going to do something strange to you? And even if you aren't using a 3rd party library... I like the fact that the compiler is watching my back when I write functions. Declaring my intention to not change a variable and then letting the compiler keep me honest simply reduces possible bugs.

So why is this construct missing? I don't know frankly. I suspect it was an effort to "simplify" the language. But in their effort to simplify things, they've made things a lot less safe... when safety was one of their primary selling points.
# Posted at 1:25 PM by Nick  |  Comment Feed Link No Comments  |  No Trackbacks

 Add to del.icio.us |  Digg this Post | Filed Under: Old Blog

Comments are closed.


© Copyright 2012 Nick Schweitzer
Powered By newtelligence dasBlog 1.9.7067.0
Theme Based on Design By maystar