• 0 Posts
  • 23 Comments
Joined 3 years ago
cake
Cake day: July 24th, 2023

help-circle





  • You can design a language where you don’t need to generate code to accomplish this.

    Other people have python scripts generate C, so having on in the same codebase and language is certainly an improvement.

    My question isn’t why this is necessary in Rust. My question is why Rust was designed such that this was necessary.

    Because otherwise the compiler team either also needs to maintain a huge amount libraries or cut corners and move things to runtime that really should happen at compile time.

    Someone mentioned elsewhere that this allows for compile-time type safety. I’m still trying to wrap my head around how that works.

    printf is a great example. According to the C type system, it takes a string and a variable amount of untyped arguments dependent on the content of the string, but that doesn’t actually describe the allowed arguments.
    Misusing printf like this printf("%s", 42); will get you a warning, but only because there is a special case for printf in the compiler. If you have your own function that does the same as printf, and you misuse the same way, you will find out by dissecting the core dump.

    In rust the format string gets parsed at compile time by a macro, which decides the type of each arguments that can than be checked by the compiler. Imagine printf(“%s %d”,…) created a function with the signature specialized_printf(char* agr0, int arg1), it would be impossible to pass the wrong types of arguments.

    Now that these tools exist people have gone further and made a library that checks SQL queries against the shema of a running database and causes a compile error if it doesn’t fit.







  • But you’re also missing one use of the impl keyword: fn func() -> impl Trait.

    […] So dropping the impl in [return position] might not be completely impossible like the other uses of impl.

    But the impl markes that it is a trait to the programmers.
    Take the following functions:

    func1()->A{...}
    func2()->A{...}
    

    Does the following snippet compile?

    let mut thing = func1();
    thing = func2();
    

    Under the current rules we know it will. But if A could be a trait, the functions could return different types. We currently mark that with the impl.


    Why? What value does -> () provide? Why not elide that?

    What value is provided by keeping it?

    What value does cluttering up your code with -> () provide?

    Why a syntactic special-case for exactly that type and not any other random type?

    Because the unit type is special, just like the never ! type. () also has the special importance of being the return value of an empty statement and some other stuff.


    languages w/o [semicolons] feel awkward since you’re generally limited to one statement per line

    Then fixing that might make sense. :-)

    It’s fixed with semicolons ;-)









  • I was a bit apprehensive because rust has like a gazillion different function types but here it seems to work like just any other language with a HM type system.

    The fn(T)->R syntax works for functions without associated data, it discards details of the implementation and works like function pointers in C. This allows them to be copy and 'static.

    The other function types can have data with them and have more type information at compile time which allows them to be inlined.
    These functions each have their own unwritable type that implements the function traits (Fn(T)->R, FnMut(T)->R and FnOnce(T)->R) depending on their enclosed data.

    I hope I remembered everything right from this video by Jon Gjengset.