tags:

views:

228

answers:

6

Was practicing Generics. Consider a stack method below. What is the best way of doing error checking other than throwing exceptions in a generic method. What if I want to return some result in this method.

public T pop()
{
    if (top >= 0)
        return arr[top--];
    return -1 or null;
}
+3  A: 

You could do return default(T), which will return 0 initialized value types (ex. all numeric types will be initialized to 0), and null for reference types.

BioBuckyBall
+1, should add a bit that it returns 0 initialized values for all struct types (essentially expand the numeric types part)
JaredPar
This is a bad idea because then you can't distinguish between an object which got popped whose value is `default(T)` and an error signaled by returning `default(T)`.
Trillian
@JaredPar True, done.
BioBuckyBall
@Trillian Neither could you determine that from the OP's original implementation returning -1
BioBuckyBall
+6  A: 

The only thing you could do is return default(T), which is the default value for the type T (null for reference types, zero for integral types and zeroed-fields object for other value types). However, this is generally a bad idea as you'll have no way to distinguish between a 0 that was popped or a 0 that indicates an error. Exceptions are generally the best way to go in such cases, but you could also change your method as follows:

public bool TryPop(out T value)
{
    if (top >= 0)
    {
        value = arr[top--];
        return true;
    }
    value = default(T);
    return false;
}
Trillian
Thanks All! Needed an alternative to exceptions. Didnt know about default(T).
Tech Xie
Hmmm, a function that changes a parameter... how un-functional (yes, I use TryParse but I try to stay away from things that call themselves functions but aren't really).
Edgar Sánchez
@Edgar don't see it as changing a parameter, see it as a second return value. It's no worse than returning a `Tuple<bool, T>`. What you're afraid of are `ref` parameters.
Trillian
@Trillian Subtle. Conceptually, you're right. In practice, we still leave open the possibility of (unexpectedly) changing the value of a variable in the invoker's scope. It would be nice if C# had tuples á la F# :-)
Edgar Sánchez
@Edgar: It really shouldn't be unexpected. The `out` keyword indicates that the variable **must** be assigned a new value by the method. So if you're calling a method with an `out` parameter, you just have to be aware that the value of whatever you passed in *will* change (which is why it's actually pointless to assign it a value ahead of time). Not *might*, but *will*.
Dan Tao
Tuple is the .NET framework, of course. C# doesn't have syntactic sugar for them, but they're there.
Judah Himango
A: 

Your question is unclear. Error checking can be done the same ways as always - catching exceptions. Raising errors should generally be done by throwing exceptions. That is what they're for, after all.

If you want to return null you can do that, but then you have to make sure that type T is a class, not a struct, like so:

public T pop()
    where T: class
{
     ...
}
Evgeny
A: 

It seems like your question really has two parts

The first part being how to provide a default value if one is not available. As other people have pointed out the C# expression default(T) will work for this scenario. It returns null for reference types and 0 initialized values for structs.

The second part being what is the best way to handle the error case other than to throw an exception. Collection APIs tend to use the TryXXX pattern for this type of scenario

bool TryPop(out T value) { 
  if ( top >= 0 ) {
    value = arr[top--];
    return true;
  }
  value = default(T);
  return false;
}
JaredPar
A: 

If you want to be able to return null when the stack is empty you can try something like this:

class GenericStack<T>
{
    T[] arr;
    int top;

    public T pop()
    {
        if (top >= 0)
            return arr[top--];
        return default(T);
    }
}

And then you can use use like this:

        var stack = new GenericStack<int?>();

        var res = stack.pop(); // res will be null

Notice the stack object is of type int? so we can return nulls.

Edgar Sánchez
A: 

Direct approach (use generics and return value or null)

class DemoClass<T> where T : struct
{
   public T? PopValueOrNull() 
   { 
     if ( this._top >= 0 ) { 
        return this._arr[this._top--];
      } 

      return null; 
    }
}
Andrey
It does not work, I know why, but do you? ;-)
macias
ok, i forget "where T : struct" :) ... wait a sec... added
Andrey