Thursday, February 4, 2010

Methods

Methods in C# are non-virtual by default, and have to be declared virtual explicitly if desired. In Java, all non-static non-private methods are virtual. Virtuality guarantees that the most recent override for the method will always be called, but incurs a certain runtime cost on invocation as these invocations cannot be normally inlined, and require an indirect call via the virtual method table. However, some JVM implementations, including the Sun reference implementation, implement inlining of the most commonly called virtual methods.
In Java methods are virtual by default (although they can be "sealed" by using the final modifier to disallow overriding). There is no way to letderived classes define a new, unrelated method with the same name. This can be a problem when a base class is designed by a different person, and a new version introduces a method with the same name and signature as some method already present in the derived class. In Java, this will mean that the method in the derived class will implicitly override the method in the base class, even though that was not the intent of the designers of either class. To prevent this versioning problem, C# requires that if a method should be overridden, the overridekeyword must be specified. Otherwise, the method will "hide" the inherited method. A compiler warning to this effect is issued, which can be silenced by specifying the new keyword. This avoids the problem which can arise from a base class being extended with a protected/public method whose signature is already in use by a derived class. In Java a recompilation will lead the compiler to regard the method of the derived class as an override of the method of the base class, which was probably not the intent of the base-class developer. To partially accommodate for these versioning problems, Java 5.0 introduced the @Override annotation, but to preserve backwards compatibility it could not be made compulsory, so it cannot prevent the above accidental overriding situation. Like the override keyword in C#, it can however help ensure that a method in the base class with the same signature exists and is correctly overridden.

Explicit interface implementation

In either language if a method (or property in C#) is specified with the same name and signature in multiple interfaces, the members will clash when a class is designed which implements those interfaces. An implementation will by default implement a common method for all of the interfaces. If separate implementations are required (because the methods really do serve separate purposes, or because return values differ between the interfaces) C# explicit interface implementation will solve the problem. In Java there is no way to solve this problem other than to refactor one or more of the interfaces to avoid name clashes. C# explicit implementation will also hide the method from the primary class interface, and can thus help reduce the class interface complexity.

Closures

When a reference to a method can be passed around for later execution, a problem arises about what to do when the method has references to variables/parameters in its lexical scope. C# has true closures in which the referenced method can fully capture any variable/parameter from its lexical scope. In Java's anonymous inner classes only references to final members of the lexical scope are allowed, thus requiring the developer to artificially introduce extra levels of indirections and boxing primitive types if he wants to reference and update those from the inner class.
Java does not feature closures. Although they were at one point proposed for Java SE 7, none of the proposals are going to be included in Java 7 [8].
In Java, anonymous inner classes remains the preferred way to emulate closures. Aside from being a more verbose construction, this approach also has some drawbacks compared to real closures, such as limited access to variables from the enclosing scopes (only final members can be referenced).

Lambdas and expression trees

C# features a special type of inline closures called lambdas. These are anonymous methods: they have a signature and a body, but no name. They are not methods in that they cannot form part of a class interface. They are mainly used to specify local function-valued arguments in calls to other methods, a technique mainly associated with functional programming. On top of that, lambda functions can double as a way to define special data structures called expression trees. Whether they are seen as an executable function or a data structure depends on compiler type inference and what type of variable or parameter they are assigned/cast to. Lambdas and expression trees play key roles in LINQ. Java does not feature lambdas or expression trees; its primary mechanism for inline scope capture and method definition is the anonymous inner class syntax.

Partial methods

Related to partial classes C# allows partial methods to be specified within partial classes. A partial method is an intentional declaration of a method with a number of restrictions on the signature. These restrictions ensure that if a definition is not actually provided by any class part, then the method and every call to it can be safely erased. This feature allows code to provide a large number of interception points (like thetemplate method GoF design pattern) without paying any runtime overhead if these extension points are not being used by another class part at compile time. Java has no corresponding concept.

Extension methods

Using a special this designator on the first parameter of a method, C# allows the method to act as if it were a member method of the type of the first parameter. This extension of the foreign class is purely syntactical. The extension method needs to be static and defined within a purely static class. It must obey any restriction on such external static methods and thus cannot break object encapsulation. The "extension" is only active within scopes where the namespace of the static host class has been imported. Java has no corresponding concept.

Generator methods

A C# method which is declared as returning IEnumerable, IEnumerator or the generic versions of these interfaces, can be implemented using yield syntax. This is a form of limited, compiler-generated continuations and can drastically reduce the code required to traverse or generate sequences, although that code is just generated by the compiler instead. The feature can also be used to implement infinite sequences, e.g. the sequence of Fibonacci numbers. Java has no corresponding concept.

0 Comments: