S h o r t S t o r i e s

// Tales from software development

C# StorageValue type part 2: Struct

leave a comment »

Almost as soon as I started on a struct implementation I decided to change the type used to hold the storage value from the long (System.Int64) type used in the class implementation to a ulong (System.UInt64). I’d considered this previously and decided that a signed value might be useful for storage/memory calculations but, the more I thought about it the more I realised this didn’t make much sense and it would be better to use an unsigned value.

The class implementation of the StorageClass type in the previous post was useful to developing the code required to parse and format storage values. However, I knew that I really wanted the semantics and behaviour associated with the built in value types such as int.

Another change I considered was to use the implicit operator to allow conversion from a string value without an explicit cast.

With the current implementation, assignment looks like this:

StorageValue s1 = new StorageValue(100 * 1024);
StorageValue s2 = new StorageValue("1.5MB");

but I really wanted to be able to do this:

StorageValue s1 = 100 * 1024;
StorageValue s2 = "1.5MB";

In fact, it’s very easy to do this, whether the type is a class or struct, by implementing the implicit operator:

 public static implicit operator StorageValue(int value)
 {
    return new StorageValue(value);
 }
 
 public static implicit operator StorageValue(string value)
 {
    return StorageValue.Parse(value);
 }

Unfortunately, this is represents an abuse of what the implicit operator is designed for. To explain why, it’s worth considering the intent of the explicit operator first. Typically, when a conversion might fail or will potentially result in data loss, the compiler requires an explicit cast, e.g.

long gb = 1024 * 1024 * 1024;
int i = (int)gb // cast required

This conversion using a cast is implemented using the explicit operator. The point of this is to allow the conversion but only when the programmer uses a cast, i.e. it ensures that the programmer is aware of the potential for failure or data loss.

The implicit operator implements the conversion without requiring the cast, i.e. the programmer is not made aware of the possible failure or data loss when the conversion is performed.

So, while it would be nice to allow syntax such as

StorageValue s2 = "1.5GB";

it is not correct use of the implicit operator as this conversion could easily fail if the string is not correctly formatted, e.g.

StorageValue s2 = "Hello world!";

There is a much bigger issue with a struct implementation rather than a class implementation which is simply that it will be passed by value rather than by reference. For this implementation this is probably the correct behaviour but, again, it really comes down to what feels right.

Written by Sea Monkey

January 30, 2017 at 6:18 pm

Posted in Development

Tagged with ,

Leave a comment