Rust



  • Kellerautomat schrieb:

    Erzwungene {}

    Das geht echt gar nicht! Viel schlimmer als die (), die du in C und C++ für if, while und for brauchst. 😉

    Und so Fehler wie das "goto fail;" gibt's in der Realität auch nicht. {} statt () ist also eine voll bescheuerte Idee und richtet sich gegen meine Gewohnheit! Wie können die nur? 😉



  • Implizites move

    Gibt es in C++ auch. Beispielsweise beim return.

    void f()
    {
        std::string s;
        return s; // Falls copy-elision nicht greift wird auf jeden Fall der Move-Konstruktor genommen.
    }
    

    Gleiches gilt für throw-expressions.

    Implizites const

    Gibt's auch bei C++ ab und an.

    Returns ohne 'return'

    Naja. So schlimm? Unkonventionell halt. Außerdem kannst du return verwenden. Es wäre AFAICS nützlich für süße kleine Funktionen, bei denen return ; schon 25% des Funktionskörpers ausmachen würde.

    TyRroXX (ich kann seinen Namen niemals korrekt buchstabieren) schrieb:

    Das sind eindeutige Vorteile gegenüber C++.

    Du meinst, abgesehen vom mittleren Punkt?

    Außerdem denke ich bei jeder Sprache die

    let program = "+ + * - /";
    

    erlaubt an "Skriptkiddie-Scheiß".

    Gibt es bei der Sprache aber auch irgendwelche objektiven Vorteile? Edit: Ach, hier ist's gelistet: http://www.rust-lang.org/



  • Kellerautomat schrieb:

    Pattern matching

    Meinst du da das Konzept an sich oder die syntaktische Umsetzung?



  • Arcoth schrieb:

    TyRroXX (ich kann seinen Namen niemals korrekt buchstabieren) schrieb:

    Das sind eindeutige Vorteile gegenüber C++.

    Du meinst, abgesehen vom mittleren Punkt?

    Naja, das ist eher eine Geschmacksfrage als alles andere. Der {}-Zwang spart dir dafür die runden Klammern bei if, for, while. Es nimmt sich also vom Tippaufwand her nichts. Jetzt kann man sich fragen und drüber streiten, welcher Ansatz vielleicht weniger fehleranfällig oder konsistenter ist … aber ich denke nicht, dass das irgendwohin führt…

    Arcoth schrieb:

    Implizites const

    Gibt's auch bei C++ ab und an.

    Ich wüsste nicht wo. Meinst du vielleicht Regeln, die auf die Wertkategorie abzielen? (Prvalue --/-> non-const ref)

    Arcoth schrieb:

    Außerdem denke ich bei jeder Sprache die

    let program = "+ + * - /";
    

    erlaubt an "Skriptkiddie-Scheiß".

    Das kann man ja eigentlich positiv werten, zumal es eben kein "Skriptkiddie-Scheiß" ist. 😃 Boilerplate Code ist ja jetzt nicht unbedingt wünschenswert.



  • Ich wüsste nicht wo.

    Moment, von was für impliziten const s reden wir eigentlich? Ich dachte an etwas wie implizites const bei den operator() s von closure Typen.



  • Arcoth schrieb:

    Ich dachte an etwas wie implizites const bei den operator() s von closure Typen.

    Ja stimmt! Da ist ein implizites const. Hab ich nicht dran gedacht. Und wenn man das nicht haben will, muss man mutable verwenden. So ist das bei Rust im Prinzip fast überall:

    &T     --> shared reference (erlaubt i.d.R. nur "lesenden" Zugriff)
    &mut T --> mutable reference (erlaubt auch Schreibzugriff)
    
    fn main() {
        let x = 23;      // per default immutable
        let mut y = 42;  // kann ich nachträglich ändern
    }
    


  • Die Ownership-Semantik gefällt mir. Nicht etwas dass ich mir in C++ wünschen würde, aber sicherlich sehr interessant.



  • Arcoth schrieb:

    Die Ownership-Semantik gefällt mir.

    Du meinst inklusive Borrowing/Freezing? Weil Ownership allein ist ja nix neues…

    Die beste Erklärung dieser Konzepte kommt IMHO immer noch in diesem Vortrag vor. Hatte ich hier vor ca. einem Jahr auch schon verlinkt.



  • krümelkacker schrieb:

    Du meinst inklusive Borrowing/Freezing?

    Ja. Dass ein Binding an ein Vector -Element einen daran hindert dieses Binding durch bestimmte Operationen auf diesem Vector (e.g. push_back ) ungültig zu machen.



  • TyRoXx schrieb:

    Kellerautomat schrieb:

    • Returns ohne 'return'

    Unwichtiges, syntaktisches Detail, woran man sich schnell gewöhnt.

    'return' sticht in meinem Code hervor und ist klar und deutlich zu erkennen. Implizites return nicht.

    TyRoXx schrieb:

    Kellerautomat schrieb:

    • Implizites const
    • Erzwungene {}
    • Implizites move

    Das sind eindeutige Vorteile gegenüber C++.

    Implizites const: Ich hab mir noch nie gedacht "Waere diese Variable mal const gewesen, dann haette ich diesen Fehler nie gemacht.". Das einzige was es macht, ist dass ich ueberall 'mut' hinschreiben muss. Nervt.
    {}: Blaehen meinen Code sinnlos um 100% auf. Aus 2 Zeilen werden 4.
    Implizites move: Einfach nur extrem gefaehrlich, wenn man nicht sofort erkennen kann, wo eine Variable veraendert wird. Die haetten einen move-Operator einfuehren sollen.

    TyRoXx schrieb:

    Kellerautomat schrieb:

    • unions versteckt als enums
    • Pattern matching

    union in C ist etwas anderes als enum in Rust.
    Pattern matching ist die längst überfällige Überführung von switch ins 21. Jahrhundert.

    Pattern matching: Hat keine predictable Performance und ist ein unnoetiges Konzept. So wie funktionale Programmierung generell unnoetig ist.
    enums: Sind nix anderes als typsichere unions. Mischen von Konzepten (Aufzaehlungen, variants) geht gar nicht. Wie kommt man ueberhaupt auf so ne bloede Idee?



  • Kellerautomat schrieb:

    enums: Sind nix anderes als typsichere unions. Mischen von Konzepten (Aufzaehlungen, variants) geht gar nicht. Wie kommt man ueberhaupt auf so ne bloede Idee?

    Die blöde Idee ist hier, Begriffe zu verwenden, die einem Programmierer mit C++-Hintergrund vertraut sind. Normalerweise heißt das ganze Algebraic Data Type und ist durchaus typtheoretisch motiviert und untersucht. Und nur durch die „Vermischung“ entsteht tatsächlich ein Mehrwert im Typsystem, weil man eben Datenelemente haben kann, die nur in bestimmten Fällen vorhanden sind.

    Zum Beispiel kann man einen Optional-Typ wie boost::optional zur Zeit in C++ nicht typsicher implementieren. Man kann das Interface typsicher machen, aber auch nur, wenn man auf Funktionen wie get() verzichtet. Mit ADTs und Pattern Matching (welches sich bei ADTs wirklich quasi natürlich ergibt) ist allerdings die Darstellung ganz einfach und inhärent typsicher.

    Ich verstehe nicht, wie du darauf kommst, die Performance von Pattern Matching wäre nicht predictable. Matchen geht immer in konstanter Zeit, bei verschachtelten Patterns muss ggfs. mehrmals gematcht werden. In der Praxis wird jedes Match etwa die Performance eines switch haben. Das ändert sich natürlich, wenn noch so Features wie Integer-Ranges o.ä. dazu kommen, dennoch ist die Performance nicht weniger nachvollziehbarer als bei anderen Konstrukten wie z.B. virtual .

    Davon abgesehen finde ich aber auch, wenn man keine ADTs hat, bringt Pattern Matching keinen großen Mehrwert.

    Ich sehe ein, dass du noch nie mit ADTs gearbeitet hast, du solltest dich aber nicht aus Ignoranz vorschnell darauf festlegen, dass sie nicht nützlich wären. Das ist tatsächlich einer der Fälle, wo man vorher nicht weiß, was man eigentlich verpasst. Man nimmt die vorhandenen Limitierungen (in dem Fall des Typsystems) hin und es kommt einem gar nicht in den Sinn, dass es auch besser ginge.

    Ähnlich scheint es bei dir auch mit der Immutabilität auszusehen. Natürlich gab es noch keinen Fehler, den du auf const geschoben hast. Es gab sicherlich Fehler, wo eine Variable irgendwo fälschlich überschrieben wurde, aber dir kam nicht in den Sinn, dass das hätte vermieden werden können, wenn sie immutabel gewesen wäre. Mutabilität der Variablen wird nicht in Frage gestellt und als alternativlos angesehen, sich daraus ergebende Nachteile also gar nicht erst darauf zurückgeführt, sondern als inhärente Probleme gesehen, mit denen man einfach leben muss.

    Der Seitenhieb auf die funktionale Programmierung ist übrigens im Thema verfehlt. Erstmal ist generell fast gar nix nötig, wir könnten alle in Maschinensprache programmieren, zum anderen geht es hier aber gar nicht darum, C++ funktional zu machen, sondern Konstrukte, die sich innerhalb der funktionalen Programmierung bewährt haben, auch in C++ zu integrieren (wie es auch in der Vergangenheit und in vielen anderen Sprachen der Fall war).



  • Kellerautomat, ich finde es bemerkenswert, wie sehr du dich dabei anstrengst, Rust doof zu finden. Leider ist davon kaum etwas lesenswert. Du prognostizierst hier Probleme und Gefahren wo gar keine sind. Versuch doch bitte beim nächsten Mal, die Sache etwas fundierter anzugehen.

    Kellerautomat schrieb:

    'return' sticht in meinem Code hervor und ist klar und deutlich zu erkennen. Implizites return nicht.

    Das ist nur für die Fälle interessant, wo man mittendrin die Ausführung der Funktion beenden will. Genau das geht in Rust auch nur mit return . Du machst dir hier über etwas grundlos sorgen.

    Kellerautomat schrieb:

    Implizites const: Ich hab mir noch nie gedacht "Waere diese Variable mal const gewesen, dann haette ich diesen Fehler nie gemacht.". Das einzige was es macht, ist dass ich ueberall 'mut' hinschreiben muss. Nervt.

    Ich benutze "mut" in Rust gefühlt weniger als "const" in C++ und denke nicht, dass dich "mut" nerven würde. Es ist einfach deine Prognose basierend auf mangelnder Erfahrung mit Rust.

    Kellerautomat schrieb:

    {}: Blaehen meinen Code sinnlos um 100% auf. Aus 2 Zeilen werden 4.

    Der Klammerungs-Stil, der sich in Rust etabliert hat, ist der ägyptische. Das bringt dir im Vergleich genau ein linefeed mehr ein. Und andererorts verbietet man {}-lose if s in einigen C/C++ style guides, da man der Meinung ist, es wäre fehleranfälliger und schlechter Stil. So oder so finde ich diese Geschmacksfragen uninteressant. "Syntax bikeshedding" ist das, was man macht, wenn man sonst nix zu sagen hat.

    Kellerautomat schrieb:

    Implizites move: Einfach nur extrem gefaehrlich, wenn man nicht sofort erkennen kann, wo eine Variable veraendert wird. Die haetten einen move-Operator einfuehren sollen.

    Hier bist du schlecht informiert. Guck dir bitte selbst an, wie das mit den Moves in Rust funktioniert und warum da nix schiefgehen kann.

    Kellerautomat schrieb:

    Pattern matching: Hat keine predictable Performance

    genauso wenig oder viel wie ein switch in C. Leute, die das interessiert, gucken sich den Assembler-Code an, der dabei rauskommt. Ich habe das bisher nicht gemacht, weiß aber, dass die Rust-Entwickler stolz auf ihre Pattern-Matching-Implementierung sind.

    Kellerautomat schrieb:

    und ist ein unnoetiges Konzept. So wie funktionale Programmierung generell unnoetig ist.

    Du kennst das Blub-Paradox?

    As long as our hypothetical Blub programmer is looking down the power continuum, he knows he's looking down. Languages less powerful than Blub are obviously less powerful, because they're missing some feature he's used to. But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn't realize he's looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as well. Blub is good enough for him, because he thinks in Blub.

    So kommt mir dein Verhalten gerade vor … wie das des Blub Programmierers, der in seiner Denke festgefahren ist und keinen Nutzen in den Dingen sehen kann, die in Blub entweder anders (move Semantik) oder gar nicht (ADTs) vorhanden sind.

    Kellerautomat schrieb:

    enums: Sind nix anderes als typsichere unions. Mischen von Konzepten (Aufzaehlungen, variants) geht gar nicht. Wie kommt man ueberhaupt auf so ne bloede Idee?

    Das eine ist ein Spezialfall des anderen. Da wird nichts vermischt, was konzeptionell nichts miteinander zu tun hat.



  • Kellerautomat schrieb:

    • Returns ohne 'return'

    aus meiner erfahrung mit anderen sprachen kenn ich das als echt leidliche fehlerquelle. ein wenig eine paradoxe entscheidung fuer die eigentliche zielsetzung von Rust.



  • rapso schrieb:

    Kellerautomat schrieb:

    • Returns ohne 'return'

    aus meiner erfahrung mit anderen sprachen kenn ich das als echt leidliche fehlerquelle. ein wenig eine paradoxe entscheidung fuer die eigentliche zielsetzung von Rust.

    Aber es gibt doch in Rust gar kein "return ohne return". return ist für zwei Dinge zuständig: Es legt den Rückgabewert fest und beendet die Funktion vorzeitig. Wenn man diese zwei Dinge haben will, muss man dafür auch return in Rust schreiben. Wie damit die Wertrückgabe in Funktionen in Rust eine "leidliche Fehlerquelle" sein soll, kann ich mir nicht selbst zusammenreimen. Diese Gefahr sieht meines Wissen, auch sonst kein anderer Rustaceaner. Das ist auch keine Rust-eigene Erfindung. Man hat sich da von der ML-Sprachfamilie inspirieren lassen. Mir ist auch nicht bekannt, dass Programmierer, die sich in dieser ML-Sprachfamilie bewegen, das als Fehlerpotential sehen.

    Welche Sprachen meinst du? Kannst Du Beispiele für dieses angebliche Fehlerpotential zeigen? Ich habe nämlich den Verdacht, dass es euch ungewohnt vorkommt und ihr deswegen ein Fehlerpotential seht.

    In Rust sind einfache Blöcke, match … { … } , if … { … } else { … } nunmal selbst Ausdrücke. Das ist extrem praktisch — gerade in Rust. Und da liegt es nahe, den Wert des äußeren Blocks einer Funktion als Rückgabewert zu benutzen.

    Ich kann Euch sofort zwei Beispiele für "praktisch" zeigen:

    Das vec!-Makro, das man so benutzen kann

    fn main() {
        let v = vec![1,2,3,4];
    }
    

    würde diesen Code in folgenden umbauen

    fn main() {
        let v = {
            let mut tmp = Vec::with_capacity(4);
            tmp.push(1);
            tmp.push(2);
            tmp.push(3);
            tmp.push(4);
            tmp // Kein Semikolon => Wert des Ausdrucks wird nicht weggeschmissen
                //                   sondern als Wert des Blocks verwendet
        };
    }
    

    Andererorts gibt es Leute, die sich einen Keks freuen, wenn sie darauf kommen, dass man mit Lambda-Ausdrücken in C++ auch etwas konstantes erzeugen kann, was während der Erzeugung noch nicht konstant war:

    #include <vector>
    
    int main() {
        const std::vector<int> v = [](){
            std::vector<int> temp;
            temp.reserve(4);
            temp.push_back(1);
            temp.push_back(2);
            temp.push_back(3);
            temp.push_back(4);
            return temp;
        }();
    }
    

    (Ja, ich weiß, in diesem Beispiel kann man das auch über eine Initialisierungsliste machen.)

    Die Fehlerbehandlung macht davon auch Gebrauch:

    fn dings() -> io::Result<()> {
        let mut f = try!(fs::File::create("datei.txt"));
        try!(f.write_all(b"hello world\n"));
        Ok(())
    }
    

    File::create liefert einen Wert vom Typ io::Result<File> und write_all gibt wie dings auch io::Result<()> zurück, wobei () gleichzeitig Unit-Typ und Unit-Wert ist (quasi void ). try! ist hier das Makro, was einem im Vergleich zur Fehlerbehandlung in C das Manuelle Überprüfen und Abzweigen des Kontrollflusses erspart. io::Result<T> ist ein Alias für Result<T, io::Error> , wobei Result<T, E> ein Beispiel eines algebraischen Typs ist, der die Wertemengen von T und E vereint: Ein Wert vom Typ Result<T,E> kann entweder Ok(Wert vom typ T) sein oder Err(Wert vom Typ E) . Das try! -Makro macht aus obigem Code ungefähr folgendes:

    fn dings() -> io::Result<()> {
        let mut f = match fs::File::create("datei.txt") {
            Ok(x) => x,
            Err(e) => return Err(e)
        };
        match f.write_all(b"hello world\n") {
            Ok(x) => x,
            Err(e) => return Err(e)
        };
        Ok(())
    }
    

    (In Wirklichkeit ist das try! Makro noch flexibler und kann auch zwischen Fehler-Typen via convert::From konvertieren.)



  • krümelkacker schrieb:

    Ich habe nämlich den Verdacht, dass es euch ungewohnt vorkommt und ihr deswegen ein Fehlerpotential seht.

    Ich sagte ich habe mit solchen Sprachen gearbeitet, trotzm soll es ungewohnt sein?
    wenn Pascal/VB/Objective-C/Java/C#/Ocalm/Go/Rust/... die welt retten, na gut. aber bis dahin, programmiere ich entspannt c++ weiter.



  • rapso schrieb:

    aus meiner erfahrung mit anderen sprachen kenn ich das als echt leidliche fehlerquelle. ein wenig eine paradoxe entscheidung fuer die eigentliche zielsetzung von Rust.

    Um welche Sprachen geht es und was fuer fehler sind dabei aufgetreten? Die einzigen von mit verwendeten programmiersprachen, die rueckgaben ohne return erlauben, sind haskell und rust und mit beiden hatte ich noch nie ein Problem deswegen.



  • rapso schrieb:

    krümelkacker schrieb:

    Ich habe nämlich den Verdacht, dass es euch ungewohnt vorkommt und ihr deswegen ein Fehlerpotential seht.

    Ich sagte ich habe mit solchen Sprachen gearbeitet, trotzm soll es ungewohnt sein?

    Bisher habe ich hier keine Begründungen und keine Beispiele bzgl Fehlerpotential gesehen. Ich kann mir das selbst leider nicht zusammenreimen, wo da ein Problem sein soll. Ich stelle auch fest, dass du meinen Fragen in der Richtung ausgewichen bist. Natürlich gehe ich im Moment davon aus, dass diese "Kritik" sich eher auf "bin ich nicht gewohnt" reduzieren lässt. Ich lasse mich aber auch gern vom Gegenteil überzeugen.





  • Heise hat auch schon über die erste Version von Rust berichtet:http://www.heise.de/newsticker/meldung/C-Herausforderer-Rust-1-0-erschienen-2650494.html

    Klar wird es viele Jahre dauern, bis man von C++ zu Rust gewechselt ist. Von C zu C++ war es auch ein langer Weg und man setzt heute C nur noch ein wenn es nicht anders geht. Genauso wird man C++ irgendwann nur noch einsetzen, wenn es nicht anders geht.

    C++ ist ja nun keine Sprache für die Ewigkeit. Auch in der IT geht die Evolution weiter, da hilft alles Trampeln auf dem Boden ala Rumpelstilzchen nichts.

    Die alten C++ Libs können mir wenig Aufwand erst einmal weiter genutzt werden. Der C++-Kuchen wird also sehr langsam anfangen zu schrumpfen.

    Mit der ersten guten IDE und ersten Bücher/Video2Brains etc. wird der Startschuss dann abgefeuert werden und die Menge wird Jubel wenn Mozilla den neuen Browser vorstellt und er tatsächlich weniger Sicherheitslücken allein dadurch aufweist weil Rust benutzt wurde. Wenn das passiert, dann gibt es kein Halten mehr. Da können auch die ewig Gestrigen wenig dagegen tun, außer sich vielleicht abends in ihr C++-Kissen zu weinen.



  • Rust hat nur ein verdammtes Problem: Es sieht sau hässlich aus.


Anmelden zum Antworten