Slide with text: “Rust teams at Google are as productive as ones using Go, and more than twice as productive as teams using C++.”

In small print it says the data is collected over 2022 and 2023.

  • FizzyOrange@programming.dev
    link
    fedilink
    arrow-up
    11
    ·
    8 months ago

    I totally agree, though I think it’s worth adding:

    • The advantages of static types is not just finding bugs (though it does do that quite well). It also massively helps with productivity because a) types are now documented, b) you can use code intelligence tools like renaming variables, go-to-definition, find-references, etc. (assuming you use a good editor/IDE).

    • In general stronger types are better but I do think there is a point at which the effort of getting the types right is too high to be worth the benefit. I would say Rust hasn’t reached that point, but if you look at formal verification languages like Dafny, it’s pretty clear that you wouldn’t want to use that except in extreme circumstances. Similarly I think the ability to use an any or dynamic escape hatch is quite useful, even if it should be used very sparingly.

    • arendjr@programming.devOP
      link
      fedilink
      arrow-up
      4
      ·
      8 months ago

      You are right. But I think similar secondary benefits also come from using the borrow checker. Rust developers, by necessity, try to avoid using circular references and prefer immutability where they can. Both of these are advantages because they tend to make for systems that are easier to understand and are easier to maintain.

    • orclev@lemmy.world
      link
      fedilink
      English
      arrow-up
      3
      ·
      8 months ago

      It also massively helps with productivity

      Absolutely! Types are as much about providing the programmer with information as they are the compiler. A well typed and designed API conveys so much useful information. It’s why it’s mildly infuriating when I see functions that look like something from C where you’ll see like:

      pub fn draw_circle(x: i8, y: i8, red: u8, green, u8, blue: u8, r: u8) -> bool {
      

      rather than a better strongly typed version like:

      type Point = Vec2<i8>;
      type Color = Vec3<u8>;
      type Radius = NonZero<u8>;
      pub fn draw_circle(point: Point, color: Color, r: Radius) -> Result<()> {
      

      Similarly I think the ability to use an any or dynamic escape hatch is quite useful, even if it should be used very sparingly.

      I disagree with this, I don’t think those are ever necessary assuming a powerful enough type system. Function arguments should always have a defined type, even if it’s using dynamic dispatch. If you just want to not have to specify the type on a local, let bindings where you don’t explicitly define the type are fine, but even in that case it still has a type, you’re just letting the compiler derive it for you (and if it can’t it will error).

      • FizzyOrange@programming.dev
        link
        fedilink
        arrow-up
        8
        arrow-down
        2
        ·
        8 months ago

        Without static type annotations you can only make best effort guesses that are sometimes right. Better than nothing but not remotely the same as actual static types. The LSP you linked works best when you use static type annotations.

        Also I would really recommend Pylance over that if you can - it’s much better but is also closed source unfortunately.

        • asdfasdfasdf@lemmy.world
          link
          fedilink
          arrow-up
          4
          arrow-down
          2
          ·
          8 months ago

          Why would it just be best effort? To find references for a specific thing, it still would parse an AST, find the current scope, see it’s imported from some module, find other imports of the module, etc.

          • Buttons@programming.dev
            link
            fedilink
            English
            arrow-up
            5
            ·
            edit-2
            8 months ago
            if random() > 0.5:
                x = 2
            else:
                x = "hello"
            

            Where is the definition of x? What is the type of x? If you can’t identify it, neither can the LSP.

            This kind of thing actually happens when implementing interfaces, inheritance, etc. Thus, LSPs in dynamic languages are best effort both theoretically and in practice.

            • asdfasdfasdf@lemmy.world
              link
              fedilink
              arrow-up
              2
              arrow-down
              1
              ·
              edit-2
              8 months ago
              1. Look at entire file instead of snippet.
              2. If there is anything that could create a variable x before this area, then that’s where x originates. If not, and if it’s a language where you can create x without using a keyword like let or var, then x is created in the scope in your snippet.

              Types are not necessary at all.

              • Buttons@programming.dev
                link
                fedilink
                English
                arrow-up
                3
                arrow-down
                1
                ·
                8 months ago

                then x is created in the scope in your snippet

                Saying “x is defined somewhere in the entire program” isn’t satisfactory to many users. Also, you didn’t tell me what type x has. Can I do x + 5?

                • asdfasdfasdf@lemmy.world
                  link
                  fedilink
                  arrow-up
                  2
                  arrow-down
                  1
                  ·
                  8 months ago
                  1. That isn’t what I said at all. Reread?
                  2. Find references / go to definition / rename has absolutely nothing to do with types.
                  • FizzyOrange@programming.dev
                    link
                    fedilink
                    arrow-up
                    1
                    ·
                    8 months ago

                    Find references / go to definition / rename has absolutely nothing to do with types.

                    It absolutely does. Without static types an IDE/LSP can’t reliably find all the references / definition and therefore can’t refactor reliably either.

                    Consider something like this:

                    class Foo:
                      bar: int
                    
                    class Baz:
                      bar: str
                    
                    def a(f: Foo) -> int:
                      return f.bar + 1
                    
                    def b(f: Baz) -> str:
                      return f.bar + "1"
                    

                    Now imagine you want to rename Foo.bar or find all references to it. Impossible without the type annotations.

            • Miaou
              link
              fedilink
              arrow-up
              1
              ·
              8 months ago

              Tbf this example can be deducted as string | int just fine.

          • FizzyOrange@programming.dev
            link
            fedilink
            arrow-up
            2
            arrow-down
            1
            ·
            8 months ago
            def get_price(x):
               return x.prize
            

            Ok imagine you are a LSP. What type is x? Is prize a typo? What auto-complete options would you return for x.?

              • FizzyOrange@programming.dev
                link
                fedilink
                arrow-up
                2
                ·
                8 months ago

                How are you going to find references to prize, go to its definition or rename it without knowing what type x is? It’s impossible without static types.