• Lucy :3@feddit.org
      link
      fedilink
      arrow-up
      4
      ·
      20 hours ago

      Average Rust code:

      macro_rules! sum {
          ( $initial:expr $(, $expr:expr )* $(,)? ) => {
              $initial $(+ $expr)*
          }
      }
      
      fn remove_prefix<'a>(mut original: &'a str, prefix: &str) -> &'a str
      
      let mut up = 1;
          'outer: loop {
      

      This is on the level of the esolang I made at 8 y/o, with random characters denoting random actions everywhere, at random positions.

      • 5C5C5C@programming.dev
        link
        fedilink
        arrow-up
        16
        ·
        18 hours ago

        It’s incredibly disingenuous to call this average Rust code and further erodes your credibility. I may as well point to hundreds of lines of preprocessor macros in a C++ header and call it average C++ code.

        This is not what an average Rust developer is writing 99% of the time. If someone on my team submitted a PR with an implementation of sum that uses macro_rules! I would almost certainly reject it.

      • jackr@lemmy.dbzer0.com
        link
        fedilink
        arrow-up
        5
        ·
        20 hours ago

        Perl is ugly but great. It’s like shell scripting with a more solid programming language. I’d never use it outside of simple scripts in my os, but whenever I do use it it’s very fun. Anyway, yeah, rust looks fine to me. Maybe they are not very experienced with it? I know some of my programs used to have lines with just x.unwrap().unwrap().unwrap() or whatever, which is not pretty.

        • Ephera@lemmy.ml
          link
          fedilink
          English
          arrow-up
          4
          ·
          13 hours ago

          I know some of my programs used to have lines with just x.unwrap().unwrap().unwrap() or whatever, which is not pretty.

          That goes away with experience, though. At least, I can’t think of a reason why you’d nest three Results or Options. Normally, you would collate them right away.

          The most you see in the wild is something like Result<Option<_>> to express that a check can fail, but even if it doesn’t, then a valid result can still be that there is nothing there.

          If you don’t care that your program crashes (like .unwrap() does), then anyhow is the error handling library of choice. With it, you can just write a ? in place of an .unwrap() for practically any error type. And well, it automatically combines the errors, so you won’t be writing ??? either.

          • jackr@lemmy.dbzer0.com
            link
            fedilink
            arrow-up
            1
            ·
            5 hours ago

            yeah that was what I meant, I can see someone writing a mistake that requires ugly rust to solve and then believing rust is ugly because of it.

    • rtxn@lemmy.world
      link
      fedilink
      arrow-up
      17
      ·
      edit-2
      1 day ago

      Enums and nested blocks. I understand the importance of Option and Result, but it’s fucking infuriating when I have to check and destructure the result of every function call and either bubble the result up the stack from six levels of nested if let blocks or risk Cloudflaring my program by using .unwrap(). And while I like being able to extract a return value from an if...else expression, the structure gets really convoluted when multiple if and match blocks are nested (of course each one returning a value), and it gets completely fucked once closures are introduced.

      I like Rust, but calling it pretty is delusional.

      • tatterdemalion@programming.dev
        link
        fedilink
        arrow-up
        1
        ·
        3 hours ago

        Enums are the best part of the Rust language IMO, so I’m not sure how you can view them as ugly. Having the choice to destructure something is fantastic. You generally aren’t required to destructure every return value. Make sure you’re using the ? operator as much as possible. If destructuring is getting in your way, it sounds like the code is not very idiomatic.

        I can’t really comment on your issue with nested if and match. Too much nesting is bad in any language; try extracting more functions and let bindings to make it more readable.

        You can enable a clippy lint to deny .unwrap() if you’re worried about it.

      • calcopiritus@lemmy.world
        link
        fedilink
        arrow-up
        1
        ·
        9 hours ago

        Most of the times you can just let ... else (which is basically a custom ? if you need if let ... else it’s because you actually need 2 branching code paths. In any other language you also do if ... else when you have 2 different code branches. I don’t see why this is a rust-specific issue.

      • SorryQuick@lemmy.ca
        link
        fedilink
        arrow-up
        4
        ·
        edit-2
        12 hours ago

        You can also use let else.

        let (Some(count\_str), Some(item)) = (it.next(), it.next()) else {
            panic!("Can't segment count item pair: '{s}'");
        };
        

        But really it’s the exact same as other languages, it just forces you to handle it better. C-based languages will return 0/null/-1 and you’ll have to check all 3 of those because they might not mean the same thing. How is that better?

      • marcos@lemmy.world
        link
        fedilink
        arrow-up
        21
        ·
        1 day ago

        have to check and destructure the result of every function call

        Learn how to use enum error types, how error bubbling works, and how to convert between Options and Results.

        It’s Rust you are talking about, not Go.

        • rtxn@lemmy.world
          link
          fedilink
          arrow-up
          6
          ·
          1 day ago

          This isn’t about some feature of the language being good or bad. It’s about Rust being ugly or not. The things I mentioned will always look ugly in the source code.

          • 5C5C5C@programming.dev
            link
            fedilink
            arrow-up
            12
            ·
            22 hours ago

            It’s hilarious to me that people talk about “ugly” as if their opinions are objective.

            I found Rust unpleasant to look at for the first two weeks of learning it, and now that I’ve been using it professionally for three years I loathe when I need to read code in other languages.

            No other language can rival Rust in showing the exact information needed to understand the code — never too much and never too little — while being concise, correct, and handling all edge cases.

            You can be more concise in other languages, but it will come the loss of handling every little possible bug. You can be prettier in other languages, but it will come at the price of adding a lot of useless boilerplate.

            Of course there are cases where Rust can be verbose or confusing, but that’s when you’re doing very esoteric things that would be just as confusing in other languages.

            Like any opinion on aesthetics, how someone feels about the prettiness of a language will have far more to do with familiarity than with any objective metrics.

        • balsoft@lemmy.ml
          link
          fedilink
          arrow-up
          4
          ·
          edit-2
          1 day ago

          Sadly there’s still no truly good way to handle errors in rust. TBH I’m not sure if we as an industry have figured out an efficient, foolproof, composable, not overly verbose way to handle errors, so it’s not entirely on Rust.

          • calcopiritus@lemmy.world
            link
            fedilink
            arrow-up
            3
            ·
            8 hours ago

            Rust allows you to choose whatever method you want.

            • Early return propagating the error
            • Early return ignoring the error (maybe by returning a default value)
            • Explicit handling by if-else (or match) to distinguish between error and not error cases.
            • Early return and turn the error into another type that is easier to handle by the caller.
            • Assume there is no error, and just panic if there is. (.unwrap)

            There are only 2 error handling methods that you cannot do:

            • Exceptions
            • Ignore the error and continue execution

            And that is because both of them are bad because they allow you to do the second one, when .unwrap is just there and better.

            If your concept of “not ugly” is “I just want to see the happy path” then you either write bad code that is “not ugly” or write good code that is “ugly”. Because there is no language that allows you to handle errors while not having error handling code near where the errors are produced.

            • balsoft@lemmy.ml
              link
              fedilink
              arrow-up
              1
              ·
              7 hours ago

              I am well aware, I wrote quite a lot of Rust, including professionally. I’m not necessarily talking about the “clear happy path”, even though that is relatively nice to have (Rust sort-of allows that with the ? sugar and the pseudo-functor and pseudo-monad methods on wrappers); I’m talking more about the fine line between the overly verbose lists of all the errors that a function could produce (thiserror-style) or just a single messy error type that makes error handling difficult (anyhow-style). There surely must be something in between there that is concise, type-safe, and composable, but I haven’t seen it in any language yet.

              • calcopiritus@lemmy.world
                link
                fedilink
                arrow-up
                2
                ·
                6 hours ago

                In my case, I don’t usually encounter cases where I can’t just ?. But when I do, just make an error enum (kinda like thiserror) that encapsulates the possible errors + possibly adds more.

                On the call site, just convert to string if I don’t care about specifics (anyhow-style).

                I don’t find this much painful.

                Concise: not much on the declaration side, since you have to create an entire enum for each function in worst-case scenario. But on code side, it’s just .map_err(MyError)?.

                Type-safe: can’t beat errors as enum values wrapped in Result.

                Composable: i don’t think you can beat rust enums in composability.

                I don’t use anyhow/thiserror, so I’m not sure. But I believe thiserror fixes the conciseness issue for this.

                • balsoft@lemmy.ml
                  link
                  fedilink
                  arrow-up
                  1
                  ·
                  6 hours ago

                  thiserror helps a bit with conciseness. But it’s still the most annoying part of writing Rust for me, even more annoying than async closure capture semantics, and one that I happily offload to deepseek whenever I have to write it. I was even thinking of making some insane proc_macro that would traverse a function and extract the list of all ?, deduce the types, and come up with the final error type (maybe with some hints). But this turned out to be too difficult for a weekend project and ain’t nobody wants to pay me to write it.

                  Type-safe: can’t beat errors as enum values wrapped in Result.

                  I’m talking more about the anyhow-style here. It’s not very type-safe.

                  Composable: i don’t think you can beat rust enums in composability.

                  Well, thiserror-style enums are composable-ish, but they can be too structured for their own good. Sometimes you want only a particular property of an error (e.g. one of the HTTP requests returned 429 or something), and don’t care about the particular branch of the call tree it came from. Rust doesn’t really have the compile-time flexibility to write such a check without a ton of boilerplate that will also break once the call tree changes.

          • Ephera@lemmy.ml
            link
            fedilink
            English
            arrow-up
            1
            ·
            22 hours ago

            Yeah, I was gonna say, error handling easily makes up 80+% of the code paths, and depending on whether you’re building a library or service or script etc., different strategies are most suitable for how to deal with those code paths.

            In a script, you often just want it to crash. In a library, you want to make these code paths matchable, in case the user cares why something failed. And then you have the awkward in-between, which is that 99% of your application codebase will be used by your main-function like a library, but you don’t want to spend as much effort on error handling for that as a proper library does, in particular also because you know what all consumers of your application-library need to know.

            So, it’s kind of multiple different problems, with overlap, and people are hoping for one easy solution to cover all these problems.

      • Kacarott@aussie.zone
        link
        fedilink
        arrow-up
        11
        ·
        22 hours ago

        The majority of its syntax is very similar to many other languages. Can you give an example of a language with pretty syntax?

        • Lucy :3@feddit.org
          link
          fedilink
          arrow-up
          2
          ·
          20 hours ago

          Key point being, similar to some random languages. JS and Python Syntax don’t fit a typed and compiled language at all.

          Pretty syntax would probably be something like C, where not every single character already widely reserved for specific keywords (like !, ', =) is reused in completely random ways.

          • Kacarott@aussie.zone
            link
            fedilink
            arrow-up
            7
            ·
            edit-2
            18 hours ago

            Ah yes I also found macro syntax like vec![ and println!( to be a bit jarring at first. However I don’t know if I would say that C’s approach to macros is any nicer, with it’s #define magic

      • 5C5C5C@programming.dev
        link
        fedilink
        arrow-up
        3
        ·
        22 hours ago

        Being unable to give an actual example proves you’re just a foaming-mouth hater with nothing to contribute.

        • Lucy :3@feddit.org
          link
          fedilink
          arrow-up
          6
          ·
          20 hours ago

          From the first syntax examples on Wikipedia:

          fn main() {
              let foo = 10; 
              // Suddenly, types are implicit now. A safe language should never have implicit types (now it's the (IDEs) implementations judgement which type that is. Combined with the variable shadowing "feature", this seems like a major clusterfuck. Now the IDE is the sole thing to tell you that you totally fucked up the logic, and both declarations/definitions (well which one is it? Would be nice to always have a direct KEYWORD telling you which type this fucking variable has. But no, the lazy piece of shit Rust 'programmer' left that as an exercise to the dear reader. Because in they just need to leave that part out instead of explicitly stating "I'm a lazy piece of shit" by *instead* typing 'auto'.) This is just Python-level BS. Yes, I also hate C++ for its auto keyword - but at least it explicit.
              println!("The value of foo is {foo}");
              let foo = 20;
              println!("The value of foo is {foo}");
          }
          
          fn add_two(x: i32) -> i32 {
          // That is, again, the syntax of Python. Why? Because Python is explicitly untyped. So having types be a *literal* afterthought is Ok. They're fully optional anywhere there. Now we're in Rust. They're sometimes optional, sometimes not, but they're always preferred. Yet, they're also an afterthought, seemingly.
              x + 2
              // Implicit statements are bad. Very bad. They so much invite to glossing over stuff, especially when your brain expects to see something else. Also, having every statement ended with ;, except context blocks, but suddenly *not* having statements ending with ;, is fucking ugly (which is the entire point of this rant). It's completly inconsistent. Which in itself is a huge magnet for errors.
          }
          
          if x > 5 {
          // Now why would you leave the parantheses, which are a major contributor to readability, away. Or even allow this. Rust is just memory safe, like dozens of other mainstream languages, but continues by allowing, promoting and requiring hazardous practices.
              println!("value is greater than five");
          }
          

          Now I’m slowly getting annoyed from typing on phone (at least in nvim), and my throat gets clogged with mucus again.

          Remember, some of that are subjective preferences and opinions. And the core idea of Rust - fast but safe programs - is good, yet very obvious and not innovative at all, while the syntax and implementation (of cargo (yes I like to wait an hour for a simple webapp to compile because there aren’t binary crates and cargo just doesn’t multicore 99% of the time)) is subpar to something that’s hailed as the savior for everyone and everything by such a large cult.

          • fruitcantfly@programming.dev
            link
            fedilink
            arrow-up
            4
            ·
            9 hours ago

            In practice, type inference in Rust is not a problem since the language is so strongly typed. In fact, it is more strongly typed than both C and C++, and will force you to cast values explicitly in cases where C and C++ will happily mess up your variables without warning. The absence of type inference would also be a major pain, since nested types such as iterators can get quite complex and very verbose. If you’ve programmed using older C++ standards, then you know this pain

          • calcopiritus@lemmy.world
            link
            fedilink
            arrow-up
            2
            ·
            8 hours ago

            “not having mandatory parenthesis in if statements is hazardous, so I prefer to write C instead of rust, because I really care about safety” < that’s how you sound.

          • 5C5C5C@programming.dev
            link
            fedilink
            arrow-up
            17
            ·
            18 hours ago

            Types are not implicit, they’re inferred by the compiler when there is no ambiguity about what the type needs to be. This is a huge benefit for refactoring code and reducing maintenance. I acknowledge that sometimes you might care to know the exact type of the variable, and sometimes that’s not as easy for a human to infer as it is for the compiler, but every decent IDE will provide inline type hints for you. Interpreting code by reading it in plaintext is an exercise in masochism.

            Python is actually the opposite on this, and it’s one of Python’s worst characteristics. The type is unknown until runtime unless you annotate it, and then the annotation isn’t really enforced. It’s the worst of every dimension.

            C++11 introduced auto, and now the community is split between “almost always auto” and “never auto”.

            JavaScript needed a whole new compiled language (Typescript) to fix its type system problems, and Typescript is only an incremental improvement at best.

            Rust has the best type system of any modern language by far. If you’re tripped up by not always seeing the type declarations then you’re either focusing on the wrong details in the code or you just need a little more practice. The key thing that needs to sink in for new Rust users is that the compiler is always providing safety rails. That means it’s no longer your job to verify that every aspect of the code is correct. You can relax a little and actually have something akin to duck typing without all the pitfalls that usually come with it.

            • Shanmugha@lemmy.world
              link
              fedilink
              arrow-up
              1
              ·
              18 hours ago

              Sorry for intrusion, but mhm, nah. I get it there are people who want to play around and have language/compiler babysit them, but there are also people like me who want to see exactly what something is. So no, Rust, just like JavaScript, can be liked by some people, but it is in no way something that has “best type system”

              There actually is no such thing as best type system, same way there is no such thing as best language

              • 5C5C5C@programming.dev
                link
                fedilink
                arrow-up
                8
                ·
                16 hours ago

                I get it there are people who want to play around and have language/compiler babysit them, but there are also people like me who want to see exactly what something is.

                This is a false dichotomy when it comes to Rust. Despite everything I said and despite Lucy’s complaint, there is nothing that actually stops someone from explicitly annotating the exact type when declaring a variable. It’s just not required by the language, and most developers eventually realize that it’s not actually useful.

                You’re right that these preferences are subjective, be although much of that subjectivity has more to do with how our past experiences have shaped what we’re familiar with, rather than any intrinsic characteristics of person. By that I mean, someone who uses Rust enough will most likely come to like the way the general community styles its code, sooner or later. In the meantime you’re welcome to do things in a way that suits your needs.

                The only thing that Rust’s type system is weak on is runtime reflection. There are ways to achieve it within Rust’s type system, but it’s considerably more work than what you get in Python and JavaScript. Imo the only reason to choose a language other than Rust for a greenfield project is if you have a strong need for runtime reflection all over the place and aren’t very concerned about performance, threading, or avoiding entire categories of bugs that the Rust compiler protects you from.

                • Shanmugha@lemmy.world
                  link
                  fedilink
                  arrow-up
                  1
                  ·
                  14 hours ago

                  or that I don’t want to twist my brain with Rust way of things. But I agree with you on everything else :)

              • [object Object]@lemmy.world
                link
                fedilink
                arrow-up
                3
                ·
                14 hours ago

                If you don’t realize that x = 10 denotes an integer of some default length, and that y = 10.0 is a float, then the language isn’t the problem.

                  • [object Object]@lemmy.world
                    link
                    fedilink
                    arrow-up
                    4
                    ·
                    edit-2
                    11 hours ago

                    You betray so much of what your programming environment is like, with that comment. Because, you see, if you can’t behold the first x= expression on the same screen or, at very worst, the one above, then your code is majorly and deplorably fucked. It’s utterly trashed and is in immediate need of repair. If scrolling back to the first x= expression is overwhelming and exhausting work for you, then the codebase that you work in is mutilated beyond belief and any immediate hope. You need to drop what you’re doing, and get to unfucking you code right away so that you can have it in a comprehensible state that isn’t dependent on reminding the reader on every single line what stuff is like. You need to learn to split things in smaller things that humans can understand as their own self-contained units of meaning. When you reach the balance of formulating the code in self-contained units that can be comprehended easily, you won’t need type reminders on every line.

                    Not to mention that if you name your identifiers properly, you won’t have to wonder what their type should be.

          • [object Object]@lemmy.world
            link
            fedilink
            arrow-up
            11
            ·
            20 hours ago

            If you don’t understand how having any statement be an expression is useful, you don’t have enough experience to criticize programming languages.