D: Namespaces

Namespaces? So etwas hat D doch gar nicht. Dafür gibt es Module.
Das ist richtig.
Es mag den einen oder anderen geben, der sich aus C# oder C++ an namespaces (in deutsch: Namensräume) gewöhnt hat und diese nun in D vermisst.
Walter Bright, der Erfinder von D, ist der Meinung, dass Module die Aufgabe von namespaces vollständig übernehmen.
Bis zu einem gewissen Grad hat er auch recht, allerdings gibt es einige Dinge, die man vermisst, wenn man sie von namespaces her kennt.

Ein Modul z.B. kann keine Funktionen oder Variablen nach außen hin kapseln, mit der Möglichkeit, später per Prefix oder (in C++ durch using namespace …) je nach Wahl gänzlich verfügbar zu machen. Die Betonung liegt dabei auf später & auf Prefix. Man kann auch nicht explizit verlangen, dass das Modul als namespace dienen soll, denn dann müsste man irgendwie erzwingen, dass das Modul per static import importiert wird.

Was man aber tun könnte: statische Variablen in einer (finalen) Klasse kapseln. Allerdings: was macht man bei Funktionen?
More »

D: Benchmark für Parameter storage classes

Eventuell kennen manche das aus C++.
Objekte werden bei Parameter Übergabe kopiert, wenn nicht anders angegeben. Deswegen ist es in C++ Standard geworden, Objekte von denen man nur bestimmte Daten braucht, als Referenz zu übergeben. Und damit sie Konstant und damit nicht innerhalb dieser Methode/Funktion unglücklicherweise aus Versehen geändert wird, schreiben wir auch const davor.
Etwa so:

void Foo::get_something(const Bar & bar) const {
    std::cout << "Punkte: " << b.get_points() << std::endl;
}

In D ist es dagegen wie in Java oder C#: Objekte werden Standardmäßig als (Konstante) Referenz übergeben, auch genannt call by reference.
Allerdings nicht so bei Structs. Diese werden wie gewohnt als Kopie übergeben (call by value) und können damit einiges an Speicher und Laufzeit fressen.
Also bietet es sich hier an, wie in C++ zu verfahren und mit Referenzen statt mit Kopien zu arbeiten, um effizientere Programme zu schreiben. Aber wie groß ist eig. der Unterschied in D? Wegen dieser Frage habe ich mir in den letzten Tagen folgendes Benchmark Script geschrieben und diverse Parameter Storage Klassen (in*, out, ref, const, const ref, ref const) getestet, aber auch die normale Übergabe per Kopie.
Dabei ist out als nicht wirklich ernst zunehmender Konkurrent angetreten. Warum? Weil out alles auf die Initialisierungs- bzw Ausgansform zurücksetzt. So auch bei diesem Test, bei dem eigentlich x mal (drei Durchgänge á 500.000, sowie drei Durchgänge á 100.000) ein Array eines Struct mit 25.000 Elementen befüllt und dann intern durchgegangen und benutzt wurde.
Mittels out wurde natürlich wieder alles geleert. out kann somit als leerer Vergleich angesehen werden, sprich wie lange das Struct ohne 25.000 Array Elemente gebraucht hätte.

*Mir ist klar, das in nur ein alias für const scope ist, aber es ist hier dennoch der Vollständigkeitshalber & weil mich evtl. auftretende Unterschiede interessierten.

Benchmark Script:

Show »

import std.stdio;
import core.time;
 
class Timer {
    private TickDuration _timer;
    private long _starttime;
    private ubyte _count;
 
    void start() {
		_count++;
 
		_starttime = _timer.currSystemTick().msecs;
	}
 
    double stop() {
		long time = _timer.currSystemTick().msecs - _starttime;
 
		float ticksPerSec = 1000.f;
		/*
		writefln("[%d] Elapsed time = %d.%010d seconds",
			_count,
			cast(int) (time / ticksPerSec),
			cast(int) (time % ticksPerSec)
		);
		*/
		return time / ticksPerSec;
    }
}
 
struct Node {
	int[] array;
 
	this(const int n) {
		for (uint i = 0; i < n; i++) {
			array ~= i;
		}
	}
 
	void doStuff() const {
		foreach (const int i; array) {
			int k = i * 2;
		}
	}
}
 
class A {
 
	this(Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("normal: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
class B {
	this(const Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("const: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
class C {
	this(in Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("in: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
class D {
	this(ref Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("ref: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
class E {
	this(const ref Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("const ref: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
class F {
	this(ref const Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("ref const: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
class G {
	this(out Node n) {
		static bool cout = false;
		if (!cout) {
			cout = true;
			writeln("out: ", typeid(n));
		}
 
		n.doStuff();
	}
}
 
void main() {
	immutable ushort num = 25000;
	immutable uint c = 500000;
 
	Timer t = new Timer();
 
	double runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		A obj  = new A(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
 
	runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		B obj  = new B(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
 
	runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		C obj  = new C(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
 
	runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		D obj  = new D(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
 
	runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		E obj  = new E(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
 
	runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		F obj  = new F(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
 
	runtime = 0.0;
	for (uint j = 0; j < c; j++) {
		t.start();
		Node n = Node(num);
		G obj  = new G(n);
		runtime += t.stop();
	}
	writefln("Elapsed Time: total: %f sec. average: %f sec.", runtime, runtime / c);
}

More »

D: gleichnamige Methode als Template führt zu Konflikt

Vor ein paar Tagen fiel mir ein Bug oder zumindest ein merkwürdiges Verhalten in D auf.
Jeder kennt das nette Feature, dass zwei Methoden den gleichen Namen tragen dürfen, sofern sie sich in ihren Parametern (und/oder return Typ) unterscheiden.
Außerdem ist es möglich, das eine der gleich benannten Methoden ein Template ist.
Bspw. möchte man eine Koordinaten oder Rechteck Klasse haben, in der man explizit ein short für einen x oder y Punkt zurückerwartet, aber möchte dem Benutzer das manuelle umcasten von bspw. float in short Werte abnehmen.
Man definiert also eine Template Methode, welche einen impliziten Typ deklariert den man später in der Methode zu short castet (idealerweise nur, wenn es nicht schon ein short ist ;) ).
More »

How to: Templates und Operator Overloading

In diesem Artikel möchte ich die Nützlichkeit von Templates (vor allen was Makro Anhänger in C++ angeht) und dem überschreiben von (Arithmetischen) Operatoren in C++ und D zeigen.
Ich werde ein bei mir aktuelles Bsp. aufgreifen und dann einen Lösungsweg Stück für Stück in D entwickeln, aber auch den C++ Äquivalent dazu.

Vielleicht kennt jemand das Problem schon:
Angenommen, man hat eine derartige Template Struktur

  1. alias Vector2!(float) Vector2f;
  2. alias Vector2!(short) Vector2s;
  3.  
  4. struct Vector2(T) {
  5. 	T x, y;
  6.  
  7. 	this(in T x, in T y) {
  8. 		this.x = x;
  9. 		this.y = y;
  10. 	}
  11. }

Und des Weiteren hat man ein Element wie Vector2f v1 = Vector2f(1.5, 2.3); und muss es, aus irgendeinem Grund, in einen Vector2s umwandeln/casten.
Wie stellt man das am besten an?
More »

Dgame beta

Dgame geht endlich online. Der Doku fehlt es zwar noch an ausführlichen Beschreibungen der einzelnen Modul Methoden, jedoch sollten die meisten selbsterklärend sein, zudem gibt es ja einige Beispiele ;) Vervollständigt wird die Dokumentation aber dennoch noch.
Die Doku und das Framework an sich kann hier angesehen bzw. runtergeladen werden.
Wie auch schon der Titel sagt, ist Dgame zur Zeit nur eine Beta Version (um genauer zu sein Version 1.3), also nicht groß getestet, nur um Beschwerden vorzubeugen.
Dgame wird also weiter entwickelt.

Copyright © All Rights Reserved · Green Hope Theme by Sivan & schiy · Proudly powered by WordPress