Difference between revisions of "Programming in D for CSharp Programmers"

From D Wiki
Jump to: navigation, search
Line 261: Line 261:
 
   }
 
   }
 
  }
 
  }
 +
 +
== 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.
  
 
= Resources =
 
= Resources =

Revision as of 22:29, 15 April 2015

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.

Resources