Software Testing Blog

Why Java folks should stop looking down on C# [2/4] A brand new world

At Kalistick we are a Java shop from the beginning: the first version of our product analyzed only Java code. But we are not bigot, we are using and analyzing C# too since 2008. We notice that Java developers generally tend to look scornfully at C#, as a copycat created by Microsoft and used by dummies. In theses blog series, I am going to try to sweep this nonsense and show some of the C# goodness.
In the previous post, I showed the “minor” differences between C# and Java in features shared by the two languages. In this post, I am going to show you the features that truly differentiate C# from Java.

Delegate: Method as a first-class citizen

A delegate is a special type that defines a method signature. Delegates are like C function pointers with type safety that allow methods to be passed as parameters and stored in a structure or a class.

// Declaration of a delegate type
delegate string StringOperation(string str); 

public class Delegates
{
  public static string Reverse(string str) // doesn't support full unicode charset
  {
    char[] arr = str.ToCharArray();
    Array.Reverse(arr);
    return new string(arr);
  }

  public static void Main(string[] args)
  {
    StringOperation normalizeOp;

    // Creation of a delegate instance
    normalizeOp = Delegates.Reverse;
    Console.WriteLine(normalizeOp("abcd")); // dcba

    // Instantiate the delegate using an anonymous method.
    normalizeOp = delegate(String str) { return str.Trim(); };
    Console.WriteLine(normalizeOp("  abcd "));  // abcd
  }
}

To mimic this feature in Java, the developer will have to create a class implementation (generally an anonymous inner class) where one method performs the action.

interface StringOperation 
{
  String invoke(String str);
}

public class Delegates
{
  public static String reverse(String str)
  {
    return new StringBuffer(str).reverse().toString();
  }

  public static void main(String[] args)
  {
    StringOperation normalizeOp;

    normalizeOp = new StringOperation(){
      public String invoke(String str)
      {
      	return Delegates.reverse(str);
      }
    };

    System.out.println(normalizeOp.invoke("abcd")); // dcba

    normalizeOp = new StringOperation(){
      public String invoke(String str)
      {
      	return str.trim();
      }
    };

    System.out.println(normalizeOp.invoke("  abcd ")); // abcd
  }
}

The ability to refer to a method as a variable or as a parameter makes delegates ideal for a lot of usage, delegates are used everywhere in C#, as event handlers, thread actions, callbacks in asynchronous programming, in LINQ…

Event

In a GUI environment, any number of controls can raise an event (button click, menu selection, completion of a file transfer). Other classes will be interested in responding to these events but the publisher of the event is not interested by how classes receiving the event will respond. C# provide a specific syntax to enable event-driven programming implementing the publish/subscribe pattern.

class Button
{
  public delegate void Action();
  public event Action Click;

  public void PerformClick()
  {
    OnClick();
  }

  private void OnClick()
  {
    if (Click != null)
    {
      Click();
    }
  }
}

class Program
{
  static void PerformAction()
  {
    Console.WriteLine("Work!");
  }

  public static void Main()
  {
    Button button = new Button();

    // Subscribe to the event
    button.Click += PerformAction;
    button.PerformClick(); // Work!

    // Unsubscribe
    button.Click -= PerformAction;
    button.PerformClick(); // Nothing
  }
}

In Java, there is no general mechanism for event handling, instead events are manually implemented with the observer pattern: anonymous inner classes are commonly used to implement the listener, allowing the developer to define the body of the class and create an instance of it in a single point in the code.

public interface ClickListener extends EventListener 
{
  public void click();
}

public class Button 
{
  protected EventListenerList listenerList = new EventListenerList();

  public void addMyEventListener(ClickListener listener) 
  {
    listenerList.add(ClickListener.class, listener);
  }

  public void removeMyEventListener(ClickListener listener) 
  {
    listenerList.remove(ClickListener.class, listener);
  }

  public void performClick()  
  {  
    onClick();  
  } 

  void onClick() 
  {
    Object[] listeners = listenerList.getListenerList();
    for (int i=0; i<listeners.length; i+=2) 
    {
      if (listeners[i]==ClickListener.class) 
      {
        ((ClickListener)listeners[i+1]).click();
      }
    }
  }
}

public class Program 
{
  public static void main(String[] args) 
  {
    Button button = new Button();
    button.addMyEventListener(new ClickListener() {
      public void click(EventArgs evt) 
      {
        System.out.println("Work!");
      }
    });

    button.performClick();
  }
}

Lambda Expression: Delegate on steroids

A lambda expression is an anonymous function that can be used to create delegates. Syntacticly it is composed of three parts: an input parameters list, the lambda operator =>, and a method body. Thanks to type inference, you often do not have to specify a type for the input parameters: the compiler can infer the type based on the body and the underlying delegate type.

delegate bool Assertion(int value);

// Equivalent to (int x) => x == 42;
Assertion isUniverseAnswer = x => x == 42;
isUniverseAnswer(42); // true

One of the most important features of Lambda Expressions (and anonymous methods) is that they execute in the context of their declaration. Therefore, they can use the values of variables defined in that context.

List<User> FindAllYoungerThan(List<User> users, int limit)
{
  // The lambda expression uses the outer variable "limit"
  return users.FindAll(user => user.Age < limit);
}

Lambda expressions can be used to implement closures. Closures can be defined as functions that capture the state of the environment that is in scope where they are declared.

delegate void Action();

static Action CreateAction()
{
  int counter = 0;
  // Returns a delegate, the action is not executed here.
  return () => Console.WriteLine("counter={0}", counter++);
}

void Main()
{
  Action action = CreateAction();
  action(); // counter=0
  action(); // counter=1
}

LINQ’s awakening

LINQ (Language-Integrated Query) is a set of technologies based on the integration of query capabilities directly into C#. With LINQ, queries are a first-class language construct.

IEnumerable<int> query = 
              from user in users
              select user.Age;

Query expressions are written in a declarative query syntax allowing filtering, ordering, and grouping operations. The same query expression could be used to query and transform data in from various sources: databases, datasets, XML documents, and collections. A single query can retrieve data from a SQL database, and produce an XML stream as output. The execution of the query is deferred until the result is requested. Deferred execution can greatly improve performance when manipulating large data collections with a series of chained queries or manipulations.

// 1. DataSource
int[] numbers = new int[] { 0, 1, 2, 3, 4, 5, 6 };

// 2. Query creation.
IEnumerable<int> numQuery = from num in numbers
                            where (num % 2) == 0
                            select num;

// 3. Query execution.
foreach (int num in numQuery)
{
  Console.Write("{0,1} ", num); // 0 2 4 6
}

There is no magic behind LINQ: at compile time, query expressions are converted to standard method calls using query operators.

IEnumerable<int> querySyntax = 
              from user in users
              select user.Age;

IEnumerable<int> methodSyntax = users.Select(user => user.Age);

No more StringUtils with Extension method

It is rather common to have classes full of utility methods that mostly enhance the functionalities of some other classes (StringUtils, ArrayUtils…)

Extension methods enable you to “add” methods to existing types without creating a new derived one or modifying the original. They are called as if they were instance methods on the extended type. The extension methods will hang on the type, so they will be easier to find with completion than an Util class.

string reversed = "Example".Reverse();
reversed = StringUtils.Reverse("Example")

Extension methods are used for LINQ to add standard query operators on existing IEnumerable types (Select, Where, GroupBy, OrderBy, Average…).

Pass by reference

In Java, arguments to a method are passed by value; a method operates on copies of the items passed to it instead of on the actual items: a copy of the value for primitive type and a copy of the reference for objects. Because of that simple things like swapping two numbers in a method are not easily doable in Java (must use a wrapper or some arithmetic).

By default, it works the same way in C# but it is possible to specify that the arguments of a method must be pass by reference. This is particularly useful when you want to create a method that returns more than one object.

A common pattern in the .NET framework is the TryXXX pattern. For example methods int Int32.Parse(string) and bool Int32.TryParse(string, out int) use this pattern, Int32.Parse is used to convert a string to an integer. The TryParse method is like the Parse method, except that TryParse does not throw an exception if the conversion fails. It eliminates the need to use exception handling in case the string cannot be successfully parsed.

// Using Parse method, with exception handling
int quantity;
try
{
  quantity = int.Parse(input);
}
catch (FormatException)
{
  quantity = 0;
}

// Using TryParse
int quantity;
if (!Int32.TryParse(txtQuantity.Text, out quantity))
{
  quantity = 0;   
}

This feature could also be used to improve performance when dealing with value type. When a value type is passed to a method its value is copied, if the value type is large (e.g. a 4×4 matrix includes 16 floats) it is better to pass a reference of the value type instead of a copy of it.

Matrix view = ...;
Matrix projection = ...;

Matrix viewProjection;
Matrix.Multiply(view, projection, out viewProjection); 
// viewProjection = view * projection;

Partial type

.NET is big into automatic code generation: Visual Studio uses this for Windows Forms, Web service wrapper code creation. To facilitate the usage of generated code it is possible to split the definition of a class, a struct, an interface or a method over two or more source files. Each source file contains a section of the type or method definition, and all parts are combined when the application is compiled. That way one part of the type is edited by the code generator while the other part could be edited by the developer without the risk of the generator overwriting that code later.

// In file A
partial class HumptyDumpty
{
  private string name = "Humpty Dumpty";

  public void Rhyme()
  {
    Sat();
    Fall();
    TryPutTogether(); 
  }

  public void TryPutTogether()
  {
    string putTogether = @"All the king's horses and all the king's men
                           Couldn't put Humpty together again.";
    Console.WriteLine(putTogether);
  }
}
// In file B
partial class HumptyDumpty
{
  void Sat()
  {
    Console.WriteLine("{0} sat on a wall,", name);
  }

  void Fall()
  {
    Console.WriteLine("{0} had a great fall.", name);
  }
}

One useful usage is unit testing: the set of unit tests for a class is often much larger than the class implementation itself; the tests could be split into chunks using partial types. That way it is easier to work with the test suite but all the tests could still be run in one session (it is still a single test class).

Is that all?

Dynamic

Since version 4, C# provides a dynamic type. The main point is interoperability with COM API (Office API for example) and dynamic language such as IronPython or IronRuby (Python and Ruby running on the CLR). This feature will not be used by many developers in their day-to-day coding, but it can be useful and the cleaner way in some situation.

Example of C# code calling a python method through dynamic and IronPython.

ScriptRuntime py = Python.CreateRuntime();
dynamic random = py.UseFile("random.py");

int[] items = new int[]{0,1,2,3,4,5};

random.shuffle(items);

Null-coalescing operator

The null-coalescing operator ?? is used to define a default value. It is like a conditional binary operator tweaked for null value.

string address = user.BillingAddress ?? 
                 user.ShippingAddress ??
                 user.ContactAddress;

// Equivalent to:
string address = user.BillingAddress;
if (address == null)
{
  address = user.ShippingAddress; 
  if (address == null)
  {
    address = user.ContactAddress;
  }
}

Automatic Resource Management

The using keyword provides an easy way to manage resource by handling resource disposal automatically.

string line = String.Empty;
StreamReader reader;
try
{
  reader = new StreamReader("file.txt"));
  line = reader.ReadLine();
}
finally
{
  if (reader != null)
    reader.Dispose();
}

This sample which uses the using keyword is equivalent to the previous one.

string line = String.Empty;
using (StreamReader reader = new StreamReader("file.txt"))
{
  line = reader.ReadLine();
}
Console.WriteLine(line);

Automatic resource management will be introduced in Java 7 as well (through java.lang.AutoCloseable interface).

try ( FileInputStream in = new FileInputStream("input.txt");
       FileOutputStream out = new FileOutputStream("output.txt")) 
{
  int c;
  while((c=in.read()) != -1 )
    out.write();
}

And more

  • Easy lazy iterator with yield
  • Nullable type
  • Unsafe code
  • Conditional compilation

It’s a wrap!

In this post I have showed C# features that differentiate the language from Java and which make C# a broader language with functional and dynamic pieces, with the objective of improving the expressiveness of the language.

In the following post I am going to describe the platform and infrastructure: framework, ide, build tool, continuous integration server…

  1. Pour info le “project Lambda” du JDK8 devrait apporter les expressions Lambda, les types SAM et les les références de méthodes, ce qui devrait apporter des possibilités similaires aux lambda/delegate de C# (malgré une approche un peu différente).

    Il sera possible d’avoir des éléments proches des events et de LINQ par exemple (sans le langage spécifique pour ce dernier).

    En ce qui concerne les méthodes d’extensions par contre, le JDK8 semble partir vers une orientation assez différentes mais tout aussi intéressante avec les “defender’s methods”.

    a++

  2. At my first job I got the opposite reaction from C# developers. At the time I couldn’t see any real difference between C# and Java and only leant towards Java for my own projects because I had more experience in it. Now C# has made the huge improvements that you listed while Java has stagnated. But I still keep ending up coding in Java

  3. Nice. Though there are more differences, these are most important for Java folks. Looking forward to read the next article.

  4. EventListenerList is old very old anyone implenting it in this day and age will use List listeners = new CopyOnWriteArrayList();and for(Listener listener : listeners) listener.call();

    also a button is a poor example as one generally should use an Action which you share/pass around and has state. Actual wiring of events should rare.

    There are also libraries around which allow you to do the same in java though annotations and doesn’t involve introducing new semantics to the operators.

  5. C# is a Java clone except for the multi-platform feature. Microsoft could have joined the JCP, but no, instead it tried to kill Java by all means. Then when they noticed that they couldn’t kill Java, they decided to make their own Java, instead of admitting their defeat and joining the JCP: C# was born. Not the best way to convince Java developers.   
    I think that C# engineers certainly made a smarter decisions than the Sun engineers, so C# is certainly a good language, possibly even better than Java, but the point is that a lot of good programmers love open source (many good programmers like to learn, to hack, adapt, explore and open source is allowing them to do so), and despite what Microsoft wants to make you believe, C# just is not. Furthermore C# is exclusively targeted at the worst OS (series) ever, while many good programmers prefer to use a good OS. I think that they look down on these issues, directly related to the language, rather then the language itself.

  6. interface StringOperation  
    {  
      String invoke(String str);  
    }
    public class ReverseOperation implements StringOperation {
          public String invoke(String str)        {          return new StringBuffer(str).reverse().toString();        }}

    public class TrimOperation implements StringOperation {      public String invoke(String str)        {          return str.trim();        }}public class Delegates  

      
      public static void main(String[] args)  
      {  
        StringOperation normalizeOp;  
      
        normalizeOp = new ReverseOperation();  
      
        System.out.println(normalizeOp.invoke(“abcd”)); // dcba  
      
        normalizeOp = new TrimOperation();  
      
        System.out.println(normalizeOp.invoke(“  abcd ”)); // abcd  
      }  
    }Sans prendre les développeurs C# de haut, j’aime Java justement parce qu’il m’offre un rigueur très orientée objet.Ca pousse juste à créer des classes propres et réutilisables !Ce qui me gène c’est quand on vante le fait de pouvoir écrire du code dans tous les sens sans rigueur.On préserve le principe du SoChttp://en.wikipedia.org/wiki/Separation_of_concerns

    1. Mais comme disait estiedi dans son commentaire, ce n’est pas une histoire de langage, chaque langage a ses particularités, forces, faiblesses. Je constate que C# semble un langage de qualité. Mais le combat Java / .Net est plus un combat entre un modèle propriétaire et un modèle plus ouvert (bien que le rachat par Oracle pourrait changer la donne).

      1. Je crois qu’il fautp as mélanger open source et le language utilisé. Un programme en c# peut être open source, et inversément un prog en java ne veut pas dire qu’il est open source.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Current day month ye@r *