Vortrag über Ideen für eine neue Sprache für Spieleentwickler [youtube]



  • Artchi schrieb:

    Also ne Toolbar mußte ich bei Java nie mitinstallieren. Ich bin wirklich kein Java-Fan, aber fair sollte man schon noch bleiben. 🙄

    Siehe hier. Einfach nur 'ne lächerliche Frechheit dieses Java. Bei einer Runtime drehen die einem Adware an... 👎



  • Ich hatte noch nie eine Java-Toolbar installiert. Und selbst wenn ist Java sehr weit entfernt von tot und es gibt viele und sehr gute Entwicklungsumgebungen.



  • volkard schrieb:

    Du stellst Dich anscheinend als Verteidiger der "C-in-C++"-Programmierer hin,

    Das tue ich nicht. Ich bin keiner von den "C-in-C++"-Programmierern. Ich stecke bei Dir nur fälschlicherweise in so einer Schublade drin.

    volkard schrieb:

    sagst die typischen C-Fehler seien in C++ voll normal.

    Das kann ich auch nicht bestätigen, wenn Du es so formulierst. Ich denke, wir belegen "typische C-Fehler" mit einer anderen Bedeutung. Ich sage, dass bzgl Speichersicherheit C++ nicht wirklich viel besser als C darsteht. Ein bisschen. Nicht viel.

    Zum Beispiel bieten einige Standardbibliotheksimplementierungen zu Debugzwecken so etwas wie "checked iterators" und co an und std::vector<T>::operator[] sowie std::array<T,N>::operator[] werden in so einem Modus auch testen, ob der Index gültig ist. Das ist prima! Deswegen würde ich sagen, C++ ist "ein bisschen besser" bzgl Speichersicherheit, weil es zumindest im Debugmodus bei gescheiter Nutzung der Standardbibliothek zur Laufzeit einige Fehler besser/früher abfangen kann.

    Aber diese Art der Fehlererkennung führt leider dazu, dass die Programme sehr langsam laufen. Das ist zumindest bei g++ der Fall gewesen, last time I checked. Deswegen verwende ich so einen Modus auch nur dann, wenn mir mein C++ Programm mal um die Ohren geflogen ist. Das passiert extrem selten, so selten, dass ich mich nicht mehr daran erinnere, was das für Fehler waren. Aber meine Anwendungsdomäne (number crunching command line tools) ist da auch kein großes Problem in der Hinsicht. Diese Fehlererkennungsmöglichkeiten sind leider auch etwas löchrig. Cooler wär's natürlich, wenn alle Arten von "Referenzen", die ungültig geworden sind, irgendwie abgefangen werden könnten, nicht nur Iteratoren. Und noch cooler wär's, wenn der Großteil dieser Checks schon zur Compilezeit laufen könnten und keine Laufzeitkosten verursachen würden. Dann kann man es sich sogar erlauben, die restlichen Checks drin zu lassen. Denn im Endeffekt wirst Du den C++ Code im "release mode" kompilieren und laufen lassen. Es kommt dann darauf an, ob du bei den vorherigen Testläufen schon alle Fehler abfangen konntest. Ich stelle es mir schwierig vor, Testfälle zu erzeugen, die alle Sicherheitslücken abdecken werden. Denn sonst gäb's nicht so viele Sicherheitslücken in C++ Software.

    Es ist super easy mit einer kleinen Recherche Sicherheitsprobleme in C++ Software zu finden. Ein nicht zu verachtender Teil sind Spechersicherheitsfehler (u.a. use-after-free). Und da ist C++ Software bei, die nicht von Idioten geschrieben wurden, sondern von Leuten wie Du und ich, die "von C++ Ahnung" haben. Statt das anzuerkennen sprichst Du Leuten reflexartig Kompetenzen ab, ohne wirklich einen Überblick über deren Anwendungsdomäne zu haben. Natürlich kommt mir das ignorant und eingebildet vor. Es hilft auch keinem. Es verschlechtert nur den Signal-Rausch-Abstand.

    volkard schrieb:

    Kellerautomat schrieb:

    Es gibt einfach keine Faelle, in denen Exceptions irgendwie sinnvoll sind. Halt, doch. Da war doch was mit Konstruktoren. Hm, vielleicht einfach Konstruktoren entfernen und Funktionen bereitstellen? Koennte klappen. Oder einfach nix im Konstruktor machen, was fehlschlagen koennte. Hey, das klingt doch gut.

    Gefällt mir. Die Sonderrolle der Konstruktoren war mir immer zuwider.

    volkard schrieb:

    Kellerautomat schrieb:

    Andererseits, fuer Sachen wie mathematische Vektoren ist es doch ganz praktisch, wenn ich vector3f(1.f, 2.f, 3.f) schreiben kann. Hmmmm...

    Ja, vector3f(1.f, 2.f, 3.f) ist toll, ist nur Aufrufmagie. Die andere Seite stört mich. Konstruktoren sind static-Methoden, ohne daß ein static da steht. Sie haben einen seltsamen Namen, statt wie in anderen Sprachen new, _construct oder so. Die haben keinen Rückgabetyp, nichtmal void.

    volkard schrieb:

    Ja, auch ein Punkt, den ich doof finde: Objekte wegmoven, ohne daß der Bezeichner verschwindet. Ich hätte gerne

    ding.foo();
    aufruf(move(ding));
    //ding.foo();//gäbe compilerfehler
    

    volkard, das sind super Steilvorlagen von Dir, denen ich nicht entziehen kann: In Rust gibt es diese destruktiven Moves und statt Konstruktoren statische Methoden und Funktionen. Es gibt da auch eine Lösung für das Problem, Member aus Objekten rauszumoven, ohne dass man immer Option benutzen muss (kommt auf den Fall an). Es gibt noch replace und Methoden, die ihr Objekt konsumieren können, so dass der Aufrufer es nicht mehr weiter benutzen kann. In diesen Methoden darf man natürlich das Objekt komplett auseinander nehmen.

    IBV schrieb:

    Scala kennt Null nur von Java, benutzt es in eigenen Libs allerdings nicht. Es wird höchstens None (eher bei Listen. Alle Operationen sind jedoch noch anwendbar.) zurückgegeben oder ein bestimmter Fehlertyp (bei der Verarbeitung von Daten).
    Z. B.:

    request.body.validate[User] match {
      case jsUser: JsSuccess[User] => // Do something
      case error: JsError => // Error Handling
    }
    

    Allgemeine Fehlerbehandlung (diese Konstellation taucht eher selten auf):

    request.body.validate[User] match {
      case jsUser: JsSuccess[User] => // Do something
      case _ => // General Error Handling
    }
    

    Interessant. Das sieht in Rust fast genauso aus. Gibt es in Scala auch so etwas wie das Haskell- do oder das Rust- try! , womit man sich das manuelle match en in vielen Fällen sparen kann?

    type MyResult<T> = Result<T, SendStr>;
    //                           ^^^^^^^ beliebiger Typ für den Fehlerfall
    // SendStr kann String-Objekte oder Verweise auf Stringliterale speichern
    
    fn foo(i: int) -> MyResult<int> {...}
    fn bar(i: int) -> MyResult<int> {...}
    
    fn dings(i: int) -> MyResult<int> {
        try!(foo(i)) * 2 + try!(bar(i+3))
    }
    
    fn main() {
       match dings(23) {
          Err(msg) => println!("Klappte nicht. Fehlermeldung: {}", msg),
          Ok(i) => println!("Das Ergebnis ist {}", i)
       }
    }
    

    wobei try! hier im Normalfall den erwarteten Wert auspackt und im Fehlerfall die Funktion mit dem Fehlerwert per return frühzeitig beendet. Aber es funktioniert bis jetzt nur, wenn der Fehlertyp derselbe ist. Man arbeitet z.Zt. daran, es etwas aufzuboren und benutzerdefinierte Konvertierungen von Fehlertypen zuzulassen. Result bietet auch ein paar nützliche Methoden an, mit denen man sich das eine oder andere match sparen kann.

    In C++ nutze ich Ausnahmen hauptsächlich dazu, Fehlermeldungen bzgl Eingabefehler des Benutzers zur catch -Klausel an main durchzureichen. Wenn man RAII/SBRM konsequent einsetzt, seh' ich da auf Anhieb keine großen Probleme. Ausnahmesicherheit ist für mich aber nicht der einzige Grund für RAII/SBRM.



  • krümelkacker schrieb:

    Interessant. Das sieht in Rust fast genauso aus. Gibt es in Scala auch so etwas wie das Haskell- do oder das Rust- try! , womit man sich das manuelle match en in vielen Fällen sparen kann?

    Nicht, dass ich wüsste, aber das match kann man sich teils auch mit getOrElse sparen.
    Die einfache Variante sieht so aus: http://whileonefork.blogspot.de/2011/05/magic-of-getorelse.html
    Die komplexere mit map so:

    request.session.get(UUID_KEY).map { uuid =>
      // Do something
    }.getOrElse {
      BadRequest("UUID could not be mapped to a captcha solution. Only one try per captcha possible.")
    }
    

    L. G.,
    IBV



  • krümelkacker schrieb:

    Cooler wär's natürlich, wenn alle Arten von "Referenzen", die ungültig geworden sind, irgendwie abgefangen werden könnten, nicht nur Iteratoren.

    Clang hat den Address Sanitizer, der schon einiges mit nur rund 100% Overhead zur Laufzeit finden soll.



  • IBV schrieb:

    Nicht, dass ich wüsste, aber das match kann man sich teils auch mit getOrElse sparen.

    Solche und ähnliche Operationen sind auch praktisch manchmal. (In Rust z.B. unwrap_or , unwrap_or_else )

    TyRoXx schrieb:

    krümelkacker schrieb:

    Cooler wär's natürlich, wenn alle Arten von "Referenzen", die ungültig geworden sind, irgendwie abgefangen werden könnten, nicht nur Iteratoren.

    Clang hat den Address Sanitizer, der schon einiges mit nur rund 100% Overhead zur Laufzeit finden soll.

    Achja, Clang's AdressSanatizer gibt's ja auch noch. Den habe ich noch nicht getestet. Von einem anderen Tool, was die Ausfürhung auch "nur halb so schnell" werden lassen soll, habe ich hier gehört. Den Vortrag kann man sich auch angucken. Ich fand den nicht schlecht.

    Eine Version, die halb so schnell läuft und dabei alle "Speicherfehler" abfangen kann, reicht wahrscheinlich für Testläufe. Und für manche Anwendungen ist das vllt auch schnell genug, um es produktiv einzusetzen, wenn man sich Sorgen um Angreifer macht, die einbrechen wollen.



  • krümelkacker schrieb:

    Interessant. Das sieht in Rust fast genauso aus. Gibt es in Scala auch so etwas wie das Haskell- do oder das Rust- try! , womit man sich das manuelle match en in vielen Fällen sparen kann?

    type MyResult<T> = Result<T, SendStr>;
    //                           ^^^^^^^ beliebiger Typ für den Fehlerfall
    // SendStr kann String-Objekte oder Verweise auf Stringliterale speichern
    
    fn foo(i: int) -> MyResult<int> {...}
    fn bar(i: int) -> MyResult<int> {...}
    
    fn dings(i: int) -> MyResult<int> {
        try!(foo(i)) * 2 + try!(bar(i+3))
    }
    
    fn main() {
       match dings(23) {
          Err(msg) => println!("Klappte nicht. Fehlermeldung: {}", msg),
          Ok(i) => println!("Das Ergebnis ist {}", i)
       }
    }
    

    http://www.scala-lang.org/api/current/#scala.util.Try


Anmelden zum Antworten