it-swarm.dev

Was macht C ++ besser als D?

Ich habe kürzlich D gelernt und fange an, mich mit der Sprache vertraut zu machen. Ich weiß, was es bietet, ich weiß noch nicht, wie ich alles verwenden soll, und ich weiß nicht viel über D-Redewendungen und so weiter, aber ich lerne.

Ich mag D. Es ist eine nette Sprache, die in gewisser Weise ein riesiges Update auf C ist und gut gemacht wurde. Keines der Features scheint "angeschraubt" zu sein, aber eigentlich ziemlich gut durchdacht und gut gestaltet.

Sie werden oft hören, dass D das ist, was C++ hätte sein sollen (ich überlasse die Frage, ob dies jedem Einzelnen zutrifft oder nicht, um selbst in der richtigen Reihenfolge zu entscheiden unnötige Flammenkriege zu vermeiden). Ich habe auch von mehreren C++ - Programmierern gehört, dass sie D viel mehr mögen als C++.

Selbst wenn ich C kenne, kann ich nicht sagen, dass ich C++ kenne. Ich würde gerne von jemandem hören, der sowohl C++ als auch D kennt, wenn er der Meinung ist, dass C++ etwas besser kann als D als Sprache (was nicht das Übliche bedeutet "Es hat mehr Bibliotheken von Drittanbietern" oder "Es gibt mehr Ressourcen" oder "Es gibt mehr Jobs, die C++ erfordern, als D existiert").

D wurde von einigen sehr erfahrenen C++ - Programmierern ( Walter Bright und Andrei Alexandresc mit Hilfe der D-Community) entwickelt, um viele der Probleme zu beheben, die C++ hatte, aber hatte Gibt es etwas, das eigentlich doch nicht besser geworden ist? Etwas, das er vermisst hat? Etwas, von dem Sie denken, dass es keine bessere Lösung ist?

Beachten Sie auch, dass ich von D 2. spreche, nicht von D 1. .

135
Anto

Die meisten Dinge, die C++ besser "macht" als D, sind Meta-Dinge: C++ hat bessere Compiler, bessere Tools, ausgereiftere Bibliotheken, mehr Bindungen, mehr Experten, mehr Tutorials usw. Grundsätzlich hat es immer mehr von allen externen Dingen, die Sie haben würde von einer reiferen Sprache erwarten. Das ist unbestreitbar.

Was die Sprache selbst betrifft, gibt es einige Dinge, die C++ meiner Meinung nach besser macht als D. Es gibt wahrscheinlich noch mehr, aber hier sind einige, die ich ganz oben auflisten kann:

C++ hat ein besser durchdachtes Typsystem
Im Moment gibt es einige Probleme mit dem Typsystem in D, die im Design als Versehen erscheinen. Beispielsweise ist es derzeit nicht möglich, eine const-Struktur in eine nicht-const-Struktur zu kopieren, wenn die Struktur aufgrund der Transitivität von const und der Art und Weise, wie Postblit-Konstruktoren mit Werttypen arbeiten, Klassenobjektreferenzen oder -zeiger enthält. Andrei sagt, er weiß, wie man das löst, gab aber keine Details an. Das Problem ist sicherlich behebbar (die Einführung von Kopierkonstruktoren im C++ - Stil wäre eine Lösung), aber es ist derzeit ein großes Problem in der Sprache.

Ein weiteres Problem, das mich gestört hat, ist das Fehlen einer logischen Konstante (d. H. Kein mutable wie in C++). Dies ist ideal zum Schreiben von thread-sicherem Code, macht es jedoch schwierig (unmöglich?), Eine verzögerte Intialisierung innerhalb von const-Objekten durchzuführen (stellen Sie sich eine const 'get'-Funktion vor, die den zurückgegebenen Wert beim ersten Aufruf erstellt und zwischenspeichert).

Angesichts dieser bestehenden Probleme mache ich mir schließlich Sorgen darüber, wie der Rest des Typsystems (pure, shared usw.) mit allem anderen in der Sprache interagieren wird, sobald sie angewendet werden verwenden. Die Standardbibliothek (Phobos) nutzt das fortschrittliche Typsystem von D derzeit nur sehr wenig, daher halte ich die Frage für vernünftig, ob es unter Stress standhält. Ich bin skeptisch, aber optimistisch.

Beachten Sie, dass C++ einige Warzen vom Typsystem hat (z. B. nicht-transitive Konstante, die iterator sowie const_iterator Erfordert), die es ziemlich hässlich machen, aber während das Typensystem von C++ an einigen Stellen ein wenig falsch ist, es hindert Sie nicht daran, Arbeit zu erledigen, wie es D manchmal tut.

Bearbeiten: Zur Verdeutlichung glaube ich, dass C++ ein besseres durchdachtes Typsystem hat - nicht unbedingt ein besseres - wenn das Sinn macht. Im Wesentlichen besteht in D das Gefühl, dass die Verwendung aller Aspekte seines Typsystems, die in C++ nicht vorhanden sind, mit einem Risiko verbunden ist.

D ist manchmal etwas zu bequem
Eine Kritik, die Sie oft von C++ hören, ist, dass es einige Probleme auf niedriger Ebene vor Ihnen verbirgt, z. Einfache Zuweisungen wie a = b; können viele Dinge wie das Aufrufen von Konvertierungsoperatoren, das Aufrufen von Überlastungszuweisungsoperatoren usw. ausführen, was im Code möglicherweise schwer zu erkennen ist. Manche Leute mögen das, andere nicht. In jedem Fall ist es in D schlechter (besser?) Aufgrund von Dingen wie opDispatch, @property, opApply, lazy, die das Potenzial haben, unschuldig zu werden Code in Dinge untersuchen, die Sie nicht erwarten.

Ich denke nicht, dass dies persönlich ein großes Problem ist, aber einige mögen dies abstoßend finden.

D erfordert Müllabfuhr
Dies könnte als kontrovers angesehen werden, da es möglich ist, D ohne GC auszuführen. Nur weil es möglich ist, heißt das noch lange nicht, dass es praktisch ist. Ohne GC verlieren Sie viele Funktionen von D, und die Verwendung der Standardbibliothek wäre wie ein Spaziergang in einem Minenfeld (wer weiß, welche Funktionen Speicher zuweisen?). Persönlich halte ich es für völlig unpraktisch, D ohne GC zu verwenden, und wenn Sie kein Fan von GCs sind (wie ich), kann dies ziemlich abstoßend sein.

Naive Array-Definitionen in D weisen Speicher z
Dies ist ein Haustier von mir:

int[3] a = [1, 2, 3]; // in D, this allocates then copies
int a[3] = {1, 2, 3}; // in C++, this doesn't allocate

Um die Zuordnung in D zu vermeiden, müssen Sie anscheinend Folgendes tun:

static const int[3] staticA = [1, 2, 3]; // in data segment
int[3] a = staticA; // non-allocating copy

Diese kleinen Zuweisungen hinter Ihrem Rücken sind gute Beispiele für meine beiden vorherigen Punkte.

Bearbeiten: Beachten Sie, dass dies ein bekanntes Problem ist, an dem gearbeitet wird.
Bearbeiten: Dies ist jetzt behoben. Es findet keine Zuordnung statt.

Fazit
Ich habe mich auf die Negative von D gegen C++ konzentriert, weil dies die Frage war, aber bitte sehen Sie diesen Beitrag nicht als Aussage, dass C++ besser ist als D. Ich könnte leicht einen größeren Beitrag von Orten erstellen wobei D besser ist als C++. Es liegt an Ihnen, die Entscheidung zu treffen, welche Sie verwenden möchten.

124
Peter Alexander

Als ich zu D Development kam, war ich in der eigentümlichen Position, einer der Leute zu sein, die am meisten über C++ wissen. Jetzt bin ich in der noch eigentümlicheren Position, auch einer der Menschen zu sein, die am meisten über D wissen. Ich sage dies nicht zu angemessenen Krediten oder prahlenden Rechten, sondern zu der Bemerkung, dass ich neugierig bin vorteilhafte Position zur Beantwortung dieser Frage. Gleiches gilt für Walter.

Im Großen und Ganzen ist die Frage, was C++ (und damit meine ich C++ 2011) besser macht als D, ebenso widersprüchlich wie die Frage: "Wenn Sie einen Fachmann für die Reinigung Ihres Hauses bezahlen, welche Orte werden sie verlassen." schmutziger als zuvor? " Was auch immer von Wert war, dass C++ das konnte, was D nicht konnte, es war für mich und Walter immer wie ein schmerzender Daumen, also gibt es fast per Definition nichts, was C++ jemals tun kann, was nicht in Ds Reichweite ist.

Eine Sache, die im Sprachdesign selten verstanden wird (weil nur wenige Menschen das Glück haben, tatsächlich etwas zu tun), ist, dass es viel weniger ungezwungene Fehler gibt, als es scheint. Viele von uns Sprachbenutzern schauen sich das eine oder andere Konstrukt an und sagen: "Ew! Das ist so falsch! Was haben sie gedacht?" Tatsache ist, dass die meisten unangenehmen Fälle in einer Sprache nach einigen grundlegenden Entscheidungen auftreten, die alle fundiert und wünschenswert sind, aber grundsätzlich miteinander konkurrieren oder sich widersprechen (z. B. Modularität und Effizienz, Knappheit und Kontrolle usw.).

In diesem Sinne werde ich einige Dinge aufzählen, an die ich denken kann, und für jedes werde ich erklären, wie sich Ds Wahl aus dem Wunsch ergibt, eine andere, übergeordnete Charta zu erfüllen.

  1. D geht davon aus, dass alle Objekte durch bitweises Kopieren beweglich sind. Dies überlässt eine Minderheit von Designs C++, insbesondere solchen, die interne Zeiger verwenden, d. H. Eine Klasse, die Zeiger in sich enthält. (Ein solches Design kann ohne oder mit vernachlässigbaren Effizienzkosten in D übersetzt werden, es wäre jedoch ein Übersetzungsaufwand erforderlich.) Wir haben diese Entscheidung getroffen, um die Sprache erheblich zu vereinfachen, das Kopieren von Objekten ohne oder mit minimalem Benutzereingriff effizienter zu gestalten und zu vermeiden Der gesamte Morast der Kopienkonstruktion und die rWert-Referenzen sind insgesamt enthalten.

  2. D verbietet mehrdeutige Geschlechtsarten (die nicht entscheiden können, ob es sich um Wert- oder Referenztypen handelt). Solche Designs werden in C++ einstimmig gemieden und sind fast immer falsch, aber einige von ihnen sind technisch korrekt. Wir haben diese Wahl getroffen, weil sie meistens falschen Code und nur einen winzigen Bruchteil des korrekten Codes nicht zulässt, der neu gestaltet werden kann. Wir glauben, dass es ein guter Kompromiss ist.

  3. D verbietet Hierarchien mit mehreren Wurzeln. Ein vorheriges Poster hier war sehr aufgeregt über dieses spezielle Thema, aber dies ist ausgetretener Boden und es gibt keinen greifbaren Vorteil von wurzellosen Hierarchien gegenüber Hierarchien, die alle eine gemeinsame Wurzel haben.

  4. In D kann man nicht z. ein int. Sie müssen ein Objekt werfen, das Throwable erbt. Kein Wettbewerb, der Stand der Dinge ist in D besser, aber es ist eine Sache, die C++ kann, die D nicht kann.

  5. In C++ ist die Kapselungseinheit eine Klasse. In D ist es ein Modul (d. H. Eine Datei). Walter traf diese Entscheidung aus zwei Gründen: um die Kapselung auf natürliche Weise der Dateisystemschutzsemantik zuzuordnen und die Notwendigkeit eines "Freundes" zu vermeiden. Diese Wahl lässt sich sehr gut in das gesamte Modularitätsdesign von D integrieren. Es wäre möglich, Dinge so zu ändern, dass sie eher C++ ähneln, aber das würde die Dinge erzwingen. Die Auswahlmöglichkeiten für den Kapselungsbereich von C++ sind nur für das physische Design von C++ geeignet.

Es könnte ein oder zwei kleinere Dinge geben, aber insgesamt sollte es das sein.

132

Ich denke, dass es Ihnen sehr schwer fallen wird, in D viel zu finden, was objektiv schlechter ist als C++. Die meisten Probleme mit D, bei denen man objektiv sagen kann, dass es schlechter ist, sind entweder Probleme mit der Qualität der Implementierung (die im Allgemeinen darauf zurückzuführen sind, wie jung die Sprache und die Implementierung sind und in letzter Zeit mit halsbrecherischer Geschwindigkeit behoben wurden) oder Probleme mit einem Mangel an Bibliotheken von Drittanbietern (die mit der Zeit kommen werden). Die Sprache selbst ist im Allgemeinen besser als C++, und die Fälle, in denen C++ als Sprache besser ist, werden im Allgemeinen entweder ein Kompromiss sein, bei dem C++ in eine Richtung und D in eine andere Richtung ging, oder in dem jemand subjektive Gründe dafür hat denke, dass einer besser ist als der andere. Es gibt jedoch wahrscheinlich nur wenige objektive Gründe, warum C++ als Sprache besser ist.

Tatsächlich muss ich mir wirklich den Kopf zerbrechen, um Gründe zu finden, warum C++ als Sprache besser ist als D. Was mir im Allgemeinen in den Sinn kommt, sind Kompromisse.

  1. Da Ds const transitiv ist und die Sprache nveränderlich hat, hat sie weitaus stärkere Garantien als C++ 's const, was bedeutet, dass D dies nicht tut und kann nicht mutable haben. Es kann nicht logische Konstante haben. Sie erhalten also einen enormen Gewinn mit dem const-System von D, aber in einigen Situationen können Sie const einfach nicht wie in C++ verwenden.

  2. D hat nur einen Cast-Operator, während C++ hat 4 (5, wenn Sie den C-Cast-Operator zählen). Dies erleichtert den Umgang mit Casts in D im allgemeinen Fall, ist jedoch problematisch, wenn Sie tatsächlich die zusätzlichen Komplikationen/Vorteile wünschen , die const_cast und seine Brüder sorgen. Aber D ist tatsächlich leistungsfähig genug, dass Sie Vorlagen verwenden können, um die Casts von C++ zu implementieren. Wenn Sie sie also wirklich wollen, können Sie sie haben (und sie können sogar irgendwann in der Standardbibliothek von D landen).

  3. D hat weit weniger implizite Casts als C++ und erklärt mit größerer Wahrscheinlichkeit, dass zwei Funktionen miteinander in Konflikt stehen (was Sie dazu zwingt, genauer zu bestimmen, welche der Funktionen Sie meinen - entweder mit Casts oder indem Sie den vollständigen Modulpfad angeben ). Manchmal kann das ärgerlich sein, aber es verhindert alle Arten von Funktionsentführung Problemen. Sie wissen, dass Sie wirklich die Funktion aufrufen, die Sie beabsichtigen.

  4. Ds Modulsystem ist weitaus sauberer als C++ 's #includes (ganz zu schweigen von schneller schneller beim Kompilieren), aber es fehlen alle Art von Namespace über die Module selbst hinaus. Wenn Sie also einen Namespace innerhalb eines Moduls möchten, müssen Sie die Route Java] gehen und statische Funktionen für eine Klasse oder Struktur verwenden. Es funktioniert, aber wenn Sie wirklich einen Namespace wünschen, ist dies offensichtlich nicht der Fall So sauber wie ein echter Namespace. In den meisten Situationen ist der Namespace, den die Module selbst bieten, jedoch reichlich (und ziemlich ausgefeilt, wenn es um Konflikte geht).

  5. Wie Java und C # hat D eher eine Einzelvererbung als eine Mehrfachvererbung, aber im Gegensatz zu Java und C # gibt es einige fantastische Möglichkeiten, den gleichen Effekt ohne zu erzielen) Alle Probleme, die die Mehrfachvererbung von C++ hat (und die Mehrfachvererbung von C++ kann manchmal sehr chaotisch werden). D hat nicht nur Schnittstellen) , aber es hat String-Mixins , Template-Mixins und alias this . Das Endergebnis ist also wohl mächtiger und nicht haben alle Probleme, die die Mehrfachvererbung von C++ verursacht.

  6. Ähnlich wie bei C # trennt D Strukturen und Klassen . Klassen sind Referenztypen, die Vererbung haben und von Object abgeleitet sind, während Strukturen Werttypen ohne Vererbung sind. Diese Trennung kann sowohl gut als auch schlecht sein. Es beseitigt das klassische Slicing-Problem in C++ und hilft dabei, Typen, die wirklich Werttypen sind, von solchen zu trennen, die polymorph sein sollen, aber zunächst könnte die Unterscheidung für a ärgerlich sein C++ - Programmierer. Letztendlich gibt es eine Reihe von Vorteilen, aber es zwingt Sie dazu, etwas anders mit Ihren Typen umzugehen.

  7. Mitglied Funktionen von Klassen sind standardmäßig polymorph. Sie können sie nicht deklarieren nicht virtuell . Es liegt an dem Compiler zu entscheiden, ob sie es können (was wirklich nur der Fall ist, wenn sie final sind und eine Funktion aus einer Basisklasse nicht überschreiben). Dies kann in einigen Fällen ein Leistungsproblem sein. Wenn Sie den Polymorphismus jedoch wirklich nicht benötigen, müssen Sie nur structs verwenden, und dies ist kein Problem.

  8. D hat einen eingebauten Garbage Collector . Viele von C++ würden dies als ernsthaften Nachteil betrachten, und um ehrlich zu sein, könnte die Implementierung derzeit ernsthafte Arbeit erfordern. Es hat sich verbessert, ist aber definitiv noch nicht mit Javas Garbage Collector vergleichbar. Dies wird jedoch durch zwei Faktoren gemildert. Erstens, wenn Sie hauptsächlich structs und andere Datentypen auf dem Stapel verwenden, ist dies kein großes Problem. Wenn Ihr Programm nicht ständig Inhalte auf dem Heap zuweist und die Zuordnung aufhebt, ist dies in Ordnung. Und zweitens können Sie den Garbage Collector überspringen, wenn Sie möchten, und einfach Cs malloc und free verwenden. Es gibt einige Sprachfunktionen (wie Array Slicing ), die Sie vermeiden oder mit denen Sie vorsichtig sein müssen, und einige der Standardbibliotheken können ohne die Verwendung von - nicht wirklich verwendet werden. GC (insbesondere Zeichenfolgenverarbeitung), aber Sie können in D schreiben, ohne den Müll zu verwenden Sammler, wenn Sie wirklich wollen. Das Klügste ist wahrscheinlich, es allgemein zu verwenden und es dann zu vermeiden, wenn die Profilerstellung zeigt, dass es Probleme für leistungskritischen Code verursacht, aber Sie können es vollständig vermeiden, wenn Sie möchten. Und die Qualität der Implementierung von GC wird sich im Laufe der Zeit verbessern, wodurch viele der Bedenken beseitigt werden, die bei der Verwendung eines GC kann verursachen. Letztendlich wird das GC also kein so großes Problem sein, und im Gegensatz zu Java können Sie es vermeiden, wenn Sie möchten.

Es gibt wahrscheinlich auch andere, aber das kann ich mir im Moment einfallen lassen. Und wenn Sie bemerken, sind sie alle Kompromisse. D hat sich entschieden, einige Dinge anders als C++ zu machen, die bestimmte Vorteile gegenüber C++ haben, aber auch einige Nachteile haben. Was besser ist, hängt davon ab, was Sie tun, und in vielen Fällen wird es wahrscheinlich zuerst nur schlechter erscheinen, und dann werden Sie kein Problem damit haben, wenn Sie sich daran gewöhnt haben. Wenn überhaupt, werden die Probleme in D im Allgemeinen neue sein, die durch neue Dinge verursacht werden, die andere Sprachen zuvor noch nicht oder nicht ganz so gemacht haben wie D. Insgesamt hat D sehr gut aus den Fehlern von C++ gelernt.

Und D als Sprache verbessert sich in vielerlei Hinsicht gegenüber C++, so dass ich denke, dass D im Allgemeinen objektiv besser ist.

  1. D hat bedingte Kompilierung . Dies ist eine der Funktionen, die ich beim Programmieren in C++ häufig vermisse. Wenn C++ es hinzufügen würde, würde sich C++ sprunghaft verbessern, wenn es um Dinge wie Vorlagen geht.

  2. D hat Reflexion zur Kompilierungszeit .

  3. Variablen sind standardmäßig threadlokal, können jedoch shared sein, wenn Sie dies möchten. Dies macht den Umgang mit Threads weitaus sauberer als in C++. Sie haben die vollständige Kontrolle. Sie können immutable und Message Passing verwenden, um zwischen Threads zu kommunizieren, oder Sie können Variablen shared erstellen und dies auf C++ - Weise mit Mutexen und Bedingungsvariablen tun. Auch das wird gegenüber C++ durch die Einführung von synchronisiert (ähnlich wie C # und Java) verbessert. Die Threading-Situation von D ist also weitaus besser als die von C++.

  4. Ds Vorlagen sind weitaus leistungsfähiger als die Vorlagen von C++, sodass Sie viel einfacher und einfacher arbeiten können. Und mit dem Hinzufügen von Vorlageneinschränkungen sind die Fehlermeldungen viel besser als in C++. D macht Vorlagen sehr leistungsfähig und benutzerfreundlich. Es ist kein Zufall, dass der Autor von Modern C++ Design einer der Hauptmitarbeiter von D ist. Ich finde, dass C++ - Vorlagen im Vergleich zu D-Vorlagen ernsthaft fehlen, und es kann manchmal sehr frustrierend sein, wenn in C++ programmiert wird.

  5. D hat eingebaute Vertragsprogrammierung .

  6. D hat ein eingebautes nit Test Framework.

  7. D unterstützt Unicode mit string (UTF-8), wstring (UTF-16) und dstring (UTF-32). Es macht es einfach, mit Unicode umzugehen. Und wenn Sie nur string verwenden möchten und sich im Allgemeinen keine Gedanken über Unicode machen möchten, können Sie dies - obwohl ein gewisses Verständnis der Grundlagen von Unicode bei einigen der Standardbibliotheksfunktionen hilfreich ist.

  8. D's Operator Overloading ist viel besser als das von C++, sodass Sie mit einer Funktion mehrere Operatoren gleichzeitig überladen können. Ein Paradebeispiel hierfür ist, wenn Sie die grundlegenden arithmetischen Operatoren überladen müssen und ihre Implementierungen bis auf den Operator identisch sind. String-Mixins machen es zu einem Kinderspiel und ermöglichen Ihnen eine einfache Funktionsdefinition für alle.

  9. D's Arrays sind weitaus besser als C++ Arrays. Sie sind nicht nur ein geeigneter Typ mit einer Länge, sondern können auch angehängt und in der Größe geändert werden. Sie zu verketten ist einfach. Und das Beste ist, sie haben Schneiden . Und das ist ein großer Segen für eine effiziente Array-Verarbeitung. Strings sind Arrays von Zeichen in D, und das ist kein Problem (in der Tat ist es großartig!), Weil Ds Arrays so mächtig sind.

Ich könnte weiter und weiter gehen. Viele der Verbesserungen, die D bietet, sind Kleinigkeiten (wie die Verwendung von this für Konstruktornamen oder das Nichtzulassen, ob Anweisungen oder Schleifenkörper, bei denen ein Semikolon der gesamte Körper ist), aber einige davon sind ziemlich groß, und wenn Sie Alles zusammen ergibt ein viel besseres Programmiererlebnis. C++ 0x fügt einige der Funktionen hinzu, die D hat, für die C++ fehlte (z. B. auto und Lambdas), aber trotz all seiner Verbesserungen wird es nicht viel geben, was objektiv besser an C++ ist als Sprache als D.

Es steht außer Frage, dass es viele subjektive Gründe gibt, sich gegenseitig zu mögen, und die relative Unreife der Implementierung von D kann manchmal ein Problem sein (obwohl sie sich in letzter Zeit sehr schnell verbessert hat - insbesondere seit die Repositories verschoben wurden - github ), und das Fehlen von Bibliotheken von Drittanbietern kann definitiv ein Problem sein (obwohl die Tatsache, dass D leicht C-Funktionen aufrufen - und in geringerem Maße C++) kann Funktionen - mildert das Problem definitiv). Dies sind jedoch eher Probleme bei der Qualität der Implementierung als Probleme mit der Sprache selbst. Und da die Qualität der Implementierungsprobleme behoben ist, wird die Verwendung von D umso angenehmer.

Ich nehme also an, dass die kurze Antwort auf diese Frage "sehr wenig" ist. D als Sprache ist C++ im Allgemeinen überlegen.

65

RAII- und Stack-Speichernutzung

D 2.0 lässt RAII nicht auf dem Stapel zu, da der Wert des Schlüsselworts scope beim Zuweisen von Klasseninstanzen auf dem Stapel entfernt wurde.

Sie können in D keine Vererbung vom Werttyp durchführen, sodass Sie gezwungen sind, eine Heap-Zuweisung für jede Form von RAII vorzunehmen.
Das heißt, es sei denn, Sie verwenden emplace, aber das ist sehr schmerzhaft zu verwenden, da Sie den Speicher von Hand zuweisen müssen. (Ich finde es noch nicht praktisch, emplace in D zu verwenden.)

9
user541686

C++ kann Sie viel besser dazu zwingen, ausführlich zu sein. Dies kann in Ihren Augen besser oder schlechter sein, je nachdem, ob Sie Inferenz oder Ausführlichkeit mögen.

Vergleiche Laufzeitmemo in C++ :

template <typename ReturnType, typename... Args>
function<ReturnType (Args...)> memoize(function<ReturnType (Args...)> func)
{
    map<Tuple<Args...>, ReturnType> cache;
    return ([=](Args... args) mutable {
            Tuple<Args...> t(args...);
            return cache.find(t) == cache.end()
                ? cache[t] : cache[t] = func(args...);
    });
}

mit dem gleichen in D:

auto memoize(F)(F func)
{
    alias ParameterTypeTuple!F Args;
    ReturnType!F[Tuple!Args] cache;
    return (Args args)
    {
        auto key = Tuple(args);
        return key in cache ? cache[key] : (cache[key] = func(args));
    };
}

Beachten Sie zum Beispiel die zusätzliche Ausführlichkeit mit template <typename ReturnType, typename... Args> gegen (F), Args... versus Args, args... versus args usw.
Zum Guten oder Schlechten ist C++ ausführlicher.

Natürlich können Sie dies auch in D tun:

template memoize(Return, Args...)
{
    Return delegate(Args) memoize(Return delegate(Args) func)
    {
        Return[Tuple!Args] cache;
        return delegate(Args args)
        {
            auto key = Tuple(args);
            return key in cache ? cache[key] : (cache[key] = func(args));
        };
    }
}

und sie würden fast identisch aussehen, aber dann würde dies ein delegate erfordern, während das ursprünglich akzeptierte any aufrufbare Objekt. (Die C++ 0x-Version erfordert ein std::function Objekt, so oder so, es ist ausführlicher und restriktiver in seinen Eingaben ... was gut sein könnte, wenn Sie Ausführlichkeit mögen, schlecht, wenn Sie es nicht tun.)

6
user541686

Ich weiß nicht viel über D, aber viele, viele C++ - Programmierer, von denen ich weiß, dass sie es nicht mögen, und ich muss persönlich zustimmen - ich mag das Aussehen von D nicht und werde es nicht näher betrachten.

Um zu verstehen, warum D nicht mehr Zugkraft gewinnt, müssen Sie zunächst verstehen, was Menschen an C++ interessiert. In einem Wort ist der Hauptgrund die Kontrolle. Wenn Sie in C++ programmieren, haben Sie die vollständige Kontrolle über Ihr Programm. Möchten Sie die Standardbibliothek ersetzen? Du kannst. Möchten Sie unsichere Zeigerwürfe machen? Du kannst. Willst du gegen die Konstanz verstoßen? Du kannst. Möchten Sie den Speicherzuweiser ersetzen? Du kannst. Möchten Sie den Rohspeicher ohne Rücksicht auf seinen Typ kopieren? Wenn du wirklich willst. Möchten Sie von mehreren Implementierungen erben? Es ist deine Beerdigung. Zum Teufel, Sie können sogar Garbage Collection-Bibliotheken bekommen, wie den Boehm-Sammler. Dann haben Sie Probleme wie die Leistung, die genau der Kontrolle folgt. Je mehr Kontrolle ein Programmierer hat, desto optimierter kann er sein Programm erstellen. Die Leistung ist einer der Hauptgründe für die weitere Verwendung von C++.

Hier sind einige Dinge, die ich gesehen habe, als ich ein wenig recherchiert und mit ein paar Leuten gesprochen habe, die es versucht haben:

Einheitliche Typhierarchie. C++ - Benutzer verwenden die Vererbung sehr selten, die meisten C++ - Programmierer bevorzugen die Komposition, und Typen sollten nur dann durch Vererbung verknüpft werden, wenn es einen sehr guten Grund dafür gibt. Das Konzept des Objekts verstößt stark gegen dieses Prinzip, indem es jeden Typ miteinander verbindet. Darüber hinaus verstößt es gegen eines der grundlegendsten Prinzipien von C++ - Sie verwenden nur das, was Sie wollen. Die Entscheidung, von Object zu erben, und die damit verbundenen Kosten stehen in starkem Widerspruch zu dem, wofür C++ als Sprache steht, um dem Programmierer die Kontrolle über sein Programm zu geben.

Ich habe von Problemen mit Funktionen und Delegierten gehört. Anscheinend hat D beide Funktionen und Delegaten als zur Laufzeit aufrufbare Funktionstypen, und sie sind nicht gleich, aber sie sind austauschbar oder ... etwas ? Mein Freund hatte einige Probleme mit ihnen. Dies ist definitiv ein Downgrade von C++, das nur std::function Hat und Sie sind fertig.

Dann haben Sie Kompatibilität. D ist nicht besonders kompatibel mit C++. Ich meine, keine Sprache ist mit C++ kompatibel, seien wir ehrlich, außer C++/CLI, die eine Art Betrug ist, aber als Eintrittsbarriere ist es muss erwähnt werden.

Dann gibt es noch einige andere Dinge. Lesen Sie zum Beispiel einfach den Wikipedia-Eintrag.

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

printf ist eine der unsichersten Funktionen, die jemals entwickelt wurden, in derselben Familie wie große Probleme wie gets aus der alten C-Standard-Bibliothek. Wenn Sie bei Stack Overflow danach suchen, werden Sie viele, viele Fragen im Zusammenhang mit dem Missbrauch finden. Grundsätzlich ist printf eine Verletzung von DRY - Sie geben den Typ in der Formatzeichenfolge an und geben ihn dann erneut an, wenn Sie geben es ist ein Argument. Eine Verletzung von DRY Wenn Sie etwas falsch machen, passieren sehr schlimme Dinge, wenn Sie ein typedef von einer 16-Bit-Ganzzahl in eine 32-Bit-Ganzzahl geändert haben. Es ist auch nicht erweiterbar Stellen Sie sich überhaupt vor, was passieren würde, wenn jeder seine eigenen Formatspezifizierer erfinden würde. Die Iostreams von C++ sind möglicherweise langsam, und die Auswahl des Operators ist möglicherweise nicht die beste, und die Benutzeroberfläche könnte Arbeit gebrauchen, aber sie sind grundsätzlich garantiert sicher und = DRY wird nicht verletzt und kann leicht erweitert werden. Dies kann nicht über printf gesagt werden.

Keine Mehrfachvererbung. Das ist sehr nicht der C++ Weg. C++ - Programmierer erwarten eine vollständige Kontrolle über ihr Programm, und die Sprache, mit der erzwungen wird, was Sie nicht erben können, verstößt gegen dieses Prinzip. Darüber hinaus wird die Vererbung (noch) fragiler, da plötzlich der gesamte Code Ihres Benutzers beschädigt wird, wenn Sie einen Typ von einer Schnittstelle in eine Klasse ändern, weil Sie eine Standardimplementierung oder etwas anderes bereitstellen möchten. Das ist keine gute Sache.

Ein weiteres Beispiel ist string und wstring. In C++ ist es bereits ziemlich schmerzhaft, zwischen ihnen konvertieren zu müssen, und unterstützt diese Bibliothek Unicode, und diese alte C-Bibliothek verwendet nur const char* Und muss je nach Typ des Zeichenfolgenarguments unterschiedliche Versionen derselben Funktion schreiben Sie wollen. Insbesondere die Windows-Header enthalten beispielsweise einige äußerst irritierende Makros, um das Problem zu lösen, das häufig Ihren eigenen Code beeinträchtigen kann. Das Hinzufügen von dstring zum Mix wird die Sache nur noch schlimmer machen, da Sie jetzt anstelle von zwei Zeichenfolgentypen drei verwalten müssen. Wenn mehr als ein Zeichenfolgentyp vorhanden ist, werden die Wartungsprobleme erhöht und sich wiederholender Code für Zeichenfolgen eingeführt.

Scott Meyers schreibt:

D ist eine Programmiersprache, mit der Programmierer die Herausforderungen der modernen Softwareentwicklung bewältigen können. Dazu werden Module gefördert, die über präzise Schnittstellen miteinander verbunden sind, ein Zusammenschluss eng integrierter Programmierparadigmen, eine sprachgesteuerte Thread-Isolation, modulare Typensicherheit, ein effizientes Speichermodell und vieles mehr.

Eine sprachgesteuerte Thread-Isolation ist kein Plus. C++ - Programmierer erwarten die volle Kontrolle über ihre Programme, und die Sprache, die etwas erzwingt, entspricht definitiv nicht den Anweisungen des Arztes.

Ich werde auch die Manipulation von Zeichenfolgen zur Kompilierungszeit erwähnen. D kann D-Code zur Kompilierungszeit interpretieren. Dies ist kein Plus. Betrachten Sie die massiven Kopfschmerzen, die durch den relativ begrenzten Präprozessor von C verursacht werden, der allen erfahrenen C++ - Programmierern bekannt ist, und stellen Sie sich dann vor, wie stark diese Funktion missbraucht wird. Die Möglichkeit, D-Code zur Kompilierungszeit zu erstellen, ist großartig, sollte jedoch semantisch und nicht syntaktisch sein.

Darüber hinaus können Sie einen gewissen Reflex erwarten. D hat eine Garbage Collection, die C++ - Programmierer mit Sprachen wie Java und C #) verknüpfen, die in Philosophien ziemlich direkt dagegen sind, und die syntaktischen Ähnlichkeiten werden sie auch in den Sinn bringen. Dies ist nicht der Fall notwendigerweise objektiv gerechtfertigt, aber es ist etwas, das auf jeden Fall beachtet werden sollte.

Grundsätzlich bietet es nicht so viel, was C++ - Programmierer noch nicht können. Vielleicht ist es einfacher, ein faktorielles Metaprogramm in D zu schreiben, aber wir können bereits faktorielle Metaprogramme in C++ schreiben. Vielleicht können Sie in D einen Raytracer zur Kompilierungszeit schreiben, aber das will sowieso niemand wirklich. Im Vergleich zu den grundlegenden Verstößen gegen die C++ - Philosophie ist das, was Sie in D tun können, nicht besonders bemerkenswert.

Selbst wenn diese Dinge nur oberflächliche Probleme sind, bin ich mir ziemlich sicher, dass die Tatsache, dass D an der Oberfläche überhaupt nicht wie C++ aussieht, wahrscheinlich ein guter Grund dafür ist, dass viele C++ - Programmierer nicht nach D migrieren. Vielleicht muss D selbst besser werben.

2
DeadMG

Das Wichtigste, was C++ "besser macht" als D, ist die Schnittstelle zu Legacy-Bibliotheken . Verschiedene 3D-Engines, OpenCL und gleichermaßen. Da D neu ist, stehen weitaus weniger verschiedene Bibliotheken zur Auswahl.

Ein weiterer wichtiger Unterschied zwischen dem C++ und dem D besteht darin, dass das C++ mehrere finanziell unabhängige Anbieter hat, aber ab 2014 hat das D praktisch nur einen , den 2 -man Team, das es erstellt hat. Es ist interessant, dass das "Prinzip der zweiten Quelle" , das besagt, dass Projekte niemals von Technologie abhängen sollten, Komponenten, die nur einen einzigen Anbieter haben, auch für Software zu gelten scheint.

Zum Vergleich wurde die erste Version des Interpreters Ruby vom Erfinder von Ruby, dem Yukihiro Matsumoto, geschrieben, aber der Mainstream-Interpreter Ruby aus der Ära 2014 wurde von anderen Leuten praktisch von Grund auf neu geschrieben . Daher kann Ruby als eine Sprache angesehen werden, die mehr als einen finanziell unabhängigen Anbieter hat. D hingegen kann eine großartige Technologie sein, hängt jedoch von den wenigen Entwicklern ab, die sie entwickeln.

Die Geschichte von Java zeigt, dass selbst wenn eine Technologie, in diesem Fall Java, einen guten, aber einzigen Finanzier hat, ein großes Risiko besteht, dass die Technologie unabhängig vom großen Unternehmensbenutzer im Wesentlichen gelöscht wird Base. Ein Zitat der Apache Software Foundation , wobei die EG für "Executive Committee" steht:

Oracle stellte der EU eine Spezifikationsanforderung und -lizenz für Java SE 7 zur Verfügung, die sich selbst widersprechen, die Verteilung unabhängiger Implementierungen der Spezifikation stark einschränken und vor allem die Verteilung unabhängiger Open Source-Implementierungen der Spezifikation.

Als historische Anmerkung kann gesagt werden, dass Java Applets Jahre vor der Entwicklung des HTML5-WebGL die Hardware-beschleunigte 3D-Leinwand hatten. Das Problem mit der Startgeschwindigkeit von Java-Applets hätte gelöst werden können, wenn Java ein Community-Projekt gewesen wäre, aber die Führungskräfte des einzigen Finanziers von Java, Sun Microsystems, hätten dies getan finde es nicht wichtig genug, die Implementierung von Java zu reparieren. Das Endergebnis: HTML5-Canvas von mehreren Anbietern als "Replik des armen Mannes" der Java GUI-Frameworks (Swing usw.). Interessanterweise hat die Programmiersprache Python auf der Serverseite die gleichen Vorteile, die die Java versprochen hat: einmal schreiben, auf jedem Server ausführen, unabhängig von der Hardware, vorausgesetzt, die Python Anwendung wird nicht zu Maschinencode kompiliert. Das Python ist ungefähr so ​​alt/jung wie das Java, aber im Gegensatz zum Java wird es von mehr als einem unabhängig finanzierten Entwicklerteam (dem PyPy und dem Hauptstrom _) unterstütztPython Interpreter).

Zusammenfassung:

Bei der Bewertung von Technologien für den Produktionsgebrauch sind die wichtigsten Eigenschaften von Technologien die Personen, die sie entwickeln, der soziale Prozess, in dem die Entwicklung stattfindet, und die Anzahl der finanziell unabhängigen Entwicklungsteams.

Ob es vorteilhafter ist, die Technologie T1 gegenüber der Technologie T2 zu verwenden, hängt von den Anbietern der Technologien ab und ob die Technologie T1 die kostengünstigere Lösung projektbezogener Probleme als T2 ermöglicht. Wenn beispielsweise das Problem mit einem einzelnen Lieferanten ignoriert würde, wäre Java für Informationssysteme eine "bessere" Technologie als C++, da Java Binärdateien bei der Bereitstellung in nicht neu kompiliert werden müssen Neue Hardware und der Umfang der mit der Speicherverwaltung verbundenen Softwareentwicklungsarbeit sind für Java geringer als für C++. Projekte, die von Grund auf neu entwickelt wurden, z. Projekte, die nicht von anderen Bibliotheken abhängen, sind in D möglicherweise billiger zu entwickeln als in C++. Andererseits hat C++ mehr als einen Anbieter und ist daher auf lange Sicht weniger riskant. (Das Java Beispiel, in dem die Sun Microsystems fast in Ordnung waren, aber das Orakel Java praktisch zum "neuen COBOL" machte.)

Eine mögliche Problemumgehung für einige der C++ - Einschränkungen

Eine der möglichen Problemumgehungen für einige der Einschränkungen von C++ besteht darin, ein Entwurfsmuster zu verwenden, bei dem die anfängliche Aufgabe in Teile zerlegt und die Teile "sortiert" werden (klassifiziert, gruppiert, geteilt, andere-nette-Wörter-für-) das Gleiche) zu 2 Klassen: Steuerlogik-bezogene Aufgaben , bei denen Speicherzugriffsmuster keine Lokalität zulassen; signalverarbeitungsähnliche Aufgaben , bei denen die Lokalität leicht erreicht werden kann. Die "ähnlichen" Aufgaben der Signalverarbeitung können als eine Reihe relativ vereinfachter Konsolenprogramme implementiert werden. Die Steuerlogik-bezogenen Aufgaben werden alle in einem einzigen Skript abgelegt, das in Ruby oder Python oder auf andere Weise geschrieben ist, wobei der Komfort der Softwareentwicklung eine höhere Priorität als die Geschwindigkeit hat.

Um eine teure Initialisierung von Betriebssystemprozessen und das Kopieren von Daten zwischen Betriebssystemprozessen zu vermeiden, kann der Satz kleiner C++ - Konsolenanwendungen als einzelnes C++ - Programm implementiert werden, das von Ruby/Python/etc. Als "Servlet" gestartet wird. Skript. Der Ruby/Python/etc. Das Skript fährt das Servlet vor dem Beenden herunter. Kommunikation zwischen dem "Servlet" und dem Ruby/Python/etc. Das Skript findet über eine Linux-Named-Pipe oder einen ähnlichen Mechanismus statt.

Wenn sich die anfängliche Aufgabe nicht leicht in Teile aufteilen lässt, die in die beiden oben genannten Klassen eingeteilt werden können, sollten Sie versuchen, das Problem neu zu formulieren, damit sich die anfängliche Aufgabe ändert.

1
Martin Vahi

Eine Sache, die ich in C++ schätze, ist die Fähigkeit, ein Funktionsargument oder einen Rückgabewert als C++ - Referenz anstelle eines Zeigers zu dokumentieren, was bedeutet, dass ein Wert un -null verwendet wird.

D-Version:

class A { int i; }

int foo(A a) {
    return a.i; // Will crash if a is null
}

int main() {
    A bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    return foo(bar);
}

C++ - Version:

class A { int i; };

int foo(A& a) {
    return a.i; // Will probably not crash since
                // C++ references are less likely
                // to be null.
}

int main() {
    A* bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    // Hm.. I have to dereference the bar-pointer
    // here, otherwise it wont compile.  Lets add
    // a check for null before.
    if (bar)
        return foo(*bar);
    return 0;
}

Um fair zu sein, können Sie C++ sehr nahe kommen, indem Sie A zu einem D struct machen und das Argument foo() - als ref markieren (Klassen sind Referenz Typen und Strukturen sind Werttypen in D, ähnlich wie in C #).

Ich glaube, es gibt einen Plan, stattdessen eine NonNullable Vorlage für Klassen als D-Standardbibliothekskonstrukt zu erstellen. Trotzdem mag ich die Kürze von nur Type& Im Vergleich zu NonNullable(Type) und würde es vorziehen, als Standard nicht nullbar zu sein (so etwas wie Type und Nullable(Type) zu rendern). . Aber es ist zu spät, um das für D zu ändern, und ich gehe jetzt vom Thema ab.

1
lumor