#1,072 – How the Unary Minus Operator Can Fail

There are cases when applying a unary operator to an operand results in a value that does not fit into the data type of the operand. Consider the int type, whose range is -2,147,483,648 to 2,147,483,647.  If we assign the minimum value (largest negative number) and try to negate it with the unary operator, the negation will fail.

By default, arithmetic operations work in an unchecked context.  In this case, the unary operator does nothing, just returning the value of the original operand.

            // int range is -2,147,483,648 to 2,147,483,647
            int n = int.MinValue;
            n = -n;  // n unchanged

If we do the same operation in a checked context, we’ll get an overflow exception.

1072-001

 

Note that a cast to a “larger” data type fails if it’s done outside of the unary operator.  But casting before applying the operator does work.

            long l = (long)-n;  // Still fails

            long l2 = -(long)n;  // This works

 

Advertisements

#1,071 – The Unary Minus Operator

Unary operators are operators that affect a single operand.

The unary – operator is used to negate a numeric value.  (Subtract the value from zero).  The unary + operator does not affect a value, so is not worth mentioning.

            // Unary minus operator applied to constants
            int x = 5;
            int y = -5;
            Console.WriteLine("x={0}, y={1}", x, y);

            // Unary minus operator applied to variable
            x = -x;
            y = -y;
            Console.WriteLine("x={0}, y={1}", x, y);

1071-001

The unary operator also works with floating point and decimal values.

            double d = -4.2;
            float f = -4.2f;
            Console.WriteLine("d={0}, f={0}", d, f);

            decimal m = -0.01m;
            Console.WriteLine("m={0}", m);

1071-002

 

#1,070 – A Generic Type Can Be Compiled

Recall that a generic type is a template for a class that you can define later.  The generic type contains type parameters that act as placeholders for type arguments that you supply when you define a constructed type based on the generic type.  Without defining the constructed type, the type parameters in the generic type have no assigned type.  That is, they can be of any type (unless some constraints have been specified for the type parameter).

You can compile a particular generic type without have any constructed types that make use of the generic type.  For example, List<T> is compiled and included in mscorlib.dll.  This allows you to later use the generic type in your own code.

#1,069 – Contravariance and Generic Interfaces

Generic interfaces in C# are contravariant, provided that their type parameters are constrained with the in keyword.  A contravariant generic interface allows an assignment from a constructed version of the interface on a base class to a constructed version of the interface for a derived class.

For example, if BorderCollie derives from Dog and if IAddRemove<T> is contravariant, we can do the following:

            IAddRemove<Dog> dogAddRemove;
            // Assign dogAddRemove to some class that implements IAddRemove<Dog>
            IAddRemove<BorderCollie> bcAddRemove = dogAddRemove;

Below is a full example of defining a contravariant interface. Note that the LineOf<T> class implements both the covariant interface IFirstAndLast<T> and the contravariant interface IAddRemove<T>.

        public interface IFirstAndLast<out T>
        {
            T First();
            T Last();
        }

        public interface IAddRemove<in T>
        {
            void AddToEnd(T item);
            void RemoveFromFront(T item);
        }   

        public class LineOf<T> : IFirstAndLast<T>, IAddRemove<T>
        {
            private Queue<T> theQueue = new Queue<T>();

            public void AddToEnd(T d)
            {
                theQueue.Enqueue(d);
            }

            public void RemoveFromFront(T d)
            {
                theQueue.Dequeue();
            }

            public T First()
            {
                return theQueue.Peek();
            }

            public T Last()
            {
                return theQueue.Last();
            }
        }

        static void Main(string[] args)
        {
            LineOf<Dog> dogs = new LineOf<Dog>();

            IAddRemove<BorderCollie> bcAddRemove = dogs;
            bcAddRemove.AddToEnd(new BorderCollie("Kirby"));
            bcAddRemove.AddToEnd(new BorderCollie("Shep"));
        }

#1,068 – Generic IEnumerable Interface Is Covariant

A covariant generic interface is one that allows an assignment from a constructed version of the interface on a derived class to a constructed version of the interface for a base class.

For example:

            // If herders is (or implements) IFirstAndLast<BorderCollie>:
            IFirstAndLast<Dog> dogLine = herders;

The IEnumerable<T> interface in System.Collections.Generic is covariant.  This means that you can assign a collection of a given type to an IEnumerable<T> where the represents a type further up the inheritance chain.

For example:

            List<BorderCollie> someBCs = new List<BorderCollie> {
                new BorderCollie("Shep"),
                new BorderCollie("Kirby")
            };

            // Because BorderCollie derives from Dog,
            // we can do the following
            IEnumerable<Dog> dogList = someBCs;

If MerleBorderCollie inherits from BorderCollie, which in turn inherits from Dog, we can also do:

            List<MerleBorderCollie> merles = new List<MerleBorderCollie>
            {
                new MerleBorderCollie("Lady")
            };
            IEnumerable<Dog> moredogs = merles;

#1,067 – Covariance and Generic Interfaces

Generic interfaces in C# are covariant, provided that their type parameters are constrained with the out keyword.

Let’s assume that we have the following interface.

        public interface FirstAndLast<T>
        {
            T First();
            T Last();
        }

Then assume that we define a generic class that implements this interface:

        public class LineOf<T> : IFirstAndLast<T>
        {
            private Queue<T> theQueue = new Queue<T>();

            public void AddToEnd(T d)
            {
                theQueue.Enqueue(d);
            }

            public void RemoveFromFront(T d)
            {
                theQueue.Dequeue();
            }

            public T First()
            {
                return theQueue.Peek();
            }

            public T Last()
            {
                return theQueue.Last();
            }
        }

Great, now we can use this class as follows:

            LineOf<Dog> dogs = new LineOf<Dog>();
            dogs.AddToEnd(new Dog("Lassie"));
            dogs.AddToEnd(new Dog("Rin Tin Tin"));
            Console.WriteLine(dogs.First().ToString() + ", " + dogs.Last().ToString());

            LineOf<BorderCollie> herders = new LineOf<BorderCollie>();
            herders.AddToEnd(new BorderCollie("Kirby"));
            herders.AddToEnd(new BorderCollie("Shep"));
            Console.WriteLine(herders.First().ToString() + ", " + herders.Last().ToString());

At this point, we might want to convert LineOf<BorderCollie> to IFirstAndLast<Dog>, for example we might have a method that returns IFirstAndLast<Dog>.

However, if we do the following, we get a compiler error, saying that we can’t implicitly cast LineOf<BorderCollie> to IFirstAndLast<Dog>:

            IFirstAndLast<Dog> dogLine = herders;

We could do a cast, as shown below. The code now compiles, but the conversion fails at runtime.

            IFirstAndLast<Dog> dogLine = (IFirstAndLast<Dog>)herders;

We want the IFirstAndLast<T> interface to be covariant, i.e. to allow this assignment.  To support this, we just need to add the out keyword in the interface.

        public interface IFirstAndLast<out T>

We can do this because T is only used in this interface as a return value.  Having done this, we can now do the following.  This compiles and the assignment succeeds at runtime.

            IFirstAndLast<Dog> dogLine = herders;

 

BUILD 2014 – Day 1 Keynote

BUILD 2014 – Day 1 Keynote – My notes.  (Complete with tons of screengrabs).