Programming in D for CSharp Programmers

From D Wiki
Revision as of 22:41, 15 April 2015 by O3o (talk | contribs) (Property)
Jump to: navigation, search

Introduction: Hello world

The C# Way

using System;
class Hello {
  static void Main(string[] args) {
    Console.WriteLine("Hello world!");
  }
}

The D Way

import std.stdio;
void main(string[] args) {
  writeln("Hello world");
}

Things we learnt so far:

  • standard file extension for D source code files is .d
  • we import a module instead of using a namespace;
  • static methods can be declared outside a class;
  • we can call directly any method even if it’s not declared in a class (writeln);
  • writeln is D equivalent for C# Console.WriteLine;
  • syntax is exactly the same as in C# (method definitions, string qualifiers, array declarations, comments)
  • many of the keywords are exactly the same (void, string);


Coding styles

  • D programmers prefer to use the camelCase notation instead of PascalCase for method names, variable names and enum members;
  • Module names (C# namespaces) are always in lowercase due to cross-platform compatibility regarding file names.
  • If there are conflicts between a named entity and a keyword, in C# you can use verbatim identifiers (@while). D does not have verbatim identifiers, but the convention is to add an underscore at the end of the entity (while_).

The C# Way

  • classes, structs, delegate types: PascalCase
  • methods, properties, events, enum declaration: PascalCase
  • local variables, fields: camelCase
  • constants, enum members: PascalCase

The D Way

  • classes, structs, delegate types: PascalCase
  • methods, properties, enum declaration: PascalCase
  • local variables, fields: camelCase
  • constants, enum values: camelCase


Type system

Built-in types

Basic type names are very similar in both languages with the following differences:

  • The 8 bit signed integer from C# sbyte is written in D as byte;
  • The 8 bit unsigned integer from C# byte is written in D as ubyte;
  • There is no type equivalence for decimal
  • There are three types of char in D: char, wchar and dchar, each of them corresponding to an UTF encoding : UTF-8, UTF-16 and UTF-32. Since C# is using internally UTF-16 chars, the direct equivalent of C# char is D wchar.
  • There are also three types of string in D: string, wstring and dstring. The direct equivalent of C# string is in fact D wstring. These are not keywords in D, they are in fact declared as aliases to immutable char arrays.
  • There is another floating point type in D: real with no type equivalence in C#.
  • Complex floating point types Complex<T> are keywords in D: cfloat, cdouble, creal and they imaginary counterparts are ifloat, idouble, ireal;

Arrays

Arrays in D are not too different than the ones form C# (for D see D Koans and dlang)

Static array

Initialize with a literal

The C# Way

 string[] fruits = {"banana", "mango", "apple", "orange"};
 // or long mode
 //string[] fruits = new string[4]{"banana", "mango", "apple", "orange"};
 Assert.AreEqual(fruits[0], "banana");
 Assert.AreEqual(fruits.Length, 4);

The D Way

string[4] fruits = ["banana", "mango", "apple", "orange"];
assertEquals(fruits[0], "banana");
assertEquals(fruits.length, 4);

Initialize with same value

The C# Way

// no short way
int[] b = { 1, 1, 1}; // 3 elements with same value 1

The D Way

int[3] b = 1; // 3 elements with same value 1

Dynamic array

For D see D Koans and dlang

The C# Way

List<T> works very similarly to a dynamic array

using System.Collections.Generic;
...
List<string> fruits = new List<string>{"banana", "mango"};
Assert.AreEqual(fruits.Count, 2);
fruits.Add("strawberry");
Assert.AreEqual(fruits.Count, 3);
Assert.AreEqual(fruits[2], "strawberry");


The D Way

string[] fruits = ["banana", "mango"];
assertEquals(fruits.length, 2);

fruits ~= "strawberry";
assertEquals(fruits.length, 3);
assertEquals(fruits[2], "strawberry");

Pointers

Since D is not a managed language, you are free to use pointers anywhere in the code, without encompassing them in an unsafe context. On the contrary, D code is by default unsafe, but you can force the safe context using the @safe keyword:

The C# Way

int value;
// here you can't use pointers
unsafe {
  int* p = &value
}

The D Way

int value;
int* p = &value
@safe {
  //here you can't use pointers
}

Delegates

Delegates in D are declared with the same keyword, but the return type precedes the declaration:

The C# Way

delegate int F

The D Way

int delegate(int x) Foo;
int function(int x) Foo;

Since D doesn't need to declare methods inside a class, you can declare also a function, equivalent to a delegate without class context. A notable difference between C# and D is the fact that delegates are not multicast in D, therefore you cannot join or remove them.

Enums

There is no difference between enum declarations, except that so called C# flags enums are not necessarely decorated with the [Flags] attribute:

The C# Way

enum Option { 
   Option1, 
   Option2
}
[Flags]
enum Options {
   Option1,
   Option2,
   All = Option1 | Option2
}

The D Way

The members of enums should be camelCased, so their first letter is lowercase. (see D Style

enum Color {  
  red, 
  green, 
  blue
}
enum Permission {
   read,
   write,
   all = read | wite
}

Struct

Struct are declared exactly the same way in D except:

  • There is no explicit layout in D. Nevertheless, there is a solution in the standard library.
  • Structs cannot implement interfaces

The C# Way

public struct TimeOfDay {
  public int hour;
  public int minute;
  public TimeOfDay(int h, int m) {
    hour = h;
    minute = m;
  }
}
...

var t1 = new TimeOfDay(8, 30);
Assert.AreEqual(t1.minute, 30);

// Declare a struct object without "new.
TimeOfDay t2;
t2.minute = 10;
Assert.AreEqual(t2.minute, 10);

The D Way

struct TimeOfDay {
  int hour;
  int minute;
}
... 

auto t1 = TimeOfDay(8, 30);  // preferred syntax
assertEquals(t1.minute, 30);
TimeOfDay t2 = {9, 45};      // alternate C syntax
assertEquals(t2.hour, 9);
auto t3 = TimeOfDay(10);     // not all members need to be specified
assertEquals(t3.minute, 0);


Union

D has unions, the equivalent of a C# struct with explicit layout where all fields offsets are 0

The C# Way

[StructLayout(LayoutKind.Explicit)]
struct MyUnion {
  [FieldOffset(0)]
  int someInt;
  [FieldOffset(0)]
  float someFloat;
}

The D Way

union MyUnion {
  int someInt;
  float someFloat;
}


Interfaces

Interfaces are declared in the same way as in C#, the only difference being that interfaces in D can have final methods, equivalent to C# abstract class

The C# Way

interface I {
  void Method();
}

abstract class C {
  void Method() {
    Console.WriteLine("hello");
  }
}

The D Way

interface I {
  void Method();
}

interface C {
  final void Method() {
     Console.WriteLine("hello");
  }
}

Generic Types

D is not using generics, instead it has a more powerful concept named templates.

The C# Way

public class A {
  public void Foo<T>(T arg) {}
}
public class C<T> where T: class { }
public class X { }
public class D<T> where T: X {}
...                                           
A a = new A();
a.Foo<int>(1);
C<A> c = new C<A>();
// C<int> i = new C<int>(); compiler error: int isn't a class

D<X> d = new D<X>();
//D<A> d = new D<A>();compiler error: A isn't X


The D Way

void Foo(T)(T arg);
class C(T) if is(T == class) {}
class X {} 
class D(T) if is(T : A) {}

There are no direct equivalents of other generic constraints, but the D template system is so versatile that you can create your own.

The C# Way

class C<T> where T: new() {}

The D Way

class C(T) if (is(typeof(new T()) == T))

The template constraint will be read as if the result of expresssion new T() is of type T. If the T class has no contructor or is some other type, the new T() expression will result in an error or some other type, therefore the constraint will not be satisfied.


Events

There is no such concept in D language, but D programmers prefer to use signals and slots instead of events.

If you are keen to use events in D, a quick and dirty way to implement them can be found below:

TO DO

Dynamic Types

There is no such concept in D language. All types must be known at compile time but the same semantics can be simulated by forwarding.

Boxing

TO DO u

Nullable types

'TO DO

Enumerable types

'TO DO

Code Attributes

Property

The C# Way

class Person {
  public Person() {
    Name = "Default Name";
  }
  public string Name { get; set; }
}

The D Way

class Person {
  private string _name;
  this() {
    _name = "Default Name";
  }

  @property string name() {
    return _name;
  }
  @property void name(string n) {
    _name = n;
  }
}

Resources