Difficulties with non-nullable types (part 4)

So far i've discussed two interesting problems that arise when you try to add non-nullable types to C# and .Net.  The first problem was that non-nullable instance fields might be accessed before being initialized, but we were able to come up with a good model (from C++ no less) that would allow that to work.  The second problem was with non-nullable static fields.  Unfortunately, there doesn't appear to be a great solution in place to enable these.  Oh that i wish those were the only things you had to deal with when trying to add these types.  So what's next on the menu?

Well, let's consider the following code:

 public class Test {
    void ProcessAllFiles(string[] fileNames) {
        foreach (string file in fileNames) {
            ProcessFile(file);
        }
    }

    void ProcessFile(string! fileName) {
        //Do stuff with fileName, assured that is isn't null
    }
}

As you can imagine, this would not be compile.  ProcessFile needs a non-null string, but instead we're passing it a string that could be null.  There are a couple things we could do about this.  One would be to replace the code with:

     void ProcessAllFiles(string[] fileNames) {
        foreach (string file in fileNames) {
            if (file != null) {
                ProcessFile(file);
            }
        }
    }

Now we know that "file" is not null and that it's safe to call ProcessFile with it.  Alternatively we might have a construct like so: 

     void ProcessAllFiles(string[] fileNames) {
        foreach (string file in fileNames) {
            ProcessFile( !!file );
        }
    }

The !! construct will throw if the expression it is applied to is null, and if exception still continues then it means that it's not null.  I'm not a huge fan of this construct.  I don't think it reads well, and i think it's likely to be confused with ! quite a bit.  But it's definitely something to think about.

But all this is really to make up for the fact that what you'd really like to do is write this code:

     void ProcessAllFiles(string![] fileNames) {
        foreach (string! file in fileNames) {
            ProcessFile(file);
        }
    }

Now everything is typesafe and the signature of ProcessAllFiles is set up so that it can't accept any null file names in the array that's passed in.  Seems great right?  Well, the problem now arises of how someone can create one of these arrays of a non-nullable type.  Let's take a look at how the code might look:

     void DoSomeStuff() {
        string![] fileNames = new string![2];
        fileNames[0] = "foo.txt";
        fileNames[1] = "bar.txt";

        ProcessAllFiles(fileNames);
    }

Unfortunately, this won't work.  When you instantiate the array it's going to be filled with nothing but nulls.  If you accidently use it before you've filled in all elements then someon eis going to be passed null when that should be impossible in the type system.  So what can you do about that.  Well you could limit it so that when you initialize an array of non-nullable elements you pass in all elements at construction time to ensure that it's completely filled with non-null types.  i.e.:

     void DoSomeStuff() {
        string![] fileNames = new string![] { "foo.txt", "bar.txt"};

        ProcessAllFiles(fileNames);
    }

However, this isn't a very attractive solution.  What if you have an array where you dynamically determine the set of elements at compile time.  i.e. something like this:

     void DoSomeStuff(int count) {
        string![] fileNames = new string![count];
        for (int i = 0; i < count; i++) {
           fileNames[i] = "foo" + i;
        }

        ProcessAllFiles(fileNames);
    }

You can't represent the construction of this array with a predefined set of elements since the number of elements is dependent on the passed in "count" value.  So what can be done about this?  Well as before we could not allow you to have arrays of non-null values.  But that would be extremely unfortunate.  Consider the enormous amount of APIs out there that look something like:

     string[] GetFoos() { ... }

that you would really want to look like:

     string![]! GetFoos() { ... }

(i.e., a non-null array of non-null strings).   The double-bang is a bit ugly, but not that bad.

So supporting this is definitely something that you'd want.  I've given it some thought, and the only solution i've been able to find is to introduce an intrinsic array constructor supplied by the .Net runtime that will create the array and fill it with all the non null values.  This ensures that all values will be set by the time the array is used.  I think that this would look something like this:

 public delegate T Creator<T>();

//This class is treated specially by the runtime and some type 
//system rules are relaxed when it is executing.
public class ArrayCreator<T> where T : class {
    public T[] New(int length, ArrayInitializer<T> initialize) {
        //The runtime will be fine with these elements not being initialized
        //even if T is a non-null type.
        T[] array = new T[length];

        for (int i = 0; i < length; i++) {
            array[i] = create();
        }

        return array;
    }
}

Note: we might allow a little more flexibility with "Creator" such as passing the index of the element being created.  For now, this simple example will suffice.

You can now use this like so:

     void DoSomeStuff(int count) {
        int i = 0;
        string![] fileNames = ArrayCreator<string!>.New(count, delegate {
            return "foo" + i++;
        });

        ProcessAllFiles(fileNames);
    }

It could work... but yech... it's hideous. Maybe we could some up with some nicer syntax to help out here, but nothing is leaping to mind.  Do you guys have any suggestions for a nicer method of handling this?

---

Edit: Michael astutely noticed that the check of "if (fileName != null)" would be insufficient for determining at compile time if fileName was actually null or not.  The reason for this is that the != operator might have been overridden, and so we can trust the result of it.  However, what we could add would be some sort of intrinsic operator like null() that would do this work for us and which would allow the compiler to determine using flow control if a variable was null or not.  So you could have:

if ( ! null(fileName)) {
string! nonNullFileName = fileName;
...

and have the compiler and runtime be ok with that.