Archive

Archive for February, 2011

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.

Advertisements
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
%d bloggers like this: