Rust



  • C++ ist auch nicht gerade eine Schönheit. Gewohntes sieht immer schöner aus und fühlt sich einfacher an. Veränderung bedarf Anstrengung und die will man oft vermeiden, erst recht wenn man älter wird.



  • Kugelglas schrieb:

    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

    Hmm...

    Ursprünglich war Rust als Konkurrent für Googles Sprache Go gedacht.

    Citation needed. 🙄

    Die Sprache hat sich viel geändert über die Zeit, aber die Ziele sind immer dieselben gewesen. Der heise-Artikel verlinkt sogar das Interview, was sie mit Graydon Hoare gemacht haben. Nach der Frage der Motivation hatte er vor zwei Jahren folgendes gesagt:

    Graydon Hoare: Die Unzufriedenheit mit den Kompromissen, die man beim Schreiben in C++ eingehen muss. Wie viele andere Leute, die im Umfeld von System- und Desktop-Programmen arbeiten, musste ich aus Gründen der Performance, des Speicher- und Laufzeitmodells sowie entwicklungstechnischer Einschränkungen mit dieser Sprache arbeiten. Aber ich finde C++ ziemlich fehlerträchtig.
    Es ist schwierig, damit Code zu schreiben, von dessen Fehlerfreiheit und Speichersicherheit ich überzeugt bin. Das gilt doppelt, wenn ich Dinge schreibe, die hochgradig nebenläufig sind oder mit vielen Threads arbeiten.

    Im Artikel "Junger C/C++-Herausforderer" steht

    Seit der initialen Schöpfung hat das Projekt mehrfach das Team und die Ausrichtung gewechselt, aber inzwischen seine Nische gefunden.

    Kommt wohl drauf an, wie man "Ausrichtung" definiert. 🙄

    Bzgl Schönheit: Die liegt im Auge des Betrachters.





  • hess schrieb:

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

    Und? Die einzigen wirklich schoenen sprachen sind Python und Haskell (solange man es nicht mit operatoren uebertreibt).
    Gerade an der ersten stoert viele aber die Einrueckungen als Syntaxelement.



  • Marthog schrieb:

    Gerade an der ersten stoert viele aber die Einrueckungen als Syntaxelement.

    Julia ist eine schöne Alternative aber noch leider nicht sehr ausgereift.



  • hi,

    ich versuche gerade etwas rust zu lernen...
    was macht hier &mut [u32; n] genau, wo ist der unterschied zu *mut [u32; n]? wie unterscheiden sich beide bzgl. performance?

    const n: usize = (16*1024);
    
    struct foo {
        chaMem: *mut [u32; n],
    }
    
    impl foo {
        pub fn new() -> foo {
            let mem1: *mut [u32; n] = unsafe { ::std::mem::transmute(Box::new([1; n])) };
            foo {chaMem: mem1}
        }
    
        pub fn get_sig_ptr1(&mut self) -> &mut [u32; n] {
            unsafe {
                return &mut *(self.chaMem);
            }
        }
    }
    
    // This code is editable and runnable!
    fn main() {
        let mut f = foo::new();
    
        let cha_signal: &mut [u32; n] = f.get_sig_ptr1();
    
        for i in 1..n {
            println!("{}", cha_signal[i]);
        }
    }
    


  • Was zum teufel willst du mit diesem Code anfangen? Das ist absolut haesslich, unsicher und es wundert mich, dass es ueberhaupt compiled und laeuft.

    &mut [u32; n] ist eine slice der laenge n, also eine referenz auf ein array.
    *mut [u32; n] ist ein roher pointer (wie die aus c) auf ein array der laenge n.

    Performanceunterschiede sollte es eigentlich keine geben. Die erste Variante ist ausser in Ausnahmefaellen vorzuziehen.

    Den Code hast du doch bestimmt aus einem Betriebssystem-Kernel oder einer seltsamen low-level-library?



  • Hi rusty,

    rusty schrieb:

    ich versuche gerade etwas rust zu lernen...
    was macht hier &mut [u32; n] genau, wo ist der unterschied zu *mut [u32; n]?

    &T und &mut T sind "borrowed references".
    *T und *mut T sind "unsafe pointers".

    Eine "borrowed reference" ist immer gültig (bzw. soll es sein). Borrowed references kannst du deswegen problemlos in "normalem" Rust-Code verwenden. Sie verhalten sich wie Zeiger, die nie null sind. Sie sind, wie der Name schon vermuten lässt, dazu da, Dinge zu verleihen/auszuleihen. Der Compiler achtet darauf, dass, solange etwas ausgeliehen ist, dieses etwas nicht "direkt" verändert werden kann. Wenn man etwas mit & verleiht, dann darf da keiner was dran ändern, bis die Ausleih-Aktion zu Ende ist. Wenn man etwas mit &mut ausleiht, dann hat man eine Referenz in der Hand, über die man etwas verändern kann. Von dieser Sorte kann es immer nur höchstens eine geben und das Objekt darf dann nicht über andere Wege verändert werden. Es gibt natürlich auch Ausnahmen für die Sache mit der Veränderbarkeit (=> "interiour mutability", siehe Cell, RefCell). Außerdem hängen bei dieser Art von Referenztypen noch Lebenszeitparameter mit drin, die der Compiler dazu verwendet, um zu gucken, wie lange etwas ausgeliehen wird und wie lange eine solche Rrferenz überhaupt existieren darf (bevor sie baumeln würde). &T ist also gar nicht vollständig als Typ. Vollständig aufgeschrieben ist der Typ &'x T für irgendeine Lebenszeit x . Aber Lebenszeiten müssen nicht immer einen Namen haben und meistens deduziert der Compiler das auch einfach, deswegen sind diese Lebenszeiten oft praktisch unsichtbar. Sie sind aber immer Teil der Referenz-Typen. Die Regeln drum herum sind ein wichtiger Baustein für die Speichersicherheit.

    "unsafe pointers" können null sein, abfragbar mit myunsafeptr.is_null() . Außerdem gibt es für "unsafe pointer" auch keinerlei Gültigkeitsgarantien. Deswegen darf man sie auch nur in unsafe Code dereferenzieren. Sie haben keine Lebenszeitparameter als Teil des Typs und vermeiden auch kein "mutable aliasing", weswegen man sich mit ihnen recht einfach in den Fuß schießen kann. Diese Art der Zeiger verwendet man i.d.R. nur dafür, höher-levelige, Bausteine zu konstruieren (z.B. Vec<T> ), die eine sichere Schnittstelle anbieten, die man nicht falsch benutzen kann (hinsichtlich Speichersicherheit). Wenn Du nicht gerade eine eigene optimierte Datenstruktur bauen willst (es gibt ja schon recht vieles in der Standardbibliothek) oder Du direkt mit C-Code interagieren willst (idealerweise gibt es dafür schon Bindings von Leuten, die wissen, was sie tun), dann solltest Du von "unsafe pointers" die Finger lassen.

    Auf Maschinenebene sehen diese beiden Varianten gleich aus. Das heißt, "borrowed references" sind genauso groß wie "unsafe pointers" und haben auch sonst keinen anderen Overhead zur Laufzeit. Der Unterschied liegt wirklich nur darin, dass der Compiler bei "borrowed references" mehr prüfen kann, wohingegend du bei "unsafe pointers" auf Dich allein gestellt bist. Du solltest einen wirklich guten Grund haben, wenn du "unsafe pointers" benutzen willst.

    Den Sinn Deines Codes kann ich nicht erkennen. Warum hast Du nicht einfach folgendes geschrieben?

    const N: usize = 8;
    
    struct Foo {
        cha_mem: Box<[u32; N]>,
    }
    
    impl Foo {
        pub fn new() -> Foo {
            Foo {
                cha_mem: Box::new([1; N])
            }
        }
    
        pub fn get_sig_ptr1(&mut self) -> &mut [u32; N] {
            &mut self.cha_mem
        }
    }
    
    fn main() {
        let mut f = Foo::new();
    
        for r in f.get_sig_ptr1() {
            println!("{}", *r);
        }
    }
    

    Du brauchst doch überhaupt kein unsafe . Und die Fixe Größe N , naja, das kann man so machen. Wenn die tatsächliche Größe aber erst zur Laufzeit feststeht, nimmt man natürlich lieber Vec<u32> statt Box<[u32; N]> .



  • bei dem beispiel geht es nur ob ich als return type &mut [u32; n] verwenden kann...

    @Marthog: calm down pro.
    &mut [u32; n] verwende ich für low level zeug...

    habe gerade gemerkt das man mit #[inline(never)] gewisse optimierungen abschalten kann... rust/llvm hat hier etwas optimiert was zu einem fehler geführt hatte...

    für low level zeug braucht man halt unsafe... e.g. mmap und pointer zeug...



  • rusty schrieb:

    ich versuche gerade etwas rust zu lernen...

    sehr gut!

    was macht ..., wo ist der unterschied ...? wie unterscheiden sich ...

    hier geht es allgemein um Rust, ich frage immer in:
    https://users.rust-lang.org/
    sehr zu empfehlen!



  • rusty schrieb:

    habe gerade gemerkt das man mit #[inline(never)] gewisse optimierungen abschalten kann... rust/llvm hat hier etwas optimiert was zu einem fehler geführt hatte...

    Da gibt's jetzt mindestens zwei Erklärungsmöglichkeiten: (1) Compiler Bug. (2) Du rufst undefiniertes Verhalten hervor, weil du bestimmte Dinge ignoriert hast, auf die man in unsafe-Blöcken achten muss. Dir ist hoffentlich klar, dass der Compiler z.B. davon ausgeht, dass alle benutzbaren &mut T aliasfrei sind, nä? Das kann natürlich zur Optimierung ausgenutzt werden und geht schief, wenn du per unsafe doch zwei benutzbare &mut T erzeugst, die auf dieselbe Speicherstelle zeigen.



  • @krümelkacker:
    der compiler optimiert die schleife, und kopiert 2 32-bit values mit dem befehl: stmiacs r3!, {r1, r12} ...die hardware verlangt 1 32 bit transfer at a time... so geht das schief...

    fix:

    for i in 0..n {
                  volatile_store::<u32>(&mut (*self.chaMem)[i], (*data)[i] as u32);
    }
    

    alle benutzbaren &mut T aliasfrei sind?



  • krümelkacker ist jetzt the rusty support baer hier 🙂



  • Auch gut zu gebrauchen (Deutsch).
    Hauptanteil: Erklärung der Ownership-Sachen.

    http://media.koeln.ccc.de/regional/koeln/open_chaos/2015/05/c4.openchaos.2015.05-rust.webm



  • news: "Mehr Speed für Rust 1.1 und Rust 1.2 Beta"
    https://jaxenter.de/rust-1-1-und-rust-1-2-beta-21966



  • rusty schrieb:

    news: "Mehr Speed für Rust 1.1 und Rust 1.2 Beta"
    https://jaxenter.de/rust-1-1-und-rust-1-2-beta-21966

    Das ist schoen. zz ist compilen ja so dermassen scheiss langsam.


Anmelden zum Antworten