Archive

Archive for the ‘.NET vs. Java’ Category

Covariance and Contravariance in .NET and Java – Part 2 – Constraints and Wildcards

March 22, 2011 1 comment

Sometimes we want to put constraints on the types that are valid substitutes for our formal type parameters.
Java implements constraints using wildcards. These are subdivided into unbounded wildcards and bounded wildcards. In the following, we will take a look at the wilcards and their C# equivalents.

1. Unbounded Constraints

1.1 Java

The folllowing code uses an unbounded wildcard to print a collection of any type:

	static void PrintAll(ICollection<?> list) {
		for (Object t : list) {
			System.out.println(t);
		}
	}

The ? wildcard was primarily added to allow working with legacy code that used non-generic collections. You might think that instead of an undbounded wilcard you could just use a generic method instead with an unconstrained type parameter, however there is an important semantic difference. Any ? can be assigned to Object, since ? <: Object is true for all ?. The converse however, Object <: ? is clearly not true, which is why using ? prohibits the following:

	static void  PrintAndAdd(Collection&lt;?&gt; list, Object item) {
	    for (Object t : list) {
	        System.out.println(t);
	    }
	    list.add(item);
	}

This is different from an implementation using a generic method, which will allow this just fine.

	static  void PrintAndAddGeneric(Collection list, T item) {
	    for (T t : list) {
	        System.out.println(t);
	    }
	    list.add(item);
	}

1.2 C#

In C#, there’s no direct equivalent to the unbounded wildcard, so the closest we can get is using a plain generic method:

static void PrintAll (IEnumerable list) {
    foreach (T t in list) {
        Console.WriteLine (t);
    }
}

2. Upper Bound Constraints

2. 1Java

The next Java type of wildcards java offers are so-called bounded wildcards. Bounded wildcards let you specify an upper or lower bound for your formal type parameter. Let’s first see them in action:
Suppose we haved the following classes

	class Vehicle {}
	class Car extends Vehicle {}
	class Porsche extends Car {}

and have a special print funtion that can only print cars. We can use a bounded wildcard here:

	static void PrintCars(Collection&lt;? extends Car&gt; list) {
	    for (Car c : list) {
	        System.out.println(c);
	    }
	}
	

This time, we could also use a generic method with a concrete formal type parameter and there’s no difference in semantics.

	static &lt;T extends Car&gt; void PrintCars(Collection list) {
	    for (Car c : list) {
	        System.out.println(c);
	    }
	}

Remember that we said Object is the maximum in our set of types? Now it is easy to see what concepts extends actually maps to.

“? extends T” means T is an upper bound for ?, so ? only matches a type U if U <: T.

Let’s assume we have a List, then Porsche <: Car, so we can call PrintCars(List) just fine.

2.2 C#

What is an equivalent C# construct? We can use a formal type parameter in conjunction with a where constraint to get the desired effect:

	static void PrintCars&lt;T&gt;( ICollection&lt;T&gt; list )
		where T : Car
	{
		foreach (Car c in list)
		{
			Console.WriteLine( c );
		}
	}

3. Lower Bound Constraints

3.1 Java

So we can specify an upper bound constraint. As always when there’s an upper bound, we also want to see if there’s a lower bound. Let’s establish a new sample. Suppose we have a collection and we want to flush all but the last element into a sink. Here’s the code:

	interface Sink {
		void flush(T t);
	}

	class ConcreteSink implements Sink {
		public void flush(T t) {}
	}

	static  T flushAll(Collection c, Sink&lt;super T&gt; sink) {
		T last = null;
		for (T t : c) {
			last = t;
			sink.flush(last);
		}
		return last;
	}

	public void foo(){
		Sink&lt;Vehicle&gt; sink = new ConcreteSink&lt;Vehicle&gt;();
		List&lt;Car&gt; list = Arrays.asList(new Car());

		flushAll(list, sink);
	}

The Sink<> we might have can be specialized for all sorts of vehicles, but when we have a collection of Porsches and a Sink, we’d expect we can flush the Porsche. In fact this code is perfectly fine, so:

“? super T” means T is a lower bound for ?, so ? only matches a type U if T <: U.

3.2 C#

In C# we can create an upper bound constraint by using two formal type parameters and then restricting one against the other. Here’s the sink example in equivalent C#:

	static T flushAll&lt;T, U&gt;(ICollection&lt;T&gt; c, ISink&lt;U&gt; sink) 
        where T : U
    {
		T last = default(T);
		foreach (T t in  c) {
			last = t;
			sink.flush(last);
		}
		return last;
	}

	public void foo(){
		ISink&lt;Vehicle&gt; sink = new ConcreteSink&lt;Vehicle&gt;();
        List&lt;Car&gt; list = new List&lt;Car&gt;() { new Car() };

		flushAll(list, sink);
	}

By specifying T <: U, we do effetively say that U is a superclass of T, which is just the same as “? super T”.

Final Words

In this blog post we have seen the varios constraints we can put on generic types and what constructs are equivalent. The list of constraints presented here is not exhaustive. There are additional constraints that .NET and Java offer respectively and they are tightly bound to the way generics are implemented on each platform. We have focused on the constraints that put constraints on the type relationships between formal type paramters. As we will see in a future post, this is important ground work to see where covariance and contravariance come in to play, and to what extend we have already seen it implemented by using constraints.

Categories: .NET vs. Java

Contrasting .NET and Java – Finalizers

February 11, 2011 Leave a comment

One of the interesting differences between .NET and Java I ran into while reading Joshua Bloch’s excellent “Effective Java” book is the handling of finalizers.

In both, .NET and Java, the Garbage Collector will implicitly place objects implementing a finalizer and are eligible for collection on a finalizer queue. This queue is processed by a separate finalizer thread, and no guarantees are made as to when an object may be finalized or if it will be finalized at all. The reason finalization cannot be guaranteed is that the process may crash, finalization throws an exception or similar mishappenings.

Due to the nature of the finalization, it comes with significant overhead. To avoid this overhead, .NET provides the IDisposable pattern. The Dispose method takes care of releasing all allocated resources and then instructs the Garbage Collector with a call to GC.SupressFinalizer(this) that it need not be finalized anymore.
Clients of objects implementing IDisposable are responsible (though not forced to) call IDisposable.Dispose whenever they are done with an instance. To support this scenarios, many .NET languages feature a using keyword, which is syntactic sugar for providing a scope for disposable objects. Whenever this scope is left, the appropriate Dispose method is called.

Java on the other does not provide a general purpose equivalent to IDisposable, for IO related the Closeable interface exists. As of Java 6 there is no equivalent to the using keyword, although “Automatic Resource Block Management” using the try keyword  has been announced for Java 7. Until then, you’re left with manually implementing scoping with a try/finally block. Java also doesn’t provide an equivalent of GC.SupressFinalize which means that finalizable objects will always have significant performance impacts.

A further difference is in the way base class finalization is handled. Although the .NET CLI Spec does not enforce base class finalizers are called from a derived class’ finalizer, C# and C++/CLI enforce this with their destructor syntax. In Java, it is up to the implementor not to forget calling the base class finalizer.

All these aspects, combined with the significantly better support for code issue warnings around undisposed Disposables in the .NET stack, make .NET’s handling look superior to Java’s.

Categories: .NET, .NET vs. Java, Java Tags:

Co and Contravariance in .NET and Java – Part I – Type Relations

February 8, 2011 Leave a comment

For my university courses I am learning Java at the moment, something that I have always wanted to do to broaden my horizon but also for getting some exposure to the platform that, together with .NET, features the largest market share. In a previous blog post I did a comparison of the different generics implementation in Java and the .NET framework, and now that I will be using Java a lot more often I think its the right moment to extend this comparison on Covariance and Contravariance.

This subject has been covered in great detail on the net, and I can wholeheartedly recommend Eric Lipperts and Bart de Smet’s Blog posts on the subject, which is also where I’ll reference some of the material for this postis from.

Type System Terminology

In any Object-Oriented type system the type relation of two objects A and B can be characterized in exactly one of the following ways:

  • A has the same type as B
  • A is a subtype of B
  • B is a subtype of A
  • A and B are not related.

We can establish a well defined ordering relation between two types as “X is assignment compatible to Y”, written as X <: Y. Assignment compatible means that an instance of X can be used instead of an instance of Y everywhere where Y is applicable. The easisest example of X <: Y would be string <: object, but there’s also float<: double (a float is narrower than a double, with respect to the range of values it can represent) . Assignment compatibility establishes a partial order relationship, because it fulfils the three necessary properties:

  • (reflexivity) For all types T: T<: T
  • (antisymmetry) For all types T and U: T <: U and U <: T implies U = T
  • (transitivity) For all types S, T and U: S <: U and U <: T implies S <: T

To give an example of what this means, is that given a related set of types (a linear inheritance hierachy), <: will order them from more specific to more generic ones, e.g Car <: Vehicle <: Object. As we’ll see later in this series, having a formal notion for type relations will help us formally understand the concept of Covariance and Contravariance.

The next concept I want to introduce is that of a type operation. Analogous to the mathematical definition of an operation, a type operation has the signature T -> U where T and U are types. An example for a common type transformation is a type cast. A cast to the common root class Object would be defined as c : { Type -> Type; T -> Object}. For the mathematically inclined, note that Object is the maximum in our set of Types regarding the relation <: , because for all types T, T <: Object.

The probably most interesting set of type operations is what Haskell calls a Type Constructor. Whenever you are using a constructed type (such as a generic type or an array) you are using a type constructor (not in the CLR sense where this refers to a static cctor.) IEnumerable is one of the types you’d use with such a constructor, which has the signature T -> IEnumerable. So whenever you are using a generic instantiation (a generic type with concrete Type arguments), you have effectively used a type operation.

In the next post, we’ll discuss some common type operations and define what covariance and contravariance means.

Categories: .NET vs. Java
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: