Thursday, February 4, 2010

Generics

Generics

feature
Java
C#
Type compilation
Type erasure
Reified
co-variance
use-site
limited, use-site
contra-variance
use-site
no (yes in .net 4.0)
type parameter static members
no
yes
static scope
shared among all generic realizations
separate for each generic realization
array component types
limited
all types
Both languages now support generics programming, but they have taken different paths to its implementation.
Generics in Java are a language-only construction; they are implemented only in the compiler. The generated classfiles include generic signatures only in the form of metadata (allowing the compiler to compile new classes against them). The runtime has no knowledge of the generic type system, which meant that JVM implementations only needed minimal updates to handle the new class format.
To achieve this goal the compiler replaces all generic types by their upper bounds and inserts casts appropriately in the various places where the type is used. The resulting byte code will contain no references to any generic types or parameters. This technique of implementing generics is known as type erasure. This means that runtime information about the actual types is not available at runtime, and imposes some restrictions such as the inability to create new instances or arrays of generic type arguments. (See also Generics in Java.)
C# took a different route. Support for genericity was integrated into the virtual execution system itself and first appeared in .NET 2.0. The language then becomes merely a front-end for the underlying generics support in the execution system. As in Java, the compiler provides static type safety checking, but additionally the JIT performs load time verification of the correctness. Information on generic types is fully preserved at runtime, and allows complete reflection support as well as instantiation of generic types.
Java does not allow to specialize generic classes with primitive types, while C# allows generics for both reference types and value types, including primitive types. Java instead allows the use of boxed types as type parameters (e.g., List instead of List), but this comes at a cost since all such values need to be heap-allocated. In both Java and C#, generic specializations that use different reference types share equivalent underlying code,[2] but for C# the Common Language Runtime (CLR) dynamically generates optimized code for specializations on value types.

Notation and special features

Special feature keywords

keyword
feature, example usage
checked,unchecked
In C#, checked statement blocks or expressions can enable run-time checking for arithmetic overflow.
get, set
C# implements properties as part of the language syntax with their optional corresponding get and set accessors, as an alternative for the accessor methods used in Java, which is not a language feature but a coding pattern based on method name conventions.
goto
C# supports the goto keyword. This can occasionally be useful, for example for implementing finite state machines or forgenerated code, but the use of a more structured method of control flow is usually recommended (see criticism of the goto statement). Java allows labeled breaks and continues, which make up for many of the uses of goto.
switch(color)
{
    case Color.Blue:
         Console.WriteLine("Color is blue"); break;
    case Color.DarkBlue:
         Console.WriteLine("Color is dark");
         goto case Color.Blue;
    // ...
}
out, ref
C# has support for output and reference parameters. These allow returning multiple output values from a method, or passing values by reference.
strictfp
Java uses strictfp to guarantee the results of floating point operations remain the same across platforms.
switch
In C#, the switch statement also operates on strings and longs but only allows fallthrough for empty statements. Java switch statement does not operate on strings nor long primitive type but falls through for all statements (excluding those with 'break').
throws
Java requires every method to declare the checked exceptions or superclasses of the checked exceptions that it can throw. Any method can also optionally declare the unchecked exception that it throws. C# has no such syntax.
public int readItem() throws java.io.IOException
{
    // ...
}
using
C#'s using causes the Dispose method (implemented via the IDisposable interface) of the object declared to be executed after the code block has run or when an exception is thrown within the code block.
// Create a small file "test.txt", write a string, 
// ... and close it (even if an exception occurs)
using (StreamWriter file = new StreamWriter("test.txt"))
{
    file.Write("test");
}
yield
C# allows the use of the yield keyword to express iterator generators. In Java, iterators can be defined only using (possibly anonymous) classes, requiring considerably more Boilerplate code. Below is an example of an iterator that takes an iterable input (possibly an array) and returns all even numbers.
public static IEnumerable GetEven(IEnumerable numbers)
{
    foreach (int i in numbers)
    {
        if (i % 2 == 0)
            yield return i;
    }
}

Callbacks and Event handling

C# implements object oriented method pointers in the form of delegates. A delegate is a special type which can capture a reference to an instance or static method if its signature is compatible. Multicast-delegates are called events (see below). Delegates provide support for event-driven programming. They are type-safe references to methods and can be combined to allow multicasting. To support them there is a special syntax to define events in classes and operators to register, unregister or combine event handlers. Delegates support covariance and contravariance, and can be created as anonymous methods with full-featured closure semantics. In .NET, closures and anonymous delegates are syntactic sugar.[3][4]
Java does not have a language-level construct like the C# delegate. The observer[5] pattern is used for event-driven programming in Java. Anonymous inner classes are commonly used to implement the listener, allowing you to define the body of the class and create an instance of it in a single point in the code. Java anonymous classes has been seen by some as syntactic sugar, and to be more verbose than C# delegates.[citation needed]

Numeric applications

To adequately support applications in the field of mathematic and financial computation, several language features exist.[6] In this category, Java provides the strictfp keyword, that enables strict floating-point calculations for a region of code. This will ensure that calculations return the exact same result on all platforms. C# provides no equivalent, but does provide the built-in decimal type, for accurate decimal floating-point calculations. This forgoes the problems that exist with binary floating-point representations (float, double). Such binary representations are not suited to accurately represent decimal numbers and hence introduce rounding errors. For financial applications, an accurate decimal type is essential.
The BigDecimal class also provides such characteristics for Java. BigDecimal and BigInteger are types provided with Java that allow arbitrary-precision representation of numbers. The current release of the .NET framework (3.5) does not currently include such classes, although third party implementations exist (see Arbitrary-precision arithmetic).
In Java there is no way to provide the same level of integration for library-defined types such as BigDecimal or complex numbers as there is for the primitive types. For this purpose, C# provides the following:
§                     Operator overloading and indexers providing convenient syntax (see below).
§                     Implicit and explicit conversions; allow conversions such as exist for the built-in int type that can implicitly convert to long.
§                     Valuetypes and generics based on valuetypes; in Java every custom type must be allocated on the heap, which is detrimental for performance of both custom types and collections.
In addition to this, C# can help mathematic applications with the checked and unchecked operators that allow to enable or disable run-time checking for arithmetic overflow for a region of code. It also offers rectangular arrays, that have advantages over regular nested arrays for certain applications.[6]

0 Comments: