Donnerstag, 23. April 2009

Programmierung: Ein kleiner Einblick in D

Jeder der sich schon mal mit C++ befasst hat kommt irgendwann mal an den Punkt an dem er denkt "Oh man geht das nicht auch einfacher?". Fakt ist: Kaum eine Sprache ist so schwer zu lernen und so aufwändig durch den Compiler zu kriegen wie diese, dazu kommen noch einige C Altlasten und vor allem der Preprozessor. Oft ertappt man sich dabei möglichst trickreich die Sprache aus den Angeln zu hebeln (mir fällt da spontan das sizeof Voodoo ein um zur Compilezeit herauszufinden ob ein Cast gemacht werden kann oder nicht). Viele dieser Tricks basieren auf ausgefuchsten C++-Templates und gerade die sorgen bei vielen Programmierern für spontanes "schreiend im Kreis rennen" (schon mal mit Typelists gearbeitet? :P). Hier springt D von Digitalmars in die Bresche, oder versucht es zumindest. Ein paar Highlights möchte ich hier beleuchten.

Keine Rückwärtskompatibilität

Was in C++ Anfangs noch Mittel zum Zweck war ist inzwischen zu einem unangenehmen Anhängsel geworden. Vielen geht schon beim Anblick eines const char* die Sause geschweige denn der ganze Mist den Arrays mit sich schleppen. Vieles davon bessert die STL schon lange nach (std::string und std::vector sei dank) ein wenig übel ist der Nachgeschmack dennoch... zumindest für mich ;). Besonders "schön" ist da vor allem der Preprozessor hat er doch keine Ahnung was es mit der Sprache auf sich hat und setzt nur fröhlich irgendwelche Markos oder Definitionen ein. Entscheidungen die zur Compilezeit getroffen werden gehen an im vorbei da er ja schon lange fertig ist wenn es zur Sache geht. Hier kommen dann bei C++ die Templates zum Schuss and genau dort wird es für viele kompliziert. D bietet hier ein eigenes Sprachmittel: static if.

import std.stdio;

class A {}
class B : A {}
class C {}

void main(string[] args) {
static if (is(B : A)) {
writefln("B erbt von A");
} else {
writefln("B erbt nicht von A");
}
static if (is(C : A)) {
writefln("C erbt von A");
} else {
writefln("C erbt nicht von A");
}
}

Ohne große Umwege lässt sich hier das Gewünschte ausdrücken. Ein Preprozessor würde hier versagen da er keine Ahnung von Sprachmitteln wie Vererbung hat, man wäre also auf C++-Template Voodoo angewiesen, hier ist schon alles in der Sprache drin.

Besonders Templates wurden in D stark überarbeitet, da gerade hier sich Schwächen auftuen die zu sehr großen Problemen führen können. Das ganze Elend fängt schon bei der Syntax an. Da die Spitzen Klammern die in C++ verwendet werden auch irrtümlicherweise als größer oder kleiner-Operatoren angesehen werden können (in solchen Situationen muss man dem Compiler meist noch unter die Arme greifen). D benutzt hier eine etwas gewöhnungsbedürftige Syntax die allerdings diese Probleme umgeht da sie einen Operator verwendet der im Normalfall nur unär ist hier aber binär verwendet wird, nämlich den !-Operator.

import std.stdio;

template Foo(T) {
T a = 666;
}

void main(string[] args) {
alias Foo!(int) tmp;
writefln("%d",tmp.a);
}

Hier taucht auch gleichzeitig eine andere Besonderheit von D auf, das alias. Dieses Schlüsselwort macht eigentlich nichts anderes als das was wir von C/C++ kennen, denn im Gegensatz zu diesen Sprachen verfügt D über echte Typedefs die auch überladen können.

import std.stdio;

typedef int bla;

void test(int a) {
writefln("int: %d",a);
}

void test(bla a) {
writefln("bla: %d",a);
}

void main(string[] args) {
int a = 666;
bla b = 777;
test(a);
test(b);
}

Eine andere Kleinigkeit die bei unserem Template Beispiel aufgefallen ist, ist das es sich bei diesem Template weder um eine Template-Klasse noch um eine Template-Funktion handelt. Es ist einfach nur ein Template. Das bietet eine weitere Interessante Möglichkeit, nämlich Mixins.

import std.stdio;

template Foo(T) {
void test() {
writefln("Foo.test");
}
}

class Test {
public {
mixin Foo!(int);
}
}

void main(string[] args) {
Test t = new Test;
t.test();
}

Ein nicht ganz so offensichtliches Feature ist hier der Garbage Collector und der Fakt das hier nicht mit Pointern (keine Sorge die gibt es auch noch) sondern mit Referenzen gearbeitet wird wenn eine Klasse instanziiert wird. Hier scheiden sich sicherlich die Geister denn was bei Systemprogrammierung durchaus Sinn macht, kann beim Programmieren von Applikationen schnell zur Katastrophe werden und in wirklich scheusslichen Speicherlecks enden (oder pro-aggressiven Einsätzen von auto_ptr, shared_ptr und Konsorten).

Was auch sehr viel Spass macht ist das Wegfallen von Forward-Declarations. So geht z.B. folgendes:

import std.stdio;

void foo() {
bar();
}

void bar() {
writefln("foobar");
}

void main(string[] args) {
foo();
}


Kritikpunkte

D ist eine tolle Sprache und räumt mit einigen Sachen auf die bei C++ zu Verwirrung oder schlechtem Programmierstil führen auf. Dennoch ist die Unterstützung der Sprache noch mehr als dürftig da es im Endeffekt nur sehr wenige Compiler für sie gibt die im Grunde alle auf dem DMD von Digitalmars basieren. Auch fehlen mir einige In-Depth Einblicke die in für C++ zu Hauf gibt und gerade auf der Low-Level Seite von mir schmerzlich vermisst werden (bei Nachfrage wird man dann auch gerne mit der Standardantwort "read to code" abgefrühstückt). Auch ist die eine Aufspaltung der D Community durch 2 unterschiedliche "Standard"-Bibliotheken mehr als offensichtlich und auch nervig (Flamewars gibt es wirklich schon genug). Während ein Compiler Phobos nutzt kommt der andere nur mit Tango daher. Derzeit wird auch an D2.0 herumgeschustert und man kriegt langsam das Gefühl als werde auch diese Sprache immer überladener. Dennoch ist die Sprache so entworfen das einem nicht gleich pfundweise Fehlermeldungen um die Ohren geschleudert werden da gerade auf obskure veraltete Syntax verzichtet wurde. Für alle die aber etwas gesucht haben das so schnell wie C/C++ ist und mit viel vom Java/C# Komfort daherkommt ist diese Sprache sicherlich mal einen Blick wert. Java? Ja, D verzichtet unter anderem auf Multivererbung und setzt dafür auf Interfaces. Auch Schlüsselwörter wie final, abstract und synchronized sind oft einfach hilfreich wenn es darum geht schnell und leserlich das auszudrücken was man meint.

Das hier sind nur ein paar sehr kleine Details von dem was D ausmacht und bei weitem noch nicht alle. Sollte Interesse bestehen kann ich gerne auch noch etwas auf Details eingehen (vor allem Closures dürften dein ein oder anderen sicher interessieren, das sprengt hier aber glaub ich etwas den Rahmen ^^).

Samstag, 18. April 2009

Twitscher twitscher!

Aufgrund chronischem Spieltriebs hab ich mich einfach mal dazu entschlossen mich bei Twitter anzumelden. Da ich immer mal wieder Links finde die ich für mehr oder weniger für interessant erachte (und es irgendwie sinnlos ist jedesmal einen Blogartikel drüber zu schreiben) gibts die jetzt unter meinem neuen Twitteraccount. Follow me.... i know where they hide their cookies!

Mittwoch, 25. März 2009

C++: ABI zur Laufzeit entwirren

Die C++ typeinfo ist ja immer so eine Sache. Einige Compiler entwirren die Namen, andere wieder nicht. G++ gehört zu den Compilern die das nicht von sich aus machen, aber man kann sich leicht Abhilfe schaffen.

#include <typeinfo>
#include <iostream>
#include <cxxabi.h>

#define HAVE_CXA_DEMANGLE

#ifdef HAVE_CXA_DEMANGLE
const char* demangle(const char* name)
{
char buf[1024];
unsigned int size = 1024;
int status;
char* res;
res = abi::__cxa_demangle(name,
buf,
&size,
&status);
return res;
}
#else
const char* demangle(const char* name)
{
return name;
}
#endif

int main()
{
std::cout << typeid(std::cout).name();
std::cout << std::endl;
std::cout << ::demangle(typeid(std::cout).name());
std::cout << std::endl;
return 0;
}

/* Ausgabe :
[raichoo@sparkster:~]> ./a.out
So
std::ostream
*/

Sonntag, 15. Februar 2009

Haiku: A blast from the past

Ich hab ja schon immer gerne mit Betriebssystemen der unterschiedlichsten Art rumgespielt und vor vielen Jahren bin ich auch mit BeOS in Berührung gekommen. Leider war die Liebe nicht von langer Dauer da Be irgendwann Geschichte war und damit auch dieses wunderbare Betriebssystem. Es war schon unglaublich was man damals aus einer Kiste an Performance rausholen konnte. Viele Systeme ächzen heute noch und dem was BeOS damals schon geleistet hat, und zwar auf weitaus schlechterer Hardware als heute. Umso mehr habe ich mich über das Projekt Haiku gefreut das es sich zur Aufgabe gemacht hat ein freies BeOS zu entwickeln. Was es mir besonders angetan hat ist die reichhaltige API. Keine kilometerlangen Abhängigkeitslisten mehr Haiku bietet alles was man braucht in sogenannten Kits. Alles ist sehr stark integriert und greift wunderbar ineinander. Vor allem der einheitlich Desktop hat seine Vorteile. Während Projekte wie KDE und Gnome darauf ausgelegt sind auf möglichst vielen unterschiedlichen Systemen zu laufen hat Haiku "nur" eine Oberfläche welche sämtliche Vorteile des darunterliegenden Systems nutzen kann. Dies ist bei anderen Desktop nicht ohne weiters mögliche da sie sonst ihre Portierbarkeit verlieren würden. Ein weiterer Vorteil ist das das starten von Applikationen einfach rasend schnell wird. Wer gerne mit Systemen herumspielt sollte auf jeden Fall einen Stop bei Haiku einlegen. ;)

Freitag, 9. Januar 2009

Testphase für 2009.04 hat begonnen

Mit der Veröffentlichung von Build 105 für OpenSolaris geht es jetzt los mit der Entwicklung für den nächsten Release der Distribution, um auf das Developer Repository zuzugreifen genügt der folgende Befehl:


$pfexec pkg set-authority -O http://pkg.opensolaris.org/dev opensolaris.org


Mit Build 105 wird ZFS auf die neuste Version 14 gebracht (Vorsicht: ein Upgrade führt dazu das ältere Versionen und BEs von OpenSolaris nicht mehr auf die Daten zugreifen können!), des weiteren wird die NIC-Virtualisierung Crossbow eingeführt mit der es möglich ist komplette virtuelle Netzwerkkarten (inklusive eigener MAC-Addresse) zu erstellen.

Sonntag, 21. Dezember 2008

Ruby 1.9.1 Preview2 selberbacken

Im Moment spiele ich mal wieder mit diversen Skriptsprachen herum von denen eine Ruby ist. Leider läßt sich der aktuelle Preview nur mit ein paar Umwegen unter OpenSolaris backen. Darum hier ein kleines Patch damit Vorgang durchläuft. Ich übernehme wie immer keine Verantwortung für eventuelle Probleme ^^.

--- ext/curses/curses.c Tue Nov 11 12:00:39 2008
+++ ext/curses/curses.c Sun Dec 21 17:00:44 2008
@@ -410,6 +410,9 @@
static VALUE
curses_getch(VALUE obj)
{
+#if defined(__sun)
+ eucwidth_t wp;
+#endif
int c;

rb_read_check(stdin);
@@ -416,7 +419,12 @@
curses_stdscr();
c = getch();
if (c == EOF) return Qnil;
+#if defined( __sun)
+ getwidth(&wp);
+ if (ISPRINT(c, wp)) {
+#else
if (ISPRINT(c)) {
+#endif
char ch = (char)c;

return rb_locale_str_new(&ch, 1);
@@ -1105,12 +1113,20 @@
{
struct windata *winp;
int c;
+#if defined(__sun)
+ eucwidth_t wp;
+#endif

rb_read_check(stdin);
GetWINDOW(obj, winp);
c = wgetch(winp->window);
if (c == EOF) return Qnil;
+#if defined(__sun)
+ getwidth(&wp);
+ if (ISPRINT(c, wp)) {
+#else
if (ISPRINT(c)) {
+#endif
char ch = (char)c;

return rb_locale_str_new(&ch, 1);