CsharpDiff

From Nemerle Homepage

Contents

Introduction

This document lists basic differences between Nemerle and C# in a terse form. If you know Java or C++ you also should be able to use it.

It is meant as a reference for people already programming in Nemerle, not as a tutorial. For hints about learning Nemerle please consult the documentation.

Most changes (vs C#) are dictated by features, so please check them out first before judging about anything here :-)

There are also some minor differences, that didn't fit into this table.

New stuff

This section talks about the stuff more or less absent in C#.

C# Nemerle Remarks
void m(int _unused1, string _unused2) 
{ ... }
m (_ : int, _ : string) : void 
{ ... }
Upon each use the _ keyword generates a new name.
class Foo { 
  static readonly int x; 
  static int m () { ... } 
}
module Foo { 
  x : int; 
  m () : int { ... } 
}
module is a class that has all members static.


There are other things, that don't fit here very well (this document should be a short list of differences), so we just give some links.

Changes in expressions

C# Nemerle Remarks
int x = 3;
string y = "foo";
FooBarQux fbq = make_fbq ();
def x = 3;
def y = "foo";
def fbq = make_fbq ();

The values of x, y and fbq cannot be changed once defined. Immutable values have no direct equivalent in C# or Java.

int x = 3;
string y = "foo";
FooBarQux fbq = make_fbq ();
mutable x = 3;
mutable y = "foo";
mutable fbq = make_fbq();

The values of x, y and fbq can be changed. Mutable values behave like variables do in imperative languages.

expr_1 = expr_2 = expr_3;
def tmp = expr_3;
expr_2 = tmp;
expr_1 = tmp;
The type of the assignment operator is void.
cond ? expr_1 : expr_2;
if (cond) expr_1 else expr_2
No ternary operator, but everything is an expression. 'else' branch is mandatory here!
new Class (parms)
Class (parms)
The new keyword for creating an object is dropped.
new Class [size]
array (size)
If the type can be inferred from context (which is most of the time), you can drop the declaration.
new Class [size]
array (size) : array [Class]
If the type cannot be inferred, you must declare it.
new Type[] { expr_0, 
  expr_1, ..., expr_n }
array [expr_0, 
       expr_1, ..., 
       expr_n]
The array constructor.
if (cond) 
  return foo;
 
do_something ();
return bar;
if (cond) 
  foo
else {
  do_something ();
  bar
}
There is no return statement that cuts control flow in Nemerle.
if (cond) 
  answer = 42;
...
when (cond) 
  answer = 42;
...
if without else is called when. This optional short form is provided because Nemerle requires if statements to be paired with else.
if (!cond) 
  answer = 42;
...
unless (cond) 
  answer = 42;
// or: when (!cond) answer = 42;
...
if without "then" is called unless. Like when, nobody is forced to use it.
try {...} 
catch (FooException e) { ... }
catch (BarException e) { ... }
try {...} 
catch {
  | e is FooException => ...
  | e is BarException => ...
}
Nemerle's somewhat different try ... catch syntax is consistent with its match structure.
(type) expr
expr :> type
Runtime type cast, allows for downcasts and upcasts.
(type) expr
expr : type
Static cast, allows only upcast.
using System;
using SWF = System.Windows.Forms;
using System.Xml;
...
Console.WriteLine ("foo");
SWF.Form x = new SWF.Form ();
XmlDocument doc = new XmlDocument ();
using System;
using System.Console;
using SWF = System.Windows.Forms;
...
WriteLine ("foo");
def x = SWF.Form ();
def doc = Xml.XmlDocument ();

In Nemerle, you can apply the using directive to classes as well as namespaces. Opened namespaces allow you to cut the prefix of other namespaces, like System in System.Xml. More info.

using System.Windows.Forms;
 
Button button = control as Button;
 
if (button != null) 
  ...
else 
  ...
match (control) {
  | button is Button => ...
  | listv is ListView => ...
  | _ => ... // null case
}

Expressions returning null if a variable is of a given type must be simulated with match. It is a little bit longer construct, but pattern matching is a more general and powerful feature for most of the tasks where it would be used.

int y = x++;
++x;
def y = x;
x++;
++x;
The ++ and -- operators return void, just like assignment. So, both prefix and postfix versions are equivalent.

Changes in type definitions

C# Nemerle Remarks
static int foo (int x, string y) 
{ ... }
static foo (x : int, y : string) : int 
{ ... }
Types are written after variable names.
class Foo {
  public Foo (int x) 
  { ... }
}
class Foo {
  public this (x : int) 
  { ... }
}
The constructor's name is always this.
class Foo {
  ~Foo () 
  { ... }
}
class Foo {
  protected override Finalize () : void
  { ... }
}
There is no special syntax for the destructor, you just override the Finalize method.
class Foo : Bar {
  public Foo (int x) : base (x) 
  { ... }
}
class Foo : Bar {
  public this (x : int) { 
    base (x); 
    ... 
  }
}
The base constructor is called in the constructor's function body.
class Foo {
  int x;
}
class Foo {
  mutable x : int;
}
Fields to be changed outside the constructor need to be marked mutable.
class Foo {
  readonly int x;
}
class Foo {
  x : int;
}
Read-only is the default.
class C : I1, I2 {
  void I1.m () { ... }
  void I2.m () { ... }
}
class C : I1, I2 {
  I1_m () : void implements I1.m 
  { ... }
 
  I2_m () : void implements I2.m 
  { ... }
}
When two interfaces have methods which share a name, explicit names are required when implementing them.
using System.Runtime.CompilerServices.CSharp;
 
class C {
  public object this [int i] 
  { ... }
 
  [IndexerName("MyItem")]
  public int this [string name] 
  { ... }
}
class C {
  public Item [i : int] : object 
  { ... }
 
  public MyItem [name : string] : int 
  { ... }
}
Nemerle allows defining named indexers in an easier way, just like in VB.NET.

Generics in C#...

The syntax and semantics of parametric polymorphism in Nemerle is the same as what is called generics in C# 2.0. You will see a naming convention of prefixing type variables with an ', like 't. You need not obey it, though.

C# Nemerle Remarks
class A <T> { readonly T x; }
class A ['t] { x : 't; }
Type parameters are written in square brackets [...].
class A <T> where T : IComparable <T> 
{ ... }
class A ['t] where 't : IComparable ['t] 
{ ... }
class A <T> where T : IFoo, IBar 
{ ... }
class A ['t] where 't : IFoo, IBar 
{ ... }
class A <X,Y> where X : IFoo, IBar 
              where Y : IBaz 
{ ... }
class A ['x,Y] where 'x : IFoo, IBar 
               where Y : IBaz 
{ ... }
Multiple type variables. Using ' is optional, but it is a common naming convention in functional programming.
typeof(A<,>);
typeof(A[_,_]);
typeof expression
int meth<A> (A x) 
{ ... }
meth ['a] (x : 'a) : int 
{ ... }
Polymorphic method.
int meth<A> (A x) 
  where A : IFoo { ... }
meth ['a] (x : 'a) : int
  where 'a : IFoo { ... }
Polymorphic method with constraints.

The same (mostly)

This section lists things that are written (mostly) the same way as they are in C#. It only includes cases when it could be doubtful.

C# Nemerle Remarks
// A comment.
/* A possibly multiline
   comment. */
// A comment.
/* A possibly multiline
   comment. */
throw new System.ArgumentException ("foo");
throw System.ArgumentException ("foo")
throw is the same (but new is dropped).
@"foo\bar"
@"foo\bar"
Quoted string literals.
using System;
Console.WriteLine("Hello C#.");
using System.Console;
WriteLine("Hello Nemerle.");
In Nemerle the using directive can be applied to classes as well as namespaces.
try { 
  foo (); 
  bar (); 
} 
catch (Exception e) { 
  baz (); 
} 
finally { 
  qux (); 
}
try { 
  foo (); 
  bar () 
} 
catch { 
  e => baz () 
} 
finally { 
  qux () 
}
Simple try ... catch structures are nearly the same (note the match syntax in catch). Also, semi-colons are optional at the end of code blocks.

Other minor differences

There are some minor differences, mainly on the semantics level.

remember
You are very welcome to contribute to the documentation here!