Programming in D for CSharp Programmers
Contents
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 ofusing
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_).
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 asbyte
; - The 8 bit unsigned integer from C#
byte
is written in D asubyte
; - There is no type equivalence for
decimal
- There are three types of char in D:
char
,wchar
anddchar
, 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 Dwchar
. - There are also three types of string in D:
string
,wstring
anddstring
. The direct equivalent of C#string
is in fact Dwstring
. 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 areifloat
,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
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; }
- Resources