Ist man mit der Programmiersprache D 2.0 anstatt C++ (C++11) schneller am Ziel?



  • Wir sind hier mit dem "wie funktioniert D" wahrscheinlich off-topic. Ist mir aber egal gerade ^^

    Ich frag' mich jetzt, was new A(42) in D zurückliefert, wenn es kein A ist, weil A ja kein Referenztyp ist. Aber es beantwortet schonmal meine Frage, ob sich so ein A überhaupt im Heap anlegen lässt. Zumindest sieht es für mich gerade wegen new so aus, als ob es im Heap landen würde. Das konnte ich leider bis jetzt der Online-Doku nicht entnehmen. Was für ein Heap wäre das? Ist das einer, den sich alle Threads teilen? Schenkt der GC der in Unique!A gespeicherten "Referenz" (oder "Zeiger", oder was auch immer die Terminologie in D dafür ist) irgend eine Aufmerksamkeit?

    Ich rate mal dass new T ein T* zurück gibt, falls T ein Werttyp ist, und sonst ein T . Sieht zumindest so aus, wenn ich bei der Implementierung von Unique reinschaue, die ich hier gefunden habe. Die "Doesn't work yet"-Kommentare irritieren mich da aber.

    Ethon schrieb:

    Deterministisch etwas zerstören zu müssen und es nicht dem GC zu überlassen sehe ich mal als Spezialfall an.

    Wenn der GC nicht deterministisch zerstört, kann man ihm die deterministische Zerstörung natürlich nicht überlassen. 🙂 Wie auch immer: Sehr schade, dass in D die Nutzung des GCs nicht als Ausnahme sondern als Regel verstanden wird. Wundert mich dann auch nicht, wenn man Teile (wie groß auch immer) der StdLib ohne GC nicht verwenden kann. Das beißt sich doch alles. Es kann doch nicht sein, dass man nicht-Speicher-Ressourcen nur per ScopeGuard managen können soll wenn man 'ne zeitige Freigabe haben möchte und nicht auf die Gunst des GCs angewiesen sein will, der irgendwelche Destruktoren irgengwann von irgendeinem Thread aus aufruft. Das skaliert doch nicht. Ich sehe nicht, wo mir D Mittel an die Hand gibt, Ownership und die damit verbundenen Pflichten von nicht-Speicher-Resourcen vernünftig zu delegieren. ScopeGuards sehen da wie eine Krücke aus. Sorry, aber ich habe lang genug Java programmiert und musste beim Wechsel zu C++ feststellen, dass C++ das Ressourcenproblem elegant und eben nicht nur für Speicherressourcen löst -- zumindest für all die Sachen, die ich so baue. Da will ich nicht wirklich zurück und mir irgendetwas andrehen lassen, was ich nicht brauche.

    Ethon schrieb:

    Würde voll passen wenn die StdLib Implementierung von Unique nicht ewig brachliegen würde

    Es passt also nicht? Was bedeutet das denn? Taugt Unique nichts? Was bedeuten die "doesn't work yet"-Kommentare da? Verstehe ich das richtig, dass D nicht wirklich zwischen Copy und Move unterscheiden kann? Ist Unique!A kopierbar und wenn ja, was passiert da bzgl double-delete?!

    Schönes WE und so!



  • großbuchstaben schrieb:

    Ethon schrieb:

    Hmm? Eine struct ist ein Objekt das auf dem Stack lebt und bei verlassen des Scopes zerstört wird, genau wie in C++.

    nur, daß eine struct in C++ kein *Objekt*, sondern eine *Klasse* ist, deren members und bases public sind, wenn nichts Anderes angegeben wird (im Unterschied zu class, wo sie privat sind, wenn nicht anders angegeben). Ein Objekt wird daraus durch Instanziierung.

    Also, man kann sich offenbar auch extra Mühr geben, jemanden falsch zu verstehen. Ist doch klar, was Ethon meinte -- auch wenn "Stack" natürlich dann nicht zutrifft, wenn es um Datenmember einer Klasse geht, die bei D ja dann immer im Heap leben würden. Springender Punkt: Weder in C++, C# noch in D hast du bei struct s eine aufgezwungene Indirektion. Immerhin. 🙂



  • kkaw schrieb:

    Weder in C++, C# noch in D hast du bei struct s eine aufgezwungene Indirektion. Immerhin. 🙂

    ...ist bei Rust übrigens auch so. 🙂 Aber von den genanngen Sprachen scheinen nur C++ und Rust die Sache mit "Ownership", "Moves" und deterministischer Freigabe richtig ernst zu nehmen.



  • Es ist doch völlig egal ob man mit D schneller ans Ziel kommt. Ist wie mit Windows , da gibt es die meiste Software für und die meisten Leute nutzen es.

    Daher ist es total egal, ob ein anderes System besser ist, wenn es nur wenige nutzen und es wenig dafür gibt geht es unter.



  • totalegal schrieb:

    Daher ist es total egal, ob ein anderes System besser ist, wenn es nur wenige nutzen und es wenig dafür gibt geht es unter.

    Man sollte ein Desktop Environment für Linux darin programmieren, dann würde die Sprache zum Selbstläufer werden, wenn das DE was taugt und Open Source ist.



  • kkaw schrieb:

    Ich frag' mich jetzt, was new A(42) in D zurückliefert, wenn es kein A ist, weil A ja kein Referenztyp ist. Aber es beantwortet schonmal meine Frage, ob sich so ein A überhaupt im Heap anlegen lässt. Zumindest sieht es für mich gerade wegen new so aus, als ob es im Heap landen würde. Das konnte ich leider bis jetzt der Online-Doku nicht entnehmen. Was für ein Heap wäre das? Ist das einer, den sich alle Threads teilen? Schenkt der GC der in Unique!A gespeicherten "Referenz" (oder "Zeiger", oder was auch immer die Terminologie in D dafür ist) irgend eine Aufmerksamkeit?

    Unique verwaltet nur einen Zeiger der dem GC ebenso bekannt ist.
    Wenn das Unique aus dem Scope geht dann wird delete aufgerufen, dh. das Objekt wird zerstört und der Speicher freigegeben.

    kkaw schrieb:

    Wenn der GC nicht deterministisch zerstört, kann man ihm die deterministische Zerstörung natürlich nicht überlassen. 🙂 Wie auch immer: Sehr schade, dass in D die Nutzung des GCs nicht als Ausnahme sondern als Regel verstanden wird. Wundert mich dann auch nicht, wenn man Teile (wie groß auch immer) der StdLib ohne GC nicht verwenden kann.

    Naja, ein GC erlaubt weit eleganteren, fehlerfreieren und oft performanteren Code. Macht imho schon Sinn diesen primär zu nutzen und nicht die ganze Zeit ein Auge auf Speicherverwaltung haben zu müssen.

    kkaw schrieb:

    Das beißt sich doch alles. Es kann doch nicht sein, dass man nicht-Speicher-Ressourcen nur per ScopeGuard managen können soll wenn man 'ne zeitige Freigabe haben möchte und nicht auf die Gunst des GCs angewiesen sein will, der irgendwelche Destruktoren irgengwann von irgendeinem Thread aus aufruft. Das skaliert doch nicht. Ich sehe nicht, wo mir D Mittel an die Hand gibt, Ownership und die damit verbundenen Pflichten von nicht-Speicher-Resourcen vernünftig zu delegieren. ScopeGuards sehen da wie eine Krücke aus. Sorry, aber ich habe lang genug Java programmiert und musste beim Wechsel zu C++ feststellen, dass C++ das Ressourcenproblem elegant und eben nicht nur für Speicherressourcen löst -- zumindest für all die Sachen, die ich so baue. Da will ich nicht wirklich zurück und mir irgendetwas andrehen lassen, was ich nicht brauche.

    Du kannst ja trotzdem mit structs arbeiten wenn du C++ vermisst, kommt ja dann auf das gleiche raus. struct die eine Resource wrappt.

    kkaw schrieb:

    Es passt also nicht? Was bedeutet das denn? Taugt Unique nichts? Was bedeuten die "doesn't work yet"-Kommentare da? Verstehe ich das richtig, dass D nicht wirklich zwischen Copy und Move unterscheiden kann? Ist Unique!A kopierbar und wenn ja, was passiert da bzgl double-delete?!

    Schönes WE und so!

    Unique - wie es aktuell in Phobos ist - ist Müll.
    Scheint aus einer sehr alten Zeit von D zu stammen als man noch nichtmal Kopien verbieten konnte, das ist nämlich auskommentiert.
    Muss da mal nen Patch einsenden.
    Mit dem kleinen Fix verhält es sich exakt wie MoveOnly-Typen in C++.



  • Ethon schrieb:

    Naja, ein GC erlaubt weit eleganteren, fehlerfreieren und oft performanteren Code. Macht imho schon Sinn diesen primär zu nutzen und nicht die ganze Zeit ein Auge auf Speicherverwaltung haben zu müssen.

    Wenn Du das so siehst, dann baust Du wohl ganz andere Anwendungen als ich. In meiner Anwendungsdomäne kann ich das, was Du da gesagt hast, nicht bestätigen. So gar nicht. Eine gewisse C++ Kompetenz unterstelle ich Dir da einfach mal. Aber offensichtlich fehlt Dir der Blick über den eigenen Tellerrand.

    Ethon schrieb:

    Du kannst ja trotzdem mit structs arbeiten wenn du C++ vermisst, kommt ja dann auf das gleiche raus. struct die eine Resource wrappt.

    Ich sehe nicht, wie Move-Semantik damit möglich sein soll. Hatte Dich ja auch gebeten, mir zu zeigen, wie man diese unique_ptr-Aufgabe in D schreiben würde. Aber da kam bisher nur der Hinweis auf ein verwaistes StdLib-Feature, dessen Quellcode mit "does not work yet" gespickt ist und was für mich im Moment so aussieht, als ob man ein Unique!A kopieren könnte, was zu einem double-delete führen würde. So funktioniert Move-Semantik nicht.

    Ethon schrieb:

    Unique - wie es aktuell in Phobos ist - ist Müll.

    Sieht so aus, ja.

    Ethon schrieb:

    Muss da mal nen Patch einsenden. Mit dem kleinen Fix verhält es sich exakt wie MoveOnly-Typen in C++.

    Dann zeig' doch mal endlich. Wie baut man in D structs (also ohne aufgezwungene Indirektion der "Referenztypen"), die nicht kopierbar aber movebar sind, wobei der struct-Autor festlegen kann, was bei einem Move passiert. Und wie skaliert das? Kann ich solche structs vernünftig schachteln oder muss das umschließende Struct sich um jeden Datenmember selbst kümmern, statt dass das die "Sub-Structs" erledigen? Nee, ich seh' nicht, dass das skaliert. Dafür sind structs in D einfach nicht gedacht ... was sehr schade ist ... aber auch diesen Java-lastigen Programmierstil bzgl Ressourcen in D erklärt. "optional GC" my ass.



  • IMO wer professional entwickelt/programmiert lässt die Hände weg. D ist ein inkonsistenter Paradigma-Mix mit verbuggter Entwicklungsplatform.



  • Zeus schrieb:

    D ist ein inkonsistenter Paradigma-Mix

    Beweise anhand von Beispielen!

    mit verbuggter Entwicklungsplatform.

    Nur weil eine Entwicklungsplattform noch unvollständig ist, ist sie nicht verbuggt.
    Außerdem, auf welche soll das zutreffen? Es gibt viele IDEs und es gibt bei D auch 3 Compiler.



  • Code bitte! schrieb:

    Zeus schrieb:

    D ist ein inkonsistenter Paradigma-Mix

    Beweise anhand von Beispielen!

    mit verbuggter Entwicklungsplatform.

    Nur weil eine Entwicklungsplattform noch unvollständig ist, ist sie nicht verbuggt.
    Außerdem, auf welche soll das zutreffen? Es gibt viele IDEs und es gibt bei D auch 3 Compiler.

    Beispiele sind keine Beweise, und weil ich schon IMO geschriebe ist die Forderung schon lächerlich. Abgesehen meine ich als Entwicklungsplatform, den Compiler, den Linker, die Laufzeitumgebung etc.



  • Zeus schrieb:

    Code bitte! schrieb:

    Zeus schrieb:

    D ist ein inkonsistenter Paradigma-Mix

    Beweise anhand von Beispielen!

    mit verbuggter Entwicklungsplatform.

    Nur weil eine Entwicklungsplattform noch unvollständig ist, ist sie nicht verbuggt.
    Außerdem, auf welche soll das zutreffen? Es gibt viele IDEs und es gibt bei D auch 3 Compiler.

    Beispiele sind keine Beweise,

    Wenn es dir gelingt, dann darfst du auch gerne dies anhand mathematischer Beweisführung beweisen.
    Ich hätte mich allerdings auch schon mit Beispielen die ein konkretes Problem aufzeigen zufrieden gegeben, denn damit kann man arbeiten, denn Beispiele kann man überprüfen und man sieht auch, ob der Behaupter über die Sprache vielleicht etwas nicht kennt oder falsch gedacht hat und seine Behauptung somit falsch ist und sich die Sache in der Sprache dennoch lösen lässt.
    Manchmal braucht man eben mehr als nur 2 Augen, um einen größeren Horizont zu erlangen.



  • Zeus schrieb:

    und weil ich schon IMO geschriebe ist die Forderung schon lächerlich.

    Das IMO bezog sich nur auf deinen ersten Satz, in der du der Ansicht warst, dass das nichts für die professionelle Entwicklung ist.



  • kkaw schrieb:

    Dann zeig' doch mal endlich. Wie baut man in D structs (also ohne aufgezwungene Indirektion der "Referenztypen"), die nicht kopierbar aber movebar sind, wobei der struct-Autor festlegen kann, was bei einem Move passiert. Und wie skaliert das? Kann ich solche structs vernünftig schachteln oder muss das umschließende Struct sich um jeden Datenmember selbst kümmern, statt dass das die "Sub-Structs" erledigen? Nee, ich seh' nicht, dass das skaliert. Dafür sind structs in D einfach nicht gedacht ... was sehr schade ist ... aber auch diesen Java-lastigen Programmierstil bzgl Ressourcen in D erklärt. "optional GC" my ass.

    import std.stdio;
    
    struct Unique(T)
    {
        static if (is(T:Object))
            alias RefT = T;
        else
            alias RefT = T*;
    
        private RefT _p;
    
        this(RefT p)
        {
            _p = p;
        }
    
        ~this()
        {
            if(_p) delete _p;
        }
    
        bool isEmpty() const
        {
            return _p is null;
        }
    
        Unique release()
        {
            auto u = Unique(_p);
            _p = null;
            return u;
        }
    
        RefT opDot()
        {
            return _p;
        }
    
        @disable this(this);
    }
    
    struct A
    {
        int v;
    
        this(int v)
        {
            this.v = v;
            writeln("A Create ", v);
        }
    
        this(this)
        {
            writeln("A Postblit ", v);
        }
    
        ~this()
        {
            writeln("A Destroy ", v);
        }
    }
    
    Unique!A source()
    {
       return Unique!A(new A(1));
    }
    
    void sink(Unique!A p)
    {
        writeln(p.v);
    }
    
    void main()
    {
        sink(source());
    
        auto a = Unique!A(new A(2));
        // sink(a); Error: struct bla.Unique!(A).Unique is not copyable because it is annotated with @disable
        sink(a.release());
    }
    

    Jap, das erfordert bei Verschachtelungen Handarbeit. Aber wie gesagt ist das in der Praxis selten ein Problem was man daran sieht dass sich niemand für Unique interessiert.



  • Ethon schrieb:

    kkaw schrieb:

    Dann zeig' doch mal endlich. Wie baut man in D structs (also ohne aufgezwungene Indirektion der "Referenztypen"), die nicht kopierbar aber movebar sind, wobei der struct-Autor festlegen kann, was bei einem Move passiert. Und wie skaliert das? Kann ich solche structs vernünftig schachteln oder muss das umschließende Struct sich um jeden Datenmember selbst kümmern, statt dass das die "Sub-Structs" erledigen? Nee, ich seh' nicht, dass das skaliert. Dafür sind structs in D einfach nicht gedacht ... was sehr schade ist ... aber auch diesen Java-lastigen Programmierstil bzgl Ressourcen in D erklärt. "optional GC" my ass.

    import std.stdio;
    
    struct Unique(T)
    {
        static if (is(T:Object))
            alias RefT = T;
        else
            alias RefT = T*;
            
        private RefT _p;
    
        this(RefT p)
        {
            _p = p;
        }
    
        ~this()
        {
            if(_p) delete _p;
        }
        
        bool isEmpty() const
        {
            return _p is null;
        }
        
        Unique release()
        {
            auto u = Unique(_p);
            _p = null;
            return u;
        }
        
        RefT opDot()
        {
            return _p;
        }
    
        @disable this(this);
    }
    
    struct A
    {
        int v;
        
        this(int v)
        {
            this.v = v;
            writeln("A Create ", v);
        }
        
        this(this)
        {
            writeln("A Postblit ", v);
        }
        
        ~this()
        {
            writeln("A Destroy ", v);
        }
    }
    
    Unique!A source()
    {
       return Unique!A(new A(1));
    }
     
    void sink(Unique!A p)
    {
        writeln(p.v);
    }
    
    void main()
    {
        sink(source());
        
        auto a = Unique!A(new A(2));
        // sink(a); Error: struct bla.Unique!(A).Unique is not copyable because it is annotated with @disable
        sink(a.release());
    }
    

    Du willst uns verarschen, oder?



  • 😕



  • Ethon schrieb:

    😕

    volkard meint, ihm ist das zu kompliziert.



  • Ethon schrieb:

    Jap, das erfordert bei Verschachtelungen Handarbeit.

    Kannst Du das bitte näher erklären? Das war bei mir ja nur eine Vermutung, ein Gefühl ... bin mir da auch nicht mehr so sicher.

    Ethon schrieb:

    Aber wie gesagt ist das in der Praxis selten ein Problem was man daran sieht dass sich niemand für Unique interessiert.

    Wie schon gesagt: Schade. Das gibt dem "GC ist optional"-Argument IMHO ordentlich Wind aus den Segeln.

    Was ich auch schade finde, ist, dass man offensichtlich nicht explizit moven kann. Du bist stattdessen gezwungen, die release -Funktion aufzurufen und setzt auf die implizite Konvertierung von T* zu Unique!T . Das finde ich etwas problematisch.



  • Wie auch immer: Danke Ethon für Deine Mühen! Hab ja was gelernt. So richtig dolle beeindruckt von D bin ich aber immer noch nicht.

    In Rust werden da glaub'ich auch einfach nur Bits verschoben bei einem Move. Das Move ist aber das Standardverhalten bei lokalen Variablen von Typen, die davon profitieren würden. Ein use-after-move wird zur Compilezeit ausgeschlossen. Man kann also nicht aus Versehen etwas moven, ohne dass der Compiler sich beschweren würde. Ein eplizites "std::move" wird damit überflüssig. Explizit muss man werden, wenn man doch eine Kopie haben will:

    fn main() {
       let mut x: Vec<int> = Vec::new(); // hier steht zwar new, hat aber nix mit
                                         // Heap-Allozierung zu tun, ist nur eine
                                         // statische Memberfunktion, die einen
                                         // Vector per Wert zurück gibt.
       x.push(1);
       x.push(2);
       x.push(3);
    
       let y = x.clone(); // Kopie erzwingen, clone gibt auch einen Wert zurück.
                          // x und y sind wie in C++ jeweils drei auf dem Stack
                          // lebende Zeiger für einen Vektor mit size und capacity.
    
       let z = y;         // von y nach z moven
       // y können wier ab hier nur als Ziel einer Zuweisung benutzen
       // (sonst würde es einen Compilezeit-Fehler geben)
    
       y = x;             // von x nach y moven
       // x können wier ab hier nur als Ziel einer Zuweisung benutzen
       // (sonst würde es einen Compilezeit-Fehler geben)
       // y ist wieder gültig
    
       for i in y.iter() {
          println!("{}",*i);
       }
    }
    

    (ungetestet, da ich gerade rustc nicht zur Hand habe)



  • kkaw schrieb:

    Ethon schrieb:

    Jap, das erfordert bei Verschachtelungen Handarbeit.

    Kannst Du das bitte näher erklären? Das war bei mir ja nur eine Vermutung, ein Gefühl ... bin mir da auch nicht mehr so sicher.

    Ich beziehe mich auf die Fälle wenn man aus einem lvalue ein rvalue machen möchte, dh. eine release Methode oä. implementieren muss.

    kkaw schrieb:

    Ethon schrieb:

    Aber wie gesagt ist das in der Praxis selten ein Problem was man daran sieht dass sich niemand für Unique interessiert.

    Wie schon gesagt: Schade. Das gibt dem "GC ist optional"-Argument IMHO ordentlich Wind aus den Segeln.

    Was ich auch schade finde, ist, dass man offensichtlich nicht explizit moven kann. Du bist stattdessen gezwungen, die release -Funktion aufzurufen und setzt auf die implizite Konvertierung von T* zu Unique!T . Das finde ich etwas problematisch.

    Man erstellt einfach eine lokale Kopie, invalidiert das Original und gibt die Kopie zurück.
    Wo siehst du denn da das Problem?



  • kkaw schrieb:

    Wie auch immer: Danke Ethon für Deine Mühen! Hab ja was gelernt. So richtig dolle beeindruckt von D bin ich aber immer noch nicht.

    Hast du dir denn den Rest von D angeschaut? Das Template-System, (Template-) Mixins etc? 😉


Anmelden zum Antworten